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