Published
Edited
Jan 29, 2022
10 forks
Importers
70 stars
Also listed in…
Data Analysis
Plot
Insert cell
Insert cell
Insert cell
{
const
colorDomain = ["Increase", "Decrease", "Total"],
colorRange = ["#649334", "#cc392b", "#1f77b4"];
const plot = Plot.plot({
width: width,
x: {
align: 0,
round: false,
domain: waterfall.map(d => d.month)
},
y: {
grid: true,
nice: true,
label: "Profit",
tickFormat: d3.format(".2s")
},
color: {
domain: colorDomain,
range: colorRange
},
marks: [
Plot.barY(waterfall, {
x: "month",
y1: "prior",
y2: "accu",
fill: d => d.month === "Total" ? "Total" : d.profit >= 0 ? "Increase" : "Decrease",
title: d => d.month === "Total"
? `Total: ${fmt(d.accu)}`
: `${d.month}\nProfit: ${fmt(d.profit)}\nRunning Total: ${fmt(d.accu)}`
}),
Plot.ruleY(waterfall, {
x1: "month",
x2: "nextMonth",
y: "accu",
strokeDasharray: "1.5"
}),
Plot.ruleY([0], {strokeDasharray: "1.5"}),
plotLabel(waterfall.filter(d => d.profit >= 0), -7),
plotLabel(waterfall.filter(d => d.profit < 0), 7)
//plotLabel(waterfall.filter(d => d.profit >= 0), "bottom"),
//plotLabel(waterfall.filter(d => d.profit < 0), "top")
]
})
return wrap(
Swatches({color: d3.scaleOrdinal(colorDomain, colorRange)}),
plot
);
}
Insert cell
//plotLabel = (data, anchor) =>
plotLabel = (data, dy) =>
Plot.text(data, {
x: "month",
y: "accu",
dy: dy,
//frameAnchor: anchor,
fontWeight: "bold",
text: d => d3.format(".2s")(d.accu)
})
Insert cell
Insert cell
waterfall = {
let last = 0, accu = 0;
const waterfall = numbers.map((d, i) => {
last = accu;
accu += d.profit;
return {
month: d.month,
nextMonth: i < 11 ? numbers[i + 1].month : "Total",
prior: last,
accu: accu,
profit: d.profit
}
});
waterfall.push({
month: "Total",
nextMonth: null,
prior: 0,
accu: accu,
profit: 0
});
return waterfall;
}
Insert cell
Insert cell
{
const territories = [...new Set(ribbon.map(d => d.territory))];
const plot = Plot.plot({
width: width,
x: {
align: 0,
round: false,
domain: months
},
y: {
grid: true,
label: "Profit",
nice: true,
tickFormat: d3.format(".2s")
},
color: {
type: "categorical",
domain: territories
},
marks: [
Plot.areaY(ribbon, Plot.stackY({
x: d => months[d.month],
y: "profit",
curve: "bump-x",
fill: "territory",
fillOpacity: 0.7,
order: "value"
})),
Plot.barY(ribbon, Plot.stackY({
x: d => months[d.month],
y: "profit",
fill: "territory",
order: "value",
insetLeft: 19,
insetRight: 19,
title: d => `${months[d.month]} - ${d.territory}\nRank: ${d.rank}\nProfit: ${fmt(d.profit)}`
}))
]
})
return wrap(
Swatches({color: d3.scaleOrdinal(territories, d3.schemeTableau10)}),
plot
)
}
Insert cell
Insert cell
ribbon = {
const data = await FileAttachment("ribbon@1.csv").csv({typed: true});
return d3.groups(data, d => d.month)
.sort((a, b) => a[0] - b[0])
.flatMap(m => m[1].map((d, i) => ({...d, month: d.month - 1, rank: i + 1})));
}
Insert cell
Insert cell
{
const plot = Plot.plot({
height: 500,
marginLeft: 100,
x: {
axis: "top",
grid: true,
nice: true,
tickFormat: d => d3.format(".0s")(Math.abs(d))
},
y: {
label: "Sales Territory",
domain: d3.groupSort(tornado, g => -d3.sum(g, d => d.profit), d => d["territory"])
},
marks: [
Plot.barX(tornado, Plot.stackX({
x: d => d.profit * (d["year"] === "CY2014" ? -1 : 1),
y: d => d["territory"],
fill: "year",
title: d => `${d["year"]}\n${d["territory"]}\n${fmt(d.profit)}`
})),
Plot.text(tornado, {
filter: d => d["year"] === "CY2014",
dx: -5,
x: d => -d.profit,
y: d => d["territory"],
text: d => d3.format(".3s")(d.profit),
textAnchor: "end",
fontWeight: "bold"
}),
Plot.text(tornado, {
filter: d => d["year"] === "CY2015",
dx: 5,
x: d => d.profit,
y: d => d["territory"],
text: d => d3.format(".3s")(d.profit),
textAnchor: "start",
fontWeight: "bold"
}),
Plot.ruleX([0])
]
})
return wrap(
Swatches({color: d3.scaleOrdinal(["CY2014", "CY2015"], d3.schemeTableau10)}),
plot
)
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const data = linedot.slice(0, m);
return Plot.plot({
width: width,
marginTop: 50,
marginRight: 50,
x: {
domain: linedot.map(d => d.Month)
},
y: {
grid: true,
nice: true,
domain: d3.extent(linedot.map(d => d.SalesAmount)),
tickFormat: "s"
},
r: {
domain: d3.extent(linedot.map(d => d.GrossProfit)),
range: [10, 50]
},
color: {
domain: d3.extent(linedot.map(d => d.GrossProfit)),
scheme: "bupu"
},
marks: [
Plot.line(data, {
x: "Month",
y: "SalesAmount",
stroke: "#457b9d"
}),
Plot.dot(data, {
x: "Month",
y: "SalesAmount",
r: "GrossProfit",
fill: "GrossProfit",
title: d => `${d.Month}\nSales Amount: ${fmt(d.SalesAmount)}\nGrossProfit: ${fmt(d.GrossProfit)}`
})
]
})
}
Insert cell
Insert cell
Insert cell
Insert cell
{
const plot = Plot.plot({
width: 500,
height: 500,
padding: 0,
x: {axis: null},
y: {axis: null},
color: {
type: "categorical",
scheme: "tableau10"
},
marks: [
Plot.cell(waffles[0], {
x: "x",
y: "y",
rx: 4, ry: 4,
fill: "index",
inset: 1.5,
title: d => `${chartData[d.index].territory}\n${d3.format(",d")(chartData[d.index].profit)} (${chartData[d.index].ratio.toFixed(1)}%)`
})
]
})
return wrap(
Swatches({color: d3.scaleOrdinal(chartData.map(d => d.territory), d3.schemeTableau10)}),
plot
)
}
Insert cell
import {chartData, waffles} from "@analyzer2004/waffle-chart"
Insert cell
Insert cell
Plot.plot({
height: 500,
marginLeft: 100,
x: {
axis: null,
nice: true
},
y: {
label: "Subcategory",
domain: d3.groupSort(funnel, g => -d3.sum(g, d => d.amount), d => d.subcategory)
},
marks: [
Plot.barX(funnel, {
x1: d => -d.amount / 2,
x2: d => d.amount / 2,
y: "subcategory",
fill: "subcategory",
title: d => `${d.subcategory}\n${fmt(d.amount)}`
}),
Plot.text(funnel, {
x: 0,
y: "subcategory",
text: d => d3.format(".2s")(d.amount),
fontWeight: "bold",
fill: "white"
})
]
})
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