Public
Edited
Aug 22, 2024
1 fork
1 star
Insert cell
Insert cell
{
const svg = html`
<svg width="${width}" height="${height}" >
<style>
.legend {
font-family: monospace;
text-transform: uppercase;
letter-spacing: 7px;
font-size: 20px;
opacity: 70%;
font-weight: 900;
text-shadow: 0 1px 0px white;
}
</style>
<linearGradient id="linearColor1" x1="0" y1="0" x2="1" y2="0">
<stop offset="95%" stop-color="#00000033"></stop>
<stop offset="100%" stop-color="#000000"></stop>
</linearGradient>
<linearGradient id="linearColor2" x1="0" y1="0" x2="0.7" y2="1">
<stop offset="97%" stop-color="#00000033"></stop>
<stop offset="98%" stop-color="#000000"></stop>
</linearGradient>
<linearGradient id="linearColor3" x1="0" y1="0" x2="0.7" y2="1">
<stop offset="97%" stop-color="#00000033"></stop>
<stop offset="98%" stop-color="#000000"></stop>
</linearGradient>
<linearGradient id="linearColor4" x1="0" y1="0" x2="0.64" y2="1">
<stop offset="99%" stop-color="#00000033"></stop>
<stop offset="100%" stop-color="#000000"></stop>
</linearGradient>
<circle r="${r1}" cx="${400}" cy="${350}" stroke="none" stroke-opacity="0.5" fill="none"></circle>
<circle r="${r2}" cx="${400}" cy="${350}" stroke="none" stroke-opacity="0.5" fill="none"></circle>
<circle r="${rselected}" cx="${400}" cy="${350}" stroke="none" stroke-opacity="0.5" fill="none"></circle>
<circle r="${100}" cx="${400}" cy="${350}" stroke-opacity="0.5" fill="#00000009" stroke="url(#linearColor1)"></circle>
<circle r="${175}" cx="${400}" cy="${350}" stroke-opacity="0.5" fill="none" stroke="url(#linearColor2)"></circle>
<circle r="${250}" cx="${400}" cy="${350}" stroke-opacity="0.5" fill="none" stroke="url(#linearColor3)"></circle>
<circle r="${325}" cx="${400}" cy="${350}" stroke-opacity="0.5" fill="none" stroke="url(#linearColor4)"></circle>
<text x="510" y="360" class="legend">← Selected</text>
<text x="515" y="500" class="legend">← High Relevance</text>
<text x="562" y="560" class="legend">← Low Relevance</text>
<text x="610" y="620" class="legend">← Potential Relevance</text>
</svg>`;
const node = d3.select(svg)
.selectAll()
.data(nodes)
.join("circle")
.attr("r", d => d.r)
.attr("cx", x)
.attr("cy", y)
.attr("fill", "#00000029")
const link = d3.select(svg)
.append("g")
.attr("stroke", linkColor)
.attr("stroke-opacity", 0.6)
.selectAll()
.data(links)
.join("line")
.attr("stroke-width", d => Math.sqrt(d.value));

function assignNodeToRandomTier(d) {
if(selector.includes(d.id)) return rselected;
switch(d.type) {
case "a":
case "c":
case "d":
case "g":
return r1;
break;
case "h":
return r3;
break;
default:
return r2;
}
}

const simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id).strength(0.1))
.force('collide', d3.forceCollide().radius(d => d.r + 1))
.force("r", d3.forceRadial(d => assignNodeToRandomTier(d), 400, 350).strength(0.5))
.on("tick", ticked)
.alphaTarget(0.1);

function ticked() {
node.attr("cx", d => d.x).attr("cy", d => d.y);
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
}

ticked();
invalidation.then(() => simulation.stop());
return svg;
}
Insert cell
viewof linkColor = radio({options: [
{label: 'Hidden', value: "#00000000"},
{label: 'Shown', value: "#00000020"},
{label: 'Highlighted', value: "#ff0000"},
], value: "#00000000"})
Insert cell
height = width*0.6
Insert cell
viewof x = slider({
min:0,
max:width,
value:width/2,
title: "cx"
})
Insert cell
viewof y = slider({
min:0,
max:height,
value:height/2,
title: "cy"
})
Insert cell
viewof r1 = slider({
min:0,
max:300,
value:293,
title: "Possible"
})
Insert cell
viewof r2 = slider({
min:205,
max:300,
value:280 ,
title: "Low"
})
Insert cell
Insert cell
viewof rselected = slider({
min:0,
max:300,
value:10,
title: "Selected"
})
Insert cell
viewof selector = radio({options: [
{label: 'NIL', value: comboNone},
{label: 'Combo 1', value: comboA},
{label: 'Combo 2', value: comboB},
{label: 'Combo 3', value: comboC},
], value: comboNone})
Insert cell
comboNone = [];

Insert cell
comboA = [1,12,31,41];

Insert cell
comboB = [5,9,42,51,49,43,44,45];

Insert cell
comboC = [61,62,63,64,65];
Insert cell
Insert cell
function randomNode() {
let i = parseInt(Math.random() * nodes.length);
return nodes[i].id
}
Insert cell
nodes = [].concat(
d3.range(12).map(function() { return {type: "a", r: 5}; }),
d3.range(23).map(function() { return {type: "b", r: 7}; }),
d3.range(10).map(function() { return {type: "c", r: 10}; }),
d3.range(5).map(function() { return {type: "d", r: 13}; }),
d3.range(10).map(function() { return {type: "e", r: 8}; }),
d3.range(5).map(function() { return {type: "f", r: 15 }; }),
d3.range(4).map(function() { return {type: "g", r: 20 }; }),
d3.range(7).map(function() { return {type: "h", r: 6 }; }),
).map((d,id) => ({id, ...d, x:Math.random() * height,y:Math.random() * height}))
Insert cell
d3 = require("d3")
Insert cell
import {slider, radio} from "@jashkenas/inputs"
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