Add a static/definite legend in D3JS graph

2019-08-12 16:03发布

问题:

I have a D3JS scatter plot, whose data source is a MYSQL request. Basically data points are (x, y, category) and category can be (A,B,C,D,E). Sometimes, there is no point in MySQL Select request whose category is A, or B.

BUT, I want all categories to be included in my legend, no matter if there is at least one point for each category represented in data source.

Today, I have the following code for dots, where color is "harcoded" to ensure that Category "A" dots are ALWAYS in color #4a9b5b (and same for B, C, D E):

            // draw dots
            svg.selectAll(".dot")
                .data(data)
            .enter().append("circle")
                .attr("class", "dot")
                .attr("r", 7)
                .attr("cx", xMap)
                .attr("cy", yMap)
                .style("fill", function(d) {
                    if (d.category == "A") {return "#4a9b5b"}
                    else if (d.category == "B") { return "#5caeb9" }
                    else if (d.category == "C") { return "#df4b4b" }
                    else if (d.category == "D") { return "#cb7e51" }
                    else { return "#ffffff" }
              ;})
              . [ ... ]

And the following legend [ NOT WORKING ] :

var legend = svg.selectAll(".legend")
     .data(color.domain())
.enter().append("g")
     .attr("class", "legend")
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

// draw legend colored rectangles
legend.append("rect")
     .attr("x", width - 18)
     .attr("width", 18)
     .attr("height", 18)
     .style("fill", color);

// draw legend text
legend.append("text")
     .attr("x", width - 24)
     .attr("y", 9)
     .attr("dy", ".35em")
     .style("text-anchor", "end")
     .text(function(d) { return d;});

I am looking for something similar to the dots, to have the same legend no matter the data source, something like :

Category A [#4a9b5b"]
Category B [#5caeb9"]
Category C [#df4b4b"]
Category D [#cb7e51"]
Category E [#ffffff"]

回答1:

Do like this for making color scale:

//make color as re the possible domain
var color = d3.scale.ordinal()
  .domain(["A", "B", "C", "D", "E"])
  .range([#4a9b5b", "#5caeb9" , "#df4b4b", "#cb7e51", "#ffffff"]);


svg.selectAll(".dot")
                .data(data)
            .enter().append("circle")
                .attr("class", "dot")
                .attr("r", 7)
                .attr("cx", xMap)
                .attr("cy", yMap)
                .style("fill", function(d) {
                   return color(d.category);//no need for if now
              ;})

Make legend like this

var legend = svg.selectAll(".legend")
     .data(["A", "B", "C", "D", "E"])//hard coding the labels as the datset may have or may not have but legend should be complete.
.enter().append("g")
     .attr("class", "legend")
     .attr("transform", function(d, i) { return "translate(0," + i * 20 + ")"; });

// draw legend colored rectangles
legend.append("rect")
     .attr("x", width - 18)
     .attr("width", 18)
     .attr("height", 18)
     .style("fill", function(d){return color(d)});

// draw legend text
legend.append("text")
     .attr("x", width - 24)
     .attr("y", 9)
     .attr("dy", ".35em")
     .style("text-anchor", "end")
     .text(function(d) { return d;});

Hope this helps!