UNHCR Logo
  • Guidance
  • Chart types
  • Resources
  • Tutorials
  • Product gallery
Tutorials
  • R
    • Change over time
    • Comparison
    • Correlation
    • Distribution
    • Geospatial
    • Part-to-a-whole
    • Ranking
  • Matplotlib
    • Change over time
    • Comparison
    • Correlation
    • Distribution
    • Part-to-a-whole
    • Ranking
  • Plotly Python
    • Comparison
  • D3
    • Change over time
    • Comparison
    • Correlation
    • Distribution
    • Geospatial
    • Part-to-a-whole
On this page
  • 100% stacked column chart
  • Donut chart
  • Pie chart
  • Treemap
  1. Home
  2. Tutorials
  3. D3
  4. Part-to-a-whole

100% stacked column chart

100% stacked column charts are similar to stacked column charts in that categories are represented as vertical bars and series as components of those bars. However, in a 100% stacked column chart, each series bar represents the percentage of the whole to which it belongs, where the total (cumulative) of each stacked bar always equals 100%.

More about: 100% stacked column chart - Other tutorials: R Matplotlib

            
              <!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="full_column_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("#full_column_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/part_to_a_whole/column_stacked_100perc_d3.csv")
              .then(function(data){

              // list of value keys
              const typeKeys = data.columns.slice(1);
     
              // stack the data
              const stack = d3.stack()
                 .keys(typeKeys)
                 .order(d3.stackOrderNone)
                 .offset(d3.stackOffsetNone)
              const stackedData =stack(data)

              // X scale and Axis
              const xScale = d3.scaleBand()
                .domain(data.map(d => d.Year)) 
                .range([0, width])
                .padding(.2); 
              const xAxis = svg
                .append('g')
                .attr("transform", `translate(0, ${height})`)
                .call(d3.axisBottom(xScale).tickSize(0).tickPadding(8));
              
              // Y scale and Axis
              const yScale = d3.scaleLinear()
                  .domain([0, 1])
                  .range([height, 0]);
              svg
                .append('g')
                .call(d3.axisLeft(yScale).ticks(10, "%").tickSize(0).tickPadding(4))
                .call(d => d.select(".domain").remove());

              // color palette
              const color = d3.scaleOrdinal()
                .domain(typeKeys)
                .range(["#0072BC", "#FFC740", "#32C189", "#6CD8FD"])
              
              // set horizontal grid line
              const GridLine = function() {return d3.axisLeft().scale(yScale)};
              svg
                .append("g")
                  .attr("class", "grid")
                .call(GridLine()
                  .tickSize(-width,0,0)
                  .tickFormat("")
              ); 

              // create a tooltip
              const tooltip = d3.select("body")
                .append("div")
                  .attr("class", "tooltip");

              // tooltip events
              const mouseover = function(d) {
                  tooltip
                      .style("opacity", 1)
                  d3.select(this)
                      .style("stroke", "#EF4A60")
                      .style("opacity", .5)
              };
              const mousemove = function(event,d) {
                  const subgroupName = d3.select(this.parentNode).datum().key;
                  const subgroupValue = d.data[subgroupName];
                  const f = d3.format(".0f");
                  tooltip
                  .html(`<b>${subgroupName}</b>:  ${f(subgroupValue*100)}%`)
                      .style("top", event.pageY - 10 + "px")
                      .style("left", event.pageX + 10 + "px")
              };
              const mouseleave = function(d) {
                  tooltip
                      .style("opacity", 0)
                  d3.select(this)
                      .style("stroke", "none")
                      .style("opacity", 1)
              };
              
              // create bars
              svg.append("g")
                .selectAll("g")
                .data(stackedData)
                .join("g")
                    .attr("fill", d => color(d.key))
                .selectAll("rect")
                .data(d => d)
                .join("rect")
                    .attr("x", d => xScale(d.data.Year))
                    .attr("y", d => yScale(d[1]))
                    .attr("width", xScale.bandwidth())
                    .attr("height", d => yScale(d[0]) - yScale(d[1]))
                .on("mouseover", mouseover)
                .on("mousemove", mousemove)
                .on("mouseleave", mouseleave)
                                
              // set title
              svg
                .append("text")
                  .attr("class", "chart-title")
                  .attr("x", -(margin.left)*0.7)
                  .attr("y", -(margin.top)/1.5)
                  .attr("text-anchor", "start")
                .text("Levels of earmarking | 2012-2020")
              
              // set source
              svg
                .append("text")
                  .attr("class", "chart-source")
                  .attr("x", -(margin.left)*0.7)
                  .attr("y", height + margin.bottom*0.7)
                  .attr("text-anchor", "start")
                .text("Source: UNHCR")

              // set copyright
              svg
                .append("text")
                  .attr("class", "copyright")
                  .attr("x", -(margin.left)*0.7)
                  .attr("y", height + margin.bottom*0.9)
                  .attr("text-anchor", "start")
                .text("©UNHCR, The UN Refugee Agency")
              
              //set legend
              svg
                  .append("rect")
                      .attr("x", -(margin.left)*0.7)
                      .attr("y", -(margin.top/2.5))
                      .attr("width", 13)
                      .attr("height", 13)
                      .style("fill", "#0072BC")
              svg
                  .append("text")
                      .attr("class", "legend")
                      .attr("x", -(margin.left)*0.6+15)
                      .attr("y", -(margin.top/3.5))
                  .text("Earmarked")
              svg
                  .append("rect")
                      .attr("x", 60)
                      .attr("y", -(margin.top/2.5))
                      .attr("width", 13)
                      .attr("height", 13)
                      .style("fill", "#FFC740")
              svg
                  .append("text")
                      .attr("class", "legend")
                      .attr("x", 80)
                      .attr("y", -(margin.top/3.5))
                  .text("Softly earmarked")
              svg
                  .append("rect")
                      .attr("x", 170)
                      .attr("y", -(margin.top/2.5))
                      .attr("width", 13)
                      .attr("height", 13)
                      .style("fill", "#32C189")
              svg
                  .append("text")
                      .attr("class", "legend")
                      .attr("x", 190)
                      .attr("y", -(margin.top/3.5))
                  .text("Tightly earmarked")
              svg
                  .append("rect")
                      .attr("x", 290)
                      .attr("y", -(margin.top/2.5))
                      .attr("width", 13)
                      .attr("height", 13)
                      .style("fill", "#6CD8FD")
              svg
                  .append("text")
                      .attr("class", "legend")
                      .attr("x", 310)
                      .attr("y", -(margin.top/3.5))
                  .text("Unearmarked")
              })
            
          

