jzou19950715 commited on
Commit
14b70ba
·
verified ·
1 Parent(s): e6e26d0

Update components/visualization.py

Browse files
Files changed (1) hide show
  1. components/visualization.py +219 -36
components/visualization.py CHANGED
@@ -7,41 +7,224 @@ class D3Visualizer:
7
  def create_interactive_plot(plot_type: str, data: dict) -> str:
8
  """Create interactive D3 visualization"""
9
 
10
- templates = {
11
- "histogram": """
12
- <div id="d3-histogram" class="visualization"></div>
13
- <script src="https://d3js.org/d3.v7.min.js"></script>
14
- <script>
15
- const data = {data};
16
- // D3 histogram code here...
17
- </script>
18
- """,
19
- "probability_cone": """
20
- <div id="d3-probability-cone" class="visualization"></div>
21
- <script src="https://d3js.org/d3.v7.min.js"></script>
22
- <script>
23
- const data = {data};
24
- // D3 probability cone code here...
25
- </script>
26
- """,
27
- "distribution": """
28
- <div id="d3-distribution" class="visualization"></div>
29
- <script src="https://d3js.org/d3.v7.min.js"></script>
30
- <script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  const data = {data};
32
- // D3 distribution plot code here...
33
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  """
35
- }
36
-
37
- return templates.get(plot_type, "Unsupported visualization type")
38
-
39
- @staticmethod
40
- def get_html_template() -> str:
41
- """Get HTML template for visualizations"""
42
- return """
43
- <link rel="stylesheet" href="static/styles.css">
44
- <div class="visualization-container">
45
- {visualization}
46
- </div>
47
- """
 
7
  def create_interactive_plot(plot_type: str, data: dict) -> str:
8
  """Create interactive D3 visualization"""
9
 
