Published
Edited
Jun 18, 2020
Insert cell
Insert cell
Insert cell
Insert cell
paintings = {
return await d3.csv(
"https://raw.githubusercontent.com/danielefadda/Web-Gallery-of-Art/master/data/paintings.csv"
);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
md`Create a variable to count the number of paintings and use this value to modify intro text`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
d3.nest()
.key(d => d.TIMEFRAME)
.entries(paintings)
Insert cell
Insert cell
d3.nest()
.key(d => d.TIMEFRAME)
.entries(paintings)
.map(d => d.key)
Insert cell
Insert cell
timeframes= ["1400 - 1900"].concat(
d3.nest()
.key(d => d.TIMEFRAME)
.entries(paintings)
.map(d => d.key)
.sort(d3.ascending)
)
Insert cell
Insert cell
schoolSize = new Set(paintings.map(d=>d.SCHOOL)).size
Insert cell
locationSize = new Set(paintings.map(d=>d.LOCATION)).size
Insert cell
typeSize = new Set(paintings.map(d=>d.TYPE)).size
Insert cell
paintingSize = paintings.length
Insert cell
Insert cell
Insert cell
Insert cell
f_paintings= paintings
.filter(d => +d.TIMEFRAME.substring(0,4))
.filter(d => `${time}`!="1400 - 1900" ? d.TIMEFRAME===`${time}`:d.TIMEFRAME) //`${timeframes}`
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
caption_barchart = html`Top 10 by <mark> ${g_by}</mark>`
Insert cell
Insert cell
Insert cell
function gByData (data, criteria) {
const gdata = d3.nest()
.key(d => d[criteria])
.rollup(v => v.length) //count
.entries(data)
.sort((a,b) => d3.descending(a.value, b.value)) // javascrit order by
return gdata
}
Insert cell
Insert cell
gByData(f_paintings,"TYPE")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
hdata = d3.hierarchy(
{ key: 'ALL MUSEUMS', values: d_goruped_paintings.slice(0, 9) },
d => d.values
)
Insert cell
Insert cell
pack(hdata)
Insert cell
Insert cell
pack = data => d3.pack()
.size([width, height])
.padding(10)
(hdata
.sum(d => d.value)
.sort((a, b) => b.value - a.value))
Insert cell
Insert cell
treemapMusei = treemapChart(hdata)
Insert cell
Insert cell
paintings
Insert cell

cpaintings = paintings
.map(d => {
const nd = {
jpg_link: d.jpg_link,
AUTHOR: d.AUTHOR,
TITLE: d.TITLE,
TECHNIQUE: d.TECHNIQUE,
LOCATION: d.LOCATION,
TYPE: d.TYPE,
SCHOOL: d.SCHOOL,
TIMEFRAME: d.TIMEFRAME,
colorsCSS2: {},
colorsCSS3: {},
colorsESA: {},
};
d3.range(9).map(n=> `CSS2_${(n+1)}`)
.forEach(k => {
nd.colorsCSS2[d[k]] = nd.colorsCSS2[d[k]] ? nd.colorsCSS2[d[k]] + 1: 1;
})
d3.range(9).map(n=> `CSS3_${(n+1)}`)
.forEach(k => {
nd.colorsCSS3[d[k]] = nd.colorsCSS3[d[k]] ? nd.colorsCSS3[d[k]] + 1: 1;
})
d3.range(9).map(n=> `ESA_${(n+1)}`)
.forEach(k => {
nd.colorsESA[d[k]] = nd.colorsESA[d[k]] ? nd.colorsESA[d[k]] + 1: 1;
})

return nd;
})

Insert cell
time_cpaintings = d3
.nest()
.key(d => d.TIMEFRAME)
.rollup(l => {
const allColors = {};
l.forEach(c => {
const cols = c.colorsCSS2;
d3.keys(cols).forEach(ck => {
allColors[ck] = allColors[ck] ? allColors[ck] + cols[ck] : cols[ck];
});
});

return allColors;
})
.entries(cpaintings)
.sort((a, b) => d3.ascending(a.key, b.key))
Insert cell
Insert cell
colorList = {
const listColor = [];
time_cpaintings
.map(d => d.value) // lista di dizionari con i colori per ogni timeframe
.forEach(t => listColor.push(d3.keys(t))); // estraggo le chiavi di ogni dizionario e le aggiungo in una lista di liste
return [...new Set(listColor.flat())].sort(); //flat della lista precedente, set per prendere i valori unici quindi trasformo di nuovo in un array e ordino
}
Insert cell
Insert cell
Insert cell
time_cpaintings
Insert cell
//non va bene, deve restituire un array di oggetti non un oggetto.

timeSeriesData = {
let obj={}
time_cpaintings.forEach(function (el,i) {
let countColors = {};
colorList.forEach(item => countColors[item]=el.value[item] ? el.value[item]:0);
el.value = countColors
// obj[timeFrame[i]]=countColors;
})
return obj
}
Insert cell
//nome colore
colorDict= {
let colorDict ={}
colorList.map(color => {
let qColor =[];
time_cpaintings.map(x => x.value).forEach(item => {
qColor.push(item[color])
})
colorDict[color]=qColor;
})
return colorDict
}
Insert cell
Insert cell
colorTimeline = {
const div = DOM.element('div');

let dataT = []
colorList.map(color => {
const trace = {
name:color,
mode:'line',
y: colorDict[color],
x: time_cpaintings.map(x => x.key.split("-")[1]),
stackgroup: 'one',
groupnorm:stacked,
fillcolor: color,
mode: 'none',
text:colorDict[color],
hoverinfo:"text",
}
dataT.push(trace);
})

const layout = {
title: ``,
showlegend: true,
width: 1000,
height: 500,
margin: {pad:5,bottom:100},
legend:{
orientation:'h'
},
paper_bgcolor:'rgba(0,0,0,0)',
plot_bgcolor:'rgba(0,0,0,0)',
// xaxis: {
// rangeselector: {
// buttons: [{
// step: 'all',
// }]},
// rangeslider: {}
// },
};
Plotly.newPlot(div, dataT, layout,{displayModeBar: false});
return div;
}
Insert cell
Insert cell
css3All=cpaintings.map(d => d.colorsCSS3)
Insert cell
time_cpaintings
Insert cell
Insert cell
Insert cell
cpaintings
Insert cell
cData = d3.hierarchy({key:'ALL PAINTINGS', values:allColors}, d => d.values)
Insert cell
Insert cell
caption_treemapcolor = md`This "painting" is the result of the sum of ${f_paintings.length} paintings during the period: ${time} `
Insert cell
caption_treemapcolor2 = html`This "painting" is the result of the sum of <mark> ${f_paintings.length} </mark>paintings during the period: <mark>${time} </mark>`
Insert cell
treemapColor = treemapColors(cData)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
chartNet = {
const radius = 6;
const height = 500;
const weightFilter = 500;
const links = dataNet.links
.map(d => Object.create(d))
.filter(f => f.value > weightFilter);
const nodes = dataNet.nodes.map(d => Object.create(d));

const simulation = d3
.forceSimulation(nodes)
.force(
"link",
d3
.forceLink(links)
.id(d => d.id)
.distance(200)
)
.force(
"charge",
d3
.forceManyBody()
.strength(-1500)
.distanceMax(300)
.distanceMin(10)
)
.force("center", d3.forceCenter(width / 2, height / 2))
.force("x", d3.forceX())
.force("y", d3.forceY())
.force("center", d3.forceCenter(width / 2, height / 2));

const svg = d3.select(DOM.svg(width, 600));

// scale per riproporzionare le dimensioni di nodi (r) e archi (e)
const r = d3
.scaleSqrt()
.domain([0, d3.max(nodes, d => d.value)])
.range([0, 30]);

const e = d3
.scaleSqrt()
.domain([0, d3.max(links, d => d.value)])
.range([0, 10]);

const link = svg
.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", d => e(d.value));

const node = svg
.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", d => r(d.value))
.attr("fill", d => d.id)
.call(drag(simulation));

node.append("title").text(d => d.id);

simulation.on("tick", () => {
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);

node
.attr(
"cx",
d => (d.x = Math.max(r(d.value), Math.min(width - r(d.value), d.x)))
)
.attr(
"cy",
d => (d.y = Math.max(r(d.value), Math.min(height - r(d.value), d.y)))
);
});

invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
Insert cell
chartRadial = {
const h=800;
const weightFilter = 5;
const radiusRadial = 350;
const links = dataNet.links.map(d => Object.create(d))
.filter(f => (f.value > weightFilter));
const nodes = dataNet.nodes.map(d => Object.create(d));

const r = d3.scaleSqrt()
.domain([0, d3.max(nodes, d => d.value)])
.range([0, 30]);
const e = d3.scaleLinear()
.domain([0, d3.max(links, d => d.value)])
.range([0, 10]);
const simulation = d3.forceSimulation(nodes)
.force("center", d3.forceCenter(width / 2, h / 2))
.force("collide", d3.forceCollide().radius(d=> r(d.value) + 1).iterations(2))
// .force('center', d3.forceCenter(width/2, height/2))
.force('radial', d3.forceRadial(radiusRadial, width/2, h/2))
// per disegnare i link ma senza applicare forze.
.force("link", d3.forceLink(links).id(d => d.id).strength(0))

const svg = d3.select(DOM.svg(width, h))
.style('max-width', '1920')
.style('max-height', '1000');
const link = svg.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.selectAll("line")
.data(links)
.join("line")
.attr("stroke-width", d => e(d.value));

const node = svg.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 1.5)
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("r", d => r(d.value)) //sistemare con una scala appropriata
.attr("fill", d => d.id)
.call(drag(simulation));

node.append("title")
.text(d => d.id);


simulation.on("tick", () => {
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);

node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
});

