Published
Edited
Jul 19, 2021
1 star
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
data = FileAttachment("2015-10-2021-04-combined-data.csv").csv({
typed: true
})
Insert cell
colors = new Map([
["Brandy", "#f16913"],
["Rum", "#fd8d3c"],
["Vodka", "#fdae6b"],
["Whisky", "#fdd0a2"],
["Gin", "#fee6ce"],
["Beer", "#807dba"],
["Wine", "#bcbddc"]
])
Insert cell
abvs = new Map([
["Brandy", 0.36],
["Rum", 0.36],
["Vodka", 0.36],
["Whisky", 0.36],
["Gin", 0.36],
["Beer", 0.049],
["Wine", 0.125]
])
Insert cell
Insert cell
color = d3
.scaleOrdinal()
.domain(activeColors.keys())
.range(activeColors.values())
Insert cell
dataByDrink = {
const drinks = Array.from(colors.keys());

const keySuffices = ["_excise_duty", "_bulk_litre"];

function initialiseDateObj() {
const obj = {};
const emptyDrinkObj = keySuffices.reduce((acc, key) => {
acc[changeCase.camelCase(key)] = 0;
return acc;
}, {});

drinks.forEach((drink) => {
obj[drink] = { ...emptyDrinkObj };
});

return obj;
}

function sumData(dataObj, rawData) {
const obj = { ...dataObj };
drinks.forEach((drink) => {
keySuffices.forEach((suffix) => {
if (obj[drink]) {
obj[drink][changeCase.camelCase(suffix)] +=
rawData[`${drink.toLowerCase()}${suffix}`];
}
});
});
return obj;
}

const dataByDate = rows.reduce((acc, d) => {
const { date } = d;

if (acc[date] === undefined) {
acc[date] = { date, ...initialiseDateObj() };
}

acc[date] = { ...sumData(acc[date], d) };

return acc;
}, {});

let flattenedByDate = Object.keys(dataByDate).map((k) => dataByDate[k]);

flattenedByDate = flattenedByDate.map((d) => {
const onDate = { ...d };
drinks.forEach((drink) => {
d[drink].standardLitre = d[drink].bulkLitre * abvs.get(drink);
});
return onDate;
});

return flattenedByDate;
}
Insert cell
chartData = {
const data = dataByDrink.map((d) => {
const obj = { date: d.date };

Object.keys(d).forEach((key) => {
if (key !== "date") {
obj[key] =
stat.value === "volume"
? d[key].bulkLitre
: stat.value === "stdVolume"
? d[key].standardLitre
: d[key].exciseDuty;
}
});

return obj;
});

return {
data,
yTickFormat: stat.value === "tax" ? formatRevenue : formatNumbers
};
}
Insert cell
typeOfStats = [
{ label: "Tax Revenue", value: "tax" },
{ label: "Volume", value: "volume" },
{
label: "Alcohol Volume",
value: "stdVolume"
}
]
Insert cell
series = {
const stack = d3
.stack()
.keys(activeColors.keys())
.value((group, key) => group[key])
.order(d3.stackOrderReverse);

return stack(chartData.data).map(
(s) => (
s.forEach((d) => {
d.data = { ...d.data };
d.data.key = s.key;
}),
s
)
);
}
Insert cell
x = d3
.scaleBand()
.domain(chartData.data.map((d) => d.date))
.rangeRound([margin.left, width - margin.right])
Insert cell
y = d3
.scaleLinear()
.domain([0, d3.max(series, (d) => d3.max(d, (d) => d[1]))])
.range([height - margin.bottom, margin.top])
Insert cell
formatDate = d3.timeFormat("%b, %y")
Insert cell
xAxis = (g) =>
g.attr("transform", `translate(0,${height - margin.bottom})`).call(
d3.axisBottom(x).tickFormat((date, i) => {
return i % 3 !== 0 ? null : formatDate(date);
})
)
Insert cell
yAxis = (g) =>
g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).tickFormat((x) => chartData.yTickFormat(x)))
.call((g) =>
g
.select(".tick:last-of-type text")
.clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text(stat.value !== "tax" ? "Litres" : "")
)
Insert cell
formatRevenue = x => {
if (currencyRounding === "Crores") {
return +(x / 1e7).toFixed(2) >= 1
? `₹${(x / 1e7).toFixed(2)}Cr`
: +(x / 1e5).toFixed(2) >= 1
? `₹${(x / 1e5).toFixed(2)}L`
: `₹${(x / 1e3).toFixed(2)}K`;
}
return +(x / 1e9).toFixed(2) >= 1
? `₹${(x / 1e9).toFixed(2)}B`
: +(x / 1e6).toFixed(2) >= 1
? `₹${(x / 1e6).toFixed(2)}M`
: `₹${(x / 1e3).toFixed(2)}K`;
}
Insert cell
formatNumbers = (x) => {
return +(x / 1e9).toFixed(2) >= 1
? `${(x / 1e9).toFixed(2)}B`
: +(x / 1e6).toFixed(2) >= 1
? `${(x / 1e6).toFixed(2)}M`
: `${(x / 1e3).toFixed(2)}K`;
}
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