Public
Edited
Feb 10
2 forks
Insert cell
Insert cell
d3 = require("d3@^6.0")
Insert cell
Insert cell
//links = d3.csvParse(await FileAttachment("parsint_mod_completo_pre_new_4@2.csv").text())
//links = FileAttachment("parsint_mod_completo_pre_new_4-2.csv").csv({typed: true})
Insert cell
Insert cell
Insert cell
types = Array.from(new Set(links2.map(d => d.type)))
Insert cell
Insert cell
Insert cell
listafrasi=getSid(lisid)
Insert cell
function getColor(st){
return sentenceFunctionsColor2(st)
}
Insert cell
clauseType='subord I'
Insert cell
col=getColor(clauseType)
Insert cell
data_frasi=getFrasi(listafrasi)
Insert cell
sentenceTypes = data_frasi.nodes.slice(1).map(function(d){return d.s_type});
Insert cell
sentenceNodeNames = data_frasi.nodes.slice(1).map(function(d){return d.visible});
Insert cell
// use the idToNode function to map node ID with a pointer
idToNode =
{
let dict = {};
data_frasi.nodes.slice(0).forEach(function(n) {
dict[n.id] = n;
});
return dict;
}
Insert cell
Insert cell
Insert cell
Insert cell
getTypes=function name(mtype) {
if(syntactic_macrotypes[mtype])
return syntactic_macrotypes[mtype]
if(syntactic_types[mtype])
return syntactic_types[mtype]
return mtype
}
Insert cell
Insert cell
md`#### Creating SVG`
Insert cell
margin = ({top: 20, bottom: 30, left: 5, right: 30});
Insert cell
height = 360 - margin.top - margin.bottom;
Insert cell
sentenceheight=((sentenceNodeNames.length+1) * 33)
Insert cell
width = 760
Insert cell
Insert cell
yScale = d3.scalePoint()
.domain(sentenceNodeNames)
.range([0,sentenceheight])
//.range([0, Math.min(height, sentenceNodeNames.length * 40)])
Insert cell
syntfunction = new Set(data_frasi["links"].slice(1), d => d.type);
Insert cell
// use the d3 color scheme "dark2" to color code different types of syntactyc function
sentenceFunctionsColor = {return d3.scaleOrdinal(d3.schemePastel1).domain(types.values());}
Insert cell
// use the d3 color scheme "dark2" to color code different types of syntactyc function
sentenceFunctionsColor2 = {return d3.scaleOrdinal(d3.schemeSet1).domain(types.values());}//syntfunction.values());}
Insert cell
Insert cell
Insert cell
colorssp = d3.scaleQuantize()
.domain([0,17])
.range(["#1f78b4", "#a6cee3", "#b2df8a", "#33a02c", "#fb9a99", "#e31a1c", "#fdbf6f", "#ff7f00",
"#cab2d6", "#6a3d9a", "#ffff99", "#b15928", "#F46D43",
"#D53E4F", "#9E0142", "#e377c2", "#7f7f7f", "#bcbd22"]);
Insert cell
colorssp1 = d3.scaleQuantize()
.domain([0,17])
.range(["#3288bd", "#66c2a5", "#e41a1c", "#4daf4a", "#984ea3", "#d53e4f", "#f46d43", "#ABDDA4",
"#E6F598", "#FFFFBF", "#FEE08B", "#FDAE61", "#F46D43",
"#D53E4F", "#9E0142", "#e377c2", "#7f7f7f", "#bcbd22"]);
Insert cell
maptypestopalette=({"princ": 0, "subord I": 1, "subord II": 3, "subord III": 4, "coord": 5,
"coord I": 9, "coord II": 10, "subord IV": 5, "subord V": 6, "parent": 17,
"coord III": 11, "pcoord":14, "coord 0": 16, "subord VI": 7 , "coord IV": 12,
"coord V": 13, "pcoord I": 15, "subord VII": 8})
Insert cell
Insert cell
lisid='2_1_1'
Insert cell
import {swatches} from "@d3/color-legend"
Insert cell
Insert cell
Insert cell
periodo=data_frasi.nodes[0].visible
Insert cell
Insert cell
// adapted from https://www.d3-graph-gallery.com/graph/arc_highlight.html

