Public
Edited
Mar 17, 2023
Insert cell
Insert cell
chart(temporal_text_mining)
Insert cell
Insert cell
chart = function(test){
// after manually setting parameters in chart_param_init, height will be defined based on those params
var chart_param = Object.assign(
chart_param_init,
{
height: chart_param_init.margin.top + chart_param_init.margin.bottom +
(test.length+1) * chart_param_init.margin.ridge + chart_param_init.ridge_height
})
/*** init svg plot ***/
const year_start = test[0].data[0]['week']
const data_length = test[0].data.length
const year_end = test[0].data[data_length-1]['week']
const svg = d3.select(DOM.svg(chart_param.width, chart_param.height)),
cp = chart_param;
var y = d3.scaleLinear()
.domain(d3.extent(test.map(d => d.data).flat(), d => d.interest))
.range([chart_param.ridge_height, 0])
var x = d3.scaleLinear()
.domain([year_start, year_end])
.range([0, chart_param.width - chart_param.margin.left - chart_param.margin.right])
// similar to line1, just with curve to enclose data with a smooth ridge
var line2 = d3.line()
.curve(d3.curveCardinal)
.x(d => x(d.week_num))
.y(d => y(d.interest));
// a simple line to plot to fill under the ridge (showing true data)
var line1 = d3.line()
.x(d => x(d.week_num))
.y(d => y(d.interest));

var color = d3.scaleOrdinal()
.domain([0,1,2,3,4])
.range(d3.schemeCategory10)
// var color = d3.scaleLinear()
// .domain(d3.extent(test, d => d.interest_avg))
// .range(["#d65e9b", "#8bb56e"])

// 2. draw axis groups
let date_points = []
for(let i=year_start; i<year_end; i++){
date_points.push(i)
}
const x_date = d3.scaleLinear()
.domain([year_start, year_end])
.range(x.range());
const ag = svg.selectAll("g.axis_group")
.data(date_points).enter()
.append("g")
.classed("axis_group", true)
.attr("transform", d => `translate(${cp.margin.left + x_date(d)},
${cp.margin.top})`);
// 3. draw axis lines
ag.append("line")
.classed("axis_line", true)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", 0)
.attr("y2", cp.height - cp.margin.top - cp.margin.bottom)
.style("stroke", "#c9c9c9");
// 4. draw axis labels
ag.append("text")
.classed("axis_text", true)
.attr("x", 0)
.attr("y", cp.height - cp.margin.top - cp.margin.bottom + 5)
.style("font-size", "14px")
.style("text-anchor", "middle")
.style("alignment-baseline", "hanging")
.text((d,i)=>{if(d%5==0){return d}});
// 5. create object to cover axis lines above top ridge
let cover_path = [...test[0].data];
// cover_path.push({week_num: 53, interest: 100});
// cover_path.push({week_num: 1, interest: 100});
// console.log(cover_path)
svg.append("path")
.attr("id", "axis_line_cover")
.attr("d", line2(cover_path))
.attr("transform", `translate(${cp.margin.left}, ${cp.margin.top})`)
.style("fill", "white");
/*** create ridges ***/
// 1. create ridge groups in correct location with hover events
const rg = svg.selectAll("g.ridge_group")
.data(test).enter()
.append("g")
.classed("ridge_group", true)
.attr("transform", d => `translate(${cp.margin.left},
${cp.margin.top + (d.order - 1) * cp.margin.ridge})`)
.on("mouseover", (e, d) => {
svg.selectAll("g.ridge_group")
.style("opacity", d0 => d0.search === d.search ? 1 : 0.5);
})
.on("mouseout", (e, d) => {
svg.selectAll("g.ridge_group")
.style("opacity", 1);
});
// 2. add ridge labels
rg.append("text")
.classed("ridge_label", true)
.attr("x", -5)
.attr("y", cp.ridge_height)
.style("font-size", "14px")
.style("text-anchor", "end")
.style("alignment-baseline", "middle")
.text(d => d.search);
// 3. add path for ridge fill
rg.append("path")
.classed("ridge_fill", true)
.attr("d", d => {
// take original data and add points for bottom corners to create fill
let path = [...d.data];
// path.push({week_num: 53, interest: 0});
// path.push({week_num: 1, interest: 0});
return line1(path);
})
.style("fill", d => color(d.link_label))
.style('opacity',0.5)
.style("stroke", "none");
// 4. add path for ridge
rg.append("path")
.classed("ridge_path", true)
.attr("d", d => line2(d.data))
.style("fill", "none")
.style("stroke", d => color(d.link_label));
// 5. add hover box (where user can hover)
rg.append("rect")
.attr("x", -cp.margin.left)
.attr("y", cp.ridge_height * 0.65)
.attr("width", width)
.attr("height", cp.margin.ridge)
.style("fill", "rgba(0, 0, 0, 0)");
return svg.node();
}
Insert cell
chart_param_init = ({
width: width,
ridge_height: 40,
margin: {
top: 20,
right: 25,
bottom: 20,
left: 210,
ridge: 20
}
})
Insert cell
// {
// return html`${d3
// .ticks(d3.min(data, d => d.interest_avg), d3.max(data, d => d.interest_avg), 20)
// .map(color)
// .map(
// t =>
// `<span style="background:${t}; height: 50px; width:4%; display: inline-block;">&nbsp;</span>`
// )}`;
// }
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// temporal_text_mining = FileAttachment("temporal_text_mining.json").json()
Insert cell
author_volume_rendering = FileAttachment("author_volume_rendering@1.json").json()
Insert cell
Insert cell
author_information_theory = FileAttachment("author_information_theory.json").json()
Insert cell
chart(author_information_theory)
Insert cell
stream_tm = FileAttachment("stream_tm@2.json").json()
Insert cell
chart(stream_tm)
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