dbj44
dbj44

Reputation: 1998

D3: Create bars of many colored rectangles

I have created a D3 bar chart, which takes in my data, applies a scale and then draws my rectangles. Here's my current output:

enter image description here

I would like to make it more visual. The values are temperatures, so I'd like to create something like the first bar here:

enter image description here

Basically I want to make a bar that is made up of many rectangles of different colors.

After considering several options, I decided to try to inject a pattern into my bars. I tried making my pattern from paths, and then I attempted rectangles, but no success.

I'm not tied to the 'pattern' approach, so an different approach, or how I can make this pattern, is what I'm after. Here's my code:

// Set variables.
var dataset = // an array of objects, each with two properties: location and temperature
w = 500,
h = 800,
xScale = d3.scale.linear()
  .domain([-30, 40])
  .range([5, 350]),
yScale = d3.scale.ordinal();

// Create SVG element.
var svg = d3.select("body")
  .append("svg")
    .attr("width", w)
    .attr("height", h);

/* svg.append("defs")
  .append("pattern")
    .attr("id", "heatHatch")
    .attr("patternUnits", "userSpaceOnUse")
    .attr("width", 350)
    .attr("height", 25);
     .append("path")
      .attr("d", "M10 0 L10 20 L0 20 L0 0 Z M22 0 L22 20 L12 20 L12 0 Z")
      .attr("fill", "pink")
    .append("path")
      .attr("d", "M22 0 L22 20 L12 20 L12 0 Z")
      .attr("fill", "red");
    .append("rect")
      .attr("x", 0)
      .attr("y", 0)
      .attr("width", 10)
      .attr("height", 20)
      .attr("fill", "pink"); */

// Create bars.
svg.selectAll("rect")
  .data(dataset)
  .enter()

  .append("rect")
    .attr("x", 0)
    .attr("y", function(d, i) {
      return i * 25;
    })
    .attr("width", function(d) {
      return xScale(d[1]);
    })
    .attr("height", 20);
    /*.attr("fill", "url(#heatHatch)"); */

Thanks.

Upvotes: 2

Views: 1031

Answers (1)

Mark
Mark

Reputation: 108517

If you want pattern that scales to the bar size, use a gradient pattern:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <script>
  
    var w = 500,
      h = 500;

    var svg = d3.select("body").append("svg:svg")
      .attr("width", w)
      .attr("height", h);

    var color = d3.scale.category10();

    var gradient = svg.append("svg:defs")
      .append("svg:linearGradient")
      .attr("id", "gradient")
      .attr("x1", "0%")
      .attr("y1", "50%")
      .attr("x2", "100%")
      .attr("y2", "50%")
      .attr("spreadMethod", "pad");

    d3.range(10).forEach(function(d, i) {
      var c = color(i);
      gradient.append("svg:stop")
        .attr("offset", (i * 10) + "%")
        .attr("stop-color", c)
        .attr("stop-opacity", 1);
      gradient.append("svg:stop")
        .attr("offset", ((i + 1) * 10) + "%")
        .attr("stop-color", c)
        .attr("stop-opacity", 1);
    });

    svg.selectAll("bar")
      .data(d3.range(10))
      .enter()
      .append("rect")
      .attr("class", "bar")
      .attr("width", function(d,i){
        return (w / 10) * i;
      })
      .attr("height", (h / 10) - 10)
      .attr("y", function(d,i){
        return (h / 10) * i;
      })
      .style("fill", "url(#gradient)");
  </script>
</body>

</html>

If you want a pattern with statically sized colors, create a pattern of rects:

<!DOCTYPE html>
<html>

<head>
  <script data-require="[email protected]" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
</head>

<body>
  <script>
  
    var w = 500,
      h = 500;

    var svg = d3.select("body").append("svg")
      .attr("width", w)
      .attr("height", h);

    var color = d3.scale.category10();

    var pattern = svg.append("svg:defs")
      .append("svg:pattern")
      .attr("width", w)
      .attr("height", 4)
      .attr("id", "myPattern")
      .attr("patternUnits","userSpaceOnUse");

    d3.range(10).forEach(function(d, i) {
      var c = color(i);
      pattern.append("rect")
        .attr("height", "4px")
        .attr("width", w / 10)
        .attr("x", (w / 10) * i)
        .attr("fill", c);
    });
    
    svg.selectAll("bar")
      .data(d3.range(10))
      .enter()
      .append("rect")
      .attr("class","bar")
      .attr("width", function(d,i){
        return (w / 10) * i;
      })
      .attr("height", (h / 10) - 10)
      .attr("y", function(d,i){
        return (h / 10) * i;
      })
      .style("fill", "url(#myPattern)");
  </script>
</body>

</html>

Upvotes: 2

Related Questions