Public
Edited
Apr 27
Fork of Vietnam Map
1 fork
1 star
Insert cell
Insert cell
data = FileAttachment("map_data.csv").csv()



Insert cell
color = d3.scaleSequential()
.domain(d3.extent(data, d => +d.Value)) // adjust based on min/max
.interpolator(d3.interpolateOrRd)

Insert cell
choropleth = {
const provinces = topojson.feature(vietnam, vietnam.objects.vn_iso_province),
country = topojson.mesh(vietnam, vietnam.objects.vn_iso_province, (a, b) => a === b)

const projection = d3.geoMercator()
.fitSize([width, width], provinces)

const path = d3.geoPath(projection)

const valueMap = new Map(data.map(d => [d.Province, +d.Value]))

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, width])
// Group by province name (Name_EN), only keep the first feature per province
const uniqueProvinces = Array.from(
d3.group(provinces.features, d => d.properties.Name_EN).values(),
features => features.reduce((a, b) => d3.geoArea(a) > d3.geoArea(b) ? a : b)
);


const g = svg.append("g")

// Draw provinces
g.selectAll("path")
.data(provinces.features)
.join("path")
.attr("fill", d => {
const val = valueMap.get(d.properties.Name_EN)
return val != null ? color(val) : "#eee"
})
.attr("stroke", "lightgray")
.attr("d", path)

// Draw province names
// Now use uniqueProvinces instead of provinces.features for labels
g.selectAll("text")
.data(uniqueProvinces)
.join("text")
.filter(d => valueMap.get(d.properties.Name_EN) != null) // Only if province has a value
.attr("x", d => projection(d3.geoCentroid(d))[0])
.attr("y", d => projection(d3.geoCentroid(d))[1])
.text(d => d.properties.Name_EN)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "central")
.attr("font-size", 5)
.attr("fill", "black")
.style("pointer-events", "none")

svg.append("path")
.datum(country)
.attr("fill", "none")
.attr("stroke", "gray")
.attr("d", path)

return svg.node()
}

Insert cell
chart = {
// Prepare map features.
const provinces = topojson.feature(vietnam, vietnam.objects.vn_iso_province),
country = topojson.mesh(vietnam, vietnam.objects.vn_iso_province, (a, b) => a == b)

const tooltip = new Tooltip()

//Draw map.
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, width])

svg.append("g")
.selectAll("path")
.data(provinces.features)
.join("path")
.attr("fill", "white")
.attr("stroke", "lightgray")
.attr("d", path(provinces))
.attr("cursor", "pointer")
.on("mousemove", function(e, d) {
const pointer = d3.pointer(e, svg.node())
tooltip.show(pointer, d)
d3.select(this)
.attr("fill", "lightgray")
})
.on("mouseout", function() {
tooltip.hide()
d3.select(this)
.attr("fill", "white")
})

svg.append("path")
.datum(country)
.attr("fill", "none")
.attr("stroke", "gray")
.attr("d", path(country))

svg.append(() => tooltip.node)
return svg.node();
}
Insert cell
sample_data_observable.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3geo = require("d3-geo-projection")
Insert cell
vn_simple.json
SQL
Insert cell
vn_simple = FileAttachment("vn_simple.json").json()
Insert cell
sample_data_observable.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

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