Public
Edited
Apr 27
Fork of Chart 2
8 forks
Importers
Insert cell
Insert cell
Insert cell
Insert cell
qtst = {
let g = new gla_chart_all(qtrtest,
{
cwidth: 1200,
type: "date",
ytickformat: ".2s",
ttxformat: "%Y",
xFontsize: "9pt"
}, {
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 : "legend",
lgg : {o: "top"}
}}
Insert cell
metaopts = {return {
title : "Unemployment in the sector",
sub : "Usually a much longer substring",
link : "Link to source",
includetitles : true
}}
Insert cell
Insert cell
Insert cell
chart_from_sqlite("aq_no2")
Insert cell
chrt = {
let dat
// let data = unempl
if(chartopts.convert_wide) {
// console.log("_________________________________________")
dat = long_to_wide(unempl)
console.log(dat)
} else {
dat = unempl
}
console.log("GETTING CHARTS")


let g = new gla_chart_all(dat, chartopts, metaopts)
console.log("DONE G")
return g.draw()
}
Insert cell
foodsec = FileAttachment("foodsec.csv").csv()
Insert cell
//DOM.download(() => rasterize(unc), "chart.png", "Save as PNG")
Insert cell
Insert cell
{
let dark_wide = long_to_wide(dark)
let g = new gla_chart_2v(dark_wide,
{type: "date", charttype: "bar", stackgroup: "stack", silent_x: true, stack: true},
spending,
{type: "date", leglab: "legend"})
return g.draw()
}
Insert cell
Insert cell
Insert cell
function gla_chart_all(data, chartopts, {
cwidth = 1000,
cheight = 500,
title = "",
sub = "",
link = "",
text = "",
dv = "",
subheads = ["", ""],
includetitles = true,
horiz = false,
multichart = "none",
header_size = "21pt",
sub_size = "15pt"
} = {}) {
console.log(`HORIZ: ${horiz} | TITLE: ${includetitles}`)
// console.log(chartopts)

let self = this;
let asvg
let chart

function get_svg() {
return asvg
}

self.alterdims = function(w, h) {
if(w > 0){
cwidth = w;
chartopts.cwidth = w;
chart = new gla_chart(data, asvg, chartopts)
}
if(h > 0) cheight = h
}

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) {


let ttl = asvg.append("text")
.text(title)
.attr("name", `maintitle`)
.classed("title", true)
//.attr("alignment-baseline", "hanging")
.style("font-size", header_size)
.style("font-family", "Arial")
.style("fill", "#2a3135")
.attr("x", 0)
.attr("y", 0);


let ht = get_bbox(asvg, "maintitle")

ttl.attr("y", ht.height) // Title needs to be moved down to fit into the chart
let subttl = asvg.append("text")
.text(sub)
.attr("name", "subtitle")
.classed("title", true)
//.attr("alignment-baseline", "hanging")
.style("font-size", sub_size)
.style("font-family", "Arial")
.style("fill", "#515a5e")
.attr("x", 0)
.attr("y", (ht.height)*2); // It's height * 2, so that it fits under the title

// wrap_text(subttl, cwidth - 30, 15, `subttl`, asvg, "hanging") // wrap to 200?
asvg.append("text")
.html(link)
.attr("name", "link")
.classed("title", true)
.attr("alignment-baseline", "ideographic")
.style("font-size", "13pt")
.style("font-family", "Arial")
.style("fill", "#AAAAAA")
.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 + 23
chartopts["cheight"] = cheight - lk.height - 12
} else { // end if include titles
console.log("NOT INCLUDING TITLES")
chartopts["mTop"] = 30
chartopts["cheight"] = cheight
}

if(multichart == "none") {
const regex = new RegExp('^E09')
if(regex.test(data[0].xd)) {
let chart = new boroughMap(data, asvg, {
width: chartopts.cwidth,
height: chartopts.cheight,
g_code: "xd",
valname: "y",
mTop: chartopts.mTop
})
} else {
chart = (chartopts.horiz ? new gla_chart_h(data, asvg, chartopts) : new gla_chart(data, asvg, chartopts))
}
let dg = asvg.append("g")
.classed("dialog", true)

/*let db = new dialog(data, asvg, {
cwidth: cwidth,
cheight: cheight,
marginTop: chartopts["mTop"],
chart: chart
}, dg)*/
} 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
console.log(dats)
// 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]



// let tchart = new gla_chart(dats.d1, asvg, chartopts)
chartopts.forcecols[dats.dkeys[1]] = dats.cols[1]
//chartopts.nolabels = true
console.log("DOING FIRST CHART")
let tchart = new gla_chart(dats.d1, asvg, chartopts)
chartopts.nolabels = false
chartopts.forceMarginRight = tchart.marginRight
chartopts.chart_id = 2
console.log("DOING OTHER CHART")
let bchart = new gla_chart(dats.d2, asvg, chartopts)
console.log("DONE CHARTS")
console.log(tchart.getSharedRange())
let rr = tchart.getSharedRange()
if(!isNaN(rr[0])) {
bchart.setSharedRange(tchart.getSharedRange())
}
bchart.shiftChart(0, cheight / 2)

} else if (multichart == "vsplit_line_3") {
// group data into two distinct data sets
let dats = split_data_vertical(data)
chartopts.cheight = chartopts.cheight / 3
// 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]



// 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") {
let ttls_ht = 20 + chartopts.mTop
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", ttls_ht);
let subl = get_bbox(asvg, "subtitle_l")

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", ttls_ht);
let subr = get_bbox(asvg, "subtitle_r")

chartopts.mTop = (subr.height > subl.height ? chartopts.mTop + subr.height : chartopts.mTop + subl.height)
let dats = split_data_simple(data)
// chartopts.forceYDomain = get_padded_range(d3.extent(data, d => d.y), 0.25, "line")

let shared_y = false
chartopts.cwidth = halfchart
let dd1 = d3.extent(dats.d1, d => d.y)
let dd2 = d3.extent(dats.d2, d => d.y)
if(dd1[0] >= (dd2[0] * 0.9) && dd1[1] <= (dd2[1] * 1.1)) {
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] - range < 0 ? 0 : yext[0] - rangepad)
chartopts.forceYDomain = [ymm, yext[1] + rangepad]
shared_y = true
}
let lchart = new gla_chart(dats.d1, asvg, chartopts)
//chartopts.nolabels = true
chartopts.chart_id = 2;
chartopts.nolabels = shared_y;
//chartopts.leglab = "none";


