Published
Edited
Jul 13, 2020
1 fork
Insert cell
Insert cell
Insert cell
chart = {
const svg = d3.create("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("font-size", 10)
.attr("font-family", "sans-serif")
.style("width", "100%")
.style("height", "auto");

const chords = chord(data.matrix);
const colores = data.colores;

const group = svg.append("g")
.selectAll("g")
.data(chords.groups)
.join("g");

//Aca dibjua las cajitas del circulo
group.append("path")
.attr("fill", d => colores.get(d.index))
.attr("stroke", d => colores.get(d.index))
.attr("d", arc);

//Aca pone el texto con el nombre de la persona o del objeto
group.append("text")
.each(d => { d.angle = (d.startAngle + d.endAngle) / 2; })
.attr("dy", ".35em")
.attr("transform", d => `
rotate(${(d.angle * 180 / Math.PI - 90)})
translate(${innerRadius + 26})
${d.angle > Math.PI ? "rotate(180)" : ""}
`)
.attr("text-anchor", d => d.angle > Math.PI ? "end" : null)
.text(d => data.nameByIndex.get(d.index));

// aca dibuja los archos
svg.append("g")
.attr("fill-opacity", 0.67)
.selectAll("path")
.data(chords)
.join("path")
.attr("stroke", d => d3.rgb(colores.get(d.source.index)).darker())
.attr("fill", d => colores.get(d.source.index))
.attr("d", ribbon);

return svg.node();
}
Insert cell
Insert cell
{
// 1. Creamos el área de dibujo
const svg = d3.create('svg')
.attr("viewBox", [-datos.ancho / 2, -datos.alto / 2, datos.ancho, datos.alto])

const circle = svg.selectAll('circle')
.data( datos.lista_personas.concat(datos.lista_objetos))
.enter()
.append("circle")
.attr('r', d => d.radio)
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.style('fill', d => d.color);
svg.selectAll("text")
.data(datos.lista_personas.concat(datos.lista_objetos))
.enter()
.append("text")
.attr("dy", ".35em")
.attr("transform", d => `
rotate(${(d.angulo * 180 / Math.PI - 90)})
translate(${d.radio_general + d.traslado_texto})
${d.angulo > Math.PI ? "rotate(180)" : ""}
`)
.attr("text-anchor", d => d.angulo > Math.PI ? "end" : null)
.attr("font-size", "10px")
.text(d => d.nombre);
var link = svg.selectAll(".link")
.data(datos.uniones)
.enter().append("path")
.style("stroke", d => d.color)
.style("fill", "none")
.attr("d", d => d.ruta);

return svg.node();
}
Insert cell
// Colores personas
color_persona = d3.scaleSequential()
.domain([0, 40])
.interpolator(d3.interpolateHslLong("red", "blue"))

Insert cell
color_persona(1)
Insert cell
//colores objetos
color_objeto = d3.scaleSequential()
.domain([0, 44])
.interpolator(d3.interpolateRgb("rgb(0, 0, 40)", "rgb(0, 0, 256)"))

Insert cell
data = {
const imports = await FileAttachment("datos@3.json").json();

const indexByName = new Map;
const nameByIndex = new Map;
const object_count = new Map;
const matrix = [];
const colores = new Map;
let n = 0;



// Compute a unique index for each package name.
imports.personas.forEach(d => {
if (!indexByName.has(d = d.name)) {
colores.set(n, color_persona(n));
nameByIndex.set(n, d);
indexByName.set(d, n++);
}
});
let n_obj = 0;
imports.objetos.forEach(d => {
object_count.set(d.name,d.values.length);
if (!indexByName.has(d = d.name)) {
colores.set(n, color_objeto(n_obj++));
nameByIndex.set(n, d);
indexByName.set(d, n++);
}
});
// Construct a square matrix counting package imports.
imports.personas.forEach(d => {
const source = indexByName.get(d.name);
let row = matrix[source];
if (!row) row = matrix[source] = Array.from({length: n}).fill(0);
d.values.forEach(d => {
if(object_count.get(d) >= objeto_minimo){
row[indexByName.get(d)]++;
}
});
});

imports.objetos.forEach(d => {
const source = indexByName.get(d.name);
let row = matrix[source];
if (!row) row = matrix[source] = Array.from({length: n}).fill(0);
//d.values.forEach(d => row[indexByName.get(d)]++);
});
return {
matrix,
indexByName,
nameByIndex,
colores
};
}
Insert cell
data.colores.get(80)
Insert cell
chord = d3.chord()
.padAngle(.04)
.sortSubgroups(d3.descending)
.sortChords(d3.descending)
Insert cell
arc = d3.arc()
.innerRadius(innerRadius)
.outerRadius(innerRadius + 20)
Insert cell
ribbon = d3.ribbon()
.radius(innerRadius)
Insert cell
color = d3.scaleOrdinal(d3.schemeCategory10)
Insert cell
outerRadius = Math.min(width, height) * 0.5
Insert cell
innerRadius = outerRadius - 124
Insert cell
width = 954
Insert cell
height = width
Insert cell
d3 = require("d3@5")
Insert cell
Insert cell
function generador_circulos(datos_originales,
radio_general, traslado_texto,
escala_colores, incremento_angulo)
{
var resultado = []
var coordenadas = new Map;
var cantidades = new Map;
var maximo_escala = d3.max(datos_originales, d => d.values.length)
var minimo_escala = d3.min(datos_originales, d => d.values.length)
var escala_radios = d3.scaleLinear()
.domain([minimo_escala, maximo_escala])
.range([4, 10])
var objeto_id = 0;
datos_originales.forEach(d => {
var objeto_nuevo = Object();
objeto_nuevo.nombre = d.name;
objeto_nuevo.angulo = objeto_id * incremento_angulo;
objeto_nuevo.id = objeto_id;
objeto_nuevo.x = radio_general * Math.cos(objeto_id * incremento_angulo);
objeto_nuevo.y = radio_general * Math.sin(objeto_id * incremento_angulo);
objeto_nuevo.radio = escala_radios(d.values.length);
objeto_nuevo.color = escala_colores(objeto_id);
objeto_nuevo.radio_general = radio_general;
objeto_nuevo.traslado_texto = traslado_texto;
cantidades.set(objeto_nuevo.nombre, d.values.length);
coordenadas.set(objeto_nuevo.nombre, {x:objeto_nuevo.x,
y:objeto_nuevo.y,
color: escala_colores(objeto_id)});
resultado.push(objeto_nuevo);
objeto_id = objeto_id + 1;
});
return {resultado, coordenadas, cantidades};
}
Insert cell
linker = function(d) {
var x0 = d.origen_x;
var y0 = d.origen_y;
var y1 = d.destino_y;
var x1 = d.destino_x;
var path = d3.path();
path.moveTo(x0, y0)
path.quadraticCurveTo(x0 + ((x1-x0)*0.25),
y0 + ((y1-y0)*0.75),
x1, y1);

return path.toString();
}
Insert cell
// Cargo los datos del JSON
datos = {
const datos_crudos = await FileAttachment("datos@3.json").json();
const ancho = 900;
const alto = 900;
const centro_x = ancho / 2;
const centro_y = alto / 2;
const radio_personas = 150;
const radio_objetos = 350;


const cantidad_personas = datos_crudos.personas.length;
const color_persona = d3.scaleSequential()
.domain([0, cantidad_personas])
.interpolator(d3.interpolateHslLong("red", "blue"))

const incremento_angulo_personas = 2 * Math.PI/cantidad_personas;
var resultado_personas = generador_circulos(datos_crudos.personas,
radio_personas, 15,
color_persona, incremento_angulo_personas)


const cantidad_objetos = datos_crudos.objetos.length;
const color_objetos = d3.scaleSequential()
.domain([0, cantidad_objetos])
.interpolator(d3.interpolateRgb("rgb(220, 220, 220)", "black"))
const incremento_angulo_objetos = 2 * Math.PI/cantidad_objetos;
var resultado_objetos = generador_circulos(datos_crudos.objetos,
radio_objetos, -55,
color_objetos, incremento_angulo_objetos)
var uniones = []
datos_crudos.personas.forEach(d => {
var origen = resultado_personas.coordenadas.get(d.name);
d.values.forEach(v => {
var destino = resultado_objetos.coordenadas.get(v);
var ruta = linker({origen_x: origen.x,
origen_y: origen.y,
destino_x: destino.x,
destino_y: destino.y});
var color = origen.color;
if(resultado_objetos.cantidades.get(v) >= objeto_minimo_a_mano){
uniones.push({ruta: ruta,
color: color});}
});
});
var lista_personas = resultado_personas.resultado;
var lista_objetos = resultado_objetos.resultado;
return {
ancho,
alto,
lista_personas,
lista_objetos,
radio_personas,
radio_objetos,
uniones
};
}
Insert cell
///

Insert cell
import {slider} 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