Public
Edited
Jan 10, 2023
1 fork
Importers
Insert cell
# Y-axis

Y-axis for a typical line or bar chart. Assumes a linear scale.



Insert cell
function y_axis(data, svg, {
// svg,
width,
height,
ctype = "line",
yDomain, // [ymin, ymax]
yFormat, // a format specifier string for the y-axis
shared_scale,
fontsize = 25,
tickFormat = ".0f",
marginTop = 10,
marginBottom = 20,
marginLeft = 0,
marginRight = 0,
yRange = [(height - marginTop - marginBottom), marginTop], // [left, right]
showYgrid = true,
suffix = "",
ticks = Math.floor(height/110),
nolabels = false,
chart_id = 1
} = {}, contg) {
console.log(`Y axis - ${yDomain}`)

//// Constructor ////
let self = this
if(contg == undefined) contg = svg;
this.marginRight = marginRight;

if(yDomain === undefined) {
let yext = d3.extent(data, d => d.y)
let range = yext[1] - yext[0]
let rangepad = range * .25
console.log(`Range: [${yext[0]}, ${yext[1]}] (${range}) | Rangepad: ${rangepad}`)
let ymm = (yext[0] >= 0 && yext[0] - range < 0 ? 0 : yext[0] - rangepad)
if(ctype == "bar") {
ymm = (yext[0] < 0 ? yext[0] - (range * .05) : 0)
}
yDomain = [ymm, yext[1] + rangepad];
}
self.yDomain = yDomain

self.yRange = yRange

let yg = contg.append("g")
.classed("yaxis", true)
.attr("name", "yaxis")

//// Accessor functions ////

self.setMarginRight = function(mr) { self.marginRight = mr}

// mostly from https://observablehq.com/@d3/line-chart
self.setHeight = function(h) {
height = h;
yRange = [(height - marginTop - marginBottom), marginTop]
}

self.setMarginTop = function(mt) {
marginTop = mt;
yRange = [(height - marginTop - marginBottom), marginTop]

}

self.setMarginBottom = function(mb) {
marginBottom = mb;
yRange = [(height - marginBottom), marginTop]

}

self.setYRange = function(yrng) {
yRange = yrng
}

self.getYRange = function() {
return yRange
}

self.getDomain = function() {
return yDomain
}





self.draw = function() {
// Construct scales and axes.
self.yScale = d3.scaleLinear(yDomain, yRange);

self.range = yRange
const yAxis = d3.axisLeft(self.yScale)


let yax = yg
.call(yAxis
.ticks(ticks)
.tickSize(-width)
.tickFormat(d3.format(tickFormat)));

let nms = []
let nmix = 0

yax.selectAll(".tick text")
.text(d => (nolabels ? "" : `${d3.format(tickFormat)(d)}${suffix}`))
.style("font-family", "Arial")
.style("font-size", `${12}pt`)
.style("text-anchor", "start")
.style("fill", "#665c54")
.attr("name", (d) => {
nmix++;
nms.push(`yax_${nmix}`)
return `yax_${nmix}`
})

if(showYgrid) {
yax.selectAll(".tick text")
.attr('x', '5')
.attr('dy', '-4');
yax.selectAll(".tick line")
.attr("x2", (width - this.marginRight) - 5)
} else {
yax.selectAll(".tick text")
.attr('x', '5');
yax.selectAll(".tick line")
.attr("x2", 0)
}

self.txtlft = 0;
nms.forEach((n) => {
let yxb = get_bbox(svg, n)
self.txtlft = (self.txtlft > yxb.width ? self.txtlft : yxb.width )
})


let bb = get_bbox(svg, "yaxis")

yg.select(".domain").remove();
yg.selectAll(".tick line")
.style("stroke", "#ababab")
.style("stroke-opacity", 0.4)
}
}



Insert cell
function y_axis_h(data, svg, {
// svg,
width,
height,
ctype = "line",
yDomain, // [ymin, ymax]
yFormat, // a format specifier string for the y-axis
fontsize = 25,
tickFormat = ".0f",
marginTop = 10,
marginBottom = 20,
marginLeft = 0,
marginRight = 0,
// yRange = [(height - marginTop - marginBottom), marginTop], // [left, right]
yRange = [marginLeft, (width - marginLeft - marginRight)],
showYgrid = true,
ticks = Math.floor(height/110)
} = {}, contg) {

//// Constructor ////
let self = this
if(contg == undefined) contg = svg;
this.marginRight = marginRight;


if(yDomain === undefined) {
/*let yext = d3.extent(data, d => d.y)
let range = yext[1] - yext[0]
let rangepad = range * .25
let ymm = (yext[0] >= 0 && yext[0] - rangepad < 0 ? 0 : yext[0] - rangepad)
if(ctype == "bar") {
ymm = 0
}
yDomain = [ymm, yext[1]];*/
yDomain = get_padded_range(d3.extent(data, d => d.y), 0.25, ctype)
}


let yg = contg.append("g")
.classed("yaxis", true)
.attr("name", "yaxis")

//// Accessor functions ////

self.setMarginRight = function(mr) { self.marginRight = mr}

// mostly from https://observablehq.com/@d3/line-chart
self.setHeight = function(h) {
height = h;
yRange = [(height - marginTop - marginBottom), marginTop]
}

self.setMarginLeft = function(ml) {
marginLeft = ml;

yRange = [marginLeft, (width - marginLeft - marginRight)]
}



self.draw = function() {
// Construct scales and axes.
self.yScale = d3.scaleLinear(yDomain, yRange);
self.range = yRange
const yAxis = d3.axisBottom(self.yScale)


let yax = yg
.call(yAxis
.ticks(ticks)
.tickSize(0)
.tickFormat(d3.format(tickFormat)));

let nms = []
let nmix = 0

yax.selectAll(".tick text")
.style("font-family", "Arial")
.style("font-size", `${12}pt`)
//.style("text-anchor", "end")
.style("fill", "#665c54")
.attr("name", (d) => {
nmix++;
nms.push(`yax_${nmix}`)
return `yax_${nmix}`
})

/*if(showYgrid) {
yax.selectAll(".tick text")
.attr('x', '5')
.attr('dy', '-4');
yax.selectAll(".tick line")
.attr("x2", (width - this.marginRight) - 5)
} else {
yax.selectAll(".tick text")
.attr('x', '5');
yax.selectAll(".tick line")
.attr("x2", 0)
}*/



self.txtlft = 0;
nms.forEach((n) => {
//let yxb = get_bbox(svg, `yax_${n}`)
let yxb = get_bbox(svg, n)
self.txtlft = (self.txtlft > yxb.width ? self.txtlft : yxb.width )
self.lheight = yxb.height
})

let bb = get_bbox(svg, "yaxis")

yg.select(".domain").remove();
yg.selectAll(".tick line").style("stroke", "#ABABAB")

yg.attr("transform", `translate(0, ${height - this.lheight - 5})`)
}
}



Insert cell
import {get_bbox, get_padded_range} from "@joeheywood/utils"
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more