Published
Edited
Feb 9, 2021
2 forks
19 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
dms = {
let dimensions = {
width: width,
height: width * 0.6,
marginTop: 10
};

dimensions.marginLeft = dimensions.marginTop;
dimensions.marginBottom = dimensions.marginTop;
dimensions.marginRight = dimensions.marginTop;

dimensions.chartWidth =
dimensions.width - dimensions.marginLeft - dimensions.marginRight;
dimensions.chartHeight =
dimensions.height - dimensions.marginTop - dimensions.marginBottom;

return dimensions;
}
Insert cell
Insert cell
crosswalk = {
const attached = await FileAttachment("ISOCodes.csv").text();
return d3.csvParse(attached);
}
Insert cell
selection = ["MLI", "BEN", "BFA", "CIV", "TGO", "BEN", "GHA"]
Insert cell
data = {
const attached = await FileAttachment("2018-Edited.csv").text();

return d3.csvParse(attached);
}
Insert cell
dataByReporter = d3.rollup(
data,
v =>
v
.filter(d => d["Partner"] != "World")
.map(e => {
return {
reporterName: e["Reporter"],
reporterISO: e["ISO"],
partnerName: e["Partner"],
partnerISO: e["PartnerISO"],
exportGross: +e["Gross Export"],
exportShare: +e["Share"]
};
})
.sort((a, b) => d3.descending(a["partnerName"], b["partnerName"])),
d => d["ISO"]
)
Insert cell
dataByReporterTotals = d3.rollup(
data,
v => d3.sum(v, e => +e["Gross Export"]),
d => d["ISO"]
)
Insert cell
dataByReporterTotalsAggregated = d3.rollup(
data,
v =>
d3.sum(
v.filter(f =>
[...dataByPartnerAggregatedTrimmed.keys()].includes(f["PartnerISO"])
),
e => +e["Gross Export"]
),
d => d["ISO"]
)
Insert cell
dataByReporterTotalsAggregatedTrimmed = new Map(
Array.from(dataByReporterTotalsAggregated.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.filter(d => selection.includes(d[0]))
)
Insert cell
dataByPartner = {
const merged = d3
.merge(Array.from(dataByReporter.values()))
.filter(d => d["partnerISO"].length > 0);

return d3.group(merged, d => d["partnerISO"]);
}
Insert cell
dataByPartnerTotals = {
const merged = d3
.merge(Array.from(dataByReporter.values()))
.filter(d => d["partnerISO"].length > 0);

return d3.rollup(
merged,
v => d3.sum(v, e => e["exportGross"]),
d => d["partnerISO"]
);
}
Insert cell
dataByPartnerAggregated = {
const filtered = d3.merge(
Array.from(dataByPartner.values())
.map(d => d.filter(e => selection.includes(e["reporterISO"])))
.filter(e => e.length > 0)
);

// return filtered;

return d3.rollup(
filtered,
v => d3.sum(v, e => e["exportGross"]),
d => d["partnerISO"]
);
}
Insert cell
dataAggregatedTotal = d3.sum([...dataByPartnerAggregated.values()])
Insert cell
dataByPartnerAggregatedTrimmed = new Map(
Array.from(dataByPartnerAggregated.entries())
.sort((a, b) => d3.descending(a[1], b[1]))
.slice(0, 5)
)
Insert cell
Insert cell
exportTotals = d3
.scaleLinear()
.domain([0, d3.max(Array.from(dataByPartnerTotals.values()))])
.range([0, 1])
Insert cell
exportAggregated = d3
.scaleLinear()
.domain([0, d3.max(Array.from(dataByPartnerAggregated.values()))])
.range([0, 1])
Insert cell
Insert cell
countries = {
const attached = await FileAttachment("WorldMapSimplified-2.json").json();

let geo = topojson.feature(
attached,
attached["objects"]["ne_10m_admin_0_countries_lakes"]
);

geo["features"] = geo["features"].filter(
d => d["properties"]["CONTINENT"] != "Antarctica"
);

return geo;
}
Insert cell
countriesMentioned = {
const codes = d3.merge([
selection,
Array.from([...dataByPartnerAggregatedTrimmed.keys()])
]);

const shapes = countries["features"].filter(d =>
codes.includes(d["properties"]["ISO_A3"])
);

return { type: "FeatureCollection", features: shapes };
}
Insert cell
countriesSelectedMerged = {
const attached = await FileAttachment("WorldMapSimplified-2.json").json();

let merged = topojson.merge(
attached,
attached["objects"]["ne_10m_admin_0_countries_lakes"][
"geometries"
].filter(d => selection.includes(d["properties"]["ISO_A3"]))
);

return merged;
}
Insert cell
Insert cell
projection = proj4d3(
"+proj=laea +lon_0=53.44 +lat_0=19.67 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
).fitExtent(
[
[dms.marginLeft, dms.marginTop],
[dms.width - dms.marginRight, dms.height - dms.marginBottom]
],
countriesMentioned
)
Insert cell
graticule = d3.geoGraticule().step([30, 30])
Insert cell
path = d3.geoPath(projection)
Insert cell
Insert cell
hash = function(defs, id, color) {
return defs
.append("pattern")
.attr("id", id)
.attr("width", "4")
.attr("height", "4")
.attr("patternUnits", "userSpaceOnUse")
.attr("patternTransform", "rotate(45)")
.append("path")
.attr("d", "M 0 0 V 4")
.attr("stroke-width", 2)
.attr("transform", "translate(0,0)")
.attr("stroke", color);
}
Insert cell
arrowhead = function(defs, id, color) {
return defs
.append("marker")
.attr("id", id)
.attr("markerWidth", 8)
.attr("markerHeight", 8)
.attr("refX", 5)
.attr("refY", 4)
.attr("orient", "auto")
.append("path")
.attr("d", "M 3 2 L 5 4 L 3 6")
.attr("stroke-width", 0.6)
.attr("stroke", color)
.attr("fill", "none");
}
Insert cell
colors = {
return {
exportDark: "#64974B",
exportLight: "#A7CE95",
importLight: "#ACC0DD",
background: "#E2E2E2"
};
}
Insert cell
reporterStrokeWidths = new Map(
Array.from(dataByReporterTotalsAggregatedTrimmed).map(d => [
d3.group(crosswalk, d => d["ISO"]).get(d[0])[0]["name"],
exportAggregated(d[1]) * 8
])
)
Insert cell
Insert cell
distance = function(a, b) {
return Math.sqrt(Math.pow(b[0] - a[0], 2) + Math.pow(b[0] - a[0], 2));
}
Insert cell
midpoint = function(a, b) {
return [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
}
Insert cell
curvepoint = function(a, b, bend) {
return [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2 - bend];
}
Insert cell
Insert cell
Insert cell
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