Public
Edited
Jan 10, 2023
Fork of Chart
1 fork
Insert cell
Insert cell
qtst = {
let g = new gla_chart_all(qtrtest,
{
cwidth: 1200,
type: "date",
yformat: ".1s",
ttxformat: "%Y"
}, {
title : "Unemployment in the sector",
sub : "Usually a much longer substring",
link : "Link to source"
})
return g.draw()
}
Insert cell
chartopts = { return {
type: "date",
yformat: ".1s",
yvlkp: ["London", "Rest UK"],
high: true,
ttxformat: "%Y",
leglab : "labels",
lgg : {}
}}
Insert cell
metaopts = {return {
title : "Unemployment in the sector",
sub : "Usually a much longer substring",
link : "Link to source",
includetitles : true
}}
Insert cell
chrt = {
// let data = unempl
let g = new gla_chart_all(unempl, chartopts, metaopts)
return g.draw()
}
Insert cell
{
let g = new gla_chart_all(foodsec, {
type: "character",
charttype: "bar",
bar: true,
stackgroup: "stack",
stack: true,
horiz: true,
lgg: [],
silent_x: false,
forcecols : {
"Very low":"#00163e",
"Marginal": "#065d8e",
"Low": "#6da7de"
},
sort_data: "Very low",
nolabels: false
}, metaopts)
return g.draw()
}
Insert cell
foodsec = FileAttachment("foodsec.csv").csv()
Insert cell
//DOM.download(() => rasterize(unc), "chart.png", "Save as PNG")
Insert cell
function gla_chart_all(data, chartopts, {
cwidth = 1200,
cheight = 500,
title = "",
sub = "",
subheads = ["", ""],
link = "",
text = "",
dv = "",
includetitles = true,
horiz = false,
multichart = "none"
} = {}) {

console.log(`MULTI: ${multichart}`)
let self = this;
let asvg

let eld = document.getElementById(dv)
if(eld != undefined) {

cwidth = eld.offsetWidth;
cheight = eld.offsetHeight - 200;
}

asvg = d3.create("svg")
.attr("width", cwidth)
.attr("height", cheight)
.attr("viewBox", [0, 0, cwidth, cheight])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;");
if(includetitles) {

asvg.append("text")
.text(title)
.attr("name", `maintitle`)
.attr("alignment-baseline", "hanging")
.style("font-size", "28pt")
.style("font-family", "Arial")
.style("color", "#333333")
.attr("x", 0)
.attr("y", 0);
let ht = get_bbox(asvg, "maintitle")
asvg.append("text")
.text(sub)
.attr("name", "subtitle")
.attr("alignment-baseline", "hanging")
.style("font-size", "18pt")
.style("font-family", "Arial")
.style("color", "#999999")
.attr("x", 0)
.attr("y", ht.height);
asvg.append("text")
.html(link)
.attr("name", "link")
.attr("alignment-baseline", "ideographic")
.style("font-size", "14pt")
.style("font-family", "Arial")
.style("color", "#999999")
.attr("x", 0)
.attr("y", cheight);
let st = get_bbox(asvg, "subtitle")
let lk = get_bbox(asvg, "link")
//let cht = cheight - (ht.height + st.height + 5);
chartopts["mTop"] = ht.height + st.height
chartopts["cheight"] = cheight - lk.height
} else { // end if include titles
chartopts["mTop"] = 30
chartopts["cheight"] = cheight
}

if(multichart == "none") {
let chart = (chartopts.horiz ? new gla_chart_h(data, asvg, chartopts) : new gla_chart(data, asvg, chartopts))
} else if (multichart == "sbs_horiz_bar") {
chartopts.cwidth = chartopts.cwidth / 2
/// This is like a stacked data chart.
/// Get keys from first data item.
let dats = split_data_stack(data)

// Build colour palette
chartopts.forcecols = {}
chartopts.forcecols[dats.dkeys[1]] = dats.cols[0]
chartopts.forcecols[dats.dkeys[2]] = dats.cols[1]
// build first chart
let lchart = new gla_chart_h(dats.d1, asvg, chartopts)

let copts2 = chartopts
copts2.nolabels = true // charts share the y axis on the first chart, to remove on right chart
copts2.chart_id = 2

let rchart = new gla_chart_h(dats.d2, asvg, copts2)
rchart.shiftChart(lchart.ywidth[1], 0) // shift chart to right hand side


} else if (multichart == "vsplit_line") {
// group data into two distinct data sets
let dats = split_data_vertical(data)
chartopts.cheight = chartopts.cheight / 2
// let cgrps = d3.group(data, d => d.chart);
// get keys
// Build colour palette
chartopts.forcecols = {}
chartopts.forcecols[dats.dkeys[1]] = dats.cols[0]
chartopts.forcecols[dats.dkeys[2]] = dats.cols[1]

//console.log(dats)

// let tchart = new gla_chart(dats.d1, asvg, chartopts)
chartopts.forcecols[dats.dkeys[1]] = dats.cols[1]
chartopts.nolabels = true
let tchart = new gla_chart(dats.d1, asvg, chartopts)
chartopts.nolabels = false
chartopts.forceMarginRight = tchart.marginRight
let bchart = new gla_chart(dats.d2, asvg, chartopts)
bchart.setSharedRange(tchart.getSharedRange())

bchart.shiftChart(0, cheight / 2)
//
} else if(multichart == "lines_horiz") {
console.log("LINES HORIZ!! *************************")
const halfchart = cwidth / 2
asvg.append("text")
.text(subheads[0])
.attr("name", "subtitle_l")
//.attr("alignment-baseline", "hanging")
.style("font-size", "18pt")
.style("font-family", "Arial")
.style("fill", "#999999")
.attr("x", 0)
.attr("y", 20);
let subl = get_bbox(asvg, "subtitle_l")
chartopts.mTop = subl.height + 20
console.log(`SUBH HEIGHT: ${subl.height}`)

asvg.append("text")
.text(subheads[1])
.attr("name", "subtitle_r")
//.style("alignment-baseline", "hanging") // Does not work for the PDF/SVG versions!
.style("font-size", "18pt")
.style("font-family", "Arial")
.style("fill", "#999999")
.attr("x", halfchart)
.attr("y", 20);
let subr = get_bbox(asvg, "subtitle_r")
console.log(`MTOP: ${chartopts.mTop}`)
chartopts.mTop += (subr.height > subl.height ? subr.height : 0)
let dats = split_data_simple(data)
// chartopts.forceYDomain = get_padded_range(d3.extent(data, d => d.y), 0.25, "line")

chartopts.cwidth = halfchart
let lchart = new gla_chart(dats.d1, asvg, chartopts)
//chartopts.nolabels = true
chartopts.chart_id = 2;
//chartopts.nolabels = true
//chartopts.leglab = "none";

console.log(`DOMAIN FROM LCHART: ${lchart.yDomain}`)
let rchart = new gla_chart(dats.d2, asvg, chartopts)
rchart.shiftChart(halfchart, 0)

} else if(multichart == "lines_vertical") {
const halfchart = cheight / 2
asvg.append("text")
.text(subheads[0])
.attr("name", "subtitle_l")
//.attr("alignment-baseline", "hanging")
.style("font-size", "14pt")
.style("font-family", "Arial")
.style("fill", "#999999")
.attr("x", 0)
.attr("y", 40);
let subl = get_bbox(asvg, "subtitle_l")
chartopts.mTop += subl.height
console.log(`SUBH HEIGHT: ${subl.height}`)

asvg.append("text")
.text(subheads[1])
.attr("name", "subtitle_r")
//.attr("alignment-baseline", "hanging")
.style("font-size", "14pt")
.style("font-family", "Arial")
.style("fill", "#999999")
.attr("x", 0)
.attr("y", 40 + halfchart);
let subr = get_bbox(asvg, "subtitle_r")
chartopts.mTop += (subr.height > subl.height ? subr.height : 0)
let dats = split_data_simple(data)
chartopts.cheight = halfchart

chartopts.chart_id = 1;
console.log("CHART 1 (top)")
let rchart = new gla_chart(dats.d1, asvg, chartopts)
chartopts.chart_id = 2;

chartopts.nolabels = true;

console.log("CHART 2 (bottom)")
let lchart = new gla_chart(dats.d2, asvg, chartopts)


rchart.shiftChart(0, halfchart)
/*rchart.setSharedRange(lchart.getSharedRange())*/
}
// }


// let chart = (chartopts.horiz ? new gla_chart_h(data, asvg, chartopts) : new gla_chart(data, asvg, chartopts))
self.draw = function() {
return asvg.node();
}
}
Insert cell
// function

