Published
Edited
Jun 7, 2020
Importers
1 star
Insert cell
Insert cell
iconChart = {
yield html`
<div id="chartIcons">
</div>`;
drawDonut();
}
Insert cell
iconToCharChart = {
yield html`
<div id="chartPerCharacter">
</div>`;
}
Insert cell
Insert cell
chartFromPOV = {
var svg = d3.create("svg")
.attr("viewBox", [0, 0, dimensions.width, dimensions.height])
var g = svg
.append("g")
.attr("transform", "translate(" + dimensions.width / 2 + "," + dimensions.height / 2 + ")");
let data = dataFromCharacter[characterPOV]
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {return d.value; })
let charData = d3.entries(data).sort((a, b) => b.value - a.value)
var data_ready = pie(charData)
var arc = d3.arc()
.innerRadius(radius * 0.6) // This is the size of the donut hole
.outerRadius(radius * 0.9)
const photoImgWidth = 100

g
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d){ return(color(d.data.key)) })
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
.style('cursor', 'pointer')
.on('mouseenter', function(d) {
g.selectAll('path').filter(p => p.data.key !== d.data.key).style('opacity', 0.2);
const image = g.selectAll('image')
.data([d])
.join("image")
.attr('data-id', d => d.data.key)
.attr('height', function(d) {
return width * 0.3
})
.attr("x", d => -getWidth(d.data.key) / 2)
.attr("y", -width * 0.2)
.attr("xlink:href", d => d.data.key)
.attr('opacity',1)
const label = g.selectAll('text')
.data([d])
.join('text')
.attr("fill", "#888")
.style('font-size', width/ 20)
.attr('data-id', d => d.data.key)
.attr('text-anchor', 'middle')
.attr('y', radius * 0.35)
.text(d => d.data.value + ' POV' + (d.data.value === 1 ? '': 's'))
.attr('opacity',1);
})
.on('mouseout', function(d) {
g.select(`image[data-id="${d.data.key}"]`).remove();
g.select(`text[data-id="${d.data.key}"]`).remove();
g.selectAll('path').style('opacity', 1);

})
return svg.node()
}
Insert cell
async function drawDonutSpecific(url) {
d3.select("#chartPerCharacter").select('svg').remove()
var svg = d3.select("#chartPerCharacter")
.append("svg")
.attr("viewBox", [0, 0, dimensions.width, dimensions.height])
.append("g")
.attr("transform", "translate(" + dimensions.width / 2 + "," + dimensions.height / 2 + ")");
let data = dataPerCharacter[url]


var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {return d.value; })

var data_ready = pie(d3.entries(data))

var arc = d3.arc()
.innerRadius(radius * 0.6) // This is the size of the donut hole
.outerRadius(radius * 0.9)

