Public
Edited
Feb 6, 2023
2 forks
1 star
Insert cell
Insert cell
Insert cell
chart = {
let parent = this;
// if (!parent) {console.log(myJSON)
parent = document.createElement("div");

const svg = d3.select(DOM.svg(width, height));
const g = svg
.append("g")
.attr("transform", (d, i) => `translate(${margin.left} ${margin.top})`);

const members = svg
.append("g")
.attr("fill", "steelblue")
.selectAll("rect")
.data(data.filter(d => d.count !== 0))
.enter()
.append("rect")
.attr("x", (d) => x(d.start + d.count-1))
.attr("y", (d) => y(d.name))
.attr("rx", 3) //function (d){ if(d.country === "Secretary") {return 0} else {return 3}})
.attr("fill", (d) => color(d.region))
// .attr("opacity", (d) => opacity(d.count))
.attr("height", y.bandwidth()-(y.bandwidth()/50))
// .attr("width", (d) => x(d.end)-x(d.start));
.attr("width", x.bandwidth()-(x.bandwidth()/50));

const places = svg.append('g')
.selectAll("circle")
.data(data.filter(d => d.country === "Secretary" && d.count !== 0))
// .data(filteredData.filter(d => d.count === 1 && d.country === "Secretary"))
.enter()
.append("circle")
.attr('cx', (d) => x(d.start + d.count -1) + (x.bandwidth()/2))
.attr('cy', (d) => y(d.name) + (y.bandwidth()/2))
.attr('r', 6) //function (d){ if(d.country === "Secretary") {return 0} else {return 3}})
// .attr('stroke', 'white')
.attr("fill", "white");
// .attr("opacity", (d) => opacity(d.count))
// .attr("height", y.bandwidth())
// .attr("width", (d) => x(d.end) - x(d.start));

var s = svg.selectAll(".shapes")
.data(data.filter(d => d.mark === 2))
var sg = s.enter()
.append("g")
.attr("class", "shapes")
.attr("transform", function(d,i) {
return "translate(" + (x(d.start + d.count -1) + (x.bandwidth()/2)) + ","+ (y(d.name) + (y.bandwidth()/2))+ ")"
})
.attr("fill", "white")
.attr("stroke-width", 1)

sg.append("path")
.attr("d", function(d) {return d3.symbol().type(d3.symbolStar).size("75")()})
.attr("stroke", "black")

// .attr('cx', (d) => x(d.start + d.count -1) + (x.bandwidth()/2))
//.attr('cy', (d) => y(d.name) + (y.bandwidth()/2))


const tooltip = d3.select(document.createElement("div")).call(createTooltip);
const line = svg
.append("line")
.attr("y1", margin.top - 10)
.attr("y2", height - margin.bottom)
.attr("stroke", "pink")
.style("pointer-events", "none");

// members.attr("transform", (d, i) => `translate(0 ${y(i)})`);

members
.each(getRect)
.on("mouseover", function (event, d) {
let [xt, yt] = d3.pointer(event);
d3.select(this).select("rect").attr("fill", "white");
tooltip.style("opacity", 1).html(getTooltipContent(d));
})
.on("mouseleave", function (event, d) {
d3.select(this).select("rect").attr("fill", color(d.region));
tooltip.style("opacity", 0);
svg.selectAll(".yAxis .tick").selectAll("text").style("fill", "white")
});
svg.append("g").call(xAxis);

svg.append("g").call(yAxis);

svg.on("mousemove", function (event, d) {
let [xt, yt] = d3.pointer(event);
line.attr("transform", `translate(${xt} 0)`);
yt += 20;
svg.selectAll(".yAxis .tick").each(function(d) {
d3.select(this).select("text").style("fill", function() {
var value = data.filter(function(e) {
return e.years === x.invert(xt) && e.count !== 0 && d === e.name
})[0];
return value ? "yellow" : "black";})
})
if (xt > width / 2) xt -= 100;
tooltip.style("left", xt + "px").style("top", yt + "px");
});

parent.appendChild(svg.node());
parent.appendChild(tooltip.node());
parent.groups = members;

//let offset = height - margin.bottom / 3 + 50;
let offset = margin.top + 420;

svg
.append("text")
.attr("class", "header")
.attr("x", 370)
.attr("y", offset -420)
.attr("dy", "1em")
.attr("text-anchor", "start")
.style("font-size", width / 60)
.style("font-weight", 400)
//.style("text-transform", "uppercase")
.html("")
// .append("tspan")
.attr("font-weight", 700)
.text("circle = Secretary, star = Chair of Trustees");

svg
.append("text")
.attr("class", "header")
.attr("x", margin.left)
.attr("y", offset -250)
.attr("dy", "1em")
.attr("text-anchor", "start")
.style("font-size", width / 60)
.style("font-weight", 400)
// .style("text-transform", "uppercase")
.html("")
// .append("tspan")
.attr("font-weight", 700)
.text("Median number of Trustees by Year = 9");

svg
.append("text")
.attr("class", "header")
.attr("x", margin.left)
.attr("y", offset -200)
.attr("dy", "1em")
.attr("text-anchor", "start")
.style("font-size",18)
.style("font-weight", 400)
// .style("text-transform", "uppercase")
.html("")
// .append("tspan")
.attr("font-weight", 700)
.text("Median number of years as Trustee/Secretary = 4");

svg
.append("text")
.attr("class", "header")
.attr("x", margin.left)
.attr("y", offset -350)
.attr("dy", "1em")
.attr("text-anchor", "start")
.style("font-size",18)
.style("font-weight", 400)
// .style("text-transform", "uppercase")
.html("")
// .append("tspan")
.attr("font-weight", 700)
.text("AVERAGE Age when Appointed (Median): 52 (55). AVERAGE Age when Resigned (Median): 57 (58)");


svg
.append("text")
.attr("class", "header")
.attr("x", margin.left)
.attr("y", offset -300)
.attr("dy", "1em")
.attr("text-anchor", "start")
.style("font-size",18)
.style("font-weight", 400)
// .style("text-transform", "uppercase")
.html("")
// .append("tspan")
.attr("font-weight", 700)
.text("AGE RANGE when Appointed: 25-65. AGE RANGE when Resigned 32-74");


g.append("g")
.attr("transform", `translate(${margin.left / 3 - 5},${-15})`)
.append(() =>
legend({
color: color,
title: "",
width: 300
})
);

svg
.append("text")
.attr("class", "legend_footer")
.attr("x", width - margin.left)
.attr("y", height - margin.bottom / 3)
.text(footer);


//AVERAGE Age when Appointed (Median): 52 (55). AVERAGE Age when Resigned (Median): 57 (58)
//AGE RANGE when Appointed: 25-65. AGE RANGE when Resigned 32-74

// console.log(JSON.stringify(data))



return parent;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
color = d3.scaleOrdinal(colscheme).domain(regions)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data
Type SQL, then Shift-Enter. Ctrl-space for more options.

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
import { checkbox, select } from "@jashkenas/inputs"
Insert cell
import { legend, swatches } from "@d3/color-legend"
Insert cell
Insert cell
function invertOrdinal(val, cmpFunc) {
cmpFunc = cmpFunc || function (a, b) {
return (a >= b);
};

const scDomain = this.domain();
let scRange = this.range();

if (scRange.length === 2 && scDomain.length !== 2) {
// Special case, interpolate range vals
scRange = d3.range(scRange[0], scRange[1], (scRange[1] - scRange[0]) / scDomain.length);
}

const bias = scRange[0];
for (let i = 0, len = scRange.length; i < len; i++) {
if (cmpFunc(scRange[i] + bias, val)) {
return scDomain[Math.round(i * scDomain.length / scRange.length)];
}
}

return this.domain()[this.domain().length - 1];
}
Insert cell
url = "https://docs.google.com/spreadsheets/d/1snRkceV0qbdVdTh7zj_pwqru3_bfjv4-vufcox785O8/edit#gid=0"
Insert cell

getCsvUrl = url => {
url = new URL(url);
const id = url.pathname.split("/")[3]
const gid = new URLSearchParams(url.hash.slice(1)).get("gid") || 0;
return `https://docs.google.com/spreadsheets/d/${id}/export?format=csv&gid=${gid}`
}
Insert cell
datan = d3.csv(getCsvUrl(url), d3.autoType)
Insert cell
data = {
var arr = []
const columns = datan.columns.slice(8,33);
var x = 0
var c
datan.forEach(function (d) {
c = 0
for (x = 0; x < columns.length; x++) {
if (+d[columns[x]] > 0)
{c += 1}
else
{c =0}

arr.push({"name": d.name,"start":(parseDate(d.start)).getFullYear(), "end":(parseDate(d.end)).getFullYear(),"years": columns[x],"count": c,"country": d.country, "region": d.Region, "origin": d.origin, "mthServed":d.mthServed, c:c, "mark":parseFloat((+d[columns[x]])) })

}
})
//d[columns[x]]
//+ parseFloat((+d[columns[x]]).toFixed(2))
return arr
}

Insert cell
Insert cell
x.invert = invertOrdinal
Insert cell
myJSON = JSON.stringify(data)
Insert cell
Insert cell
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