Public
Edited
May 15, 2024
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
country = "brazil"
Insert cell
height = width * 0.525
Insert cell
width
Insert cell
keyCol = "origin_ibge_cod"
Insert cell
uniqueCompanies = Array.from(
new Set(data.map((d) => d.destination_company))
).sort()
Insert cell
uniqueMun = Array.from(new Set(SelectedDataMap1.map(d => d.destination_municipality))).sort();
Insert cell
uniqueAddress = Array.from(new Set(SelectedDataMap2.map(d => d.destination_cnpj))).sort();
Insert cell
viewof valueCompany = Inputs.select(["All", ...uniqueCompanies], {
value: "All" // Default to "All" or another logic as necessary
//label: "Select a company or 'All'"
})
Insert cell
viewof valueMun = Inputs.select(["All", ...uniqueMun], {
value: "All", // Default value, or use logic to determine
label: ""
})
Insert cell
viewof valueAddress = Inputs.select(["All", ...uniqueAddress], {
value: "All",
label: ""
})
Insert cell
uniqueSourcing = Array.from(new Set(SelectedDataMap1.map(d => d.origin_municipality)));
Insert cell
munSelected = uniqueSourcing ?.length
Insert cell
assetRiskText = calculateMode(asset.map((d) => d.asst_risk))
Insert cell
viewof valueColSelect = Inputs.select(
possibleColumns.filter((d) => d.selectable),
{ format: (d) => `${d.name} ${d.units}` }
)
Insert cell
valueCol = valueColSelect?.column
Insert cell
valueTitle = valueColSelect?.name
Insert cell
pasture_defo = d3.sum(uniqueDataMap, (d) => d[valueCol])
Insert cell
lowerRiskSum = d3.sum(uniqueDataMap, d => {
if (d.risk_score === "Lower risk") {
return d["prop_flows"];
} else {
return 0; // Return 0 for rows that do not meet the condition
}
});
Insert cell
temp = d3.sum(uniqueDataMap, (d) => {
if (d.risk_score === "Higher risk") {
return d["kg_per_mun"];
} else {
return 0; // Return 0 for rows that do not meet the condition
}
})
Insert cell
higherRiskSum = d3.sum(uniqueDataMap, d => {
if (d.risk_score === "Higher risk") {
return d["prop_flows"];
} else {
return 0; // Return 0 for rows that do not meet the condition
}
});
Insert cell
valueUnits = valueColSelect?.units
Insert cell
columnsToDisplay = {
const selected = possibleColumns.find((d) => d.column === valueCol);
const other = possibleColumns.filter((d) => d.column !== valueCol);
return [selected, ...other];
}
Insert cell
possibleColumns = [
{
column: "trase_deforestation_exposure_20",
name: "Soy deforestation area",
units: "(ha)",
selectable: true,
format: ",.0~f"
}
]
Insert cell
//tableVis
Insert cell
showLand = true
Insert cell
showBiomes = true
Insert cell
selectedData = data
.sort((a, b) =>
d3.descending(
a["trase_deforestation_exposure_20"],
b["trase_deforestation_exposure_20"]
)
)
.map((d) => {
const obj = {
Municipality: `${d["destination_municipality"]}, ${d["destination_state"]}`
};
for (const c of possibleColumns) {
obj[`${c.name} ${c.units}`] = d[c.column];
}
return obj;
})
.filter((element) => {
return element !== null;
})
Insert cell
data[0]["risk_score"]
Insert cell
SelectedDataMap1 = data.filter(
(d) => valueCompany === "All" || d.destination_company === valueCompany
)
Insert cell
SelectedDataMap2 = SelectedDataMap1.filter(
(d) => valueMun === "All" || d.destination_municipality === valueMun
)
Insert cell
SelectedDataMap = SelectedDataMap2.filter(
(d) => valueAddress === "All" || d.destination_cnpj === valueAddress
)
Insert cell
uniqueDataMap = SelectedDataMap.filter((d) => {
const seen = new Set();
if (seen.has(d.origin_ibge_cod)) {
return false;
} else {
seen.add(d.origin_ibge_cod);
return true;
}
})
Insert cell
data = await FileAttachment("soy_supply_shed_trase_2020_threshold_95%@1.csv").csv({
typed: true,
})
Insert cell
asset_raw = await FileAttachment("soy_asset_risk_trase_2020_threshold_95%@3.csv").csv({
typed: true,
})
Insert cell
asset1 = asset_raw.filter(
(d) => valueCompany === "All" || d.destination_company === valueCompany
)
Insert cell
asset2 = asset1.filter(
(d) => valueMun === "All" || d.destination_municipality === valueMun
)
Insert cell
asset = asset2.filter(
(d) => valueAddress === "All" || d.destination_cnpj === valueAddress
)
Insert cell
asset_location = {
const features = asset.map((d) => ({
type: "Feature",
properties: {
company: d.destination_company,
risk: d.asst_risk
},
geometry: {
type: "Point",
coordinates: [+d.destination_long, +d.destination_lat]
}
}));

return {
type: "FeatureCollection",
features: features
};
}
Insert cell
circle = d3.geoPath(projection)
Insert cell
data[0]
Insert cell
dataMap = new Map(
SelectedDataMap.filter((d) => {
const regionId = String(d[keyCol]).includes("-")
? String(d[keyCol]).split("-")[1]
: String(d[keyCol]);
// ignore regions with XXXXXXX id, which are domestic consumption
if (regionId !== "XXXXXXX" && regionId !== "XX") {
return d;
}
}).map((d) => {
const regionId = String(d[keyCol]).includes("-")
? String(d[keyCol]).split("-")[1]
: String(d[keyCol]);

// return [regionId, +d[valueCol]];
return [regionId, d];
})
)
Insert cell
boundaries = d3.json(
`https://unpkg.com/@trase/trase-atlas@1.1.1/files/${country.toLowerCase()}.json`
)
Insert cell
// world = d3.json("https://unpkg.com/visionscarto-world-atlas/world/50m.json")
world = FileAttachment("world-50m.json").json()
Insert cell
// biomes = FileAttachment("biomes_ecoregions_filtered_no_caatinga.json").json()
biomes_raw = FileAttachment("biome@3.topo.json").json()
Insert cell
features = topojson.feature(boundaries, boundaries.objects[`level${level}`]).features
Insert cell
// Function to filter the geometries
function filterBiomes(geojson, names) {
const filteredGeometries = geojson.objects.data.geometries.filter(
(geometry) => names.includes(geometry.properties.name)
);

return {
...geojson, // Spread the original geojson structure
objects: {
...geojson.objects, // Spread the original objects
data: {
...geojson.objects.data, // Spread the original data
geometries: filteredGeometries // Replace geometries with the filtered list
}
}
};
}
Insert cell
biomes = filterBiomes(biomes_raw, [
"AMAZONIA",
"CERRADO",
"PANTANAL",
"CAATINGA",
"MATA ATLANTICA"
])
Insert cell
bounds = topojson.feature(biomes, biomes.objects.data).features
Insert cell
// levels of data resolution - will need updating over time
levels = new Map([
["argentina", 3],
["bolivia", 3],
["brazil", 3],
["colombia", 2],
["cote_divoire", 3],
["ecuador", 3],
["paraguay", 2],
["indonesia", 3]
])
Insert cell
countries = Array.from(levels.keys())
Insert cell
level = levels.get(country.toLowerCase())
Insert cell
toTitleCase = (str) => {
return str?.toLowerCase()?.replace(/(^|\s)\S/g, (t) => t?.toUpperCase());
}
Insert cell
projections = new Map([
[
"argentina",
d3
.geoTransverseMercator()
.rotate([69, 0])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"bolivia",
d3
.geoTransverseMercator()
.rotate([50, 55])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"brazil",
d3
.geoPolyconic()
.rotate([54, 0])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"colombia",
d3
.geoTransverseMercator()
.rotate([68, 4.6])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"cote_divoire",
d3
.geoTransverseMercator()
// .rotate([68, 4.6])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"ecuador",
d3
.geoTransverseMercator()
.rotate([50, 55])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"paraguay",
d3
.geoTransverseMercator()
.rotate([63, 0])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
],
[
"indonesia",
d3
.geoTransverseMercator()
.rotate([-139.5, 0])
.fitSize(
[width, height],
topojson.mesh(boundaries, boundaries.objects.level1)
)
]
])
Insert cell
projection0 = projections.get(country.toLowerCase())
Insert cell
margin = ({
top: 5,
right: 10,
bottom: 70,
left: 5
})
Insert cell
projection = d3
.geoPolyconic()
.rotate([54, 0])
.fitExtent(
[
[margin.left, margin.top],
[width - margin.right, height - margin.bottom]
],
topojson.feature(biomes, biomes.objects.data)
)
Insert cell
colour = d3
.scaleOrdinal()
.domain(["Higher risk", "Lower risk"])
.range(["#FF6A5F", "#2EE8C5", "#E2EAE7"])
Insert cell
numberFormat = ",.0~f"
Insert cell
format = (value) =>
Math.abs(value) < 10
? d3.format(".2r")(value)
: d3.format(numberFormat)(value)
Insert cell
annotate = g => {}
Insert cell
function hover(canvas, svg) {
const path = d3.geoPath(projection);
const highlight = svg
.append("path")
.attr("stroke", "#666")
.attr("stroke-width", 1.5)
.attr("fill", "none");
const tooltip = new Tooltip();
svg.append(() => tooltip.node);
canvas
.style("cursor", "pointer")
.on("touchstart", (event) => event.preventDefault())
.on("pointerenter pointermove", (event) => {
// get feature
let [cx, cy] = d3.pointer(event);
const [x, y] = projection.invert([cx, cy]);
const candidates = index.search(x, y, x, y).map((i) => features[i]);
const f = candidates.find((f) => turf.booleanPointInPolygon([x, y], f));
// define interaction
if (f && dataMap.has(f.id)) {
(cx += 10), (cy += 10);
if (cx + tooltip.width > width) cx -= tooltip.width + 20;
if (cy + tooltip.height > height) cy -= tooltip.height;
tooltip.show(
f.properties.name,
// tooltipKeyValue(tooltipKey, format(dataMap.get(f.id)), f)
generateTooltip(f)
);
tooltip.position(cx, cy);
highlight.attr("d", path(f));
} else {
highlight.attr("d", null);
tooltip.hide();
}
})
.on("pointerout", () => {
highlight.attr("d", null);
tooltip.hide();
});
}
Insert cell
generateTooltip = (d) => {
const spacing = 4.25;
const template = (valueTitle, valueUnits, value, i) => svg`
<text>
<tspan font-size="12px" fill="#839095" x="0" dy="${
spacing * i
}em" font-weight="${
i === 0 ? 700 : 400
}" style="text-transform:uppercase">${valueTitle} ${valueUnits}</tspan>
<tspan font-family="var(--trase-sans-serif)" font-size="14px" fill="#31464e" x="0" dy="1.4em">
<tspan font-weight="${i === 0 ? 700 : 400}">${format(value)}</tspan>
</tspan>
`;
return svg`
<line x1="0" y1="30" x2="250" y2="30" stroke="#839095" />
${columnsToDisplay.map((x, i) =>
template(x.name, x.units, dataMap.get(d.id)[x.column], i)
)}
`;
}
Insert cell
tooltipKey = data.c || `${valueTitle} ${valueUnits ? valueUnits : ""}`
Insert cell
// https://observablehq.com/@rdmurphy/combining-html-canvas-svg-flatbush-for-super-efficient-hov
script = {
const blob = new Blob([`
importScripts("${await require.resolve("flatbush@3.2")}");

onmessage = (event) => {
const { data } = event.data;
const index = new Flatbush(data.length);
data.forEach(bbox => { index.add(...bbox) });
index.finish();
postMessage(index.data);
close();
};
`], {type: "text/javascript"});
const script = URL.createObjectURL(blob);
invalidation.then(() => URL.revokeObjectURL(script));
return script;
}
Insert cell
index = Generators.queue((notify) => {
const worker = new Worker(script);
invalidation.then(() => worker.terminate());
worker.addEventListener("message", ({ data }) => notify(Flatbush.from(data)));
worker.postMessage({ data: features.map((d) => turf.bbox(d)) });
})
Insert cell
import { traseColours, traseOranges, fonts } from "@trase/visual-id@1366"
Insert cell
import { legend as legendTemplate } from "@trase/legends@376"
Insert cell
import { titleCard } from "@trase/title-card"
Insert cell
import { Tooltip, tooltipKeyValue, tooltipOffset } from "@trase/tooltip@440"
Insert cell
import { tableVis } with { selectedData as data } from "@trase/table-visualization"
Insert cell
d3 = require("d3@6", "d3-geo-projection@2.9")
Insert cell
d3_annotation = require("https://cdnjs.cloudflare.com/ajax/libs/d3-annotation/2.5.1/d3-annotation.js")
Insert cell
topojson = require("topojson-client@3")
Insert cell
Flatbush = require("flatbush@3.2")
Insert cell
turf = require("@turf/turf@5")
Insert cell
simple = require("simple-statistics@7")
Insert cell
import { swatches, getLabelLength } from "@trase/legends-2-0"
Insert cell
Insert cell
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