const photoImgWidth = 100
svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d){ return(color(d.data.key)) })
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
.style('cursor', 'pointer')
.on('mouseenter', function(d) {
svg.selectAll('path').filter(p => p.data.key !== d.data.key).style('opacity', 0.2);

const label = svg.append('text')
.datum(d)
.style('font-size', width/ 20)
.attr("fill", "#888")
.attr('data-id', d => d.data.key)
.attr('text-anchor', 'middle')
.attr('y', radius * 0.3)
.text(d => d.data.value + ' POV' + (d.data.value === 1 ? '': 's') + ' from ')
.attr('opacity',1);
svg.append('text')
.datum(d)
.style('font-size', width/ 20)
.attr("fill", "#888")
.attr('data-id', d => d.data.key)
.attr('text-anchor', 'middle')
.attr('y', radius * 0.4)
.text(d => d.data.key)
.attr('opacity',1);
})
.on('mouseout', function(d) {
svg.selectAll(`text[data-id="${d.data.key}"]`).remove();
svg.selectAll('path').style('opacity', 1);
})
const image = svg.selectAll('image')
.data([url])
.join("image")
.attr('data-id', d => d)
.attr('height', function(d) {
return width * 0.3
})
.attr("x", d => -getWidth(d) / 2)
.attr("y", -width * 0.20)
.attr("xlink:href", d => d)
.attr('opacity',1)
}
Insert cell
async function drawDonut() {
var svg = d3.select("#chartIcons")
.append("svg")
.attr("viewBox", [0, 0, dimensions.width, dimensions.height])
.append("g")
.attr("transform", "translate(" + dimensions.width / 2 + "," + dimensions.height / 2 + ")");
var pie = d3.pie()
.sort(null) // Do not sort group by size
.value(function(d) {return d.value; })
var data_ready = pie(d3.entries(data))
var arc = d3.arc()
.innerRadius(radius * 0.6) // This is the size of the donut hole
.outerRadius(radius * 0.9)
const photoImgWidth = 100

svg
.selectAll('allSlices')
.data(data_ready)
.enter()
.append('path')
.attr('d', arc)
.attr('fill', function(d){ return(color(d.data.key)) })
.attr("stroke", "white")
.style("stroke-width", "2px")
.style("opacity", 1)
.style('cursor', 'pointer')
.on('click', function(d) {
drawDonutSpecific(d.data.key)
})
.on('mouseenter', function(d) {
svg.selectAll('path').filter(p => p.data.key !== d.data.key).style('opacity', 0.2);
const image = svg.selectAll('image')
.data([d])
.join("image")
.attr('data-id', d => d.data.key)
.attr('height', function(d) {
return width * 0.3
})
.attr("x", d => -getWidth(d.data.key) / 2)
.attr("y", -width * 0.2)
.attr("xlink:href", d => d.data.key)
.attr('opacity',1)
const label = svg.selectAll('text')
.data([d])
.join('text')
.style('font-size', width/ 20)
.attr("fill", "#888")
.attr('data-id', d => d.data.key)
.attr('text-anchor', 'middle')
.attr('y', radius * 0.3)
.text(d => d.data.value + ' Chapter' + (d.data.value === 1 ? '': 's'))
.attr('opacity',1);
})
.on('mouseout', function(d) {

svg.select(`image[data-id="${d.data.key}"]`).remove();
svg.select(`text[data-id="${d.data.key}"]`).remove();
svg.selectAll('path').style('opacity', 1);
})
}
Insert cell
getHeight = function(d, width) {
const w = getWidth(d.data.key)
return 150 * width / w
}
Insert cell
getWidth = function(url) {
let endIndex = url.indexOf('px-');
let w = url.slice(endIndex - 3, endIndex)
return (+w) * width * 0.002
}
Insert cell
iconDataSource = await FileAttachment("icon-distribution@1.csv").text()
Insert cell
data = {
let data = {}
let icons = d3.csvParse(iconDataSource, ({icon_url, width, count}, i) => ({[icon_url]: +count}))
for (let icon of icons) {
data = Object.assign(data, icon)
}
return data
}

Insert cell
iconCharacterDistributionData = await FileAttachment("icon-characters-distribution.csv").text()
Insert cell
dataPerCharacter = {
let data = {}
let icons = d3.csvParse(iconCharacterDistributionData, d3.autoType)
for (let icon of icons) {
if (data[icon.image_urls]) {
data[icon.image_urls][icon.character] = icon.count
} else {
data[icon.image_urls] = {
[icon.character]: icon.count
}
}
}
return data
}

Insert cell
dataFromCharacter = {
let data = {}
let icons = d3.csvParse(iconCharacterDistributionData, d3.autoType)
for (let icon of icons) {
if (data[icon.character]) {
data[icon.character][icon.image_urls] = icon.count
} else {
data[icon.character] = {
[icon.image_urls]: icon.count
}
}
}
return data
}

Insert cell
color = d3.scaleOrdinal()
.range(d3.schemeCategory10);
Insert cell
radius = width / 2
Insert cell
import {hex} from "@luciyer/hexgen"
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
dimensions = ({
height:width,
width: width,
margin: {
top: 0,
right: 0,
bottom: 0,
left: 0,
}
})
Insert cell
d3 = require("d3@5")
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