Donut chart

The donut chart is a variation of a pie charts, with the total amount divided into categories based on a proportional value. For the most part, there aren’t significant differences between a pie chart and a donut chart, so the choice of a donut over a standard circle is mostly aesthetic. One small advantage for the ring shape is that the central area can be used to show additional information such as the total amount figure.

More about: Donut chart - Other tutorials: R Matplotlib

            
              <!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="donut_chart_container"></div>
            
          
            
                             
            
          
            

              // set the dimensions and margins of the graph
              const margin = 80,
                    height = 450,
                    width = 450

              // append the svg object to the body of the page
              const svg = d3.select("#donut_chart_container")
                .append("svg")
                  .attr("width", "100%")
                  .attr("height", "100%")
                  .attr("viewBox", "0 0 450 450")
                  .attr("preserveAspectRatio", "xMinYMin")
                .append("g")
                  .attr("transform", `translate(${width / 2}, ${height / 2})`);
                
                const radius = Math.min(width, height) / 2 - margin

              // parse the Data
              d3.csv("https://raw.githubusercontent.com/GDS-ODSSS/unhcr-dataviz-platform/master/data/part_to_a_whole/pie.csv")
              .then(function(data){

              // color palette
              const color = d3.scaleOrdinal()
                .domain(data)
                .range(["#0072BC","#6CD8FD"])

              const pie = d3.pie()
                  .value(d => +d.funding_value)
                  .sort(null)

              const dataPrepared = pie(data)

              arc = d3.arc()
                  .innerRadius(radius/2.3)
                  .outerRadius(radius)

              data.forEach(function(d) {
                d.funding_value = +d.funding_value;
                d.enabled = true;
              });

              const total = d3.sum(data.map(function(d) {       
                return (d.enabled) ? d.funding_value : 0;  })); 

              // create a tooltip
              const tooltip = d3.select("body")
                .append("div")
                  .attr("class", "tooltip")
                  .attr("font-size", "20px");

              // tooltip events
              const mouseover = function(d) {
                  tooltip
                      .style("opacity", 1)
                  d3.select(this)
                      .style("opacity", .5)
              };
              const f = d3.format(",.0f");
              const mousemove = function(event,d) {
                const percent = Math.round(1000 * d.data.funding_value / total) / 10;
                tooltip
                .html(`<b>${d.data.funding_type}</b>: `+ percent + '%')
                      .style("top", event.pageY - 10 + "px")
                      .style("left", event.pageX + 10 + "px")
              };
              const mouseleave = function(d) {
                  tooltip
                      .style("opacity", 0)
                  d3.select(this)
                      .style("stroke", "none")
                      .style("opacity", 1)
              };

              svg
                .selectAll('path')
                .data(dataPrepared)
                .join('path')
                  .attr('d', arc)
                  .attr('fill', d => color(d.data.funding_type))
                  .attr("stroke", "#ffffff")
                  .style("stroke-width", "2px")
                  .each(function(d) { this._current - d; })
                  .on("mouseover", mouseover)
                  .on("mousemove", mousemove)
                  .on("mouseleave", mouseleave);

              svg
                .append("g")
                .attr("text-anchor", "middle")
                .selectAll("text")
                .data(dataPrepared)
                .join("text")
                .attr("transform", d => `translate(${arc.centroid(d)})`)
                .call(text => text.append("tspan")
                   .attr("x", "0.2em")
                   .attr("y", "-0.6em")
                   .attr("fill", "#ffffff")
                   .text(d => d.data.funding_type))
                .call(text => text.filter(d => (d.endAngle - d.startAngle) > 0.25).append("tspan")
                   .attr("x", 0)
                   .attr("y", "0.7em")
                   .attr("fill", "#ffffff")
                   .text(d => "$" + d.data.funding_value.toLocaleString()))
         
              // set title
              svg
                .append("text")
                  .attr("class", "chart-title")
                  .attr("x", -(margin/2+radius))
                  .attr("y", -(margin/2+radius))
                  .attr("text-anchor", "start")
                .text("2021 UNHCR's funding")

              //data label for total
              svg
                .append("text")
                  .attr("dy", "-1em")
                  .style("font-size", "12px")
                  .style("text-anchor", "middle")
                  .attr("class", "inner-circle")
                  .attr("fill", "#222222")
                  .text("Total required");
              svg
                .append("text")
                  .attr("dy", "0.5em")
                  .style("font-size", "16px")
                  .style("text-anchor", "middle")
                  .attr("class", "inner-circle")
                  .attr("fill", "#222222")
                  .text("$" + f(total));
                                    
              // set source
              svg
                .append("text")
                  .attr("class", "chart-source")
                  .attr("x", -(margin/2+radius))
                  .attr("y", margin/3+radius)
                  .attr("text-anchor", "start")
                .text("Source: UNHCR")

              // set copyright
              svg
                .append("text")
                  .attr("class", "copyright")
                  .attr("x", -(margin/2+radius))
                  .attr("y", margin/2.2+radius)
                  .attr("text-anchor", "start")
                .text("©UNHCR, The UN Refugee Agency")
              })

            
          