let rchart = new gla_chart(dats.d2, asvg, chartopts)
rchart.shiftChart(halfchart, 0)

} else if(multichart == "lines_v_multi") {
//let dats = split_data_vertical(data)
let dats = split_data_simple(data)
let halfheight = (chartopts.cheight-30) / 2
chartopts.cheight = halfheight //(chartopts.cheight-30) / 2
const halfchart = cwidth / 2
console.log(dats)

let ttls_ht = 20 + chartopts.mTop

// const halfchart = cwidth / 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", 20)
.attr("y", ttls_ht + 40);
let subl = get_bbox(asvg, "subtitle_l")

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", "14pt")
.style("font-family", "Arial")
.style("fill", "#999999")
.attr("x", 20)
.attr("y", ttls_ht + halfheight);
let subr = get_bbox(asvg, "subtitle_r")

// 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]*/



// let tchart = new gla_chart(dats.d1, asvg, chartopts)
//chartopts.forcecols[dats.dkeys[1]] = dats.cols[1]
//
console.log("DOING FIRST CHART")
chartopts.leglab = "legend"
//chartopts.xFontsize = "0pt"
let tchart = new gla_chart(dats.d1, asvg, chartopts)
// chartopts.nolabels = true
chartopts.leglab = "NONE"
chartopts.forceMarginRight = tchart.marginRight
chartopts.chart_id = 2
//chartopts.xFontsize = "12pt"
console.log("DOING OTHER CHART")
let bchart = new gla_chart(dats.d2, asvg, chartopts)
console.log("DONE CHARTS")
console.log(tchart.getSharedRange())
let rr = tchart.getSharedRange()
if(!isNaN(rr[0])) {
bchart.setSharedRange(tchart.getSharedRange())
}
bchart.shiftChart(0, halfheight + 30)
}


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

