score:1

Accepted answer

I'd spend a bit more time organizing my data up-front to make it simpler when passed to d3, something like this:

  // loop data once and organize
  let max = -1e9;
  data = data.map(function(d) {
    let m = Math.max(d.positive, d.negative, d.balanced, d.informational);
    if (m > max) max = m; // find max of data
    return {
      key: d.media_outlet,
      values: [{
        key: 'positive',
        value: +d.positive
      }, {
        key: 'negative',
        value: +d.negative
      }, {
        key: 'balanced',
        value: +d.balanced
      }, {
        key: 'informational',
        value: +d.informational
      }]
    };
  });

This then becomes a very straight forward d3 sub-selection to draw the bars:

  const bars = svgs
    .selectAll('.bars')
    .data(function(d) {
      return d.values;
    })
    .enter()
    .append('rect')
    .attr('class', 'bars')
    .attr('width', 10)
    .attr('x', function(d, i) {
      return x(d.key) - 5;
    })
    .attr('height', function(d, i) {
      return height - y(d.value);
    })
    .attr('y', function(d) {
      return y(d.value);
    })
    .style('fill', function(d, i) {
      return color(d.key);
    });

Full running code:

      let newsData = [{
        "media_outlet": "La OpiniĆ³n",
        "positive": "149",
        "negative": "296",
        "balanced": "142",
        "informational": "101",
        "total": "688"
      }, {
        "media_outlet": "Wall Street Journal",
        "positive": "137",
        "negative": "118",
        "balanced": "125",
        "informational": "79",
        "total": "459"
      }, {
        "media_outlet": "Univision",
        "positive": "226",
        "negative": "484",
        "balanced": "225",
        "informational": "159",
        "total": "1094"
      }, {
        "media_outlet": "San Diego Union Tribune",
        "positive": "60",
        "negative": "24",
        "balanced": "18",
        "informational": "17",
        "total": "119"
      }, {
        "media_outlet": "Fox News",
        "positive": "73",
        "negative": "102",
        "balanced": "58",
        "informational": "60",
        "total": "293"
      }, {
        "media_outlet": "Washington Post",
        "positive": "52",
        "negative": "97",
        "balanced": "56",
        "informational": "50",
        "total": "255"
      }, {
        "media_outlet": "CNN",
        "positive": "127",
        "negative": "160",
        "balanced": "102",
        "informational": "88",
        "total": "477"
      }, {
        "media_outlet": "USA Today",
        "positive": "32",
        "negative": "23",
        "balanced": "14",
        "informational": "22",
        "total": "91"
      }, {
        "media_outlet": "The Daily Beast",
        "positive": "9",
        "negative": "50",
        "balanced": "13",
        "informational": "10",
        "total": "82"
      }, {
        "media_outlet": "Bloomberg",
        "positive": "251",
        "negative": "183",
        "balanced": "158",
        "informational": "119",
        "total": "711"
      }, {
        "media_outlet": "Fusion",
        "positive": "48",
        "negative": "86",
        "balanced": "54",
        "informational": "49",
        "total": "237"
      }, {
        "media_outlet": "NPR",
        "positive": "20",
        "negative": "30",
        "balanced": "12",
        "informational": "14",
        "total": "76"
      }, {
        "media_outlet": "Dallas Morning News",
        "positive": "40",
        "negative": "34",
        "balanced": "24",
        "informational": "31",
        "total": "129"
      }, {
        "media_outlet": "TIME",
        "positive": "26",
        "negative": "30",
        "balanced": "17",
        "informational": "17",
        "total": "90"
      }, {
        "media_outlet": "Forbes",
        "positive": "97",
        "negative": "56",
        "balanced": "72",
        "informational": "37",
        "total": "262"
      }, {
        "media_outlet": "Christian Science Monitor",
        "positive": "19",
        "negative": "15",
        "balanced": "21",
        "informational": "7",
        "total": "62"
      }, {
        "media_outlet": "NBC News",
        "positive": "23",
        "negative": "34",
        "balanced": "19",
        "informational": "22",
        "total": "98"
      }, {
        "media_outlet": "Huffington Post",
        "positive": "232",
        "negative": "344",
        "balanced": "219",
        "informational": "85",
        "total": "880"
      }, {
        "media_outlet": "New York TImes",
        "positive": "90",
        "negative": "129",
        "balanced": "74",
        "informational": "62",
        "total": "355"
      }, {
        "media_outlet": "Houston Chronicle",
        "positive": "40",
        "negative": "32",
        "balanced": "31",
        "informational": "24",
        "total": "127"
      }, {
        "media_outlet": "Los Angeles Times",
        "positive": "66",
        "negative": "75",
        "balanced": "45",
        "informational": "45",
        "total": "231"
      }, {
        "media_outlet": "San Antonio Express News",
        "positive": "28",
        "negative": "22",
        "balanced": "14",
        "informational": "16",
        "total": "80"
      }, {
        "media_outlet": "Arizona Daily Star",
        "positive": "32",
        "negative": "15",
        "balanced": "6",
        "informational": "8",
        "total": "61"
      }, {
        "media_outlet": "Vice News",
        "positive": "17",
        "negative": "169",
        "balanced": "44",
        "informational": "12",
        "total": "242 "
      }];

      let data = newsData.sort(function(a, b) {
        if (+a.total < +b.total) {
          return 1;
        } else {
          return -1;
        }
      });

      let max = -1e9;
      data = data.map(function(d) {
        let m = Math.max(d.positive, d.negative, d.balanced, d.informational);
        if (m > max) max = m;
        return {
          key: d.media_outlet,
          values: [{
            key: 'positive',
            value: +d.positive
          }, {
            key: 'negative',
            value: +d.negative
          }, {
            key: 'balanced',
            value: +d.balanced
          }, {
            key: 'informational',
            value: +d.informational
          }]
        };
      });

      const tValues = ['positive', 'negative', 'balanced', 'informational'];
      const colors = ['#5cdacc', '#ff1d34', '#ffc750', '#ff8c50'];

      const margin = {
        top: 20,
        right: 50,
        bottom: 20,
        left: 50
      };
      const width = 310 - margin.left - margin.right;
      const height = 150 - margin.top - margin.bottom;

      const svgs = d3
        .select('#outlets-viz')
        .selectAll('svg')
        .data(data)
        .enter()
        .append('svg')
        .attr('class', 'media-svg')
        .attr('width', width + margin.left + margin.right)
        .attr('height', height + margin.top + margin.bottom)
        .append('g')
        .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');

      const color = d3
        .scaleOrdinal()
        .domain(tValues)
        .range(['#5cdacc', '#ff1d34', '#ffc750', '#ff8c50']);

      const x = d3
        .scalePoint()
        .domain(tValues)
        .range([0, width]);

      svgs
        .append('g')
        .attr('transform', 'translate(0,' + height + ')')
        .attr('class', 'domain')
        .call(d3.axisBottom(x).tickFormat(
          t => t[0].toUpperCase()
        ));

      const y = d3
        .scaleLinear()
        .domain([0, max])
        .range([height, 0]);

      const bars = svgs
        .selectAll('.bars')
        .data(function(d) {
          return d.values;
        })
        .enter()
        .append('rect')
        .attr('class', 'bars')
        .attr('width', 10)
        .attr('x', function(d, i) {
          return x(d.key) - 5;
        })
        .attr('height', function(d, i) {
          return height - y(d.value);
        })
        .attr('y', function(d) {
          return y(d.value);
        })
        .style('fill', function(d, i) {
          return color(d.key);
        });
<script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v5.min.js"></script>
<div id="outlets-viz"></div>


Related Query