Public
Edited
Dec 5
Insert cell
Insert cell
d3 = require("d3@7")
Insert cell
topojson = require("topojson-client@3")
Insert cell
Insert cell
crossfilter = require("crossfilter2")
Insert cell
attribs = ["spec_name", "time", "abundance", "water_temp", "sampl_site"]
Insert cell
uniqueAbundance = Array.from(
new Set(transformedSampleSites.map((d) => d.abundance))
)
Insert cell
transformedSampleSites = PMNdata.map((d) => {
const water_temp = d.water_temp;
const temp_bucket =
water_temp !== null && water_temp !== undefined
? Math.max(0, Math.floor((water_temp - 1) / 5) * 5 + 1)
: null;

return {
spec_name: d.spec_name,
abundance: d.abundance,
sampl_site: d.sampl_site,
water_temp: temp_bucket, // Add the bucket
time: new Date(d.datecollec).getFullYear()
};
}).filter(
(d) =>
d.time >= 2000 &&
d.time <= 2020 &&
d.water_temp !== null &&
d.spec_name !== null &&
d.abundance !== null &&
d.sampl_site !== null &&
d.time !== null
)
Insert cell
cs = {
// Initialize Crossfilter with the transformed data
const cs = crossfilter(transformedSampleSites);

// Create maps to store dimensions and groups
cs.dims = new Map();
cs.groups = new Map();

// Attributes to filter
const attribs = [
"spec_name",
"time",
"abundance",
"water_temp",
"sampl_site"
];

// Iterate over attributes to create dimensions and groups
for (let a of attribs) {
const dim = cs.dimension((d) => d[a]); // Create dimension for each attribute
cs.dims.set(a, dim); // Store the dimension in the map
cs.groups.set(a, dim.group()); // Store the group in the map
}

return cs; // Return the Crossfilter object with dimensions and groups
}
Insert cell
viewof sampleCharts = {
const div = html`<div style="display:flex; flex-wrap: wrap;">`; // Flex container for charts

const charts = new Map(); // Map to store charts for each attribute

// Mapping for descriptive titles
const titles = {
spec_name: "Species",
time: "Year",
abundance: "Abundance",
water_temp: "Water Temperature",
sampl_site: "Sample Location"
};

// Loop through attributes and create a chart for each
for (let a of attribs) {
const chart = BrushableBarChart()
.x("value") // Data key for x-axis
.y("key") // Data key for y-axis
.width(width / attribs.length) // Dynamic width based on number of attributes
.height(500) // Fixed height
.onBrush((selection) => {
const keys = selection.map((d) => d.key); // Get selected keys from brushing
cs.dims
.get(a)
.filter(keys.length === 0 ? null : (d) => keys.includes(d)); // Apply Crossfilter filtering
update(); // Update charts
});

charts.set(a, chart); // Store chart in the map
}

// Update function to render the charts
function update() {
d3.select(div)
.selectAll(".chart-container")
.data(attribs)
.join("div")
.attr("class", "chart-container")
.style("width", `${width / attribs.length}px`) // Dynamic width
.each(function (a) {
const container = d3.select(this);

// Add title for each chart
container
.selectAll(".chart-title")
.data([titles[a]]) // Use descriptive title from the mapping
.join("div")
.attr("class", "chart-title")
.style("text-align", "center")
.style("font-weight", "bold")
.style("margin-bottom", "10px")
.text((d) => d); // Display the descriptive title

// Add the chart
const data =
a === "sampl_site"
? cs.groups.get(a).top(10) // Show top 10 for sample sites
: cs.groups.get(a).all(); // Show all for other attributes

container
.selectAll(".chart")
.data([data])
.join("div")
.attr("class", "chart")
.datum(data) // Bind data to chart
.call(charts.get(a)); // Render chart
});
}

update(); // Initial render

return div; // Return the container with all charts
}
Insert cell
import { BrushableBarChart } from "@john-guerra/d3-reusable-brushable-barchart-pattern"
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