Public
Edited
Dec 14
1 star
Insert cell
Insert cell
chart = {
//const width = width;
const height = 1200;
const labelwidth = 200;
const margin = { top: 120, right: 30, bottom: 30, left: 40 };
const velocity = 0.4;

const xScale = d3
.scaleLinear()
.domain([0, data[0].results.length - 1])
.range([margin.left + labelwidth, width - margin.right]);
const yScale = d3
.scaleLinear()
.domain([0, data.length - 1])
.range([margin.top, height - margin.bottom]);

const svg = d3.create("svg").attr("width", width).attr("height", height);

svg
.append("rect")
.attr("width", width)
.attr("height", height)
.attr("fill", "#f0ebd8");

let colors = {
cat: "#05A8AA",
p: "#F07167",
at: "#00487C",
opp: "#445552",
film: "#8A4F7D"
};

svg
.append("text")
.attr("y", 60)
.attr("x", margin.left)
.attr("font-size", 54)
.attr("text-anchor", "start")
.attr("dominant-baseline", "middle")
.text("Google Search Trends in Norway 2024");

svg
.selectAll("text.l")
.data(data)
.join("text")
.attr("class", "l")
.attr("fill", (d) => colors[cat[d.txt]])
.attr("y", (d, i) => yScale(i) + 4)
.attr("x", margin.left + labelwidth - 5)
.attr("text-anchor", "end")
.text((d, i) => d.txt);

// Add a center line for each violin
svg
.selectAll("line.center-line")
.data(data)
.join("line")
.attr("class", "center-line")
.attr("x1", xScale(0))
.attr("x2", xScale(49))
.attr("y1", (d, i) => yScale(i))
.attr("y2", (d, i) => yScale(i))
.attr("stroke", (d) => colors[cat[d.txt]])
.attr("stroke-width", 1);

svg
.selectAll("path.violin")
.data(data)
.join("path")
.attr("class", "violin")
.attr("fill", (d) => colors[cat[d.txt]])
.attr("stroke", (d) => colors[cat[d.txt]])
//.attr("opcacity", 0.2)
.attr("d", (d, i) => {
const results = d.results; // Processed values defining the height of the violin
const y = yScale(i); // Center point for this category
const x = xScale; // X scale for the results

// Generate the path for the violin
const path = d3.path();
const controlOffset = 5; // Adjust for smoother rounding

// Start at the center bottom
path.moveTo(x(0), y);
let values = results.map((d) => d.value);
let sum = 1 / Math.log(d3.mean(values));
console.log("text", d.txt, "results", sum);

// Top edge with rounded corners
for (let idx = 0; idx < results.length - 1; idx++) {
const x1 = x(idx);
const x2 = x(idx + 1);
const y1 = y - sum * velocity * results[idx].value;
const y2 = y - sum * velocity * results[idx + 1].value;

// Use quadratic curve for smoothing
const xc = (x1 + x2) / 2;
const yc = (y1 + y2) / 2;
path.quadraticCurveTo(x1, y1, xc, yc);
}

// Mirror bottom edge with rounded corners
for (let idx = results.length - 1; idx > 0; idx--) {
const x1 = x(idx);
const x2 = x(idx - 1);
const y1 = y + sum * velocity * results[idx].value;
const y2 = y + sum * velocity * results[idx - 1].value;

// Use quadratic curve for smoothing
const xc = (x1 + x2) / 2;
const yc = (y1 + y2) / 2;
path.quadraticCurveTo(x1, y1, xc, yc);
}

// Return to the center bottom with a sharp edge
path.lineTo(x(0), y);

path.closePath(); // Close the shape
return path.toString();
});

return svg.node();
}
Insert cell
cat = ({
Temu: "cat",
EM: "cat",
"OL program": "cat",

"Juliane Snekkestad": "p",
"Morten Borg": "p",
"Marius Borg Høiby": "p",

"Gaute Grøtta Grav": "p",
"Liam Payne": "p",
"Donald Trump": "p",
"Mari Boine": "p",
"Sandra Borch": "p",
"Birgitte Lersbryggen": "p",
"Danby Choi": "p",

"Cookie dough oppskrift": "opp",
"Crumbl cookies oppskrift": "opp",
"Oksestek oppskrift": "opp",
"Dubai Sjokolade oppskrift": "opp",
"Brookies oppskrift": "opp",

"Simone Biles": "at",
"Terje Håkonsen": "at",
"Lamine Yamal": "at",
"Imane Khelif": "at",
"Markus Rooth": "at",
"Solfrid Koanda": "at",
"Katrine Lunde": "at",
"Nora Mørk": "at",
"Frank Løke": "at",

"Baby Reindeer": "film",
"It Ends With Us": "film",
Dune: "film",
Shogun: "film",
Saltburn: "film",
"Norges Dummeste": "film",
"Fool Me Once": "film",
Ibelin: "film",
Hellerudsvingen: "film",
Milliardærøya: "film"
})
Insert cell
names = {
let n = {};
data.forEach((d) => {
n[d.txt] = "cat";
});
return JSON.stringify(n, undefined, 2);
}
Insert cell
data = trends
.map((d) => ({
...d,
max: d.results.findIndex((d) => d.value === 100)
}))
.sort((a, b) => a.max - b.max)
Insert cell
Insert cell
font = "Laila"
Insert cell
html`
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=${font}:ital@0;1&display=swap">

<style>
svg {
font-family: '${font}', serif;
/* font-size: 48px; */
}
</style>
`
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