Spaces:
Sleeping
Sleeping
File size: 4,452 Bytes
2e818da | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | """Bubble chart template — flow family.
Substitution note: d3-graph-gallery.com's "circular packing" pages
(https://d3-graph-gallery.com/graph/circularpacking_basic.html and
siblings, confirmed by re-checking https://d3-graph-gallery.com/
circularpacking.html's link list) are all `d3.forceSimulation()` bubble
demos with flat dummy data, not `d3.pack()`/`d3.hierarchy()` layouts — the
same substitution note hier_circle_pack.py already made for its own nested
version of this problem. `flow_bubble` needs a FLAT, already-packed bubble
chart (not the nested tree hier_circle_pack.py uses), so this is adapted
instead from a different, real, verified flat `d3.pack()` bubble-chart
source: https://multimedia.report/classes/coding/2018/exercises/basicbubblepackchart/
— which already builds its hierarchy from a flat list exactly the way this
template needs (`d3.hierarchy({children: data}).sum(d => d.value)` then
`d3.pack().size([...]).padding(...)`, one circle + centered label per leaf),
so no nested-to-flat adaptation was even needed here. Field names are wired
to this template's own flat `BubbleData` schema (`label`/`value` instead of
the fetched source's CSV `Fruit`/`Amount` columns); circle fill color and
the radius-proportional label truncation follow the same conventions
already used by hier_circle_pack.py for its own leaf circles.
"""
from __future__ import annotations
from pydantic import BaseModel
from app.agents.d3.registry import D3Template, register
class Bubble(BaseModel):
label: str
value: float
class BubbleData(BaseModel):
title: str = ""
data: list[Bubble]
_HTML = """<!-- Adapted from https://multimedia.report/classes/coding/2018/exercises/basicbubblepackchart/ (flat-list d3.pack() bubble chart) -->
<!-- d3-graph-gallery.com's circular-packing pages are force-simulation demos, not hierarchy layouts; see module docstring -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
html, body { margin: 0; padding: 0; width: 100vw; height: 100vh; background: #FAF7F2; color: #1A3557; font-family: Georgia, 'Libre Caslon Text', serif; overflow: hidden; }
#my_dataviz { width: 100vw; height: 100vh; }
.chart-title { fill: #1A3557; font-size: 18px; text-anchor: middle; }
.node-circle { stroke: #1A3557; stroke-width: 1px; }
.node-label { fill: #1A3557; text-anchor: middle; }
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>
const data = __DATA__;
const margin = {top: 50, right: 10, bottom: 10, left: 10},
width = 960 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
const svg = d3.select("#my_dataviz")
.append("svg")
.attr("viewBox", `0 0 ${width + margin.left + margin.right} ${height + margin.top + margin.bottom}`)
.attr("preserveAspectRatio", "xMidYMid meet")
.style("width", "100%")
.style("height", "100%");
svg.append("text")
.attr("class", "chart-title")
.attr("x", (width + margin.left + margin.right) / 2)
.attr("y", 25)
.text(data.title);
const g = svg.append("g")
.attr("transform", `translate(${margin.left},${margin.top})`);
const root = d3.hierarchy({ children: data.data })
.sum(d => d.value);
d3.pack()
.size([width - 4, height - 4])
.padding(3)
(root);
const palette = ['#4A7FB5', '#7FA9D6', '#3D6690', '#A7C6E8', '#2C4A66', '#B5764A'];
const node = g.selectAll("g.node")
.data(root.leaves())
.join("g")
.attr("class", "node")
.attr("transform", d => `translate(${d.x},${d.y})`);
node.append("circle")
.attr("class", "node-circle")
.attr("r", d => d.r)
.style("fill", (d, i) => palette[i % palette.length]);
node.append("text")
.attr("class", "node-label")
.attr("dy", "0.31em")
.style("font-size", d => Math.min(14, d.r / 2.5) + "px")
.text(d => d.data.label.substring(0, d.r / 3));
</script>
</body>
</html>
"""
golden_sample = BubbleData(
title="Demo",
data=[
Bubble(label="A", value=10),
Bubble(label="B", value=20),
Bubble(label="C", value=5),
],
)
register(
D3Template(
id="flow_bubble",
family="flow",
title="Bubble chart",
when_to_use="Show relative size of a flat set of named quantities as packed circles (not a hierarchy).",
data_requirements="A flat list of labeled values (no nesting).",
schema=BubbleData,
html_template=_HTML,
golden_sample=golden_sample,
)
)
|