Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

223 heatload graph #288

Merged
merged 32 commits into from
Jan 15, 2025
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
3310626
Use rules engine output to populate heat load graph
derekvmcintire Dec 18, 2024
6abc5ae
update graph record type
derekvmcintire Dec 18, 2024
6753faa
run prettier for select files
derekvmcintire Dec 18, 2024
f27f962
fix dataKeys
derekvmcintire Dec 18, 2024
bccf96c
Use correct data and make chart pretty
derekvmcintire Dec 18, 2024
1c596d1
Graph working, but needs clean up
derekvmcintire Dec 19, 2024
cb5e6a2
Clean up and comments
derekvmcintire Dec 19, 2024
3b186ea
Comments on calculation functions
derekvmcintire Dec 19, 2024
25484de
Add icon, still need to add values underneath chart
derekvmcintire Dec 19, 2024
cd2b386
restore ws changes to types
derekvmcintire Dec 19, 2024
e6b14c4
Add columns at bottom of chart
derekvmcintire Dec 19, 2024
413d7d5
Fix reversed average and max in grid
derekvmcintire Dec 19, 2024
0b1ebd9
Fix responsiveness issues
derekvmcintire Dec 19, 2024
f57e751
Extract utility and data building functions, tool tip and constants
derekvmcintire Dec 20, 2024
35c1b5a
Add comment with link to external calculation docs
derekvmcintire Dec 20, 2024
0cd25a7
Fix tool tip
derekvmcintire Dec 20, 2024
bb63730
quick refactor
derekvmcintire Dec 23, 2024
5ee0994
clean up
derekvmcintire Dec 23, 2024
2bc4388
refactor calculating min and max for Y axis
derekvmcintire Dec 24, 2024
31053fc
set start and end temps once
derekvmcintire Dec 24, 2024
4b2d841
Add 2f to x axis so tool tip is easier to invoke
derekvmcintire Dec 24, 2024
caba695
review changes to HeatLoad.tsx
derekvmcintire Jan 8, 2025
dec9c09
All issues except legend and tool type type errors addressed
derekvmcintire Jan 8, 2025
490f351
legend working with valid value for layout
derekvmcintire Jan 8, 2025
0c730a6
break out legend and fix avg heat load endpoint
derekvmcintire Jan 8, 2025
939ac5d
Adjust x axis ticks and make design set point a global constant
derekvmcintire Jan 9, 2025
9f9fa36
fix HeatLoadGraphToolTip type error
derekvmcintire Jan 9, 2025
ce80565
Remove hard coded data
derekvmcintire Jan 9, 2025
c55f438
Add comment to calculateAvgHeatLoadEndPoint
derekvmcintire Jan 14, 2025
19ab87e
comment out inclusion_override
derekvmcintire Jan 15, 2025
7598fb4
Fix type errors
derekvmcintire Jan 15, 2025
ad87ed5
re-comment tsconfig
derekvmcintire Jan 15, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,48 +1,190 @@
import React, { useMemo } from 'react'
import {
ScatterChart,
Scatter,
ComposedChart,
Line,
XAxis,
YAxis,
CartesianGrid,
Tooltip,
ResponsiveContainer,
Legend,
Label,
Scatter,
} from 'recharts'
import { SummaryOutputSchema } from '../../../../../../types/types'
import { Icon } from '../../../icon'
import { HeatLoadGrid } from '../HeatLoadGrid'
import {
COLOR_GREY_LIGHT,
COLOR_WHITE,
COLOR_ORANGE,
COLOR_BLUE,
} from '../constants'
import {
calculateAvgHeatLoad,
calculateMaxHeatLoad,
} from '../utility/heat-load-calculations'
import { buildHeatLoadGraphData } from '../utility/build-heat-load-graph-data'
import { HeatLoadGraphToolTip } from './HeatLoadGraphToolTip'

type HeatLoadProps = {
heatLoadSummaryOutput: SummaryOutputSchema
}