sentenceArcsStructs_new = {


const radius = 4
const sty=24
const titleposy=15
const titleposx=margin.left-5 //100
const nodehpos=483
const labelhpos=nodehpos-178
const maxlabelwidth=40
const container = d3.select(DOM.svg(width+margin.left+margin.right,
sentenceheight+margin.top+margin.bottom+24))

container.append("style").text(`
.synt__info{
font-size: 13px;
font-weight: normal;
font-style: italic;
font-family: Palatino;
}
.synt__categ{
font-size: 10px;
font-weight: normal;
font-family: Palatino;
}

`)


container
.append("text")
.attr("x", titleposx)
.attr("y", titleposy)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
//.attr("class","text-warning")
.attr("font-family", 'inherit')
.style("text-anchor", "start")
.text("Clauses");

container
.append("text")
.attr("x", margin.left+labelhpos)
.attr("y", titleposy)
.attr("text-anchor", "middle")
.attr("alignment-baseline", "middle")
//.attr("class","synt__label")
.attr("font-family", 'inherit')
.style("text-anchor", "start")
.text("Function/type");
//.text("Funzioni e tipi");
/*
container.append("style").text(`
.synt__info{
font-size: 16px;
font-weight: normal;
font-style: italic;
font-family: Book Antiqua,Palatino,Palatino Linotype,Palatino LT STD,Georgia,serif;
}
.synt__categ{
font-size: 12px;
font-weight: normal;
font-family: Book Antiqua,Palatino,Palatino Linotype,Palatino LT STD,Georgia,serif;
}
.synt__label{
font-size: 16px;
font-weight: bold;
font-family: Book Antiqua,Palatino,Palatino Linotype,Palatino LT STD,Georgia,serif;
}

`)
*/
const arcGroup = container
.attr ("id", "periodograph")
.attr("width",null)
.attr("height",null)
.attr("name", lisid)
.append("g")
//.style('pointer-events', 'all')
.attr("transform", "translate(" + margin.left + "," + margin.top + ")")
// create the nodes
const nodes = arcGroup.selectAll("nodes")
.data(data_frasi.nodes.slice(1))
.enter().append("circle")
.attr("cx", margin.left+nodehpos)
.attr("cy", d => sty+yScale(d.visible))
.attr("r", radius)
//.attr("fill", d=> sentenceFunctionsColor(d.type))
.attr("fill", d => colorssp(maptypestopalette[d.type]))
.attr("id", d => d.visible)
function ypostxt(label){
//delta = (_fontsize * textarea.split("\n").length) / 2;
const label_array = wrap_text_array(label, maxlabelwidth);
return yScale(label)+ -(8 * label_array.length)/2
//return label_array.length<3? yScale(label)+3: yScale(label)-(5*(label_array.length-1))
}
function syntfunctype(funty){
const funty_array = wrap_text_array(funty, maxlabelwidth);
return (funty_array.length<2? 0: -(2.5 * funty_array.length))
}
// This code builds up the SVG path element; see nodesAndArcs for details
function buildArc(d) {
let start = sty+yScale(idToNode[d.source].visible);
let end = sty+yScale(idToNode[d.target].visible);
let lor=true;
let nodeoffset=4
if (isNaN(start))
return
const arcPath = ['M', margin.left+nodehpos+nodeoffset, start, 'A', (Math.abs(start - end)/2), ',', Math.abs(start-end)/2, 0,0,",",
lor ? 1: 0, margin.left+nodehpos+nodeoffset, end].join(' ');
return arcPath;
}
function buildReverseArc(d) {
let start = sty+yScale(idToNode[d.source].visible);
let end = sty+yScale(idToNode[d.target].visible);
let lor=true;
let nodeoffset=4
if (start < end && d.type.includes ('coord')){//.includes('coord')){
//console.log('here')
lor=false;
nodeoffset=-4
}
else
return
if (start==null)
return
const arcPath = ['M', margin.left+nodehpos+nodeoffset, start, 'A', Math.abs(start - end)/2, ',', Math.abs(start-end)/2, 0,0,",",
lor ? 1: 0, margin.left+nodehpos+nodeoffset, end].join(' ');
//console.log(start+' - '+end+', '+d.type+'; '+arcPath)
return arcPath;
}
// create the arcs
var arcs = arcGroup.selectAll("arcs")
.data(data_frasi.links.slice(1))
.enter().append("path")
.attr("d", d => buildArc(d))
.style("fill", "none")
.style('stroke-width', 0.2)
.attr("stroke", 'lightgray');//d => sentenceFunctionsColor(d.type));

// create the arcs for Coordinate

var arcs_coord = arcGroup.selectAll("arcs")
.data(data_frasi.links.slice(1))
.enter().append("path")
.attr("d", d => buildReverseArc(d))
.style("fill", "none")
.style('stroke-width', 0.2)
.attr("stroke", 'lightgray');//d => sentenceFunctionsColor(d.type));

// create the node labels
const nodeLabels = arcGroup.selectAll("nodeLabels")
.data(data_frasi.nodes.slice(1))
.enter().append("text")
//.attr("x", margin.left+labelhpos)
.attr("x", margin.left-10)
//.attr("y", d => yScale(d.visible))
.attr("dominant-baseline", "middle")
.attr("y", d=>sty+ yScale(d.visible)+syntfunctype(d.visible))
.attr("class","synt__info")
.style("font-family","Book Antiqua,Palatino,Palatino Linotype,Palatino LT STD,Georgia,serif")
.style("text-anchor", "start")
.text(d => d.visible)
// the synctatic function and types
const syntfun = arcGroup.selectAll("syntfun")
.data(data_frasi.nodes.slice(1))
.enter().append("text")
//.attr("x", margin.left-10)
.attr("x", margin.left+labelhpos)
.attr("y", d => sty+ yScale(d.visible)+syntfunctype(clauseFunctions[d.type]+", "+getTypes(d.s_type)))
//.attr("y", d=>ypostxt(d.visible))
.attr("dominant-baseline", "middle")
.attr("class","synt__categ")
.style("text-anchor", "start")
.style("font-family","Book Antiqua,Palatino,Palatino Linotype,Palatino LT STD,Georgia,serif")
.style("letter-spacing", 0)
.text(d=> clauseFunctions[d.type]+", "+getTypes(d.s_type))

// mouseover animations
nodes.on('mouseover', function(event, d) {
// Highlight selected node
d3.select(this).style("fill", d=>colorssp(maptypestopalette[d.type]));//sentenceFunctionsColor2(d.type));
var targetids=[]
// Highlight arcs
arcs
.style('stroke', function (arcd) {
if (arcd.source === d.id) { targetids.push(arcd.target)}; if (arcd.target === d.id) { targetids.push(arcd.source)};
return arcd.source === d.id || arcd.target === d.id ? d=> sentenceFunctionsColor2(d.type) : 'lightgray';})//d=> sentenceFunctionsColor(d.type);})
.style('stroke-width', function (arcd) {
return arcd.source === d.id || arcd.target === d.id ? 2 : 0.3;})

//arcs_coord
arcs_coord
.style('stroke', function (arcd) {
if (arcd.source === d.id) { targetids.push(arcd.target)}; if (arcd.target === d.id) { targetids.push(arcd.source)};
return arcd.source === d.id || arcd.target === d.id ? d=> sentenceFunctionsColor2(d.type) : 'lightgray';})
.style('stroke-width', function (arcd) {
return arcd.source === d.id || arcd.target === d.id ? 2 : 0.3;})
// Highlight syntactic types
syntfun
.style('fill', function (syntfund) {
//return syntfund.visible+syntfund.s_type === d.visible+d.s_type ? 'steelblue' : 'black' ;});
return (syntfund.visible+syntfund.s_type === d.visible+d.s_type || targetids.includes(syntfund.id)) ? darken('steelblue') : 'black' ;})
.style('font-weight', function (syntfund) {
//return syntfund.visible+syntfund.s_type === d.visible+d.s_type ? 'steelblue' : 'black' ;});
return (syntfund.visible+syntfund.s_type === d.visible+d.s_type || targetids.includes(syntfund.id)) ? 'bold' : 'normal' ;});

// Highlight node labels
nodeLabels
.style("fill", function (nodeLabeld){
return nodeLabeld.id == d.id || targetids.includes(nodeLabeld.id) ? 'black' : 'black';})
.style('font-weight', function (nodeLabeld) {
return nodeLabeld.id == d.id || targetids.includes(nodeLabeld.id) ? 'bold' : 'normal';})
});
// remove highlighting when user mouse moves out of node by restoring default colors and thickness
nodes.on('mouseout', function (event, d) {
nodes.style("fill", d=> colorssp(maptypestopalette[d.type]));//sentenceFunctionsColor(d.type));
arcs.style('stroke', 'lightgray')
arcs.style('stroke-width', 0.5);
arcs_coord.style('stroke', 'lightgray')
arcs_coord.style('stroke-width', 0.5);
syntfun.style('fill','black');
syntfun.style('font-weight','normal');
//nodeLabels.style('fill','black');
nodeLabels.style('font-weight','normal');
nodeLabels.attr("class","synt__info")
});
container.selectAll("text")
.each(function(d, i) { wrap_text_nchar(d3.select(this), maxlabelwidth) });
return container.node();
}
Insert cell
Insert cell
function darken(color, k = 1) {
const {l, c, h} = d3.lch(color);
return d3.lch(l - 18 * k, c, h);
}
Insert cell
wrap_text_array('Principale, Interrogativa Di TipoX Retorica', 40)
Insert cell
wrap_text_nchar = (text_element, max_width, line_height, unit = "em") => {
//console.log('te' +text_element)
// use a default line_height if not provided
if (!line_height) line_height = 1.0;
if (text_element.text().length>150)
line_height = 0.8
if (text_element.text().includes("ordinata") || text_element.text().includes("parentetica") ||
text_element.text().includes("principale")){
max_width=30
if (text_element.text().length>90)
line_height = 0.9
}
// wrap the text based on how many characters per line
const text_array = wrap_text_array(text_element.text(), max_width);
// append a tspan element for each line of text_array
text_element.text(null)
.selectAll("tspan")
.data(text_array).enter()
.append("tspan")
.attr("x", text_element.attr("x"))
.attr("y", text_element.attr("y"))
.attr("dy", (d, i) => `${(i * line_height)}${unit}`)
.text(d => d);
}
Insert cell
wrap_text_array = (text, max_width) => {
// split the text around spaces (to get individual words)
const words = text.split(/\s+/).reverse();
// define vars to hold individual words, lines, and all lines
let word,
lines = [ ],
line = [ ];
// add words to a line until we exceed the max_width (in characters)
// when we reach width, add the line to lines and start a new line
while (word = words.pop()) {
line.push(word);
if (line.join(" ").length > max_width || word[0]=='(') {
line.pop()
lines.push(line.join(" "));
line = [word];
}
}
lines.push(line.join(" "));
return lines;
}
Insert cell
wrap_node_text = (text, width) => {
// split the text around spaces (to get individual words)
if (text==null)
text==''
const words = text.split(/\s+/).reverse();
// define vars to hold individual words, lines, and all lines
let word,
lines = [ ],
line = [ ];
// add words to a line until we exceed the max_width (in characters)
// when we reach width, add the line to lines and start a new line
while (word = words.pop()) {
line.push(word);
if (line.join(" ").length > width) {
line.pop()
lines.push(line.join(" "));
lines.push('\n <br>');
line = [word.trim()];
}
}
lines.push(line.join(" "));
var htmllines=lines.join("")
console.log(htmllines)
return htmllines;
}
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