function gla_chart(rawdata, asvg, {
cwidth = 1000, // Width of chart
cheight = 500, // Height of chart
type = "date", // Data type of x-axis - date/character/quarter
ytickformat = ".0f", // Formatting string for y-axis
yFontsize = "12pt",
xFontsize = "12pt",
xFontsize2 = "14pt",
broke_x = 0,
lblFontsize = "13pt",
lbMarksize = 8,
bar_opacity = 0.6,
bar_stroke = 2,
yvlkp, // deprecated
parseTimeString, // If date, then string to parse xd column in data
charttype = "line", // bar/line/(area/dumbbell)
leglab = "labels", //legend or label
lgg, // legend object, see label class for more details
stack= false, // stack or group - changes the format of the data
stackgroup = "group", // (Ugh. This is redundant. FIX! See bar and data control)
high = false, // highlight
silent_x = false, // deprecated
forcecols, // force colours. Adds custom colour palette. See legend/labels for more detail
mTop = 0, // margin top
suffix = "", // for y-axis. Can add percentage signs etc.
chart_id = 1, // chart id if more than one chart
nolabels = false,
ttxformat = "%b %Y", // format for tooltip x axis (date only)
ttyformat = ytickformat,
linesize = 5,
forceMarginRight, // forces a margin right (for shared x-axis charts)
inc_mark = false, // include markers for line charts
sort_data, // array to sort data,
anns_obj = [],
forceYDomain,
forceXDomain,
ticksOnValues = false
} = {}) {
console.log(`GLA CHART: Type: ${type} | Charttype: ${charttype} | silent: ${silent_x} | Stackgroup: ${stackgroup} | ID: ${chart_id} NL: ${nolabels} | FC: ${forcecols} | MT: ${mTop} | YF: ${yFontsize} | DIM: ${cwidth}-${cheight}`)
let original_data = JSON.parse(JSON.stringify(rawdata));

// Set up variables
let self = this;
let x1, y1, ll, lns, brs, tt, anns;
if(luk !== null) {

let a = luk
let fdata = original_data.filter(function(d) { return d.chart === `Chart_${luk}`});

if(fdata.length > 0) {
rawdata = fdata
}
}


// Public variables and get/set functions
self.chartg = asvg.append("g")
.classed("chartg", true)
.attr("name", "chartg");

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

self.setSharedRange = function(rr) {
console.log(rr)
//self.chartg.selectAll("*").remove()
x1.setSharedRange(rr)
y1.setMarginBottom(x1.lheight)
y1.draw()

ll.syncXY(x1, y1) // this needs to be in configure_chart
x1.draw()
ll.draw()
self.ywidth = y1.range
setup_lines_bars()
}


self.getSharedRange = function() {
console.log("IN SHARED RANGE")
return x1.xRange
}

self.getSharedDomain = function() {
return x1.getDomain();
}

self.remove_dialog = function() {
}

self.get_data = function() {
return dc.data
}




// ---------- Call setup functions ---------- //
let dc = new data_control(rawdata, {
convert_b : yvlkp !== undefined,
xtype: type,
parseTimeString: parseTimeString,
yvlkp : yvlkp,
is_stack: stackgroup == "stack"
})


if(sort_data != undefined) {
if(stackgroup == "stack") {
dc.sort_by_var(sort_data, [])
} else {
dc.sort_by_var("", sort_data)
}
}


// Redundant code?
if(charttype == "bar" & leglab != "none") {
leglab = "legend"
} else {
console.log("NOT CHANGING THE LEGEND")
}
let data = dc.data
//


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



// y1.draw()


ll = new legend_labels(dc.data, asvg, {
highlight: high,
//yScale: y1.yScale,
width: cwidth,
height: cheight,
leglab : leglab,
lgg: lgg,
marginTop: mTop,
fontsize: lblFontsize,
marksize: lbMarksize,
categories: dc.datacols,
forceCols: forcecols,
ttxformat: ttxformat
}, self.chartg)
// ll.draw()


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

}, self.chartg);
self.yDomain = y1.getDomain()

}
// ------------------------------------------ //





// ================================= Call setup functions ================================= //

console.log("Pre")
configure_dimensions()
console.log("Mid")
setup_lines_bars()
console.log("Post")


// ======================================================================================= //

self.reset = function() {
self.chartg.selectAll("*").remove()
configure_dimensions()
setup_lines_bars()
}


// Once modular variables are initiated them, this function configures them to the page dimensions //
function configure_dimensions() {
console.log("config dims")

y1.draw()


ll.setYScale(y1.yScale)
ll.draw()

console.log("x set mgns")

x1.setMargins(ll.lbheight + mTop, ll.lbwidth, undefined, y1.txtlft + 10 )
// y1.draw()
console.log("x draw")
x1.draw()
console.log("x done")

y1.setMarginRight(ll.lbwidth)
y1.setMarginTop(ll.lbheight + mTop)
y1.setMarginBottom(x1.lheight)
y1.draw()

ll.syncXY(x1, y1)
x1.draw()
ll.draw()
self.ywidth = y1.range
}

