Public
Edited
Jul 7, 2023
Insert cell
Insert cell
To-do:
* ~~Hoverover by category - http://jsfiddle.net/bP8J8/2/~~
* ~~Add text overlay - percentage on top of the bar~~
* pop out on hover - might be able to get same effect with thicker border
* add lines connecting categories
* alternative to hover-over: animate a filter

Following might be easier as part of standalone html page:
* add class average in annotation
* add legend
* update background color
* Dynamically show percentages depending on category being hovered over on
Insert cell
// Transformed wide to long - is there a way to do this with the raw data?
// Stacked bar plot: https://d3-graph-gallery.com/graph/barplot_stacked_basicWide.html

chart = {
let plot = Plot.plot({
y: {
padding: .3 // Add padding between bars
},
marks: [
Plot.barX(longdata, {
x: "percent",
y: "Class",
title: d => `${d.Class} - ${d.category}: ${d.percent} percent`,
text: d => `${d.Class} - ${d.category}: ${d.percent} percent`,
fill: 'category'
// sort: { }
}),
Plot.ruleX([0]), // y-axis at x=0
Plot.textX(longdata,
Plot.stackX(
Plot.groupY(
{ x: "sum", text: "first" //https://observablehq.com/plot/transforms/group#groupy-outputs-options
},
{
y: "Class",
z: "category",
x: "percent",
text: (d) => `${d.percent} %`,
fill: (d) => d.category == 'Rent'?"white" : "black",
filter: (d) => d.percent > 1,
order: ["Rent", "Food", "Clothes", "Tax", "Other"] // Needed to explicitly set order
}
)
)
),
],
color: {
// // * manual color categories with mapping between the two
domain: ["Rent", "Food", "Clothes", "Tax", "Other"],
// range: ["Black", "Purple","Pink", "Gold", "Grey"],
range: ["#181815", "#775c7c","#f5a590", "#aea7a1", "#c4b5a6"],
// // If using color schemes ⬇
// scheme: "set2",
// type: "categorical"
},
z: {
domain: ["Rent", "Food", "Clothes", "Tax", "Other"],
},
y: {
domain: rawdata.map(d => d.Class)
},
height: 500, // Manually add more size
marginLeft: 100
});
d3.select(plot)
.selectAll("rect") // selects all path objects
.on("pointerenter", function () { // when hovering over a path object. use pointerenter instead of mouseover - mouseover applies to the individual elements rather than the plot object as a whole, so it results in more flickering as the mouse enters and leaves
d3.select(plot)
.selectAll("rect")
.attr("opacity", 0.2); // set opacity of everything to 0.2
// d3.select(plot)
// .selectAll("rect")
// .filter(function (d) { return d.category === this.category; })
// .attr("opacity", 1);
d3.selectAll(`rect[fill='${d3.select(this).attr("fill")}']`) // select all html elements with the same fill color as the item being hovered on. d3.filter doesn't seem to work here
//d3.select(this) // https://stackoverflow.com/questions/42339628/d3-grouped-bar-chart-selecting-entire-group
.attr("opacity", 1) // set opacity of selected path to 1
// .merge(this)
// .transition()
// .attr("height", function(d) { return d.height + 100; })
// .attr("width", function(d) { return d.width + 100; });
// Add text of the bar being hovered on https://chartio.com/resources/tutorials/how-to-show-data-on-mouseover-in-d3js/
// make pop out a little - attribute governing size, pad it a little
});

d3.select(plot).on("pointerleave", function () { // when mouse leaves
d3.select(plot).selectAll("rect").attr("opacity", 1); // set opacity of everything to 1
d3.select(this)
// .attr("height", function(d) { return d.height/1.5; })
// .attr("width", function(d) { return d.width/1.5; });
// Remove text of the bar being hovered on
});

return plot;
}


Insert cell
// d3.rollup(rawdata, v => v.Class, d => d.Class)
// rawdata.map(d => d.Class)
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