Pie chart

A pie chart shows how a total amount is divided between different categorical variables as a circle divided into proportional segments. Each categorical value corresponds with a single slice of the circle, and each arc length indicates the proportion of each category.

More about: Pie chart - Other tutorials: R Matplotlib

            
              <!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="pie_container"></div>
            
          
            
                             
            
          
            

              // set the dimensions and margins of the graph
              const margin = 80,
                    height = 450,
                    width = 450

              // append the svg object to the body of the page
              const svg = d3.select("#pie_container")
                .append("svg")
                  .attr("width", "100%")
                  .attr("height", "100%")
                  .attr("viewBox", "0 0 450 450")
                  .attr("preserveAspectRatio", "xMinYMin")
                .append("g")
                  .attr("transform", `translate(${width / 2}, ${height / 2})`);
                
                const radius = Math.min(width, height) / 2 - margin

              // parse the Data
              d3.csv("https://raw.githubusercontent.com/GDS-ODSSS/unhcr-dataviz-platform/master/data/part_to_a_whole/pie.csv")
              .then(function(data){

              // color palette
              const color = d3.scaleOrdinal()
                .domain(data)
                .range(["#0072BC","#6CD8FD"])

              const pie = d3.pie()
                .value(d => +d.funding_value)
                .sort(null)

              const dataPrepared = pie(data)

              arc = d3.arc()
                .innerRadius(0)
                .outerRadius(radius)

              data.forEach(function(d) {
                d.funding_value = +d.funding_value;
                d.enabled = true;
              });

              const total = d3.sum(data.map(function(d) {       
                return (d.enabled) ? d.funding_value : 0;                                      
                })); 

              // create a tooltip
              const tooltip = d3.select("body")
                .append("div")
                  .attr("class", "tooltip");

              // tooltip events
              const mouseover = function(d) {
                tooltip
                    .style("opacity", 1)
                d3.select(this)
                    .style("opacity", .5)
              };
              const mousemove = function(event,d) {
                const percent = Math.round(1000 * d.data.funding_value / total) / 10;
                const f = d3.format(",.0f");
                tooltip
                .html(`<b>${d.data.funding_type}</b>: `+ percent + '%')
                  .style("top", event.pageY - 10 + "px")
                  .style("left", event.pageX + 10 + "px")
              };
              const mouseleave = function(d) {
                tooltip
                  .style("opacity", 0)
                d3.select(this)
                  .style("stroke", "none")
                  .style("opacity", 1)
              };
              
              svg
              .selectAll('path')
              .data(dataPrepared)
              .join('path')
                .attr('d', arc)
                .attr('fill', d => color(d.data.funding_type))
                .attr("stroke", "#ffffff")
                .style("stroke-width", "2px")
                .each(function(d) { this._current - d; })
                .on("mouseover", mouseover)
                .on("mousemove", mousemove)
                .on("mouseleave", mouseleave);

              svg 
                .append("g")
                .attr("text-anchor", "middle")
                .selectAll("text")
                .data(dataPrepared)
                .join("text")
                .attr("transform", d => `translate(${arc.centroid(d)})`)
                .call(text => text.append("tspan")
                  .attr("x", "0.2em")
                  .attr("y", "-0.6em")
                  .attr("fill", "#ffffff")
                  .text(d => d.data.funding_type))
                .call(text => text.filter(d => (d.endAngle - d.startAngle) > 0.25).append("tspan")
                  .attr("x", 0)
                  .attr("y", "0.7em")
                  .attr("fill", "#ffffff")
                  .text(d => "$" + d.data.funding_value.toLocaleString()))
         
              // set title
              svg
                .append("text")
                  .attr("class", "chart-title")
                  .attr("x", -(margin/2+radius))
                  .attr("y", -(margin/2+radius))
                  .attr("text-anchor", "start")
                .text("2021 UNHCR's funding")
              
              // set source
              svg
                .append("text")
                  .attr("class", "chart-source")
                  .attr("x", -(margin/2+radius))
                  .attr("y", margin/3+radius)
                  .attr("text-anchor", "start")
                .text("Source: UNHCR")

              // set copyright
              svg
                .append("text")
                  .attr("class", "copyright")
                  .attr("x", -(margin/2+radius))
                  .attr("y", margin/2.2+radius)
                  .attr("text-anchor", "start")
                .text("©UNHCR, The UN Refugee Agency")
              })
            
          

