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: " NdviDifferenceGraph" ,
29+ setup () {
30+ const weatherData = ref (null );
31+ const startDate = ref (" 2018-01-01" );
32+ const endDate = ref (" 2024-12-05" );
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 NDVI (2018-2021) in ${
54+ months .value [selectedMonth .value ]
55+ } for Tempelhofer Feld` ;
56+ });
57+
58+ // Fetch and calculate historical means for all months (2018-2021)
59+ const fetchHistoricalMeans = async () => {
60+ const apiUrl = " https://thf-climate-run-1020174331409.europe-west3.run.app/index/ndvi" ;
61+ const params = {
62+ startDate: new Date (" 2018-01-01" ).getTime () / 1000 ,
63+ endDate: new Date (" 2021-12-31" ).getTime () / 1000 ,
64+ location: " TEMPELHOFER_FELD" ,
65+ temporalResolution: " MONTHLY" ,
66+ aggregation: " MEAN" ,
67+ };
68+
69+ try {
70+ const response = await axios .get (apiUrl, { params });
71+ const data = response .data ? .data ;
72+
73+ if (! data || ! Array .isArray (data)) {
74+ console .error (" Unexpected data format for historical means:" , response);
75+ return ;
76+ }
77+
78+ // Calculate means for each month (0 = January, 1 = February, etc.)
79+ const monthlyMeans = Array (12 ).fill (0 ).map ((_ , monthIndex ) => {
80+ const monthData = data .filter ((entry ) => {
81+ const date = new Date (entry .timestamp * 1000 );
82+ return date .getMonth () === monthIndex;
83+ });
84+
85+ const temperatures = monthData .map ((entry ) => entry .value );
86+ const total = temperatures .reduce ((sum , temp ) => sum + temp, 0 );
87+ return temperatures .length > 0 ? total / temperatures .length : null ;
88+ });
89+
90+ historicalMeans .value = monthlyMeans;
91+ } catch (error) {
92+ console .error (" Error fetching historical means:" , error);
93+ }
94+ };
95+
96+ // Fetch current weather data
97+ const fetchData = async () => {
98+ const apiUrl = " https://thf-climate-run-1020174331409.europe-west3.run.app/index/ndvi" ;
99+ const params = {
100+ startDate: new Date (startDate .value ).getTime () / 1000 ,
101+ endDate: new Date (endDate .value ).getTime () / 1000 ,
102+ location: " TEMPELHOFER_FELD" ,
103+ temporalResolution: " MONTHLY" ,
104+ aggregation: " MEAN" ,
105+ };
106+
107+ try {
108+ const response = await axios .get (apiUrl, { params });
109+ weatherData .value = response .data ;
110+ processData (response .data );
111+ renderPlot ();
112+ } catch (error) {
113+ console .error (" Error fetching NDVI data:" , error);
114+ }
115+ };
116+
117+ // Process data to compute deviations for the selected month
118+ const processData = (apiResponse ) => {
119+ if (! apiResponse .data || ! Array .isArray (apiResponse .data )) {
120+ console .log (" Unexpected data format:" , apiResponse);
121+ return ;
122+ }
123+
124+ const historicalMean = historicalMeans .value [selectedMonth .value ];
125+ if (historicalMean === null ) {
126+ console .error (` No historical mean available for month: ${ selectedMonth .value } ` );
127+ return ;
128+ }
129+
130+ const filteredData = apiResponse .data .filter ((entry ) => {
131+ const date = new Date (entry .timestamp * 1000 );
132+ return date .getMonth () === selectedMonth .value ;
133+ });
134+
135+ const years = filteredData .map ((entry ) =>
136+ new Date (entry .timestamp * 1000 ).getFullYear ().toString ()
137+ );
138+ const deviations = filteredData .map (
139+ (entry ) => entry .value - historicalMean
140+ );
141+
142+ plotData .value = [
143+ {
144+ x: years,
145+ y: deviations,
146+ type: " bar" ,
147+ name: months .value [selectedMonth .value ],
148+ marker: {
149+ color: deviations .map ((dev ) =>
150+ dev >= 0 ? " darkred" : " darkblue"
151+ ),
152+ },
153+ text: deviations .map ((dev ) => ` ${ dev .toFixed (2 )} ` ),
154+ hoverinfo: " text" ,
155+ textposition: " none" ,
156+ },
157+ ];
158+ };
159+
160+ // Render the Plotly chart
161+ const renderPlot = () => {
162+ const layout = {
163+ title: graphTitle .value ,
164+ xaxis: { title: " Year" , type: " category" },
165+ yaxis: { title: " Deviation from 2018-2021 Mean" },
166+ template: " plotly_white" ,
167+ };
168+
169+ Plotly .newPlot (plotlyChart .value , plotData .value , layout);
170+ };
171+
172+ // Fetch all necessary data and render the chart
173+ const fetchAndRender = async () => {
174+ await fetchHistoricalMeans (); // Fetch historical means once
175+ await fetchData (); // Fetch main data
176+ };
177+
178+ const updateGraph = () => {
179+ if (startDate .value && endDate .value ) {
180+ fetchData (); // Only fetch main data, since historical means are already cached
181+ }
182+ };
183+
184+ onMounted (() => {
185+ fetchAndRender ();
186+ });
187+
188+ return {
189+ weatherData,
190+ startDate,
191+ endDate,
192+ selectedMonth,
193+ months,
194+ updateGraph,
195+ plotlyChart,
196+ graphTitle,
197+ historicalMeans,
198+ };
199+ },
200+ };
201+ < / script>
202+
203+ < style scoped>
204+ h2 {
205+ text- align: center;
206+ margin- bottom: 10px ;
207+ }
208+
209+ .date - picker {
210+ display: flex;
211+ justify- content: center;
212+ gap: 10px ;
213+ margin- bottom: 20px ;
214+ }
215+ < / style>
216+
0 commit comments