invalidation.then(() => simulation.stop());

return svg.node();
}
Insert cell
drag = simulation => {
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.1).restart();
d.fx = d.x;
d.fy = d.y;
}

function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}

function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}

return d3
.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
}
Insert cell
md`# Sankey`
Insert cell
paintings.slice(0, 5)
Insert cell
Insert cell
tipologia = ["LOCATION", "TYPE", "SCHOOL"]
Insert cell
Insert cell
typeTimeData = d3
.nest()
.key(d => d[`${selettore}`])
.key(d => d.TIMEFRAME)
.rollup(leaves => leaves.length)
.entries(paintings)
.sort((a, b) => d3.ascending(a.key, b.key))
Insert cell
Insert cell
Insert cell
sankey = {
const sankey = d3
.sankey()
.nodeId(d => d.name)
.nodeWidth(15)
.nodePadding(10)
.extent([[1, 5], [width - 1, height - 5]])
.nodeSort(null);

return ({ nodes, links }) =>
sankey({
nodes: nodes.map(d => Object.assign({}, d)),
links: links.map(d => Object.assign({}, d))
});
}
Insert cell
chartSankey = {
const svg = d3.create("svg").attr("viewBox", [0, 0, width, height]);

const { nodes, links } = sankey(sData);

const view = svg.append("g").classed("view", true);
const node = view
.selectAll("rect")
.data(nodes)
.join("rect")
.attr("x", d => d.x0)
.attr("y", d => d.y0)
.attr("height", d => d.y1 - d.y0)
.attr("width", d => d.x1 - d.x0)
.attr("fill", colorS)
.append("title")
.text(d => `${d.name}\n${format(d.value)}`);

const link = svg
.append("g")
.attr("fill", "none")
.attr("stroke-opacity", 0.5)
.selectAll("g")
.data(links)
.join("g")
.style("mix-blend-mode", "multiply");

if (edgeColor === "path") {
const gradient = link
.append("linearGradient")
.attr("id", d => (d.uid = DOM.uid("link")).id)
.attr("gradientUnits", "userSpaceOnUse")
.attr("x1", d => d.source.x1)
.attr("x2", d => d.target.x0);

gradient
.append("stop")
.attr("offset", "0%")
.attr("stop-color", d => colorS(d.source));

gradient
.append("stop")
.attr("offset", "100%")
.attr("stop-color", d => colorS(d.target));
}

link
.append("path")
.attr("d", d3.sankeyLinkHorizontal())
.attr("stroke", d =>
edgeColor === "none"
? "#aaa"
: edgeColor === "path"
? d.uid
: edgeColor === "input"
? colorS(d.source)
: colorS(d.target)
)
.attr("stroke-width", d => Math.max(1, d.width));

link
.append("title")
.text(d => `${d.source.name} → ${d.target.name}\n${format(d.value)}`);

svg
.append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 10)
.selectAll("text")
.data(nodes)
.join("text")
.attr("x", d => (d.x0 < width / 2 ? d.x1 + 6 : d.x0 - 6))
.attr("y", d => (d.y1 + d.y0) / 2)
.attr("dy", "0.35em")
.attr("text-anchor", d => (d.x0 < width / 2 ? "start" : "end"))
.text(d => d.name);

return svg.node();
}
Insert cell
colorS = {
const color = d3.scaleOrdinal(d3.schemePaired);
return d => color(d.category === undefined ? d.name : d.category);
}
Insert cell
// https://observablehq.com/@jarrettmeyer/sankey-with-animated-gradients
Insert cell
Insert cell
d3 = require("d3@5", "d3-sankey@0.12")
Insert cell
height = width
Insert cell
format = d3.format(",d")
Insert cell
color = d3.scaleLinear()
.domain([0, 3])
// .range(["hsl(152,80%,80%)", "hsl(228,30%,40%)"])
.range(["hsl(0,0%,60%)", "hsl(0,0%,90%)"])
.interpolate(d3.interpolateHcl)
Insert cell
colorT = d3.scaleOrdinal().range(d3.schemeSet3)
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