Line column chart with D3
A line column chart is a type of visualization that combines both line and column charts together, using dual axes displayed on the left and right sides of the chart. It allows us to show the relationship of two variables with different magnitudes and scales.
More about: Line column chart
Line column chart
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Include d3 library -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<!-- Create a container to host the chart -->
<div id="viz_container"></div>
// set the dimensions and margins of the graph
const margin = {top: 80, right: 20, bottom: 50, left: 40};
const width = 450 - margin.left - margin.right;
const height = 350 - margin.top - margin.bottom;
// append the svg object to the body of the page
const svg = d3.select("#viz_container")
.append("svg")
.attr("width", "100%")
.attr("height", "100%")
.attr("viewBox", "0 0 450 350")
.attr("preserveAspectRatio", "xMinYMin")
.append("g")
.attr("transform", `translate(${margin.left}, ${margin.top})`);
// parse the Data
d3.csv("https://raw.githubusercontent.com/GDS-ODSSS/unhcr-dataviz-platform/master/data/change_over_time/line_column.csv")
.then(function(data){
// X scale and Axis
const xScale = d3.scaleBand()
.domain(data.map(d => d.year))
.range([0, width])
.padding(.2);
svg
.append('g')
.style("color", "#666666")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale).tickSize(0).tickPadding(8));
// Y scale and Axis
const yScale1 = d3.scaleLinear()
.domain([0, 90])
.range([height, 0]);
svg
.append('g')
.call(d3.axisLeft(yScale1).ticks(10).tickSize(0).tickPadding(6))
.call(d => d.select(".domain").remove());
const yScale2 = d3.scaleLinear()
.domain([0, 9])
.range([height, 0]);
svg
.append('g')
.attr("transform", `translate(${width}, 0)`)
.call(d3.axisRight(yScale2).ticks(10).tickSize(0).tickPadding(6))
.call(d => d.select(".domain").remove());
// set horizontal grid line
const GridLine = () => d3.axisLeft().scale(yScale1);
svg
.append("g")
.attr("class", "grid")
.call(GridLine()
.tickSize(-width,0,0)
.tickFormat("")
);
// create a tooltip
const tooltip = d3.select("body")
.append("div")
.attr("id", "chart")
.attr("class", "tooltip");
// tooltip events
const mouseover = function(d) {
tooltip
.style("opacity", .8)
d3.select(this)
.style("opacity", .5)
}
const mousemove = function(event, d) {
const formater = d3.format(",")
tooltip
.html(formater(+d.displaced_population))
.style("top", event.pageY - 10 + "px")
.style("left", event.pageX + 10 + "px");
}
const mouseleave = function(d) {
tooltip
.style("opacity", 0)
d3.select(this)
.style("opacity", 1)
}
// create bar
const bar = svg
.selectAll("rect")
.data(data)
.join("g")
.append("rect")
.attr("class", "bar")
.style("fill", "#0072BC")
.attr("x", d => xScale(d.year))
.attr("y", d => yScale1(+d.displaced_population))
.attr("width", xScale.bandwidth())
.attr("height", d => height - yScale1(+d.displaced_population))
.on("mouseover", mouseover)
.on("mousemove", mousemove)
.on("mouseleave", mouseleave);
// create line
svg
.append("path")
.datum(data)
.attr("class", "line")
.attr("fill", "none")
.attr("stroke", "#18375F")
.attr("stroke-width", 2)
.attr("d", d3.line()
.x(d => xScale(d.year) + xScale.bandwidth() / 2)
.y(d => yScale2(d.displaced_proportion))
);
// set title
svg
.append("text")
.attr("class", "chart-title")
.attr("x", -(margin.left)*0.5)
.attr("y", -(margin.top)/1.5)
.attr("text-anchor", "start")
.text("Trend of global displacement | 2007-2016")
// set Y axis 1 label
svg
.append("text")
.attr("class", "label_left")
.attr("x", -(margin.left)*0.5)
.attr("y", -(margin.top/4))
.attr("text-anchor", "start")
.style("fill", "#0072BC")
.text("Displaced population (millions)")
// set Y axis 2 label
svg
.append("text")
.attr("class", "label_right")
.attr("x", width+15)
.attr("y", -(margin.top/2.7))
.attr("text-anchor", "end")
.style("fill", "#18375F")
.text("Proportion displaced")
svg
.append("text")
.attr("class", "label_right")
.attr("x", width+15)
.attr("y", -(margin.top/4))
.attr("text-anchor", "end")
.style("fill", "#18375F")
.text("(Number displaced per 1,000 world population)")
// set source
svg
.append("text")
.attr("class", "chart-source")
.attr("x", -(margin.left)*0.5)
.attr("y", height + margin.bottom*0.7)
.attr("text-anchor", "start")
.text("Source: UNHCR Refugee Data Finder")
// set copyright
svg
.append("text")
.attr("class", "copyright")
.attr("x", -(margin.left)*0.5)
.attr("y", height + margin.bottom*0.9)
.attr("text-anchor", "start")
.text("©UNHCR, The UN Refugee Agency")
})