Skip to content

Commit

Permalink
highlights and crosshair are now disabled if the dataset is empty, cr…
Browse files Browse the repository at this point in the history
…oshair values are only displayed for visible lines.
  • Loading branch information
lmueller27 committed Jul 9, 2023
1 parent 65cfefa commit 8f5da87
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 46 deletions.
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
# Is today / this week / this month hotter than usual?

This web app lets you visualize and compare weather trends for any geolocation.
This web app lets you visualize and compare weather/climate trends for any geolocation.
Inspect historical data for any specific date, calender week or month in a timespan from 1940 until today.


A [Next.js](https://nextjs.org/) app using [React-Vis](https://uber.github.io/react-vis/), [Pigeon Maps](https://pigeon-maps.js.org), and the [Open Meteo API](https://open-meteo.com).

![usagegif](public/readme/usage.gif)

Trends are computed in line with the National Center for Atmospheric Research Staff (Eds). Last modified 05 Sep 2014. "The Climate Data Guide: Trend Analysis." Retrieved from [here](https://climatedataguide.ucar.edu/climate-data-tools-and-analysis/trend-analysis).
## Usage

- History of Target Date: Visualizes the development of climate data at the target date for the specified location.
- History of Target Week: Visualizes the development of climate data at the target dates calender week.
- History of Target Month: Visualizes the development of climate data in the target dates month.
- Whole Interval: Shows data for each day in the specified interval. Limited to intervals up to 10 years.

This is a [Next.js](https://nextjs.org/) app using [React-Vis](https://uber.github.io/react-vis/), [Pigeon Maps](https://pigeon-maps.js.org), and the [Open Meteo API](https://open-meteo.com).
Using the '+ Add Series' button more data series can be generated for comparison.
The legend can be used to toggle certain information on or off.

Trends are computed in line with the National Center for Atmospheric Research Staff (Eds). Last modified 05 Sep 2014. "The Climate Data Guide: Trend Analysis." Retrieved from [here](https://climatedataguide.ucar.edu/climate-data-tools-and-analysis/trend-analysis).

## Try it out

Expand All @@ -28,3 +39,4 @@ npm run dev
Open [http://localhost:3000](http://localhost:3000) to use the app.



7 changes: 4 additions & 3 deletions app/components/form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export default function Form(props: any) {
})

const [state, setState] = useState<formState>({
tempData: [[{ x: null, y: 0 }], [{ x: null, y: 0 }], [{ x: null, y: 0 }], [{ x: null, y: 0 }]],
tempData: [[{ x: todaysDate, y: 20 }], [{ x: todaysDate, y: 20 }], [{ x: todaysDate, y: 20 }], [{ x: todaysDate, y: 20 }]],
tempDataMedian: [],
tempDataMean: [],
crosshairValues: [],
Expand Down Expand Up @@ -96,10 +96,11 @@ export default function Form(props: any) {
<h4>Click on the series to freeze/unfreeze the tooltip. Drag to zoom in.</h4>
<div className={styles.figureSpace}>
<div className={styles.graphSpace}>
<AutoSizer disableHeight>
<AutoSizer disableHeight >
{({ width }: any) => (
<WeatherPlot state={state} setState={setState} width={width} />
)}</AutoSizer>
)}
</AutoSizer>
</div>
<PlotControls props={props} state={state} setState={setState} width={100} />
</div>
Expand Down
97 changes: 57 additions & 40 deletions app/components/weatherPlot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,58 +19,75 @@ export function WeatherPlot({ state, setState, width }: { state: formState, setS
lastDrawLocation.left,
lastDrawLocation.right
]
}
>
<HorizontalGridLines />
<XAxis title="" attr="x" />
}>
{state.currentVisMode === null ? <XAxis title="" attr="x" hideTicks /> : <XAxis title="" attr="x" />}
<YAxis title="Temp °C // mm" attr="y" />
<HorizontalGridLines />
{state.showMax ? <LineSeries color={myColors.Red} opacity={0.7} onNearestX={(value, { index }) => { !state.keepCrosshair ? setState({ ...state, crosshairValues: state.tempData.map(d => d[index]) }) : null }} data={state.tempData[0]} /> : null}
{state.showMax ? <AreaSeries color={myColors.Red} opacity={0.3} onNearestX={(value, { index }) => { !state.keepCrosshair ? setState({ ...state, crosshairValues: state.tempData.map(d => d[index]) }) : null }} data={state.tempData[0]} /> : null}
{state.showMean ? <LineSeries color={myColors.Green} onNearestX={(value, { index }) => { !state.keepCrosshair ? setState({ ...state, crosshairValues: state.tempData.map(d => d[index]) }) : null }} data={state.tempData[1]} /> : null}
{state.showMin ? <LineSeries color={myColors.Blue} opacity={1} onNearestX={(value, { index }) => { !state.keepCrosshair ? setState({ ...state, crosshairValues: state.tempData.map(d => d[index]) }) : null }} data={state.tempData[2]} /> : null}
{state.showMin ? <AreaSeries color={myColors.Blue} opacity={0.8} onNearestX={(value, { index }) => { !state.keepCrosshair ? setState({ ...state, crosshairValues: state.tempData.map(d => d[index]) }) : null }} data={state.tempData[2]} /> : null}
{state.showMedian ? <LineSeries color={myColors.Yellow} strokeStyle="solid" data={state.tempDataMedian} /> : null}
{state.showTrend && state.showMax ? <LineSeries strokeStyle="dashed" color={myColors.Red} data={leastSquaresLinearRegression(state.tempData[0])} /> : null}
{state.showTrend && state.showMean ? <LineSeries strokeStyle="dashed" color={myColors.Green} data={leastSquaresLinearRegression(state.tempData[1])} /> : null}
{state.showTrend && state.showMin ? <LineSeries strokeStyle="dashed" color={'white'} data={leastSquaresLinearRegression(state.tempData[2])} /> : null}
{state.showTrend && state.tempData[0] && state.showMax ? <LineSeries strokeStyle="dashed" color={myColors.Red} data={leastSquaresLinearRegression(state.tempData[0])} /> : null}
{state.showTrend && state.tempData[1] && state.showMean ? <LineSeries strokeStyle="dashed" color={myColors.Green} data={leastSquaresLinearRegression(state.tempData[1])} /> : null}
{state.showTrend && state.tempData[2] && state.showMin ? <LineSeries strokeStyle="dashed" color={'white'} data={leastSquaresLinearRegression(state.tempData[2])} /> : null}
{state.showPrec ? <LineSeries color={'lightblue'} curve={'curveStep'} data={state.tempData[3]} /> : null}
{state.showPrec ? <LineSeries color={'black'} data={leastSquaresLinearRegression(state.tempData[3])} /> : null}
{state.crosshairValues[0] ? <Crosshair className={styles.test}
values={state.crosshairValues}
style={{box:{background: 'rgba(80, 80, 80, 0.8)'}}}
titleFormat={(d) => {
if (state.currentVisMode===visualizationModes.MonthHistory){
return {title: 'x', value:`${d[0].x.getFullYear()} ${months[d[0].x.getMonth()+1]}`}
}
else if (state.currentVisMode===visualizationModes.WeekHistory) {
const weekInfo = getWeekNumber(d[0].x)
return {title: 'x', value: `${weekInfo[0]}-W${weekInfo[1]}`}
}
else {
return {title: 'x', value:d[0].x.toDateString()};
}
}}
itemsFormat={(d) => [{ title: 'max', value: d[0].y }, { title: 'mean', value: d[1].y }, { title: 'min', value: d[2].y }]}>
</Crosshair> : null}
{state.crosshairValues.length === 0 ? null : <MarkSeries
data={fetchMarkerData()}
color={'white'}
stroke="gray " />
{state.crosshairValues[0] && state.currentVisMode !== null ?
<Crosshair className={styles.test}
values={state.crosshairValues}
style={{ box: { background: 'rgba(80, 80, 80, 0.8)' } }}
titleFormat={(d) => {
if (state.currentVisMode === visualizationModes.MonthHistory) {
return { title: 'x', value: `${d[0].x.getFullYear()} ${months[d[0].x.getMonth() + 1]}` }
}
else if (state.currentVisMode === visualizationModes.WeekHistory) {
const weekInfo = getWeekNumber(d[0].x)
return { title: 'x', value: `${weekInfo[0]}-W${weekInfo[1]}` }
}
else {
return { title: 'x', value: d[0].x.toDateString() };
}
}}
itemsFormat={(d) => {
let res = []
if (state.showMax) {
res.push({ title: 'max', value: d[0].y })
}
if (state.showMean) {
res.push({ title: 'mean', value: d[1].y })
}
if (state.showMin) {
res.push({ title: 'min', value: d[2].y })
}
if (state.showPrec) {
res.push({ title: 'prec', value: d[3].y })
}
return res
}}>
</Crosshair> : null}
{state.crosshairValues.length === 0 || state.currentVisMode === null ? null :
<MarkSeries
data={fetchMarkerData()}
color={'white'}
stroke="gray " />
}
<Highlight
enableY={false}
onBrushEnd={area => {
if (area == null) { // either a simple click or reset zoom
if (lastDrawLocation) {
{state.currentVisMode === null ? null :
<Highlight
enableY={false}
onBrushEnd={area => {
if (area == null) { // either a simple click or reset zoom
if (lastDrawLocation) {
setState({ ...state, keepCrosshair: !state.keepCrosshair })
}
}
else {
setState({ ...state, keepCrosshair: !state.keepCrosshair })
}
}
else {
setState({ ...state, keepCrosshair: !state.keepCrosshair })
}
setLastDrawLocation(area)
}}
/>
setLastDrawLocation(area)
}} />
}
</XYPlot>
)

Expand Down

0 comments on commit 8f5da87

Please sign in to comment.