/**
* HeatLoad component renders a chart displaying the heating system demand based on different outdoor temperatures.
* It includes two lines for the maximum and average heat loads, with scatter points at the design temperature.
*
* @param {HeatLoadProps} props - The props containing heat load data to render the chart.
* @returns {JSX.Element} - The rendered chart component.
*/
export function HeatLoad({
heatLoadSummaryOutput,
}: HeatLoadProps): JSX.Element {
const designSetPoint = 70 // Design set point (70°F), defined in external documentation
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved
const { design_temperature } = heatLoadSummaryOutput
const startTemperature = design_temperature - 10 // Start line 10f below design temperature for clarity
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved
const endTemperature = designSetPoint + 2 // end the X axis at the designSetPoint plus 2f for clarity
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved

// data from Karle Heat Load Analysis Beta 7 2023-07-11
const data = [
{ x: 0, y: 74015 },
{ x: 60.5, y: 10045 },
{ x: 67, y: 3172 },
{ x: 70, y: 0 },
{ x: 8.4, y: 65133 },
]
/**
* useMemo to build the HeatLoad graph data.
*/
const data = useMemo(() => {
return buildHeatLoadGraphData(
heatLoadSummaryOutput,
startTemperature,
designSetPoint,
endTemperature,
)
}, [heatLoadSummaryOutput])

/**
* useMemo to iterate through the data and calculate the min and max values for the Y axis.
*/
const { minYValue, maxYValue } = useMemo(() => {
let minValue = Infinity
let maxValue = 0

for (const point of data) {
const maxLine = point.maxLine || 0
const avgLine = point.avgLine || 0

minValue = Math.min(minValue, maxLine || Infinity, avgLine || Infinity)
maxValue = Math.max(maxValue, maxLine, avgLine)
}

const minY = Math.max(0, Math.floor((minValue * 0.8) / 10000) * 10000) // 20% buffer
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might want to put some of these hardcoded files into a configuration file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

min Y value can be hardcoded to zero**

const maxY = Math.ceil((maxValue * 1.3) / 10000) * 10000 // 30% buffer
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved

return { minYValue: minY, maxYValue: maxY }
}, [data])

export function HeatLoad() {
return (
<div>
<div className="item-title">Heating System Demand</div>
<div className="min-w-[625px] rounded-lg shadow-lg">
<span className="mb-4 text-lg font-semibold">
Heating System Demand <Icon name="question-mark-circled" size="md" />{' '}
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved
</span>

<ResponsiveContainer width="100%" height={400}>
<ScatterChart
<ComposedChart
margin={{
top: 20,
right: 20,
bottom: 20,
bottom: 50,
left: 100,
}}
data={data}
>
<CartesianGrid />
<CartesianGrid stroke={COLOR_GREY_LIGHT} />
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved

<XAxis
type="number"
dataKey="x"
name=" Outdoor Temperature"
unit="°F"
dataKey="temperature"
name="Outdoor Temperature"
domain={[startTemperature, endTemperature]}
derekvmcintire marked this conversation as resolved.
Show resolved Hide resolved
tickCount={endTemperature - startTemperature + 1} // Ensure whole number ticks
>
<Label
value="Outdoor Temperature (°F)"
position="bottom"
offset={20}
/>
</XAxis>

<YAxis type="number" name="Heat Load" domain={[minYValue, maxYValue]}>
<Label
value="Heat Load (BTU/h)"
position="left"
angle={-90}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we move the label more to the center easily?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was not able to get to this

offset={30}
/>
</YAxis>

<Tooltip content={<HeatLoadGraphToolTip />} />

<Legend
wrapperStyle={{
backgroundColor: COLOR_WHITE,
border: `1px solid #ddd`,
borderRadius: '3px',
padding: '15px',
}}
align="right"
verticalAlign="top"
layout="middle"
/>

{/* Line for maximum heat load */}
<Line
type="monotone"
dataKey="maxLine"
stroke={COLOR_ORANGE}
dot={false}
name="Maximum, no internal or solar gain"
/>

{/* Line for average heat load */}
<Line
type="monotone"
dataKey="avgLine"
stroke={COLOR_BLUE}
dot={false}
name="Average, with internal & solar gain"
/>

{/* Scatter point for maximum heat load at design temperature */}
<Scatter
dataKey="maxPoint"
fill={COLOR_ORANGE}
name="Maximum at design temperature"
shape="diamond"
legendType="diamond"
/>
<YAxis type="number" dataKey="y" name=" Heat Load" unit=" BTU/h" />
<Tooltip cursor={{ strokeDasharray: '3 3' }} />
<Scatter name="Heat Load" data={data} fill="#8884d8" />
</ScatterChart>

{/* Scatter point for average heat load at design temperature */}
<Scatter
dataKey="avgPoint"
fill={COLOR_BLUE}
name="Average at design temperature"
shape="diamond"
legendType="diamond"
/>
</ComposedChart>
</ResponsiveContainer>

<HeatLoadGrid
setPoint={designSetPoint}
averageHeatLoad={calculateAvgHeatLoad(
heatLoadSummaryOutput,
design_temperature,
designSetPoint,
)}
maxHeatLoad={calculateMaxHeatLoad(
heatLoadSummaryOutput,
design_temperature,
designSetPoint,
)}
/>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react'
import { TooltipProps, TooltipItem } from 'recharts'

type HeatLoadGraphToolTipProps = {
payload: TooltipItem[]
}

/**
* CustomTooltip renders a tooltip for the heat load chart.
* @param {object} props - The props containing data for the tooltip.
* @returns {JSX.Element} - The rendered tooltip element.
*/
export const HeatLoadGraphToolTip = (
props: HeatLoadGraphToolTipProps,
): JSX.Element => {
const { payload } = props
const temperature = payload ? payload[0]?.payload?.temperature : null
const value = payload ? payload[0]?.value : null
const name = payload && payload[0] ? payload[0].name : ''

if (temperature !== null) {
return (
<div className="tooltip-content rounded border border-gray-300 bg-white p-2">
<div>{`${Number(value).toLocaleString()} BTU/h`}</div>
<div>{`${temperature}°F ${name?.replace('Line', ' Heat Load').replace('Point', ' at Design Temperature')}`}</div>
</div>
)
}

return (
<div className="tooltip-content rounded border border-gray-300 bg-white p-2">
<div>{`${Number(value).toLocaleString()} BTU/h`}</div>
<div>
{name
?.replace('Line', ' Heat Load')
.replace('Point', ' at Design Temperature')}
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
// import { AnalysisHeader } from './AnalysisHeader.tsx'
import React from 'react'
import { HeatLoad } from './Graphs/HeatLoad.tsx'
import { WholeHomeUAComparison } from './Graphs/WholeHomeUAComparison.tsx'

export function Graphs() {
interface GraphsProps {
heatLoadSummaryOutput: any;
}

export function Graphs({ heatLoadSummaryOutput }: GraphsProps) {
const fuel_type = 'Natural Gas'
const titleClassTailwind = 'text-5xl font-extrabold tracking-wide'
const componentMargin = 'mt-10'
Expand All @@ -14,7 +19,7 @@ export function Graphs() {
Fuel Type
{fuel_type}
{/* <AnalysisHeader /> */}
<HeatLoad />
<HeatLoad heatLoadSummaryOutput={heatLoadSummaryOutput} />
<WholeHomeUAComparison />
</div>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import React from 'react'

type HeatLoadGridProps = {
setPoint: number
averageHeatLoad: number
maxHeatLoad: number
}

/**
* HeatLoadGrid is a stateless functional component that displays key summary data
* in a grid format. The grid includes the set point temperature, maximum heat load,
* and average heat load values.
*
* @component
* @param {ChartGridProps} props - The props for the HeatLoadGrid component.
* @param {number} props.setPoint - The set point temperature in degrees Fahrenheit.
* @param {number} props.averageHeatLoad - The average heat load in BTU/h.
* @param {number} props.maxHeatLoad - The maximum heat load in BTU/h.
* @returns {JSX.Element} - A styled grid displaying the set point, max heat load, and average heat load.
*/
export const HeatLoadGrid = ({
setPoint,
averageHeatLoad,
maxHeatLoad,
}: ChartGridProps) => {
return (
<div className="container mx-auto p-4">
<div className="grid grid-cols-3 gap-4">
{/* Grid Item 1 */}
<div className="flex items-center justify-center border-r-2 border-gray-300 p-6">
<div className="flex flex-col items-center">
<div className="text-gray-500">Set Point</div>
<div className="font-semibold">{`${setPoint} °F`}</div>
</div>
</div>

{/* Grid Item 2 */}
<div className="flex items-center justify-center border-r-2 border-gray-300 p-6">
<div className="flex flex-col items-center">
<div className="text-gray-500">Max Heat Load</div>
<div className="font-semibold">{`${maxHeatLoad} BTU/h`}</div>
</div>
</div>

{/* Grid Item 3 */}
<div className="flex items-center justify-center p-6">
<div className="flex flex-col items-center">
<div className="text-gray-500">Average Heat Load</div>
<div className="font-semibold">{`${averageHeatLoad} BTU/h`}</div>
</div>
</div>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Constants for chart styling
export const COLOR_ORANGE = '#FF5733'
export const COLOR_BLUE = '#8884d8'
export const COLOR_GREY = '#999999'
export const COLOR_GREY_LIGHT = '#f5f5f5'
export const COLOR_WHITE = '#fff'
Loading