SERIES_COLORS = ({
"pCO2 SBE37": "gray",
"xCO2 MAP": "red",
"equilPumpOffxCO2": "blue",
"airPumpOffxCO2": "green"
})
// Helper function to filter and prepare data
function prepareTimeSeriesData(dataFrame, daysBack) {
// Process data with dates
const data_with_dates = transpose(dataFrame).map(d => ({
...d,
date: new Date(d.time)
}));
// Filter data based on days back
const cutoffDate = new Date(Date.now() - (daysBack * 24 * 60 * 60 * 1000));
const filtered_data = data_with_dates.filter(d => d.date >= cutoffDate);
// Subsample for performance
const step = Math.max(1, Math.floor(filtered_data.length / 500));
const subsampled_data = filtered_data
.filter((d, i) => i % step === 0)
.filter(d => !isNaN(d.pCO2_SBE37) && !isNaN(d.pCO2_SBE37_error));
return { filtered_data, subsampled_data };
}
// Helper function to create plot configuration
function createPlotConfig(subsampled_data, filtered_data, selectedSeries) {
// Build combined data only for selected series
const combined_data = [];
if (selectedSeries.includes("pCO2 SBE37")) {
combined_data.push(...subsampled_data.map(d => ({...d, series: "pCO2 SBE37", value: d.pCO2_SBE37})));
}
if (selectedSeries.includes("xCO2 MAP")) {
combined_data.push(...filtered_data.map(d => ({...d, series: "xCO2 MAP", value: d.xCO2})));
}
if (selectedSeries.includes("equilPumpOffxCO2")) {
combined_data.push(...filtered_data.map(d => ({...d, series: "equilPumpOffxCO2", value: d.equilPumpOffxCO2})));
}
if (selectedSeries.includes("airPumpOffxCO2")) {
combined_data.push(...filtered_data.map(d => ({...d, series: "airPumpOffxCO2", value: d.airPumpOffxCO2})));
}
// Build marks array
const marks = [];
// Add error bars only if pCO2 SBE37 is selected
if (selectedSeries.includes("pCO2 SBE37")) {
marks.push(Plot.link(subsampled_data, {
x1: "date",
x2: "date",
y1: d => d.pCO2_SBE37 - d.pCO2_SBE37_error,
y2: d => d.pCO2_SBE37 + d.pCO2_SBE37_error,
stroke: SERIES_COLORS["pCO2 SBE37"],
strokeOpacity: 0.7,
strokeWidth: 0.5
}));
}
// Add data points
marks.push(Plot.dot(combined_data, {
x: "date",
y: "value",
fill: "series",
r: 2,
tip: {
format: {
x: d => {
const date = d.toLocaleDateString("en-CA", {timeZone: "America/Los_Angeles"});
const time = d.toLocaleTimeString("en-US", {
timeZone: "America/Los_Angeles",
hour: '2-digit',
minute: '2-digit',
hour12: false
});
return `${date} ${time}`;
}
}
}
}));
return {
width: 1200,
height: 600,
marginLeft: 80,
marginRight: 80,
marginTop: 40,
marginBottom: 60,
style: {
fontFamily: "DM Mono, monospace"
},
x: {
type: "time",
},
y: {
domain: [0, 1000],
label: "xCO₂ (ppm)",
labelFontSize: 16
},
color: {
domain: Object.keys(SERIES_COLORS),
range: Object.values(SERIES_COLORS),
legend: false
},
grid: true,
marks: marks
};
}