Reputation: 118
Considering a dataset like this:
var pie_data = [{
"hard_skill": "Strategy",
"course_area_percentage": 9
}, {
"hard_skill": "Analytics",
"course_area_percentage": 18
}, {
"hard_skill": "Economics",
"course_area_percentage": 11
}, {
"hard_skill": "Finance",
"course_area_percentage": 7
}, {
"hard_skill": "HR",
"course_area_percentage": 5
}, {
"hard_skill": "Innovation",
"course_area_percentage": 2
}, {
"hard_skill": "International",
"course_area_percentage": 5
}, {
"hard_skill": "Marketing",
"course_area_percentage": 7
}, {
"hard_skill": "Operations",
"course_area_percentage": 14
}, {
"hard_skill": "Others",
"course_area_percentage": 11
}, {
"hard_skill": "Project",
"course_area_percentage": 11
}]
I'm creating a pie chart in order to show all of these skills as slices of the chart. The idea then is to give a greener color (meaning it is more important), from a red to green color scale, to the skill that has higher percentage.
I've tried using d3.scale.ordinal()
and d3.scale.linear()
with different ranges and domains, but the colors do not match to the pattern described above. They seem to be inverted, like this:
My code for the color scale:
var pie_colorScale = d3.scale.ordinal()
//.domain([0,pie_data.length])
//.range(["#d7191c", "#eef200", "#008e15"]);
//.range(["#d7191c","#f19d00","#eef200","#3fe256", "#008e15"]);
.range(["#008e15", "#3fe256", "#eef200", "#f19d00", "#d7191c"]);
Does the mapping of the colors to the values have to be manually set?
Upvotes: 1
Views: 3280
Reputation: 102174
Given your desired outcome...
the idea then is to give a greener color (meaning it is more important), from a red to green color scale, to the skill that has higher percentage.
..., an ordinal scale is not the adequate choice.
You can use a linear scale with two colours in the range, "red" and "green", but the result is not nice. So, this solution uses three colours in the range: "red", "yellow" and "green".
The trick to do that is using three values in the domain:
var color = d3.scale.linear()
.domain([d3.min(pie_data, d => d.course_area_percentage),
d3.mean(pie_data, d => d.course_area_percentage),
d3.max(pie_data, d => d.course_area_percentage)
])
.range(["red", "yellow", "green"]);
Here is a demo:
var pie_data = [{
"hard_skill": "Strategy",
"course_area_percentage": 9
}, {
"hard_skill": "Analytics",
"course_area_percentage": 18
}, {
"hard_skill": "Economics",
"course_area_percentage": 11
}, {
"hard_skill": "Finance",
"course_area_percentage": 7
}, {
"hard_skill": "HR",
"course_area_percentage": 5
}, {
"hard_skill": "Innovation",
"course_area_percentage": 2
}, {
"hard_skill": "International",
"course_area_percentage": 5
}, {
"hard_skill": "Marketing",
"course_area_percentage": 7
}, {
"hard_skill": "Operations",
"course_area_percentage": 14
}, {
"hard_skill": "Others",
"course_area_percentage": 11
}, {
"hard_skill": "Project",
"course_area_percentage": 11
}]
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.linear()
.domain([d3.min(pie_data, d=>d.course_area_percentage),
d3.mean(pie_data, d=>d.course_area_percentage),
d3.max(pie_data, d=>d.course_area_percentage)])
.range(["red", "yellow", "green"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.course_area_percentage;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll(".arc")
.data(pie(pie_data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("stroke", "gray")
.style("fill", function(d) {
return color(d.data.course_area_percentage);
});
g.append("text")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.text(function(d) {
return d.data.hard_skill;
});
function type(d) {
d.population = +d.population;
return d;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
As an alternative solution, if you want to use the color array you wrote in the question...
.range(["#008e15", "#3fe256", "#eef200", "#f19d00", "#d7191c"]);
... you should use a quantize (or quantile) scale instead:
var color = d3.scale.quantize()
.domain(d3.extent(pie_data, d => d.course_area_percentage))
.range(["#d7191c", "#f19d00", "#eef200", "#3fe256", "#008e15"]);
Here is the demo:
var pie_data = [{
"hard_skill": "Strategy",
"course_area_percentage": 9
}, {
"hard_skill": "Analytics",
"course_area_percentage": 18
}, {
"hard_skill": "Economics",
"course_area_percentage": 11
}, {
"hard_skill": "Finance",
"course_area_percentage": 7
}, {
"hard_skill": "HR",
"course_area_percentage": 5
}, {
"hard_skill": "Innovation",
"course_area_percentage": 2
}, {
"hard_skill": "International",
"course_area_percentage": 5
}, {
"hard_skill": "Marketing",
"course_area_percentage": 7
}, {
"hard_skill": "Operations",
"course_area_percentage": 14
}, {
"hard_skill": "Others",
"course_area_percentage": 11
}, {
"hard_skill": "Project",
"course_area_percentage": 11
}]
var width = 500,
height = 500,
radius = Math.min(width, height) / 2;
var color = d3.scale.quantize()
.domain(d3.extent(pie_data, d=>d.course_area_percentage))
.range(["#d7191c", "#f19d00", "#eef200", "#3fe256", "#008e15"]);
var arc = d3.svg.arc()
.outerRadius(radius - 10)
.innerRadius(0);
var pie = d3.layout.pie()
.sort(null)
.value(function(d) {
return d.course_area_percentage;
});
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");
var g = svg.selectAll(".arc")
.data(pie(pie_data))
.enter().append("g")
.attr("class", "arc");
g.append("path")
.attr("d", arc)
.style("stroke", "gray")
.style("fill", function(d) {
return color(d.data.course_area_percentage);
});
g.append("text")
.attr("text-anchor", "middle")
.attr("transform", function(d) {
return "translate(" + arc.centroid(d) + ")";
})
.attr("dy", ".35em")
.text(function(d) {
return d.data.hard_skill;
});
function type(d) {
d.population = +d.population;
return d;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Upvotes: 1