// Final step: function to initiate lines/bars once the dimensions have been configured //
function setup_lines_bars() { // call this something else?

if (charttype == "line") {
lns = new lines(dc.data, asvg, {
xScale: x1.xScale,
yScale: y1.yScale,
color: ll.color,
include_markers: inc_mark,
linesize: linesize
}, self.chartg)
lns.draw()
tt = new tooltip(dc.data, asvg, {
xaxtype : type,
yformat : ytickformat,
ttxformat: ttxformat,
width: cwidth,
height: cheight,
marginLeft: (y1.txtlft + 10),
marginRight: ll.lbwidth,
xScale: x1.xScale,
yScale: y1.yScale,
color: ll.color
}, self.chartg)
tt.draw()
ll.draw()
} else {
tt = new tooltip_bar(dc.data, asvg, {
xaxtype : type,
//yformat : ytickformat,
width: cwidth,
height: cheight,
marginLeft: (y1.txtlft + 10),
marginRight: ll.lbwidth,
xScale: x1.xScale,
yScale: y1.yScale,
color: ll.color,
yformat: ttyformat,
ttxformat: ttxformat
}, self.chartg)

self.x1 = x1
self.dc = dc;
let brs = new bars(dc.data, asvg, {
xScale: (silent_x ? x1.silentScale : x1.xScale),
yScale: y1.yScale,
color: ll.color,
cust_opac: bar_opacity,
cheight: cheight,
datacols: dc.datacols,
xvar : (silent_x ? "dtid" : "xd"),
stackgroup : stackgroup,
highlight: high,
silent_x: silent_x,
strokewidth: bar_stroke,
tt: tt
}, self.chartg)
brs.draw()
tt.draw()
}
// console.log(anns_obj)

anns = new annotations(dc.data, anns_obj, asvg, {
xScale: x1.xScale,
yScale: y1.yScale,
type: stackgroup
}, self.chartg)
anns.draw()
}

// returns drawn chart svg nodes //
self.draw = function() {
console.log("DRAWING IND CHART")

return asvg.node()
}

self.draw_save = function() {
asvg.selectAll(".dlgcont")
.style("display", "none")
return asvg.node()

}





}
Insert cell
Insert cell
import {annotations} from "@joe-heywood-gla/annotations"
Insert cell
import {y_axis, y_axis_h} from "@joe-heywood-gla/y-axis"

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

Insert cell
import {legend_labels} from "@joe-heywood-gla/legend-or-labels"

Insert cell
import {unempl, spending, data_control, pop, qtrtest, split_data_stack, dark, get_sqlite_data, get_sqlite_meta, get_sqlite_chart_meta, split_data_vertical, split_data_simple, long_to_wide, get_chapter_sections, get_section_charts, get_shared_domains} from "@joe-heywood-gla/data-controller"

Insert cell
import {get_bbox, wrap_text} from "@joe-heywood-gla/utils"

Insert cell
import {lines} from "@joe-heywood-gla/lines"
Insert cell
import {bars, bars_h} from "@joe-heywood-gla/bar-charts"
Insert cell
import {tooltip} from "@joe-heywood-gla/tooltips"
Insert cell
import {rasterize} from "@mbostock/saving-svg"
Insert cell
import {dialog} from "@joe-heywood-gla/dialog-box"
Insert cell
import {boroughMap} from "@ldn/borough-map"
Insert cell
import {tooltip_bar} from "@joe-heywood-gla/bar-chart-tool-tips"
Insert cell
Insert cell
title_from_sqlite = function(chartID) {
}
Insert cell
Insert cell
Insert cell
function chart_from_sqlite(chartID){
let data = get_sqlite_data(chartID);
let chart = get_sqlite_chart_meta(chartID);
let meta = get_sqlite_meta(chartID);
meta.includetitles = true


let g = Promise.all([data, chart, meta]).then(function(values){
if(values[1].stackgroup == "stack") {
values[0] = long_to_wide(values[0])
}
values[2].includetitles = true

return new gla_chart_all(values[0], values[1], values[2])
})
return g.then(value => value.draw())
}

Insert cell
chart_from_sqlite("sol_smoke")
Insert cell
get_sqlite_chart_meta("sol_tempacc")
Insert cell
from_sqlite = chart_from_sqlite(selected_id)
Insert cell
selected_id = "sol_uchh"
Insert cell
selected_chapter = "Communities"
Insert cell
selected_section = "Cohesion"
Insert cell
Insert cell
charts = get_section_charts(selected_section)
Insert cell
Insert cell
Insert cell
Insert cell
tst = 4
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