Public
Edited
Sep 15, 2024
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
chartSlope_v1 = {
const svg = d3.create('svg')
.attr('height', height)
.attr('width', width)
.style('font-family', 'sans-serif')
.style('font-size', 12)

const threshhold = 70; // Values higher than 70 can be considered "within the donut"
// TODO: Maybe have gradient of colors within red and green?
const c = d3.scaleOrdinal()
.domain([true, false]) // Green = we are in the safe zone (percentage >= threshhold = true)
.range(['green', 'red']);
//d3.scaleOrdinal()
//.domain(data.map(d => d.name))
//.range(d3.quantize(t => d3.interpolateSpectral(t * 0.8 + 0.1), data.length).reverse())
const planet_outer_radius = (Math.min(width, height) / 2) ;
const planet_inner_radius = planet_outer_radius * 0.5;
const human_outer_radius = planet_inner_radius * 0.9;
const human_inner_radius = human_outer_radius * 0.5; // TODO: Choose something that looks ok
const planet_outerScale = d3.scaleLinear()
.domain([100, 0])
.range([planet_inner_radius + 1, planet_outer_radius]); // TODO: Change sketchy pixel math

const human_innerScale = d3.scaleLinear()
.domain([0, 100])
.range([human_inner_radius, human_outer_radius - 1]); // TODO: Change sketchy pixel math???
const planet_arc = d3.arc()
.innerRadius(planet_inner_radius)
.outerRadius(d => planet_outerScale(d.data.percentage))
.padRadius(0.5 * planet_outer_radius)
.padAngle(2/(0.65 * planet_outer_radius))
.cornerRadius(0)

const planet_default_text_arc = d3.arc()
.innerRadius(planet_inner_radius)
.outerRadius(planet_outer_radius)
.padRadius(0.5 * planet_outer_radius)
.padAngle(2/(0.65 * planet_outer_radius))
.cornerRadius(0)

const human_arc = d3.arc()
.innerRadius(d => human_innerScale(d.data.percentage))
.outerRadius(human_outer_radius)
.padRadius(0.5 * planet_outer_radius)
.padAngle(2/(0.65 * planet_outer_radius))
.cornerRadius(0)

const human_default_text_arc = d3.arc()
.innerRadius(human_inner_radius)
.outerRadius(human_outer_radius)
.padRadius(0.5 * planet_outer_radius)
.padAngle(2/(0.65 * planet_outer_radius))
.cornerRadius(0)
const planet_pie = d3.pie()
.padAngle(0.00)
.sort(null)
.value(1) // Optional: value() sets value accessor that returns a numeric value for a given datum.
// Make this constant to make the arc length constant and arc height variable?

const human_pie = d3.pie()
.padAngle(0.00)
.sort(null)
.value(1)
const planet_data = data_new.filter(d => d.inner_or_outer == "Outer").filter(d => d.percentage !== null);
const human_data = data_new.filter(d => d.inner_or_outer == "Inner").filter(d => d.percentage !== null);
const planet_arcs = planet_pie(planet_data);
const human_arcs = human_pie(human_data);
const planet_donut = svg.append('g')
.attr('transform', `translate(${width/2},${height/2})`) // Sets the center to not (0, 0)
const human_donut = svg.append('g')
.attr('transform', `translate(${width/2},${height/2})`)
planet_donut.selectAll('path')
.data(planet_arcs)
.join('path')
.attr('fill', d => c(d.data.percentage > threshhold))
.attr('d', planet_arc)
.append('title')
.text(d => "Planet/Outside"); // TODO: This is hover tooltip text, but I don't love it because you can't hover on the text

human_donut.selectAll('path')
.data(human_arcs)
.join('path')
.attr('fill', d => c(d.data.percentage > threshhold))
.attr('d', human_arc)
.append('title')
.text(d => "Human/Inside");
planet_donut.append('g')
.attr('font-family', 'sans-serif')
.attr('font-size', 12)
.attr('text-anchor', 'middle')
.selectAll('text')
.data(planet_arcs)
.join('text')
.attr('transform', d => `translate(${planet_default_text_arc.centroid(d)})`)
.call(text => text.append('tspan')
.attr('y', '-0.4em')
.attr('font-weight', 'bold')
.text(d => d.data.category)) // TODO: uhh is this right?
.call(text => text.filter(d => (d.endAngle - d.startAngle) > 0.25).append('tspan')
.attr('x', 0)
.attr('y', '0.7em')
.attr('fill-opacity', 0.7)
.text(d => d.data.category + "\n" + d.data.percentage.toLocaleString()));

// Ok I really have no idea what I'm doing here
// const human_label_center = (arc) => {
// return {
// x: (arc.startAngle() + arc.endAngle()) / 2,
// y: (arc.innerRadius() + arc.outerRadius()) / 2
// };
// //[(arc.startAngle + arc.endAngle) / 2, (arc.innerRadius + arc.outerRadius) / 2];
// }
human_donut.append('g')
.attr('font-family', 'sans-serif')
.attr('font-size', 12)
.attr('text-anchor', 'middle')
.selectAll('text')
.data(human_arcs)
.join('text')
//.attr('transform', d => `translate(${human_label_center(d).x, human_label_center(d).y})`) // This doesn't work
.attr('transform', d => `translate(${human_default_text_arc.centroid(d)})`)
//.attr('transform', d => `translate(${human_arc.centroid(d)})`)
.call(text => text.append('tspan')
.attr('y', '-0.4em')
.attr('font-weight', 'bold')
.text(d => d.data.category)) // TODO: uhh is this right?
.call(text => text.filter(d => (d.endAngle - d.startAngle) > 0.25).append('tspan') // TODO: Uhhhh
.attr('x', 0)
.attr('y', '0.7em')
.attr('fill-opacity', 0.7)
.text(d => d.data.category + "\n" + d.data.percentage.toLocaleString()));
return svg.node()
}
Insert cell
test = {
const radius = 50;
const svg = d3.create('svg')
.attr('height', height)
.attr('width', width)
.style('font-family', 'sans-serif')
.style('font-size', 12)

const content = svg.append("g")
.attr('transform', `translate(200, 200)`)
const path = content.append("path")
.attr('id', 'eco_ceiling_curve')
.attr('d', 'M0,0 a100,100 0 0,1 200,0')
.style('fill', 'hotpink')
.style('opacity', '0.3')
content.append("text")
.attr('font-family', 'sans-serif')
.attr('font-size', 12)
.append("textPath")
.attr('text-anchor', 'middle')
.attr('startOffset', '50%')
.attr('xlink:href', '#eco_ceiling_curve')
.text("WHEEEEE OKAYYYYY YAAAA!!")

// -------------------
// const ceilingStroke = content.append("circle")
// .attr('id', 'ecological_ceiling')
// .attr('r', radius)
// .attr('fill', 'transparent')
// .attr('stroke', 'transparent')
// .attr('stroke-width', 10);

//svg.append("text")
// .append("textPath")
// .attr('xlink:href', '#sweet_donut')
// .style('text-anchor','middle')
// .attr('startOffset', '50%')
// .text("Carissa's sample text")
// -------------------
// THE d is wrong but whatever
// <path id='eco_ceiling_curve' d='M 100 100 A 50 50 0 1 0 0 0' />
// const ceilingTextHtml = `
// <path id='eco_ceiling_curve' d='M150 0 L75 200 L225 200 Z />
// <text width="200">
// <textPath xlink:href='#eco_ceiling_curve'>
// Ecological Ceiling asdfasdf
// </textPath>
// </text>
// `;
svg.append("circle")
.attr('cx', 0)
.attr('cy', 0)
.attr('r', 3)
.attr('fill', 'darkgreen')
svg.append("circle")
.attr('cx', 50)
.attr('cy', 50)
.attr('r', 3)
.attr('fill', 'green')
svg.append("circle")
.attr('cx', 100)
.attr('cy', 100)
.attr('r', 3)
.attr('fill', 'lightgreen')
content.append("circle")
.attr('cx', 0)
.attr('cy', 0)
.attr('r', 3)
.attr('fill', 'darkred')
content.append("circle")
.attr('cx', 50)
.attr('cy', 50)
.attr('r', 3)
.attr('fill', 'red')
content.append("circle")
.attr('cx', 100)
.attr('cy', 100)
.attr('r', 3)
.attr('fill', 'pink')

return svg.node();
}
Insert cell
d = describeArc(200, 200, 100, 100, 0, -90)
Insert cell
function describeArc(x, y, radius, startAngle, endAngle){

var start = polarToCartesian(x, y, radius, endAngle);
var end = polarToCartesian(x, y, radius, startAngle);

var largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";

var d = [
"M", start.x, start.y,
"A", radius, radius, 0, largeArcFlag, 0, end.x, end.y
].join(" ");

return d;
}
Insert cell
function polarToCartesian(centerX, centerY, radius, angleInDegrees) {
var angleInRadians = (angleInDegrees-90) * Math.PI / 180.0;

return {
x: centerX + (radius * Math.cos(angleInRadians)),
y: centerY + (radius * Math.sin(angleInRadians))
};
}
Insert cell
chart2 = {
const svg = d3.create("svg")
.attr("width", 400)
.attr("height", 400);

//Create an SVG path (based on bl.ocks.org/mbostock/2565344)
svg.append("path")
.attr("id", "wavy") //Unique id of the path
.attr("d", "M 10,200 a100,100 0 0,1 200,0") //SVG path
//.attr("d", "M 10,90 Q 100,15 200,70 Q 340,140 400,30") //SVG path
.style("fill", "none")
.style("stroke", "#AAAAAA")
.style("stroke-width", 10)
//Create an SVG text element and append a textPath element
svg.append("text")
.append("textPath") //append a textPath to the text element
.attr("xlink:href", "#wavy") //place the ID of the path here
.style("text-anchor","middle") //place the text halfway on the arc
.attr("startOffset", "50%")
.text("Yay, my text is on a wavy path")
.attr('fill', 'lightgreen')
//.attr('stroke', 'hotpink')

return svg.node()
}
Insert cell
Insert cell
Insert cell
Insert cell
data_new = {
const 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}`
};
return d3.csv(getCsvUrl("https://docs.google.com/spreadsheets/d/1CCFffe9HGeQidmh3Fuf-TZltFqDP8xq3RwHBPKZUGvA/edit#gid=0"), d3.autoType)
// data_new = d3.csvParse(await FileAttachment("d3-donut-sample.csv").text(), d3.autoType)
}

Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
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