10
+ # Base CSS for visualizations
11
+ base_css = """
12
+ <style>
13
+ .visualization-container { width: 100%; height: 500px; }
14
+ .bar { fill: steelblue; }
15
+ .bar:hover { fill: brown; }
16
+ .line { fill: none; stroke: steelblue; stroke-width: 2; }
17
+ .area { fill: steelblue; opacity: 0.2; }
18
+ .tooltip { position: absolute; padding: 8px; background: white; border: 1px solid #ddd; border-radius: 4px; }
19
+ .axis-label { font-size: 12px; }
20
+ </style>
21
+ """
22
+
23
+ if plot_type == "distribution":
24
+ return base_css + f"""
25
+ <div id="distribution-plot" class="visualization-container"></div>
26
+ <script src="https://d3js.org/d3.v7.min.js"></script>
27
+ <script>
28
+ (function() {{
29
+ const values = {data['values']};
30
+ const margin = {{top: 40, right: 40, bottom: 60, left: 60}};
31
+ const width = 800 - margin.left - margin.right;
32
+ const height = 400 - margin.top - margin.bottom;
33
+
34
+ // Create SVG
35
+ const svg = d3.select("#distribution-plot")
36
+ .append("svg")
37
+ .attr("width", width + margin.left + margin.right)
38
+ .attr("height", height + margin.top + margin.bottom)
39
+ .append("g")
40
+ .attr("transform", `translate(${{margin.left}},${{margin.top}})`);
41
+
42
+ // Create scales
43
+ const x = d3.scaleLinear()
44
+ .domain([d3.min(values), d3.max(values)])
45
+ .range([0, width]);
46
+
47
+ const histogram = d3.histogram()
48
+ .domain(x.domain())
49
+ .thresholds(x.ticks(20));
50
+
51
+ const bins = histogram(values);
52
+
53
+ const y = d3.scaleLinear()
54
+ .domain([0, d3.max(bins, d => d.length)])
55
+ .range([height, 0]);
56
+
57
+ // Create bars
58
+ svg.selectAll(".bar")
59
+ .data(bins)
60
+ .enter()
61
+ .append("rect")
62
+ .attr("class", "bar")
63
+ .attr("x", d => x(d.x0))
64
+ .attr("y", d => y(d.length))
65
+ .attr("width", d => Math.max(0, x(d.x1) - x(d.x0) - 1))
66
+ .attr("height", d => height - y(d.length))
67
+ .on("mouseover", function(event, d) {{
68
+ tooltip.transition()
69
+ .duration(200)
70
+ .style("opacity", .9);
71
+ tooltip.html(
72
+ `Range: ${{d.x0.toFixed(2)}} - ${{d.x1.toFixed(2)}}<br/>` +
73
+ `Count: ${{d.length}}`
74
+ )
75
+ .style("left", (event.pageX + 5) + "px")
76
+ .style("top", (event.pageY - 28) + "px");
77
+ }})
78
+ .on("mouseout", function(d) {{
79
+ tooltip.transition()
80
+ .duration(500)
81
+ .style("opacity", 0);
82
+ }});
83
+
84
+ // Add axes
85
+ svg.append("g")
86
+ .attr("class", "x-axis")
87
+ .attr("transform", `translate(0,${{height}})`)
88
+ .call(d3.axisBottom(x))
89
+ .append("text")
90
+ .attr("class", "axis-label")
91
+ .attr("x", width/2)
92
+ .attr("y", 40)
93
+ .text("Value");
94
+
95
+ svg.append("g")
96
+ .attr("class", "y-axis")
97
+ .call(d3.axisLeft(y))
98
+ .append("text")
99
+ .attr("class", "axis-label")
100
+ .attr("transform", "rotate(-90)")
101
+ .attr("y", -40)
102
+ .attr("x", -height/2)
103
+ .style("text-anchor", "middle")
104
+ .text("Frequency");
105
+
106
+ // Add tooltip
107
+ const tooltip = d3.select("#distribution-plot")
108
+ .append("div")
109
+ .attr("class", "tooltip")
110
+ .style("opacity", 0);
111
+ }})();
112
+ </script>
113
+ """
114
+
115
+ elif plot_type == "forecast":
116
+ return base_css + f"""
117
+ <div id="forecast-plot" class="visualization-container"></div>
118
+ <script src="https://d3js.org/d3.v7.min.js"></script>
119
+ <script>
120
+ (function() {{
121
  const data = {data};
122
+ const margin = {{top: 40, right: 40, bottom: 60, left: 60}};
123
+ const width = 800 - margin.left - margin.right;
124
+ const height = 400 - margin.top - margin.bottom;
125
+
126
+ // Create SVG
127
+ const svg = d3.select("#forecast-plot")
128
+ .append("svg")
129
+ .attr("width", width + margin.left + margin.right)
130
+ .attr("height", height + margin.top + margin.bottom)
131
+ .append("g")
132
+ .attr("transform", `translate(${{margin.left}},${{margin.top}})`);
133
+
134
+ // Create scales
135
+ const x = d3.scaleLinear()
136
+ .domain([0, data.time.length-1])
137
+ .range([0, width]);
138
+
139
+ const y = d3.scaleLinear()
140
+ .domain([
141
+ d3.min(data.lower),
142
+ d3.max(data.upper)
143
+ ])
144
+ .range([height, 0]);
145
+
146
+ // Create area
147
+ const area = d3.area()
148
+ .x((d, i) => x(i))
149
+ .y0(d => y(d[0]))
150
+ .y1(d => y(d[1]));
151
+
152
+ // Add confidence interval area
153
+ svg.append("path")
154
+ .datum(data.time.map((t, i) => [data.lower[i], data.upper[i]]))
155
+ .attr("class", "area")
156
+ .attr("d", area);
157
+
158
+ // Add mean line
159
+ const line = d3.line()
160
+ .x((d, i) => x(i))
161
+ .y(d => y(d));
162
+
163
+ svg.append("path")
164
+ .datum(data.mean)
165
+ .attr("class", "line")
166
+ .attr("d", line);
167
+
168
+ // Add axes
169
+ svg.append("g")
170
+ .attr("class", "x-axis")
171
+ .attr("transform", `translate(0,${{height}})`)
172
+ .call(d3.axisBottom(x))
173
+ .append("text")
174
+ .attr("class", "axis-label")
175
+ .attr("x", width/2)
176
+ .attr("y", 40)
177
+ .text("Time Period");
178
+
179
+ svg.append("g")
180
+ .attr("class", "y-axis")
181
+ .call(d3.axisLeft(y))
182
+ .append("text")
183
+ .attr("class", "axis-label")
184
+ .attr("transform", "rotate(-90)")
185
+ .attr("y", -40)
186
+ .attr("x", -height/2)
187
+ .style("text-anchor", "middle")
188
+ .text("Value");
189
+
190
+ // Add tooltip for hover
191
+ const tooltip = d3.select("#forecast-plot")
192
+ .append("div")
193
+ .attr("class", "tooltip")
194
+ .style("opacity", 0);
195
+
196
+ // Add hover interaction
197
+ const bisect = d3.bisector(d => d).left;
198
+
199
+ svg.append("rect")
200
+ .attr("class", "overlay")
201
+ .attr("width", width)
202
+ .attr("height", height)
203
+ .style("fill", "none")
204
+ .style("pointer-events", "all")
205
+ .on("mousemove", function(event) {{
206
+ const x0 = x.invert(d3.pointer(event)[0]);
207
+ const i = Math.round(x0);
208
+ if (i >= 0 && i < data.time.length) {{
209
+ tooltip.transition()
210
+ .duration(200)
211
+ .style("opacity", .9);
212
+ tooltip.html(
213
+ `Time: ${{data.time[i]}}<br/>` +
214
+ `Mean: ${{data.mean[i].toFixed(2)}}<br/>` +
215
+ `Range: [${{data.lower[i].toFixed(2)}}, ${{data.upper[i].toFixed(2)}}]`
216
+ )
217
+ .style("left", (event.pageX + 5) + "px")
218
+ .style("top", (event.pageY - 28) + "px");
219
+ }}
220
+ }})
221
+ .on("mouseout", function() {{
222
+ tooltip.transition()
223
+ .duration(500)
224
+ .style("opacity", 0);
225
+ }});
226
+ }})();
227
+ </script>
228
  """
229
+
230
+ return "Unsupported visualization type"