-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdata.js
293 lines (265 loc) · 9.75 KB
/
data.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
// import {getDate} from './components.js';
// Latest data flow
// const date = getDate().toISOString().split('T')[0].split('-');
const splitCsvAt = "https://aeronet.gsfc.nasa.gov/new_web/site_info_v3";
// const allSites = 'https://aeronet.gsfc.nasa.gov/aeronet_locations_v3.txt'
// const api_args = `?year=2023&month=6&day=11&AOD15=1&AVG=10&if_no_html=1`
export async function getAllSites(year) {
try {
const response = await fetch(
`https://aeronet.gsfc.nasa.gov/Site_Lists_V3/aeronet_locations_v3_${year}_lev15.txt`,
{ method: "GET", mode: "no-cors" },
)
.then((response) => response.text())
.catch((error) => console.log(error));
const config = {
delimiter: ",",
newline: "\n",
header: true,
skipEmptyLines: true,
};
// console.log(response)
const data = response.split(`,${year}`)[1]; // CSV
const objs = await Papa.parse(data, config); // Avg for building js objects was ~7 ms
return objs.data;
} catch (error) {
console.error(error);
throw new Error("Failed to get data");
}
}
export async function getSitesData(args, dataType, date) {
const apiUrl = "https://aeronet.gsfc.nasa.gov/cgi-bin/print_web_data_v3";
try {
var response = await fetch(apiUrl.concat(args), {
method: "GET",
mode: "no-cors",
})
.then((response) => response.text())
.catch((error) => console.log(error));
const config = {
delimiter: ",",
newline: "\n",
header: true,
skipEmptyLines: true,
};
if (dataType.toString() === "20") {
// daily avg
// If mode is ALL POINT = 20
// validate API dates
const data = response.split(splitCsvAt)[1]; // CSV
const objs = await Papa.parse(data, config);
// validate time is correct -> fixes api returning wrong date
return validateTime(objs.data, date);
// return objs.data;
}
if (dataType.toString() === "10") {
// all points
// If mode is ALL POINT = 10
// console.log(response)
// Only keep points with an currentHr from current UTC times
const data = response.split(splitCsvAt)[1]; // CSV
const objs = await Papa.parse(data, config);
return withinTime(objs.data, date);
}
} catch (error) {
throw new Error("Failed to get from API, please check api headers.");
console.error(error);
}
}
// export async function processSiteList(data) {
// const promises = data.map( async (obj) => {
// const url = createUrl(obj['Site_Name']);
// const result = await fetch(url);
// const json = await result.json
// return json;
// });
// const results = await Promise.all(promises)
//
// return results
// }
function createUrl(site) {
return `https://aeronet.gsfc.nasa.gov/cgi-bin/print_web_data_v3?year=${date[0]}&month=${date[1]}&day=${date[2]}&AOD15=1&AVG=10&if_no_html=1&site=${site}`;
}
export async function getAvgUrl(site, endDate, startDate) {
return `https://aeronet.gsfc.nasa.gov/cgi-bin/print_web_data_v3?year=${startDate[0]}&month=${startDate[1]}&day=${startDate[2]}&year2=${endDate[0]}&month2=${endDate[1]}&day2=${endDate[2]}&AOD15=1&AVG=20&site=${site}&if_no_html=1`;
}
// export async function getAllDataUrl(site, timestart, timeend)
// {
// // Get averages for one week
// const date = new Date();
// date.setDate(date.getDate() - daysToAvg);
// let time = date.toLocaleDateString();
// time = time.split('/');
// let [month, day, year] = time
// return `https://aeronet.gsfc.nasa.gov/cgi-bin/print_web_data_v3?year=${year}&month=${month}&day=${day}&AOD15=1&AVG=20&if_no_html=1&site=${site}`
// }
export function validateTime(data, date) {
const site_date = "Date(dd:mm:yyyy)";
return data.filter((obj) => {
let year, month, day;
// Date(dd:mm:yyyy)
let [objDay, objMonth, objYear] = obj[site_date].split(":").map(Number);
if (date.length === 2) {
[year, month, day] = date[0].map(Number);
} else if (date.length === 3) {
[year, month, day] = date[1].map(Number);
}
const timestamp = new Date(objYear, objMonth, objDay).getTime();
const setDate = new Date(year, month, day).getTime();
return timestamp === setDate;
});
}
export function buildChartData(data, activeDepth, endDate, startDate) {
const chartData = data.map((obj) => {
if (!obj[activeDepth].toString().includes("-999")) {
// -999 represents inactive data
return {
x: obj["Date(dd:mm:yyyy)"],
y: obj[activeDepth],
};
}
});
const cleanedData = chartData.filter((obj) => obj !== undefined);
let [endYear, endMonth, endDay] = endDate.map(Number);
let [startYear, startMonth, startDay] = startDate.map(Number);
return cleanedData.filter((obj) => {
let [day, month, year] = obj.x.split(":").map(Number);
const timestamp = new Date(year, month - 1, day).getTime();
const min = new Date(startYear, startMonth - 1, startDay).getTime();
const max = new Date(endYear, endMonth - 1, endDay).getTime();
// if min <= timestamp <= max -> data is within range
return timestamp >= min && timestamp <= max;
});
}
export function fillChartData(chartData) {
if (chartData.length > 0) {
// first date of the array
let firstDate = new Date(chartData[0].x.split(":").reverse().join("-"));
// last date of the array
let lastDate = new Date(
chartData[chartData.length - 1].x.split(":").reverse().join("-"),
);
let dateArray = [];
// build dates between start and end date
for (
let dt = new Date(firstDate);
dt <= lastDate;
dt.setDate(dt.getDate() + 1)
) {
dateArray.push(
("0" + dt.getDate()).slice(-2) +
":" +
("0" + (dt.getMonth() + 1)).slice(-2) +
":" +
dt.getFullYear(),
);
}
// traverse data new data array and if value is null add a null value after the index of the previous date
dateArray.forEach((date, i) => {
if (!chartData.some((data) => data.x === date)) {
let nextDateIndex = chartData.findIndex(
(data) => data.x === dateArray[i + 1],
);
chartData.splice(nextDateIndex, 0, { x: date, y: null });
}
});
}
// removes redundant first entry of data.x and data.y which is always null
chartData.shift();
return chartData;
}
export async function getFullData(url) {
try {
const initial_key = "AERONET_Site,";
const response = await fetch(url, { method: "GET", mode: "no-cors" })
.then((response) => response.text())
.catch((error) => console.log(error));
const config = {
delimiter: ",",
newline: "\n",
header: true,
skipEmptyLines: true,
};
let data = response.split(initial_key)[1]; // CSV
data = `${initial_key}${data}`;
const objs = await Papa.parse(data, config); // Avg for building js objects was ~7 ms
return objs.data;
} catch (error) {
throw new Error("Failed to get data");
}
}
export function getAvg(objs, site, opticalDepth) {
const activeSiteKey = "AERONET_Site";
const invalidReading = "-999.";
let totalAvg = 0;
let aodAvg = 0;
objs.forEach((element, i) =>
// get all objects that are within the list =>
element[activeSiteKey] === site &&
!element[opticalDepth].toString().includes(invalidReading)
? ((aodAvg += parseFloat(element[opticalDepth])), (totalAvg += 1))
: undefined,
);
return (aodAvg / totalAvg).toPrecision(4);
}
export function withinTime(dataset, defaultDate) {
// Site time Key
const siteTime = "Time(hh:mm:ss)";
let previousHr, hour, bufferHr, minute;
if (defaultDate.length === 2) {
[previousHr, hour, bufferHr, minute] = defaultDate[1].map(Number);
} else if (defaultDate.length === 3) {
[previousHr, hour, bufferHr, minute] = defaultDate[2].map(Number);
}
let withinTime = [];
// do tolerance check whilst adding points to map for adding only points that are within an hour tolerance of the current hour
dataset.forEach((element) => {
const [siteHours, siteMinutes, siteSeconds] = element[siteTime]
.split(":")
.map(Number);
let isBetween;
if (parseInt(hour) !== 0) {
isBetween =
(hour > siteHours ||
(hour === siteHours && minute >= siteMinutes) ||
(hour === siteHours && minute === siteMinutes)) &&
(hour > siteHours ||
(hour === siteHours && minute >= siteMinutes) ||
(hour === siteHours && minute === siteMinutes)) &&
(previousHr < siteHours ||
(previousHr === siteHours && minute <= siteMinutes) ||
(previousHr === siteHours && minute === siteMinutes));
} else {
isBetween =
(hour === siteHours && minute > siteMinutes) ||
(hour === siteHours && minute === siteMinutes) ||
previousHr < siteHours ||
(previousHr === siteHours && minute <= siteMinutes) ||
(previousHr === siteHours && minute === siteMinutes);
}
// console.log(`start Time:${previousHr}: current${minute}-${hour}:${minute} is ${siteHours}:${siteMinutes} between? ${isBetween}`);
isBetween ? withinTime.push(element) : undefined;
});
return withinTime;
}
export function latestOfSet(objs) {
const activeSiteKey = "AERONET_Site";
return Object.values(
// reduces each item using site name to get latest obj for each site name
objs.reduce((siteObjs, site) => {
siteObjs[site[activeSiteKey]] = site;
return siteObjs;
}, {}),
);
}
export async function getStateCountry(latitude, longitude) {
const response = await fetch(
`https://nominatim.openstreetmap.org/reverse?lat=${latitude}&lon=${longitude}&format=json`,
{ method: "GET", mode: "no-cors" },
)
.then((response) => response.json())
.then((data) => {
return [data["address"]["state"], data["address"]["country"]];
})
.catch((error) => console.log(error));
}