Public
Edited
Jun 16, 2023
Insert cell
Insert cell
d3 = require("d3@^6.0")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
types = Array.from(new Set(links.map(d => d.type)))
Insert cell
Insert cell
function getFrasi2(nfrase){
const mnode= []
const mlinks=[]
const usednodes=[]
//const ns=Array.from(new Set(links.flatMap(l => [l.source, l.target])), id => ({id}))
links2.map(function(item) {
var mysrc=item.source
var mytgt=item.target
var frase=item.frase
var myval='';
mytgt=mytgt.replace(' or vidi e',' or vidi - e').replace('ferma rupe ,', 'ferma rupe -,')
if (!usednodes.includes(mysrc.replace(/\s/g, '')) && nfrase.includes(frase)){
console.log('in src '+ mysrc+' ---- '+mytgt)
mnode.push({
"id" : mysrc,
"type" : item.type,
"rif" : item.frase,
"visible": item.visibile.trim(),
"s_type" : item.tipo
});
usednodes.push(mysrc.replace(/\s/g, ''))
}
if (!usednodes.includes(mytgt.replace(/\s/g, '').replace(/\n/g,'')) && nfrase.includes(frase)){
console.log('in tgt '+ mytgt.replace(/\s/g, ''))
//console.log('usednodes '+ usednodes)
mnode.push({
"id" : mytgt,
"type" : item.type,
"rif" : item.frase,
"visible": item.visibile.trim(),
"s_type" : item.tipo
});
usednodes.push(mytgt.replace(/\s/g, ''))
}
})
links2.map(function(item) {
var mysrc=item.source
var mytgt=item.target
var frase=item.frase
if (nfrase.includes(frase)){
mlinks.push({
"source" : mysrc,
"target" : mytgt,
"type" : item.type
});
}
})
var data_frase=({nodes: mnode, links: mlinks})
return data_frase;
}
Insert cell
function getSid(ids){
ids= ids.replace(/\s/g,'')
var setids= ids.split(",")
return setids
}
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_1=getFrasi(listafrasi)
Insert cell
data_frasi=getFrasi2(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
clauseFunctions= ({
"princ": "Principale",
"coord": "Coordinata",
"coord I": "Coordinata I grado",
"coord II": "Coordinata II grado",
"coord III": "Coordinata III grado",
"coord IV": "Coordinata IV grado",
"coord V": "Coordinata V grado",
"subord": "Subordinata",
"subord I": "Subordinata I grado",
"subord II": "Subordinata II grado",
"subord III": "Subordinata III grado",
"subord IV": "Subordinata IV grado",
"subord V": "Subordinata V grado",
"subord VI": "Subordinata VI grado",
"subord VII": "Subordinata VII grado",
"parent": "Parentetica",
"pcoord": "Coordinata alla parentetica",
"pcoord I": "Coordinata alla parentetica I grado",
"coord 0": "Pseudo-coordinata"
})
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='3_13_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

sentenceStructArcs_new = {


const radius = 5
const nodehpos=460
const labelhpos=nodehpos-300
const maxlabelwidth=40
const container = d3.select(DOM.svg(width+margin.left+margin.right,
sentenceheight+margin.top+margin.bottom))
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;
}

`)
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 => 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))
}
// 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("y", d => 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("letter-spacing", 0)
.text(d=> clauseFunctions[d.type]+", "+getTypes(d.s_type))

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 = yScale(idToNode[d.source].visible);
let end = yScale(idToNode[d.target].visible);
let lor=true;
let nodeoffset=0
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(' ');
return arcPath;
}
function buildReverseArc(d) {
let start = yScale(idToNode[d.source].visible);
let end = yScale(idToNode[d.target].visible);
let lor=true;
let nodeoffset=0
if (start < end && d.type.includes ('coord')){//.includes('coord')){
console.log('here')
lor=false;
nodeoffset=0
}
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.5)
.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.5)
.attr("stroke", 'lightgray');//d => sentenceFunctionsColor(d.type));

// 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 => yScale(d.visible))
.attr("r", radius)
//.attr("fill", d=> sentenceFunctionsColor(d.type))
.attr("fill", d => colorssp(maptypestopalette[d.type]))
.attr("id", d => d.visible)
// create the node labels
const nodeLabels = arcGroup.selectAll("nodeLabels")
.data(data_frasi.nodes.slice(1))
.enter().append("text")
.attr("x", margin.left+labelhpos)
//.attr("y", d => yScale(d.visible))
.attr("dominant-baseline", "middle")
.attr("y", d=>yScale(d.visible)+syntfunctype(d.visible))
.attr("class","synt__info")
//.style("font-style", "italic")
.style("text-anchor", "start")
.text(d => d.visible)
// 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.5;})

//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.5;})
// 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), 50) });
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_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

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