Public
Edited
Mar 31, 2024
Insert cell
Insert cell
Insert cell
plotScheduleCompare(demoExposureData, "behavior", 10, speciesPick)
Insert cell
Insert cell
plotSpread(demoExposureData, "behavior", 10)
Insert cell
function plotSpread(data, criteria, attenuation, ) {
const subset = data.filter(d => (d.criteria === criteria) & (d.attenuation === attenuation));
return Plot.plot({
height: 350,
width: 500,
marginLeft: 120,
x: {axis: "top", grid: true, label: "% of population"},
y: {label: null},
color: {scheme: "spectral", legend: true},
marks: [
Plot.ruleX([0]),
Plot.ruleY(subset, Plot.groupY(
{
x1: (D) => d3.min(D),
x2: (D) => d3.max(D)},
{
y: "shortName",
x1: "percentAbundance",
x2: "percentAbundance",
strokeWidth: 2,
sort: {y: "-x2"},
},
)),
Plot.dot(subset,
{
y: "shortName",
x: "percentAbundance",
fill: "sch",
r:5,
}),
]
});
}
Insert cell
plotSppGroups(demoExposureData, "behavior", 10)
Insert cell
function plotSppGroups(data, criteria, attenuation) {
const subset = data.filter(d => (d.criteria === criteria) & (d.attenuation === attenuation));
const plot = Plot.plot(
{
title: "Exposures as a percent of total population",
subtitle: htl.html`Sound Attenuation: ${attenuation} dB`,
width: 400,
height: 500,
marginRight: 200,
marginLeft: 5,
marginTop: 0,
y: {tickFormat: null, tickSize: 0, label: null, insetTop: 0},
x: {domain: [0,100], label: "Percent of Population",labelAnchor: "center", tickFormat: (d)=>d+"%"},
fy: {label: null},
color: {scheme: "Tableau10", legend: true},
marks: [
Plot.frame(),
Plot.barX(subset, {
x: "percentAbundance",
y: "sch",
fill: "sch",
fy: "species",
tip: true,
sort: {y: null, color: null, fy: {value: "-x", reduce: "sum"}}
})
]
}
);
return plot;
}
Insert cell
Insert cell
function summaryDots(data, criteria) {
const subset = data.filter(d => d.criteria === criteria);

const n = 4; // number of facet columns
const keys = Array.from(d3.union(demoExposureData.map((d) => d.species)));
const index = new Map(keys.map((key, i) => [key, i]));
const fx = (key) => index.get(key) % n;
const fy = (key) => Math.floor(index.get(key) / n);

const plot = Plot.plot({
title: "Predicted exposures for each species",
subtitle: "A comparison of exposures based on each proposed schedule, shown at both 10 and 15 dB. Note y-axis log scale.",
height: 550,
width: 700,
y: {label: "# exposures", type: "log", insetTop: 10},
x: {label: null, transform: (d) => d + "dB"},
fy: {label: null, padding: 0.05, tickFormat: null},
fx: {padding: 0.05, tickFormat: null},
color: {scheme: "Tableau10", legend: true},
grid: true,
marginLeft: 25,
marginBottom: 40,
marks: [
Plot.frame(),
Plot.dot(
subset, {
x: "attenuation",
y: "exposures",
fx: (d) => fx(d.species),
fy: (d) => fy(d.species),
tip: true,
fill: "sch",
r: 5,
}),
Plot.text(keys, {fx, fy, frameAnchor: "top-left", dx: 6, dy: 6}),
]
});
return plot;
}

Insert cell
Insert cell
{const tidy = demoExposureData.reduce((acc, { date, rate, type }) => {
if (!acc[date]) {
acc[date] = { date };
}
acc[date][type] = rate;
return acc;
}, {});
}
//const newArray = Object.values(tidy);

