Select your 🍨 flavour:
import pandas as pd
import d3
from pyodide.http import open_url
from pyodide.ffi import create_proxy, to_js
url = (
"https://raw.githubusercontent.com/Cheukting/pyscript-ice-cream/main/bj-products.csv"
)
ice_data = pd.read_csv(open_url(url)).sort_values(by=["rating"], ascending=False)
current_selected = []
flavour_elements = document.getElementsByName("flavour")
viz = d3.select("#viz")
viz.select(".loading").remove()
margin = {"top": 30, "right": 30, "bottom": 70, "left": 260}
width = 1000 - margin["left"] - margin["right"]
max_height = 1200 - margin["top"] - margin["bottom"]
svg = (viz
.append("svg")
.attr("width", width + margin["left"] + margin["right"])
.attr("height", max_height + margin["top"] + margin["bottom"])
.append("g")
.attr("transform",
f"translate({margin['left']},{margin['top']})")
)
x = d3.scaleLinear().domain([0, 5]).range([0, width])
xAxis = svg.append("g").call(d3.axisBottom(x))
y = d3.scaleBand()
yAxis = svg.append("g").call(d3.axisLeft(y))
def plot(data):
data_js = to_js(data.to_dict(orient="records"))
height = data["name"].count() * 100 - margin["top"] - margin["bottom"]
if height > max_height:
height = max_height
(
svg.transition().duration(1000)
.attr("width", width + margin["left"] + margin["right"])
.attr("height", height + margin["top"] + margin["bottom"])
)
# x-axis
xAxis.transition().duration(1000).attr("transform", f"translate(0,{height})").call(d3.axisBottom(x))
# y-axis
y.domain(list(data["name"])).range([0, height]).padding(.1)
yAxis.transition().duration(1000).call(d3.axisLeft(y))
# bars
y_fn = create_proxy(lambda record, *_:y(record["name"]))
x_fn = create_proxy(lambda record, *_:x(record["rating"]))
u = svg.selectAll("rect").data(data_js)
(
u.enter()
.append("rect")
.merge(u)
.transition()
.duration(1000)
.attr("x", x(0) )
.attr("y", y_fn)
.attr("width", x_fn)
.attr("height", y.bandwidth() )
.attr("fill", "#69b3a2")
)
u.exit().remove()
# label
label_fn = create_proxy(lambda record, *_:record["rating"])
labels = svg.selectAll(".label").remove()
l = svg.selectAll(".text").data(data_js)
(
l.enter()
.append("text")
.merge(l)
.transition()
.duration(1000)
.attr("class","label")
.attr("x", x_fn)
.attr("y", y_fn)
.attr("dy", "1.5em")
.text(label_fn)
)
l.exit().remove()
(
svg.append("text")
.attr("x", (width / 2))
.attr("y", 0 - (margin["top"] / 2))
.attr("text-anchor", "middle")
.style("font-size", "16px")
.text("⭐ Ice cream flavour ratings ⭐")
)
def select_flavour(event):
for ele in flavour_elements:
if ele.checked:
current_selected = ele.value
break
if current_selected == "ALL":
plot(ice_data)
else:
filter = ice_data.apply(lambda x: ele.value in x["ingredients"], axis=1)
plot(ice_data[filter])
ele_proxy = create_proxy(select_flavour)
for ele in flavour_elements:
if ele.value == "ALL":
ele.checked = True
current_selected = ele.value
ele.addEventListener("change", ele_proxy)
plot(ice_data)