Treemap

As a variation of a tree diagram, a treemap is meant to show hierarchical structure using the size of the rectangle to represent quantity. Each category is assigned a rectangle, with subcategories displayed inside the large rectangle, in proportionate size against each other.

More about: Treemap - Other tutorials: R Matplotlib

            
              <!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="treemap_container"></div>
            
          
            
                             
            
          
            

              // set the dimensions and margins of the graph
              const margin = {top: 30, right: 20, bottom: 30, left: 20};
              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("#treemap_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/part_to_a_whole/treemap_d3.csv")
              .then(function(data){

              data.forEach(function(d) {
                  d.staff_number = +d.staff_number;
                  d.enabled = true;
                });

              const total = d3.sum(data.map(function(d) {       
                return (d.enabled) ? d.staff_number : 0;  })); 

              // reshape data
              const treeData = d3.stratify()
                .id(d => d.region)
                .parentId(d => d.parent)
                (data);

              treeData.sum(d => d.staff_number)

              d3.treemap()
                .size([width, height])
                .padding(2)
                (treeData);

              // create a tooltip
              const tooltip = d3.select("body")
                .append("div")
                  .attr("class", "tooltip");

              // tooltip events
              const mouseover = function(d) {
                tooltip
                    .style("opacity", 1)
                d3.select(this)
                    .style("opacity", .5)
              };
              const mousemove = function(event,d) {
                f = d3.format(",")
                tooltip
                .html("Number of staff: " + `${f(d.data.staff_number)}`)
                  .style("top", event.pageY - 10 + "px")
                  .style("left", event.pageX + 10 + "px")
              };
              const mouseleave = function(d) {
                tooltip
                  .style("opacity", 0)
                d3.select(this)
                  .style("stroke", "none")
                  .style("opacity", 1)
              };

              // create rectangle
              svg
                .selectAll("rect")
                .data(treeData.leaves())
                .join("rect")
                  .attr('x', d => d.x0)
                  .attr('y', d => d.y0)
                  .attr('width', d => d.x1 - d.x0)
                  .attr('height', d=> d.y1 - d.y0)
                  .style("stroke", "none")
                  .style("fill", "#0072BC")
                .on("mouseover", mouseover)
                .on("mousemove", mousemove)
                .on("mouseleave", mouseleave);
            
              // add labels to the graph
              svg
                .selectAll("text-number")
                .data(treeData.leaves())
                .join("text")
                  .attr("class", "tree-label")
                  .attr("x", d => d.x0+5) 
                  .attr("y", d => d.y0+15)
                  .text(d => Math.round(1000 * d.data.staff_number / total) / 10 + "%")
                  .attr("font-size", "10px")
                  .style("fill", "#ffffff");
              svg
                .selectAll("text-region")
                .data(treeData.leaves())
                .join("text")
                  .attr("class", "tree-label")
                  .attr("x", d => d.x0+5) 
                  .attr("y", d => d.y0+30)
                  .text(d => d.data.region)
                  .attr("font-size", "10px")
                  .style("fill", "#ffffff");

              // set title
              svg
                .append("text")
                  .attr("class", "chart-title")
                  .attr("x", 0)
                  .attr("y", -(margin.top)/1.5)
                  .attr("text-anchor", "start")
                .text("UNHCR global workforce by region | 2021");
              
              // set source
              svg
                .append("text")
                  .attr("class", "chart-source")
                  .attr("x", 0)
                  .attr("y", height + margin.bottom*0.4)
                  .attr("text-anchor", "start")
                .text("Source: UNHCR")

              // set copyright
              svg
                .append("text")
                  .attr("class", "copyright")
                  .attr("x", 0)
                  .attr("y", height + margin.bottom*0.7)
                  .attr("text-anchor", "start")
                .text("©UNHCR, The UN Refugee Agency")
              })

            
          
Contact us
  • Guidance
  • Chart types
  • Resources
  • Tutorials
  • Product gallery

© UNHCR