Insert cell
Insert cell
demoExposureData = FileAttachment("demo-exposure-data2@2.csv").csv({typed: true})
Insert cell
speciesInfo = FileAttachment("species-info@5.csv").csv({typed: true})
Insert cell
Insert cell
speciesMap = demoExposureData.map(expItem => speciesInfo.find(specItem => specItem.species === expItem.species))
Insert cell
newAbundanceColumn = speciesMap.map(item => item.abundance)
Insert cell
demoExposureData.map((item, i) => item.abundance = newAbundanceColumn[i])
Insert cell
newHearingGroupColumn = speciesMap.map(item => item.hearing_group)
Insert cell
demoExposureData.map((item, i) => item.hearingGroup = newHearingGroupColumn[i])
Insert cell
newShortNamesColumn = speciesMap.map(item => item.shortName)
Insert cell
demoExposureData.map((item, i) => item.shortName = newShortNamesColumn[i])
Insert cell
Insert cell
demoExposureData.map(item => item.percentAbundance = 100 * item.exposures / item.abundance)
Insert cell
Insert cell
uniqueSpecies = [...new Set(demoExposureData.map(d => d.species))];
Insert cell
groupAndSummarize(demoExposureData, "hearingGroup", "exposures")
Insert cell
function groupAndSummarize(data, groupBy, valueKey) {
// Initialize an empty object to store grouped data
const groupedData = {};

// Loop through the data array
data.forEach(item => {
// Extract the value of the specified parameter to group by
const groupValue = item[groupBy];

// If the group doesn't exist yet, initialize it with an empty array
if (!groupedData[groupValue]) {
groupedData[groupValue] = [];
}

// Add the current item to the corresponding group
groupedData[groupValue].push(item);
});

// Initialize an array to store summary statistics
const summary = [];

// Loop through the grouped data
for (const [group, groupItems] of Object.entries(groupedData)) {
// Calculate summary statistics for each group
const values = groupItems.map(item => item[valueKey]);
const min = Math.min(...values);
const max = Math.max(...values);
const mean = values.reduce((acc, val) => acc + val, 0) / values.length;

// Add summary statistics to the summary array
summary.push({ group, min, max, mean });
}

return summary;
}

Insert cell
subsetTenDb = demoExposureData.filter(d => d.attenuation === 10)
Insert cell
groupedData = groupAndSummarizeTwoKeys(subsetTenDb, "hearingGroup", "criteria", "exposures")
Insert cell
groupedDataLong = groupArr(subsetTenDb, "hearingGroup", "criteria", "exposures")
Insert cell
function groupArr(data, groupBy1, groupBy2, valueKey) {
// Initialize an empty object to store grouped data
const groupedData = {};

// Loop through the data array
data.forEach(item => {
// Extract the values of the specified parameters to group by
const groupValue1 = item[groupBy1];
const groupValue2 = item[groupBy2];
const value = item[valueKey];

// If the group doesn't exist yet, initialize it with an empty array
if (!groupedData[groupValue1]) {
groupedData[groupValue1] = {};
}

if (!groupedData[groupValue1][groupValue2]) {
groupedData[groupValue1][groupValue2] = [];
}

// Add the current item to the corresponding group
groupedData[groupValue1][groupValue2].push(value);
});

// Initialize an array to store summary statistics
const summary = [];

// Loop through the grouped data
for (const [hearingGroup, groupData] of Object.entries(groupedData)) {
for (const [criteria, values] of Object.entries(groupData)) {
// Calculate summary statistics for the extracted values
const min = Math.min(...values);
const max = Math.max(...values);
const mean = values.reduce((acc, val) => acc + val, 0) / values.length;

// Add summary statistics as separate rows to the summary array
summary.push({ hearingGroup, criteria, stat: 'min', value: min });
summary.push({ hearingGroup, criteria, stat: 'max', value: max });
summary.push({ hearingGroup, criteria, stat: 'mean', value: mean });
}
}

return summary;
}

