File size: 3,582 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
"""Histogram template — fetch-and-adapt from d3-graph-gallery.com.

Adapted from d3-graph-gallery.com (Yan Holtz) —
https://d3-graph-gallery.com/graph/histogram_basic.html
"""
from __future__ import annotations
from pydantic import BaseModel
from app.agents.d3.registry import D3Template, register


class HistogramData(BaseModel):
    title: str = ""
    x_label: str = ""
    values: list[float]
    bins: int = 20


_HTML = """<!-- Adapted from d3-graph-gallery.com (Yan Holtz) — https://d3-graph-gallery.com/graph/histogram_basic.html -->
<!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; }
  .axis text { fill: #1A3557; font-size: 12px; }
  .axis path, .axis line { stroke: #1A3557; }
  .chart-title { fill: #1A3557; font-size: 18px; text-anchor: middle; }
  .axis-label { fill: #1A3557; font-size: 13px; text-anchor: middle; }
</style>
</head>
<body>
<div id="my_dataviz"></div>
<script>

const data = __DATA__;

// set the dimensions and margins of the graph
const margin = {top: 50, right: 30, bottom: 60, left: 60},
    width = 960 - margin.left - margin.right,
    height = 600 - margin.top - margin.bottom;

// append the svg object to the body of the page
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%")
  .append("g")
    .attr("transform", `translate(${margin.left},${margin.top})`);

// Chart title
svg.append("text")
  .attr("class", "chart-title")
  .attr("x", width / 2)
  .attr("y", -20)
  .text(data.title);

// X axis: scale and draw
const x = d3.scaleLinear()
  .domain(d3.extent(data.values))
  .range([0, width]);
svg.append("g")
  .attr("class", "axis")
  .attr("transform", `translate(0, ${height})`)
  .call(d3.axisBottom(x));

svg.append("text")
  .attr("class", "axis-label")
  .attr("x", width / 2)
  .attr("y", height + margin.bottom - 10)
  .text(data.x_label);

// set the parameters for the histogram
const histogram = d3.histogram()
  .domain(x.domain())
  .thresholds(x.ticks(data.bins));

// apply this function to the values to get the bins
const bins = histogram(data.values);

// Y axis: scale and draw
const y = d3.scaleLinear()
  .range([height, 0])
  .domain([0, d3.max(bins, d => d.length)]);
svg.append("g")
  .attr("class", "axis")
  .call(d3.axisLeft(y));

// append the bar rectangles to the svg element
svg.selectAll("rect")
  .data(bins)
  .join("rect")
    .attr("x", 1)
    .attr("transform", d => `translate(${x(d.x0)}, ${y(d.length)})`)
    .attr("width", d => Math.max(0, x(d.x1) - x(d.x0) - 1))
    .attr("height", d => height - y(d.length))
    .style("fill", "#4A7FB5");

</script>
</body>
</html>
"""

golden_sample = HistogramData(
    title="Demo",
    x_label="Value",
    values=[2, 4, 4, 6, 7, 7, 7, 8, 9, 12],
    bins=8,
)

register(
    D3Template(
        id="histogram",
        family="chart",
        title="Histogram",
        when_to_use="Show the distribution of a single numeric variable across many observations.",
        data_requirements="A list of numeric values (no pre-binning needed).",
        schema=HistogramData,
        html_template=_HTML,
        golden_sample=golden_sample,
    )
)