Public
Edited
Dec 8, 2022
Fork of Blog Post
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
musicData = appleMusicPlayActivity.map((d) => ({
song: d["Song Name"],
artist: d["Artist Name"],
duration: d["Media Duration In Milliseconds"],
sinceLastPlayed: d["Milliseconds Since Play"],
playDuration: d["Play Duration Milliseconds"]
}))
Insert cell
Insert cell
minDuration = d3.min(musicData, (d) => d.duration)
Insert cell
maxDuration = d3.max(musicData, (d) => d.duration)
Insert cell
minSinceLastPlayed = d3.min(musicData, (d) => d.sinceLastPlayed)
Insert cell
maxSinceLastPlayed = d3.max(musicData, (d) => d.sinceLastPlayed)
Insert cell
minPlayDuration = d3.min(musicData, (d) => d.playDuration)
Insert cell
maxPlayDuration = d3.max(musicData, (d) => d.playDuration)
Insert cell
durationCal = {
const newData = [];
for (let i = 0; i < musicData.length; i++) {
newData.push([
musicData[i].duration / maxDuration,
musicData[i].sinceLastPlayed / maxSinceLastPlayed < 0
? 0
: musicData[i].sinceLastPlayed / maxSinceLastPlayed,
musicData[i].playDuration / maxPlayDuration
]);
}
return newData;
}
Insert cell
meta = durationCal
Insert cell
viewof N = html`<input type=range min=200 max=83142 step=1 value=100>`
Insert cell
viewof perplexity = html`<input type=range min=0 max=500 step=1 value=10>`
Insert cell
Insert cell
Insert cell
Insert cell
draw = {
context.fillStyle = "rgba(255,255,255,0.4)"; // a cheap blur effect
context.fillRect(0, 0, width, height);
const X = d3
.scaleLinear()
.domain(d3.extent(solution, (d) => d[dimX]))
.range([20, width - 20]);
const Y = d3
.scaleLinear()
.domain(d3.extent(solution, (d) => d[dimY]))
.range([20, (width * 2) / 3 - 20]);
const radius = 150 / Math.sqrt(10 + solution.length);
solution.forEach((point, i) => {
let k = meta[i];
context.beginPath();
context.arc(X(point[dimX]), Y(point[dimY]), radius, 0, 2 * Math.PI);
context.fillStyle = d3.hsl(k[0] * 360, 0.3 + 0.5 * k[1], 0.3 + 0.5 * k[2]);
// (`rgb(${k[0]*256 | 0}, ${k[1]*256 | 0}, ${k[2]*256 | 0})`);
context.fill();
});
return md`A simple loop: we draw a circle for each of the points, its color informed by the points array, its position informed by the solution array.`;
}
Insert cell
genre = ["r&b", "techno", "techno", "rock"]
Insert cell
music = d3.range(1000).map((d) => ({
id: d,
duration: Math.random() * 180 + 30,
genre: randomChoice(genre)
}))
Insert cell
randomChoice = (arr) => {
return arr[Math.floor(Math.random() * arr.length)];
}
Insert cell
// one could probably use the more accurate model of color distances given in
// https://beta.observablehq.com/@mbostock/measuring-color-difference
function distanceHSL(a, b) {
let d = 0,
s = 0;
let i = 0;
s = Math.sin(Math.PI * (a[i] - b[i]));
d += s * s;
i = 1;
s = a[i] - b[i];
d += (s * s) / 2;
i = 2;
s = a[i] - b[i];
d += (s * s) / 2;
return Math.sqrt(d);
}
Insert cell
dists = meta.map((a) => meta.map((b) => distanceHSL(a, b)))
Insert cell
solution = {
model.initDataDist(dists);
var cost = 100,
cost0 = 0;
while (Math.abs(cost - cost0) > 1e-6) {
cost = cost0;
cost0 = cost * 0.9 + 0.1 * model.step();
// yield [cost, cost0];
yield model.getSolution();
}
}
Insert cell
Insert cell
Insert cell
Insert cell
d3 = require("d3")
Insert cell
import { appleMusicPlayActivity } from "@kepa/data-music-selfreflection2"
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more