Skip to content

Commit 1b9f484

Browse files
authored
Merge pull request #35 from codeuniversity/feature/difference-graphs
Add difference graphs for temperature and soil temperature
2 parents 29365c5 + 3b87a0e commit 1b9f484

File tree

4 files changed

+443
-1
lines changed

4 files changed

+443
-1
lines changed

frontend/src/components/MainSection.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
<MeanSoilMoistureGraph />
1212
<AugustMeanSoilTempGraph />
1313
<SelectMonthMeanSoilTempGraph />
14+
<TempDifferenceGraph />
15+
<SoilTempDifferenceGraph />
1416
</v-container>
1517
</template>
1618

@@ -26,6 +28,8 @@ import AugustMeanSoilTempGraph from "./WeatherGraphs/AugustSoilTempGraph.vue"
2628
import SelectMonthMeanSoilTempGraph from "./WeatherGraphs/SelectMonthSoilTempGraph.vue"
2729
import TemperatureNdviBarAndLine from "./CorrelationGraphs/TemperatureNdviBarAndLine.vue"
2830
import TemperatureNdviScatter from "./CorrelationGraphs/TemperatureNdviScatter.vue"
31+
import TempDifferenceGraph from "./WeatherGraphs/TempDifferenceGraph.vue"
32+
import SoilTempDifferenceGraph from "./WeatherGraphs/SoilTempDifferenceGraph.vue"
2933
3034
export default {
3135
name: 'MainSection',
@@ -39,6 +43,8 @@ export default {
3943
MeanSoilMoistureGraph,
4044
AugustMeanSoilTempGraph,
4145
SelectMonthMeanSoilTempGraph,
46+
TempDifferenceGraph,
47+
SoilTempDifferenceGraph,
4248
TemperatureNdviBarAndLine,
4349
TemperatureNdviScatter
4450
}

frontend/src/components/WeatherGraphs/SoilMoistureGraph.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
const apiUrl = 'https://thf-climate-run-1020174331409.europe-west3.run.app/weather/index';
4040
4141
const params = {
42-
weatherVariable: "soil_temperature_0_to_7cm",
42+
weatherVariable: "soil_moisture_0_to_7cm",
4343
startDate: new Date(startDate.value).getTime() / 1000,
4444
endDate: new Date(endDate.value).getTime() / 1000,
4545
location: "TEMPELHOFER_FELD",
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<template>
2+
<div>
3+
<h2>{{ graphTitle }}</h2>
4+
5+
<!-- Month Picker -->
6+
<div class="date-picker">
7+
<label>
8+
Select Month:
9+
<select v-model="selectedMonth" @change="updateGraph">
10+
<option v-for="(month, index) in months" :key="index" :value="index">
11+
{{ month }}
12+
</option>
13+
</select>
14+
</label>
15+
</div>
16+
17+
<!-- Plotly Chart -->
18+
<div ref="plotlyChart" style="width: 100%; height: 400px;"></div>
19+
</div>
20+
</template>
21+
22+
<script>
23+
import { ref, onMounted, computed } from "vue";
24+
import axios from "axios";
25+
import Plotly from "plotly.js-dist-min";
26+
27+
export default {
28+
name: "SoilTempDifferenceGraph",
29+
setup() {
30+
const weatherData = ref(null);
31+
const startDate = ref("1990-01-01");
32+
const endDate = ref("2023-12-31");
33+
const selectedMonth = ref(0); // Default to January (0-indexed)
34+
const months = ref([
35+
"January",
36+
"February",
37+
"March",
38+
"April",
39+
"May",
40+
"June",
41+
"July",
42+
"August",
43+
"September",
44+
"October",
45+
"November",
46+
"December",
47+
]);
48+
const plotData = ref([]);
49+
const plotlyChart = ref(null);
50+
const historicalMeans = ref([]);
51+
52+
const graphTitle = computed(() => {
53+
return `Difference from Mean Soil Temperature (1990-2008) in ${
54+
months.value[selectedMonth.value]
55+
} for Tempelhofer Feld`;
56+
});
57+
58+
// Fetch and calculate historical means for all months (1990-2008)
59+
const fetchHistoricalMeans = async () => {
60+
const apiUrl = "https://thf-climate-run-1020174331409.europe-west3.run.app/weather/index";
61+
const params = {
62+
weatherVariable: "soil_temperature_0_to_7cm",
63+
startDate: new Date("1990-01-01").getTime() / 1000,
64+
endDate: new Date("2008-12-31").getTime() / 1000,
65+
location: "TEMPELHOFER_FELD",
66+
temporalResolution: "MONTHLY",
67+
aggregation: "MEAN",
68+
};
69+
70+
try {
71+
const response = await axios.get(apiUrl, { params });
72+
const data = response.data?.data;
73+
74+
if (!data || !Array.isArray(data)) {
75+
console.error("Unexpected data format for historical means:", response);
76+
return;
77+
}
78+
79+
// Calculate means for each month (0 = January, 1 = February, etc.)
80+
const monthlyMeans = Array(12).fill(0).map((_, monthIndex) => {
81+
const monthData = data.filter((entry) => {
82+
const date = new Date(entry.timestamp * 1000);
83+
return date.getMonth() === monthIndex;
84+
});
85+
86+
const temperatures = monthData.map((entry) => entry.value);
87+
const total = temperatures.reduce((sum, temp) => sum + temp, 0);
88+
return temperatures.length > 0 ? total / temperatures.length : null;
89+
});
90+
91+
historicalMeans.value = monthlyMeans;
92+
} catch (error) {
93+
console.error("Error fetching historical means:", error);
94+
}
95+
};
96+
97+
// Fetch current weather data
98+
const fetchData = async () => {
99+
const apiUrl = "https://thf-climate-run-1020174331409.europe-west3.run.app/weather/index";
100+
const params = {
101+
weatherVariable: "soil_temperature_0_to_7cm",
102+
startDate: new Date(startDate.value).getTime() / 1000,
103+
endDate: new Date(endDate.value).getTime() / 1000,
104+
location: "TEMPELHOFER_FELD",
105+
temporalResolution: "MONTHLY",
106+
aggregation: "MEAN",
107+
};
108+
109+
try {
110+
const response = await axios.get(apiUrl, { params });
111+
weatherData.value = response.data;
112+
processData(response.data);
113+
renderPlot();
114+
} catch (error) {
115+
console.error("Error fetching temperature data:", error);
116+
}
117+
};
118+
119+
// Process data to compute deviations for the selected month
120+
const processData = (apiResponse) => {
121+
if (!apiResponse.data || !Array.isArray(apiResponse.data)) {
122+
console.log("Unexpected data format:", apiResponse);
123+
return;
124+
}
125+
126+
const historicalMean = historicalMeans.value[selectedMonth.value];
127+
if (historicalMean === null) {
128+
console.error(`No historical mean available for month: ${selectedMonth.value}`);
129+
return;
130+
}
131+
132+
const filteredData = apiResponse.data.filter((entry) => {
133+
const date = new Date(entry.timestamp * 1000);
134+
return date.getMonth() === selectedMonth.value;
135+
});
136+
137+
const years = filteredData.map((entry) =>
138+
new Date(entry.timestamp * 1000).getFullYear().toString()
139+
);
140+
const deviations = filteredData.map(
141+
(entry) => entry.value - historicalMean
142+
);
143+
144+
plotData.value = [
145+
{
146+
x: years,
147+
y: deviations,
148+
type: "bar",
149+
name: months.value[selectedMonth.value],
150+
marker: {
151+
color: deviations.map((dev) =>
152+
dev >= 0 ? "darkred" : "darkblue"
153+
),
154+
},
155+
text: deviations.map((dev) => `${dev.toFixed(2)}°C`),
156+
hoverinfo: "text",
157+
textposition: "none",
158+
},
159+
];
160+
};
161+
162+
// Render the Plotly chart
163+
const renderPlot = () => {
164+
const layout = {
165+
title: graphTitle.value,
166+
xaxis: { title: "Year", type: "category" },
167+
yaxis: { title: "Deviation from 1990-2008 Mean (°C)" },
168+
template: "plotly_white",
169+
};
170+
171+
Plotly.newPlot(plotlyChart.value, plotData.value, layout);
172+
};
173+
174+
// Fetch all necessary data and render the chart
175+
const fetchAndRender = async () => {
176+
await fetchHistoricalMeans(); // Fetch historical means once
177+
await fetchData(); // Fetch main data
178+
};
179+
180+
const updateGraph = () => {
181+
if (startDate.value && endDate.value) {
182+
fetchData(); // Only fetch main data, since historical means are already cached
183+
}
184+
};
185+
186+
onMounted(() => {
187+
fetchAndRender();
188+
});
189+
190+
return {
191+
weatherData,
192+
startDate,
193+
endDate,
194+
selectedMonth,
195+
months,
196+
updateGraph,
197+
plotlyChart,
198+
graphTitle,
199+
historicalMeans,
200+
};
201+
},
202+
};
203+
</script>
204+
205+
<style scoped>
206+
h2 {
207+
text-align: center;
208+
margin-bottom: 10px;
209+
}
210+
211+
.date-picker {
212+
display: flex;
213+
justify-content: center;
214+
gap: 10px;
215+
margin-bottom: 20px;
216+
}
217+
</style>
218+

0 commit comments

Comments
 (0)