function gla_chart(rawdata, asvg, {
cwidth = 1200, // remove?
cheight = 600, // remove?
type = "date",
yformat = ".0f",
ytickformat,
yvlkp,
parseTimeString,
charttype = "line",
leglab = "labels",
lgg,
stack= false,
stackgroup,
high = false,
silent_x = false,
forcecols,
mTop = 0,
suffix = "",
chart_id = 1,
nolabels = false,
forceMarginRight,
inc_mark = false,
sort_data,
ttxformat = "%b %Y", // format for tooltip x axis (date only)
forceYDomain
} = {}) {
console.log(`Type: ${type} | Charttype: ${charttype} | W: ${cwidth} | H: ${cheight} | NL ${nolabels} | MTOP: ${mTop} | Sort: ${sort_data} | leglab: ${leglab}`)

if(ytickformat === undefined) ytickformat = yformat
let self = this;
self.chartg = asvg.append("g")
.classed("chartg", true)
.attr("name", "chartg");

self.shiftChart = function(xmv, ymv) {
self.chartg.attr("transform", `translate(${xmv}, ${ymv})`)
}

let convb = yvlkp !== undefined


let dc = new data_control(rawdata, {
convert_b : convb,
xtype: type,
parseTimeString: parseTimeString,
yvlkp : yvlkp,
is_stack: stackgroup == "stack"
})

if(sort_data != undefined) {
//console.log("SORTING D")
dc.sort_by_var("", sort_data)
}

if(charttype == "bar") leglab = "legend"


let data = dc.data


let y1 = new y_axis(data, asvg, {
// svg: asvg,
width: cwidth,
ctype : charttype,
height: cheight,
marginLeft: 25,
//marginTop: 80,
tickFormat: ytickformat,
marginRight: 0,
yDomain : (stackgroup == "stack" ? dc.ext : forceYDomain),
suffix: suffix,
nolabels: nolabels
}, self.chartg);



y1.draw()

let ll = new legend_labels(data, asvg, {
highlight: high,
yScale: y1.yScale,
width: cwidth,
height: cheight,
leglab : leglab,
lgg: lgg,
marginTop: mTop,
categories: dc.datacols,
forceCols: forcecols,
ttxformat: ttxformat
}, self.chartg)
ll.draw()
console.log(`LL WIDTH: ${ll.lbwidth}`)


let x1;
self.setSharedRange = function(rr) {
x1.setSharedRange(rr)
}

self.getSharedRange = function() {
return x1.xRange
}

self.getYRange = function() {
return y1
}

let nlb = (nolabels == undefined ? false : nolabels)
console.log(`NOLABELS: ${nolabels}`)

if(charttype == "bar") {

x1 = new x_axis(data, asvg, {
//type: (silent_x ? "date" : "character"),
type: type,
width: cwidth,
height: cheight,
marginLeft: (y1.txtlft + 10),
marginRight: ll.lbwidth,
showXgrid : false,
add_silent: silent_x,
xType : (silent_x ? d3.scaleUtc : d3.scaleBand),
bar: true,
nolabels: nlb,
chart_id: chart_id
}, self.chartg);
} else if (charttype == "line") {
let mrgR = (forceMarginRight == undefined ? ll.lbwidth + 10 : forceMarginRight)
x1 = new x_axis(data, asvg, {
type: type,
width: cwidth,
height: cheight,
marginLeft: (y1.txtlft + 10),
marginRight: mrgR,
nolabels: nlb,
chart_id: chart_id
}, self.chartg);
}
//let type = scale
x1.draw()


//y1.setHeight(cheight - x1.lheight - ll.lbheight + 30) // this isn't right. it should be setting the marginbottom, not the height
y1.setMarginRight(ll.lbwidth)
self.marginRight = ll.lbwidth
y1.setMarginTop(ll.lbheight + mTop)
x1.setMarginTop(ll.lbheight + mTop)
y1.setMarginBottom(x1.lheight)


console.log("Redrawing")
y1.draw()
x1.draw()
ll.syncXY(x1, y1)
ll.draw()
self.ywidth = y1.range
console.log("everything ok up to drawing lines")
self.yDomain = y1.yDomain

if (charttype == "line") {
console.log("Drawing lines")
let lns = new lines(data, asvg, {
xScale: x1.xScale,
yScale: y1.yScale,
color: ll.color,
include_markers: inc_mark
}, self.chartg)
lns.draw()
console.log("fine")
/*let tt = new tooltip(data, asvg, {
xaxtype : type,
yformat : yformat,
width: cwidth,
height: cheight,
marginLeft: (y1.txtlft + 10),
marginRight: ll.lbwidth,
xScale: x1.xScale,
yScale: y1.yScale,
color: ll.color
}, self.chartg)
tt.draw()*/
} else {
self.x1 = x1
self.dc = dc;
let brs = new bars(data, asvg, {
xScale: (silent_x ? x1.silentScale : x1.xScale),
yScale: y1.yScale,
color: ll.color,
cheight: cheight,
datacols: dc.datacols,
xvar : (silent_x ? "dtid" : "xd"),
stackgroup : stackgroup,
highlight: high,
silent_x: silent_x
})
brs.draw()
}


self.draw = function() {

return asvg.node()
}


}
Insert cell
Insert cell
import {y_axis, y_axis_h} from "@joeheywood/y-axis"

Insert cell
import {x_axis_dt, x_axis_char, x_axis} from "@joeheywood/x-axis"

Insert cell
import {legend_labels} from "@joeheywood/legend-or-labels"

Insert cell
import {unempl, spending, data_control, pop, qtrtest, split_data_stack, split_data_vertical, split_data_simple} from "@joeheywood/data-controller"

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

Insert cell
import {lines} from "@joeheywood/lines"
Insert cell
import {bars, bars_h} from "@joeheywood/bar-charts"
Insert cell
import {tooltip} from "@joeheywood/tooltips"
Insert cell
// import {rgn_d} from "@joeheywood/benefits-pages"
Insert cell
import {rasterize} from "@mbostock/saving-svg"
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