Insert cell
function groupAndSummarizeTwoKeys(data, groupBy1, groupBy2, valueKey) {
// Initialize an empty object to store grouped data
const groupedData = {};

// Loop through the data array
data.forEach(item => {
// Extract the values of the specified parameters to group by
const groupValue1 = item[groupBy1];
const groupValue2 = item[groupBy2];
const value = item[valueKey];

// If the group doesn't exist yet, initialize it with an empty array
if (!groupedData[groupValue1]) {
groupedData[groupValue1] = {};
}

if (!groupedData[groupValue1][groupValue2]) {
groupedData[groupValue1][groupValue2] = [];
}

// Add the current item to the corresponding group
groupedData[groupValue1][groupValue2].push(value);
});

// Initialize an array to store summary statistics
const summary = [];

// Loop through the grouped data
for (const [group1, groupData] of Object.entries(groupedData)) {
for (const [group2, values] of Object.entries(groupData)) {
// Calculate summary statistics for the extracted values
const min = Math.min(...values);
const max = Math.max(...values);
const mean = values.reduce((acc, val) => acc + val, 0) / values.length;

// Add summary statistics to the summary array
summary.push({ group1, group2, min, max, mean });
}
}

return summary;
}

Insert cell
Plot.plot({
padding: 0,
grid: true,
x: {axis: "top", label: null, domain: ["min", "mean", "max"]},
y: {label: "Hearing Group"},
color: {type: "linear", scheme: "PiYG"},
marks: [
Plot.cell(groupedDataLong, {y: "hearingGroup", x: "stat", fy: "criteria", fill: "value", inset: 0.5}),
Plot.text(groupedDataLong, {x: "stat", y: "hearingGroup", fy: "criteria", text: (d) => d.value?.toFixed(1), fill: "white", title: "title", fontWeight:"bold"})
]
})
Insert cell
otherSubset = groupAndSummarizeThreeKeys(subsetTenDb, "hearingGroup", "criteria", "sch", "percentAbundance")
Insert cell
function groupAndSummarizeThreeKeys(data, groupBy1, groupBy2, groupBy3, valueKey) {
// Initialize an empty object to store grouped data
const groupedData = {};
// Loop through the data array
data.forEach(item => {
// Extract the values of the specified parameters to group by
const groupValue1 = item[groupBy1];
const groupValue2 = item[groupBy2];
const groupValue3 = item[groupBy3];
const value = item[valueKey];
// If the group doesn't exist yet, initialize it with an empty array
if (!groupedData[groupValue1]) {
groupedData[groupValue1] = {};
}
if (!groupedData[groupValue1][groupValue2]) {
groupedData[groupValue1][groupValue2] = [];
}

if (!groupedData[groupValue1][groupValue2][groupValue3]) {
groupedData[groupValue1][groupValue2][groupValue3] = [];
}
// Add the current item to the corresponding group
groupedData[groupValue1][groupValue2][groupValue3].push(value);
});
// Initialize an array to store summary statistics
const summary = [];
// Loop through the grouped data
for (const [hearingGroup, group1Data] of Object.entries(groupedData)) {
for (const [criteria, group2Data] of Object.entries(group1Data)) {
for (const [sch, values] of Object.entries(group2Data)) {
// Calculate summary statistics for the extracted values
const min = Math.min(...values);
const max = Math.max(...values);
const mean = values.reduce((acc, val) => acc + val, 0) / values.length;
// Add summary statistics to the summary array
summary.push({ hearingGroup, criteria, sch, min, max, mean });
}
}
}
return summary;
}
Insert cell
newSubset = subsetTenDb.filter(d => d.criteria === "behavior")
Insert cell
maxValue = d3.max(newSubset.map(d => d.percentAbundance))
Insert cell
Plot.plot({
height: 300,
y: {label: "", tickSize: 0},
fy: {domain: ["LF", "MF", "HF", "PW"]},
marks:[
Plot.barX(newSubset, {
x1: 0,
x2: d3.max(newSubset.map(d => d.percentAbundance))*1.05,
y: "sch",
insetTop: 2,
insetBottom: 2,
fy: "hearingGroup",
fill: "Gainsboro",
}),
Plot.tickX(newSubset,
{
x: "percentAbundance",
y: "sch",
fy: "hearingGroup",
stroke: "sch",
strokeWidth: 2,
channels: {"Hearing group": "hearingGroup", Species: "species"},
tip: {format: {fill: false, x: false, y: false, fy: false}},
}
)
]
})
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more