Public
Edited
Nov 4, 2024
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
svgPathString = geojsonToTranslatedScaledPoints(sampleCounty, 80, -37.6, 250)
Insert cell
circles = createMultipleCirclePath(circles2)
Insert cell
svgPath1 = "M70,16 c0,20,-10,30,-20,30 c10,0,20,10,20,30 c0,-20,10,-30,20,-30 c-10,0,-20,-10,-20,-30 z M30,0 c0,20,-10,30,-20,30 c10,0,20,10,20,30 c0,-20,10,-30,20,-30 c-10,0,-20,-10,-20,-30 z M43,42 c0,20,-10,30,-20,30 c10,0,20,10,20,30 c0,-20,10,-30,20,-30 c-10,0,-20,-10,-20,-30 z"
Insert cell
circle = "M200,300a100,100 0 1,0 200,0a100,100 0 1,0 -200,0"
Insert cell
circles2 = [
{ id: 1, cx: 543, cy: 431, radius: 19 },
{ id: 2, cx: 173, cy: 185, radius: 29 },
{ id: 3, cx: 199, cy: 554, radius: 22 },
{ id: 4, cx: 306, cy: 242, radius: 26 },
{ id: 5, cx: 76, cy: 234, radius: 14 },
{ id: 6, cx: 254, cy: 414, radius: 18 },
{ id: 7, cx: 431, cy: 96, radius: 13 },
{ id: 8, cx: 420, cy: 271, radius: 17 },
{ id: 9, cx: 527, cy: 339, radius: 25 },
{ id: 10, cx: 551, cy: 119, radius: 28 },
{ id: 11, cx: 52, cy: 502, radius: 29 },
{ id: 12, cx: 429, cy: 518, radius: 21 },
{ id: 13, cx: 354, cy: 111, radius: 24 },
{ id: 14, cx: 363, cy: 448, radius: 23 },
{ id: 15, cx: 521, cy: 187, radius: 27 },
{ id: 16, cx: 521, cy: 187, radius: 27 },
{ id: 17, cx: 521, cy: 187, radius: 27 }
]
Insert cell
function geojsonToTranslatedScaledPoints(geojsonFeature, translateX, translateY, scale) {
const pathGenerator = d3.geoPath();
const pathString = pathGenerator(geojsonFeature);

// Manually parse the SVG path string into an array of [x, y] points
const points = pathString
.split(/(?=[LMCZ])/)
.map(segment => {
const [, command, x, y] = /([LMCZ])([^,]+)?,?([^,]+)?/.exec(segment);
const point = [parseFloat(x), parseFloat(y)];
return command === 'Z' ? null : point;
})
.filter(point => point !== null);

// Apply translation and scale
const translatedScaledPoints = points.map(point => [
(point[0] + translateX) * scale,
(point[1] + translateY) * scale
]);

return translatedScaledPoints;
}
Insert cell
function moveToGrid(data) {
for (let index = 0; index < data.length; ++index) {
data[index].cx += 20;
}

return data;
}
Insert cell
interpolator = flubber.combine(
flubber.splitPathString(circles),
svgPathString,
{
maxSegmentLength: segLen,
single: true
}
)
Insert cell
Select a data source…
Type Chart, then Shift-Enter. Ctrl-space for more options.

Insert cell
Select a data source…
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
flubber = require("https://unpkg.com/flubber")
Insert cell
simplified_fixedborders_state_senate = FileAttachment("simplified_fixedborders_state_senate.geojson").json()
Insert cell
sampleCounty = simplified_fixedborders_state_senate["features"][0]
Insert cell
{
const container = yield htl.html`<div style="height: 500px;">`;
const map = L.map(container);
const layer = L.geoJSON(sampleCounty).addTo(map);
map.fitBounds(layer.getBounds(), {maxZoom: 9});
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
attribution: "© <a href=https://www.openstreetmap.org/copyright>OpenStreetMap</a> contributors"
}).addTo(map);
}
Insert cell
function createMultipleCirclePath(circleArray) {
let path = "";

for (const circle of circleArray) {
const { cx, cy, radius } = circle;
path += `M${cx},${cy - radius}A${radius},${radius} 0 1,0 ${cx},${
cy + radius
}A${radius},${radius} 0 1,0 ${cx},${cy - radius}`;
}

return path;
}
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