Published
Edited
Mar 14, 2019
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
myChart = {
//coerce to number
//make a new column observation_N_cumSum presents the cumulated sum observations as of the month
sortedbarLineData.forEach(function (d) {
d.AvgMOTP_Score = +d.AvgMOTP_Score;
d.PrincipalActiveYears = +d.PrincipalActiveYears;
});
//this line is for observable only
const div = html`<div style='max-width: 1000px; padding: 0px; margin: 0px;'></div>`;
const ttDiv = d3.select("body").append("div")
.attr("id", "myTooltip")
//-------------- create SVG -- Scalable Vector Graphics object.
const svg = d3.select(div) //tell machine you want the following changes in body tag. selects the HTML body element. use d3.select("body") when outside of observable
.append("svg") //append SVG now
.attr("width", width + margin.left + margin.right) //set the width attribute by adding margin to your width const
.attr("height", height + margin.top + margin.bottom) // set the height attribute by adding margin to your height const
.append("g") //appends a g element to the SVG. g element is used to group SVG shapes together.
.attr("transform",`translate(${margin.left}, ${margin.top})`)

//append a group element and call the xAxis function. so that all components of the x axis will be grouped under the group element. we then apply a translate transformation to align the x axis to move down as much as height from the origin
const x = svg.append("g")
.attr("class", "x axis")
.attr("transform", `translate(0, ${height})`)
.call(xAxis)
x.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.2em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
x.selectAll("line")
.attr("transform", `translate(${xScale.bandwidth()/2}, 0)`)
.attr("stroke","grey")
.attr("stroke-width","0.5px");

//append a group element and insert y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", `translate(${width},0)`)
.call(yAxis)
svg.append("g")
.attr("class", "y axis yAxisLine")
.call(yAxisLine)

// Data line and dots group
const lineAndDots = svg.append("g")
.attr("class", "line-and-dots")
.attr("transform", `translate(${xScale.bandwidth()/2}, 0)`)

// Data line
lineAndDots.append("path")
.datum(sortedbarLineData)
.attr("class", "data-line")
.style("stroke-width","3")
.style("stroke-opacity","0.5")
.attr("d", lineMaker);
// an equivalent expression
// const path = svg.append('path').attr('d', lineMaker(lineData));
/*Difference between datum() and data() in D3
# selection.data([values[, key]])
Joins the specified array of data with the current selection. The specified values is an array of data values, such as an array of numbers or objects, or a function that returns an array of values.
...
# selection.datum([value])
Gets or sets the bound data for each selected element. Unlike the selection.data method, this method does not compute a join (and thus does not compute enter and exit selections).*/
// Data dots
lineAndDots.selectAll(".dot")
.data(sortedbarLineData)
.enter().append("circle")
.attr("class", "dot")
.style("opacity","0.6")
.attr("r", 3)
.attr("cx", d=> xScale(d.Fake_DBN))
.attr("cy", d=> yScaleLine(d.AvgMOTP_Score));

// label on Data dots
lineAndDots.selectAll("text")
.data(sortedbarLineData)
.enter().append("text")
.style("fill", "purple")
.style("text-anchor", "middle")
.attr("font-size", 12)
.attr("x", d=> xScale(d.Fake_DBN))
.attr("y", d=> yScaleLine(d.AvgMOTP_Score)-1) //move text up by 1 px
.text(d=>d.AvgMOTP_Score);
//append rectangles (bars)
const g = svg.selectAll(".bar-group")
.data(sortedbarLineData)
.enter().append("g")
.attr("class","bar-group");
g.append("rect")// enter() creates the initial join of data to elements, creating one rectangle element for every data element in the data source
.attr("class", "bar")
.attr("x", d => xScale(d.Fake_DBN)) //x position of the top-left point of the rect
.attr("y", d => yScale(d.PrincipalActiveYears)) //y position of the top-left point of the rect
.attr("height", d => height - yScale(d.PrincipalActiveYears)) //height starts from the TOP and moves down due to SVG Coordinate system
.attr("width", d => xScale.bandwidth())
.style("fill", 'orange')
.style("fill-opacity","0.4")
//add lables on the bar
g.append("text")
.attr("class", "barLable")
.attr("transform", "rotate(-90)")
.style("fill", "black")
.style("text-anchor", "middle") //default is anchor on the left
.attr("x",d => height - yScale(d.PrincipalActiveYears)-yScale(0)- (height - yScale(d.PrincipalActiveYears))/2) // because of the rotate!!!
.attr("y",d=> xScale(d.Fake_DBN)+ xScale.bandwidth()/1.5) // because of the rotate!!!
// .attr("x", d => xScale(d.Fake_DBN) + xScale.bandwidth()/2) //middle of the corresponding bar horizontally
// .attr("y", d => yScale(d.PrincipalActiveYears)) //middle of the corresponding bar vertically
.text(d=>{
return ((height - yScale(d.PrincipalActiveYears))>=25? d.PrincipalActiveYears: '')
});
//add tooltip. on event
g.selectAll("rect").on("mouseover",function(d){
ttDiv.transition()
.duration(200)
.style("opacity", 0.9);
ttDiv.html("<strong>"+d.Fake_DBN+ "</strong><br/>School MOTP score Avg: <strong>"+d.AvgMOTP_Score +"</strong><br/> Principal active years: <strong>"+d.PrincipalActiveYears +"</strong><br/>" )
.style("font","13px")
.style("left", (d3.event.pageX) + "px")
.style("top", (d3.event.pageY - 28) + "px"); //Recover the mouse position when the event happens.Can add a numeric value next to pageX or Y to adjust the tooltip position
//style("top", d3.select(this).attr("cy") + "px"); Aother option -- It selects the element that is hovered. Thus, it is possible to get whatever attribute or style of this element, like its position.
d3.select(this).style("fill","yellow");//highlight the mouseover element
})
.on("mouseout", function(d) {
ttDiv.transition()
.duration(200)
.style("opacity", 0);
d3.select(this).style("fill","orange");//change color of the mouseover element back to original color
});

const colorScale = d3.scaleOrdinal()
.domain(["MOTP Avg Score to Date","Principal Active Years"])
.range(['purple', 'orange'])

const legend_g = svg.selectAll(".legend")
.data(colorScale.domain())
.enter().append("g")
.attr("font-family", "sans-serif")
.attr("font-size", 11)
.attr("transform", (d, i) => `translate(${width+20},${i * 20})`); //legend on the right edge in the SVG. 'i*20' is to space out the item vertically here
legend_g.append("rect")
.attr("x", 0)
.attr("y",height/2)
.attr("width", 10)
.attr("height", 10)
.attr("fill", colorScale);

legend_g.append("text")
.attr("x", 12)
.attr("y", height/2 + 10)
//.attr("dy", ".35em")
//.text(d=>d)
.text(d => {
return (d ==2017? '2017 rating avg.':d)
});

return div
}
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