d3.scale.category20 is too smart for me

Can anybody explain to me why these two expressions return different values…

log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"

… in the following context


Working example…

    var c20 = d3.scale.category20(),
      col = d3.range(20).map(function(c) {
        return c20(c).replace("#", "0x")
      }),
      log1 = d3.select("#log1"),
      log2 = d3.select("#log2");

    log1.text(c20(1)); // "#aec7e8"
    log2.text(d3.scale.category20()(1)); // "#1f77b4"
    $("#user-agent").text(navigator.userAgent);
#log div {
  display: inline-block;
  margin: 0 0 0 10px;
  background: #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>

<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title></title>
</head>

<body>
  <div id="container"></div>
  <p id="user-agent"></p>
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>
  <div id="log1"></div>
  <div id="log2"></div>
</body>

</html>

Expand snippet

The user agent reported in my system is

Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36


I kind of get the above behaviour but this is very strange…

Why is this…

// method 1
d3.range(20).map(d3.scale.category20())

0   #1f77b4
1   #aec7e8
2   #ff7f0e
3   #ffbb78
4   #2ca02c
5   #98df8a
6   #d62728
7   #ff9896
8   #9467bd
9   #c5b0d5
10  #8c564b
11  #c49c94
12  #e377c2
13  #f7b6d2
14  #7f7f7f
15  #c7c7c7
16  #bcbd22
17  #dbdb8d
18  #17becf
19  #9edae5

different from this…

// method 2
d3.range(20).map(function(d, i) {
    return d3.scale.category20()(i);
})  

0   #1f77b4
1   #1f77b4
2   #1f77b4
3   #1f77b4
4   #1f77b4
5   #1f77b4
6   #1f77b4
7   #1f77b4
8   #1f77b4
9   #1f77b4
10  #1f77b4
11  #1f77b4
12  #1f77b4
13  #1f77b4
14  #1f77b4
15  #1f77b4
16  #1f77b4
17  #1f77b4
18  #1f77b4
19  #1f77b4
var c20 = d3.scale.category20(),
  log1 = d3.select("#log1"),
  log2 = d3.select("#log2");

log1.text(c20(1)); // "#aec7e8"
log2.text(d3.scale.category20()(1)); // "#1f77b4"

d3.select("#t1").selectAll(".logs")
  .data(d3.range(20).map(d3.scale.category20()))
  .enter().append("tr").selectAll("td").data(function(d) {
    return [d]
  })
  .enter().append("td")
  .attr("class", "logs")
  .text(function(d, i, j) {
    return [j, d].join("\t")
  })

d3.select("#t2").selectAll(".logs")
  .data(d3.range(20).map(function(d, i) {
    return d3.scale.category20()(i);
  }))
  .enter().append("tr").selectAll("td").data(function(d) {
    return [d]
  })
  .enter().append("td")
  .attr("class", "logs")
  .text(function(d, i, j) {
    return [j, d].join("\t")
  })
#log div {
  display: inline-block;
  margin: 0 0 10px 10px;
  background: #ccc;
}
#t1,
#t2 {
  background: #ccc;
  display: inline-block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js"></script>

<div id="log">
  <div id="log1"></div>
  <div id="log2"></div>
</div>
<div id="t1"></div>
<div id="t2"></div>

Expand snippet

Just to explain, the reason I wanted to use method 2 above was because I needed to convert the hex strings into properly formatted hex numbers so I had to process the domain values on the way through. The actual use case is this:

var col = d3.range(20).map(function(c){
        return d3.scale.category20()(c).replace("#", "0x")
    });  

which doesn’t work (and I still don’t get why not), which is why I had to do this:

var c20 = d3.scale.category20(),
    col = d3.range(20).map(function(c){
        return c20(c).replace("#", "0x")
    });

Leave a Comment