Published
Edited
May 6, 2019
Importers
Insert cell
Insert cell
md`
- add g for plot area and clip path.
- seperate x and y ticks?
- add extended line options for x/y axis. (clone)
- seperate cells, mid axis Y doesn't look centered. Add points at each quadrant.
- change text size
- convert axis to cells. pass variables or global cells
`
Insert cell
Insert cell
function makeSVGChart(cfg) {
let {xMin=0, xMax=100, xaTop=true, xaMid=true, xaBottom=true, yMin=0, yMax=100, yaLeft=true, yaMid=true, yaRight=true, height=100, width=100, margin={left:50, top:50, right:50, bottom:50}, ticks=10} = cfg;
const w = width - margin.right - margin.left;
const h = height - margin.top - margin.bottom;
const x = d3.scaleLinear().domain([xMin,xMax]).range([0,w]);
const y = d3.scaleLinear().domain([yMin,yMax]).range([h,0]);

let svg = d3.select(DOM.svg(width, height));
// .append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
if (yaLeft) svg.append("g")
.attr("transform", "translate(" + margin.left + " " + margin.top + ")")
// .call(axisLeft);
.call(d3.axisLeft(y).ticks(ticks))
.selectAll(".tick line").clone()
.attr("x2", w)
.attr("stroke-opacity", 0.1);
if (yaRight) svg.append("g")
.attr("transform", "translate(" + (width - margin.right) + "," + margin.top + ")")
.call(d3.axisRight(y).ticks(ticks));

if (yaMid) svg.append("g")
.attr("transform", "translate(" + (w/2+margin.left) + "," + margin.top + ")")
.call(d3.axisLeft(y).ticks(ticks));
if (xaBottom) svg.append("g")
.attr("transform", "translate(" + margin.left + " " + (height - margin.bottom) + ")")
.call(d3.axisBottom(x).ticks(ticks));

if (xaTop) svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.bottom + ")")
.call(d3.axisTop(x).ticks(ticks))
.selectAll(".tick line").clone()
.attr("y2", h)
.attr("stroke-opacity", 0.1)

if (xaMid) svg.append("g")
.attr("transform", "translate(" + margin.top + "," + (h/2+margin.top) + ")")
.call(d3.axisTop(x).ticks(ticks));

