Skip to content

Commit 941e4c9

Browse files
committed
improve brushed bar chart. Fix text alignment, brush updates and axis
1 parent 9606290 commit 941e4c9

File tree

9 files changed

+1361
-583
lines changed

9 files changed

+1361
-583
lines changed

neuralqa/server/ui/src/components/Main.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,13 @@ import React, { Component } from "react";
1111
import { getJSONData, sampleConfig } from "./helperfunctions/HelperFunctions";
1212
import { Route, HashRouter } from "react-router-dom";
1313

14-
import ExplainView from "./explainview/ExplainView";
15-
import TestView from "./testview/TestView";
1614
import QueryView from "./queryview/QueryView";
1715
import Header from "./header/Header";
1816
import Footer from "./footer/Footer";
1917
import { createBrowserHistory } from "history";
18+
import BarViz from "./barviz/BarViz";
19+
import TestView from "./testview/TestView";
20+
// import TestView from "./testview/TestView";
2021

2122
const history = createBrowserHistory({
2223
basename: "", // The base URL of the app (see below)
Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,335 @@
1+
import React, { Component } from "react";
2+
// import { Tabs, Tab } from "carbon-components-react";
3+
import * as d3 from "d3";
4+
import "./barviz.css";
5+
// import csvdata from "./aapl.csv";
6+
7+
class BarViz extends Component {
8+
constructor(props) {
9+
super(props);
10+
11+
this.data = require("./ex.json");
12+
this.data = this.data || props.data;
13+
14+
this.state = {
15+
data: this.data,
16+
svgPath: "",
17+
};
18+
19+
this.minChartWidth = 1600;
20+
this.minChartHeight = 250;
21+
this.barWidth = 20;
22+
23+
this.numTicks = 40;
24+
this.xTicks = 7;
25+
this.brushHeight = 60;
26+
}
27+
28+
getLabel(d, i) {
29+
return i + "*.*" + d.token + " *.* (" + d.gradient.toFixed(2) + ")";
30+
}
31+
32+
componentDidUpdate(prevProps, prevState) {
33+
this.data = prevProps.explanationData;
34+
35+
if (
36+
prevProps.explanationData &&
37+
prevProps.explanationData.answer !== this.state.data.answer
38+
) {
39+
console.log("updating .. ", this.data);
40+
this.updateGraph(this.data.gradients);
41+
this.setState({
42+
data: prevProps.explanationData,
43+
});
44+
}
45+
}
46+
47+
setupScalesAxes(data) {
48+
// console.log(this.minChartWidth);
49+
50+
let self = this;
51+
this.chartMargin = { top: 5, right: 0, bottom: 5, left: 10 };
52+
this.chartWidth =
53+
this.minChartWidth - this.chartMargin.left - this.chartMargin.right;
54+
this.chartHeight =
55+
this.minChartHeight - this.chartMargin.top - this.chartMargin.bottom;
56+
this.xScale = d3
57+
.scaleBand()
58+
.domain(data.map((d, i) => self.getLabel(d, i)))
59+
.range([this.chartMargin.left, this.chartWidth - this.chartMargin.right]);
60+
61+
this.yScale = d3
62+
.scaleLinear()
63+
.domain([0, d3.max(data, (d) => d.gradient)])
64+
.nice()
65+
.range([this.chartHeight, 0]);
66+
67+
this.xAxis = d3
68+
.axisBottom(this.xScale)
69+
.ticks(this.xTicks)
70+
.tickFormat((d) => d.split("*.*")[1])
71+
.tickSize(0);
72+
this.yAxis = d3.axisRight(this.yScale).tickSize(this.minChartWidth);
73+
// .tickFormat((interval, i) => {
74+
// return i % 2 !== 0 ? " " : interval;
75+
// });
76+
}
77+
78+
updateGraph(data) {
79+
let self = this;
80+
// console.log(data[0]);
81+
this.setupScalesAxes(data);
82+
let svg = d3.select("div.barviz");
83+
84+
svg
85+
.select("svg")
86+
.attr(
87+
"width",
88+
this.chartWidth + this.chartMargin.left + this.chartMargin.right
89+
)
90+
.attr(
91+
"height",
92+
this.chartHeight + this.chartMargin.top + this.chartMargin.bottom
93+
);
94+
95+
svg
96+
.selectAll("rect")
97+
.data(data)
98+
.join("rect")
99+
.attr("x", (d, i) => self.xScale(self.getLabel(d, i)))
100+
.attr("y", (d) => self.yScale(d.gradient))
101+
.attr("height", (d) => self.yScale(0) - self.yScale(d.gradient))
102+
.attr("width", self.xScale.bandwidth())
103+
.attr("class", "barrect")
104+
.attr("fill", (d) => "rgba(0, 98, 255, " + d.gradient + ")")
105+
.transition();
106+
107+
svg
108+
.select(".x.axis")
109+
.call(self.xAxis)
110+
.selectAll("text")
111+
.attr("y", 0)
112+
.attr("x", 9)
113+
.attr("dy", ".35em")
114+
.attr("transform", "rotate(270)")
115+
.style("text-anchor", "start");
116+
}
117+
118+
createSVGBox = (selector, height) => {
119+
return d3
120+
.select(selector)
121+
.append("svg")
122+
.attr(
123+
"width",
124+
this.chartWidth + this.chartMargin.left + this.chartMargin.right
125+
)
126+
.attr("height", height + this.chartMargin.top + this.chartMargin.bottom)
127+
.append("g")
128+
.attr(
129+
"transform",
130+
"translate(" + this.chartMargin.left + "," + this.chartMargin.top + ")"
131+
);
132+
};
133+
createBarRects = (svg, x, y, data, chartclass) => {
134+
svg
135+
.append("g")
136+
.attr("class", chartclass)
137+
.selectAll("rect")
138+
.data(data)
139+
.join("rect")
140+
.attr("x", (d, i) => x(this.getLabel(d, i)))
141+
.attr("y", (d) => y(d.gradient))
142+
.attr("height", (d) => y(0) - y(d.gradient))
143+
.attr("width", x.bandwidth())
144+
.attr("class", "barrect")
145+
.attr("fill", (d) => "rgba(0, 98, 255, " + 1 + ")");
146+
};
147+
148+
drawBrushGraph(data) {
149+
let self = this;
150+
const x = this.xScale;
151+
const y = this.yScale.copy().range([this.brushHeight, 0]);
152+
const mainXZoom = d3
153+
.scaleLinear()
154+
.range([this.chartMargin.left, this.chartWidth - this.chartMargin.right])
155+
.domain([
156+
this.chartMargin.left,
157+
this.chartWidth - this.chartMargin.right,
158+
]);
159+
160+
const svg = this.createSVGBox("div.d3brush", this.brushHeight);
161+
162+
this.createBarRects(svg, x, y, data, "minibars");
163+
const brush = d3
164+
.brushX()
165+
.extent([
166+
[this.chartMargin.left, 0.5],
167+
[this.chartWidth - this.chartMargin.right, this.brushHeight],
168+
])
169+
.on("brush", brushed);
170+
// .on("end", (a)=>{
171+
// console.log(a)
172+
// });
173+
174+
const defaultSelection = [x.range()[0], (x.range()[1] - x.range()[0]) / 3];
175+
const gb = svg.append("g").call(brush).call(brush.move, defaultSelection);
176+
177+
function brushed() {
178+
const extentX = d3.event.selection;
179+
const selected = x
180+
.domain()
181+
.filter(
182+
(d) =>
183+
extentX[0] - x.bandwidth() + 1e-2 <= x(d) &&
184+
x(d) <= extentX[1] - 1e-2
185+
);
186+
187+
let originalRange = mainXZoom.range();
188+
mainXZoom.domain(extentX);
189+
190+
self.xScale.domain(data.map((d, i) => self.getLabel(d, i)));
191+
self.xScale
192+
.range([mainXZoom(originalRange[0]), mainXZoom(originalRange[1])])
193+
.paddingInner(0.4);
194+
195+
// d3.select(".wrapperGroup").select(".x-axis")
196+
// .call(mainXAxis);
197+
198+
update();
199+
console.log("we just brushed");
200+
}
201+
202+
function update() {
203+
const x = self.xScale;
204+
const y = self.yScale;
205+
const svg = d3.select("div.barviz");
206+
207+
svg
208+
.selectAll("rect")
209+
.data(self.data.gradients)
210+
.join("rect")
211+
.attr("x", (d, i) => self.xScale(self.getLabel(d, i)))
212+
.attr("y", (d) => y(d.gradient))
213+
.attr("height", (d) => y(0) - y(d.gradient))
214+
.attr("width", self.xScale.bandwidth());
215+
// .attr("class", "barrect")
216+
// .attr("fill", (d) => "rgba(0, 98, 255, " + d.gradient + ")");
217+
// .data(data, d => d.dayCount)
218+
// .attr("x", d => mainXScale(d.x))
219+
// .attr("y", d => mainHeight - mainYScale(d.y))
220+
// .attr("width", mainXScale.bandwidth())
221+
// .attr("height", d => mainYScale(d.y));
222+
223+
// function customXAxis(g) {
224+
// g.call(self.xAxis);
225+
// g.select(".domain").remove();
226+
// g.selectAll(".tick line").attr("x", 10);
227+
// g.selectAll(".tick text").attr("y", 10);
228+
// }
229+
230+
// svg.select(".x.axis").call(customXAxis);
231+
}
232+
233+
function brushended({ selection }) {
234+
if (!selection) {
235+
gb.call(brush.move, defaultSelection);
236+
}
237+
}
238+
// const defaultSelection = [x(d3.utcYear.offset(x.domain()[1], -1)), x.range()[1]];
239+
}
240+
241+
drawGraph(data) {
242+
let self = this;
243+
// data = data.slice(0, 85);
244+
this.setupScalesAxes(data);
245+
const x = this.xScale;
246+
const y = this.yScale;
247+
248+
const svg = this.createSVGBox("div.barviz", this.chartHeight);
249+
250+
const zoomer = d3.zoom().on("zoom", null);
251+
svg
252+
.call(zoomer)
253+
.on("wheel.zoom", scroll)
254+
.on("mousedown.zoom", null)
255+
.on("touchstart.zoom", null)
256+
.on("touchmove.zoom", null)
257+
.on("touchend.zoom", null);
258+
259+
function scroll() {
260+
// const gBrush = d3.select(".brush");
261+
// let selection = d3.brushSelection(gBrush.node());
262+
// let size = selection[1] - selection[0],
263+
// range = x.range(), //otodo change this to minx
264+
// x0 = d3.min(range),
265+
// x1 = d3.max(range) + x.bandwidth(),
266+
// dx = -d3.event.deltaX,
267+
// topSection;
268+
// if (selection[0] - dx < x0) {
269+
// topSection = x0;
270+
// } else if (selection[1] - dx > x1) {
271+
// topSection = x1 - size;
272+
// } else {
273+
// topSection = selection[0] - dx;
274+
// }
275+
// d3.event.stopPropagation();
276+
// d3.event.preventDefault();
277+
// gBrush.call(brush.move, [topSection, topSection + size]);
278+
}
279+
280+
this.createBarRects(svg, this.xScale, this.yScale, data, "mainbars");
281+
282+
function customYAxis(g) {
283+
g.call(self.yAxis);
284+
g.select(".domain").remove();
285+
g.selectAll(".tick line")
286+
.attr("stroke", "rgba(172, 172, 172, 0.74)")
287+
.attr("stroke-dasharray", "2,2")
288+
.attr("transform", "translate(10,0)");
289+
g.selectAll(".tick text").attr("x", -10).attr("y", 0);
290+
}
291+
292+
function customXAxis(g) {
293+
g.call(self.xAxis);
294+
g.select(".domain").remove();
295+
g.selectAll(".tick line").attr("x", 10);
296+
g.selectAll(".tick text").attr("y", 10);
297+
}
298+
299+
// svg
300+
// .append("g")
301+
// .attr("class", "x axis")
302+
// .attr("transform", "translate(0," + this.chartHeight + ")")
303+
// .call(customXAxis)
304+
// .selectAll("text")
305+
// .attr("y", 0)
306+
// .attr("x", 9)
307+
// .attr("dy", ".35em")
308+
// .attr("transform", "rotate(270)")
309+
// .style("text-anchor", "start");
310+
311+
svg.append("g").call(customYAxis);
312+
}
313+
314+
componentDidMount() {
315+
let barvizElement = document.getElementById("barviz");
316+
barvizElement.style.width = barvizElement.offsetWidth + "px";
317+
this.minChartWidth = barvizElement.offsetWidth;
318+
console.log(barvizElement.offsetWidth);
319+
this.drawGraph(this.data.gradients);
320+
this.drawBrushGraph(this.data.gradients);
321+
}
322+
323+
render() {
324+
return (
325+
<div className=" ">
326+
<div className=" ">
327+
<div id="barviz" className="barviz "></div>
328+
<div id="d3brush" className="d3brush"></div>
329+
</div>
330+
</div>
331+
);
332+
}
333+
}
334+
335+
export default BarViz;

0 commit comments

Comments
 (0)