Reputation: 281
I am new to d3 and now using the log scale method to determine what color something must be. I think there must be a way to optimize the code code below with more features of d3. How can I do that?
var logScale = d3.scale.log().domain([1, 400]).range([0, 6]);
var colorIndex = Math.round(logScale(count));
var colors = ['#D6EAF8', '#A9DFBF', '#A2D9CE', '#F1948A', '#CD6155', '#A93226', '#7B241C'];
return colors[colorIndex];
Upvotes: 2
Views: 72
Reputation: 102194
Technically speaking, what you're trying to create here is a threshold scale.
You could do it using d3.scale.threshold
(D3 v3 in your case, or d3.scaleThreshold
in v4). However, you will have to explicitly set the threshold, and the final code may be even uglier than what you have right now. Let's see it.
First, let's check the results of your code:
var logScale = d3.scale.log().domain([1, 400]).range([0, 6]);
var colors = ['#D6EAF8', '#A9DFBF', '#A2D9CE', '#F1948A', '#CD6155', '#A93226', '#7B241C'];
var result = d3.range(1, 401, 1).map(function(d) {
var colorIndex = Math.round(logScale(d));
return colors[colorIndex]
}).reduce(function(a, c) {
if (c in a) {
a[c]++
} else {
a[c] = 1
}
return a
}, {})
console.log(result)
<script src="https://d3js.org/d3.v3.min.js"></script>
That result
is just an object that I'm using to store how many times each color appears if we call your code from 1 to 400, don't be terribly worried about it right now. Just have in mind that this is the result that we will try to reproduce using the threshold scale.
For using the threshold scale, the first step is setting the thresholds. For that, will have to use your log scale:
var logScale = d3.scale.log().domain([1, 400]).range([0, 6]);
var thresholds = [];
d3.range(0.5, 6.5, 1).forEach(function(d) {
thresholds.push(logScale.invert(d))
});
console.log(thresholds)
<script src="https://d3js.org/d3.v3.min.js"></script>
Then, with those thresholds, we can use the threshold scale:
var thresholdScale = d3.scale.theshold()
.range(['#D6EAF8', '#A9DFBF', '#A2D9CE', '#F1948A', '#CD6155', '#A93226', '#7B241C'])
.domain(thresholds);
Finally, let's test our threshold scale, using the same result
object:
var logScale = d3.scale.log().domain([1, 400]).range([0, 6]);
var thresholds = [];
d3.range(0.5, 6.5, 1).forEach(function(d) {
thresholds.push(logScale.invert(d))
});
var thresholdScale = d3.scale.threshold()
.range(['#D6EAF8', '#A9DFBF', '#A2D9CE', '#F1948A', '#CD6155', '#A93226', '#7B241C'])
.domain(thresholds);
var result = d3.range(1, 401, 1).map(function(d) {
return thresholdScale(d)
}).reduce(function(a, c) {
if (c in a) {
a[c]++
} else {
a[c] = 1
}
return a
}, {})
console.log(result)
<script src="https://d3js.org/d3.v3.min.js"></script>
As you can see, the same results... yey!
Was it worth it? Well, I'd say no: your code is smaller, cleaner, easier to understand and probably faster. Yet, I wrote this answer to show you that there is a threshold scale in D3, and to show you how to convert your logic into that scale.
Upvotes: 2