function xm(d) { return x(d) + margin.left}
function ym(d) { return y(d) + margin.top}
// if (mouse_status) svg.call(mouse_status, {xm:xm, ym:ym, margin:margin})
return [svg, xm, ym, x, y];
}
Insert cell
function mouse_status(s, cfg) {
let {xm=xm, ym=ym, margin={left:0, top:0, right:0, bottom:0}} = cfg;
let mouse_margin_position = s.append("text")
.attr("id", "chart_margin_pointer_position")
.attr("font-size", "12px")
.attr("font-family", "Arial, Helvetica")
.attr("x", 5)
.attr("y", 15)
.attr("text-anchor", "start")
.attr("stroke", "black")
.attr("stroke-width", "0.5px")
.attr("opacity", 0.4)
.text(d => "xs:0, ys:0");
let mouse_position = s.append("text")
.attr("id", "mouse_position")
.attr("font-size", "12px")
.attr("font-family", "Arial, Helvetica")
.attr("x", 5)
.attr("y", 30)
.attr("text-anchor", "start")
.attr("stroke", "black")
.attr("stroke-width", "0.5px")
.attr("opacity", 0.4)
.text(d => "mx:0, my:0");
// console.log(`margin:${margin.left}`);
s.on("mousemove", function() {
const mouse = d3.mouse(this);
// s.select("#mouse_position")
mouse_position
.text(`x:${parseInt(mouse[0])}, y:${parseInt(mouse[1])}`);
mouse_margin_position
.text(`xs:${parseInt(mouse[0])-margin.left}, ys:${parseInt(mouse[1])-margin.top}`);
// .text(`xs:${parseInt(xs(mouse[0]))}, ys:${parseInt(ys(mouse[1]))}`);
});
}
Insert cell
Insert cell
Insert cell
Insert cell
data = {
let tick = ticks-1;
let cols = cwidth / tick;
let rows = cheight / tick;
// let xstep = xsc(xMax - xMin) / tick;
// let ystep = ysc(yMax - yMin) / tick;
let xstep = (xMax - xMin) / tick;
let ystep = (yMax - yMin) / tick;
let data = [];
for (let r=0; r<rows; r++) {
for (let c=0; c<cols; c++) {
// x, y
data.push([c*xstep, r*ystep])
}
}
return data;
}
Insert cell
sa1 = d3.selectAll(".gpts2").nodes().map(function(d) {
let el = d3.select(d);
// return el.attr("transform");
return el.attr("transform");
});
Insert cell
Insert cell
// plot_point(400,800)
Insert cell
svgChart = {
let svg = d3.select(DOM.svg(cwidth, cheight)).attr("id", "u20190505_2159");
let yaL = yaLeft ? svg.append("g").call(axisLeft) : false;
let yaR = yaRight ? svg.append("g").call(axisRight) : false;
let yaM = yaMid ? svg.append("g").call(axisYMid) : false;
let xaB = xaBottom ? svg.append("g").call(axisBottom) : false;
let xaT = xaTop ? svg.append("g").call(axisTop) : false;
let xaM = xaMid ? svg.append("g").call(axisXMid) : false;
return svg.node();
}
Insert cell
ticks = 10
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
xsc_m = (d) => xsc(d) + margin.left
Insert cell
ysc_m = (d) => ysc(d) + margin.top
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(ysc)
.tickFormat(d3.format("$~f"))
.tickValues(d3.scaleLinear().domain(ysc.domain()).ticks()))
.call(g => g.selectAll(".tick line").clone()
.attr("stroke-opacity", 0.2)
.attr("x2", cwidth - margin.left - margin.right))
.call(g => g.select(".domain").remove())
Insert cell
axisTop = g => g
.attr("transform", `translate(0,${margin.bottom})`)
.call(d3.axisTop(xsc).ticks(ticks))
Insert cell
axisBottom = g => g
.attr("transform", `translate(0,${cheight - margin.bottom})`)
.call(d3.axisBottom(xsc).ticks(ticks))
Insert cell
axisXMid = (g) => g
.attr("transform", `translate(0,${((cheight)/2)})`)
// .attr("transform", `translate(0,${cheight - margin.bottom})`)
.call(d3.axisBottom(xsc).ticks(ticks))
Insert cell
axisRight = (g) => {
g.attr("transform", `translate(${cwidth - margin.right},0)`)
// "translate(" + (cwidth - margin.right) + ",0)")
g.call(d3.axisRight(ysc).ticks(ticks));
}
Insert cell
axisLeft = (g) => {
// g.attr("transform", "translate(" + margin.left + " " + margin.top + ")")
g.attr("transform", `translate(${margin.left},0)`)
g.call(d3.axisLeft(ysc).ticks(ticks));
}
Insert cell
axisYMid = (g) => {
g.attr("transform", `translate(${cwidth/2+margin.left-margin.right},0)`)
g.call(d3.axisLeft(ysc).ticks(ticks));
}
Insert cell
yaLeft = true
Insert cell
yaRight = true
Insert cell
yaMid = true
Insert cell
xaTop = true
Insert cell
xaMid = true
Insert cell
xaBottom = true
Insert cell
margin = ({top: 60, right: 60, bottom: 60, left: 60})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// math = require('mathjs@5.6.0/dist/math.js')
Insert cell
md`##### To Do
- add inverse scaling.
- mouse status scaled output doesn't include margin
- add titles
- axis borders don't don't line up if opposite margin isn't the same.
- consolidate axis code.

##### References
- [@d3/sortable-bar-chart](https://observablehq.com/@d3/sortable-bar-chart)
- [template example:@ronzor](https://observablehq.com/@ronzor/common)
- [@youbastard/nba-team-scoring-differential](https://observablehq.com/@youbastard/nba-team-scoring-differential)
- [@d3/dot-plot](https://observablehq.com/@d3/dot-plot) :: legend, update, Object.assign.
- [@d3/stacked-bar-chart](https://observablehq.com/@d3/stacked-bar-chart) :: legend
- [@d3/candlestick-chart](https://observablehq.com/@d3/candlestick-chart) :: weekends
- [@d3/bar-chart](https://observablehq.com/@d3/bar-chart)
- [@d3/histogram](https://observablehq.com/@d3/histogram)

`
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more