If cell colored then circle colored the same

40 views
Skip to first unread message

Alexis Grizard

unread,
Apr 5, 2017, 11:27:40 AM4/5/17
to d3-js
Hello,

Would someone have an idea on how to color the circle on my tidy tree chart regarding on the color of cells in the .csv file.

It is the last step of my project so a hint on that would very much appreciated.

Thanks







<!DOCTYPE html>
<meta charset="utf-8">
<style>

.node circle {
  fill: #999;
}

.node text {
  font: 8px sans-serif;
}

.node--internal circle {
  fill: #555;
}

.node--internal text {
  text-shadow: 0 1px 0 #fff, 0 -1px 0 #fff, 1px 0 0 #fff, -1px 0 0 #fff;
}

.link {
  fill: none;
  stroke: #555;
  stroke-opacity: 0.4;
  stroke-width: 1.5px;
}

</style>
<svg width="960" height="2000"></svg>
<script src="file://C:/jim/d3.v4.min.js"></script>




<script>

var svg = d3.select("svg"),
    width = +svg.attr("width"),
    height = +svg.attr("height"),
    g = svg.append("g").attr("transform", "translate(40,0)");

var tree = d3.tree()
    .size([height, width - 160]);

var stratify = d3.stratify()
    .parentId(function(d) { return d.id.substring(0, d.id.lastIndexOf(".")); });

d3.csv("flare.csv", function(error, data) {
  if (error) throw error;

  var root = stratify(data)
      .sort(function(a, b) { return (a.height - b.height) || a.id.localeCompare(b.id); });

  var link = g.selectAll(".link")
    .data(tree(root).descendants().slice(1))
    .enter().append("path")
      .attr("class", "link")
      .attr("d", function(d) {
        return "M" + d.y + "," + d.x
            + "C" + (d.y + d.parent.y) / 2 + "," + d.x
            + " " + (d.y + d.parent.y) / 2 + "," + d.parent.x
            + " " + d.parent.y + "," + d.parent.x;
      });

  var node = g.selectAll(".node")
    .data(root.descendants())
    .enter().append("g")
      .attr("class", function(d) { return "node" + (d.children ? " node--internal" : " node--leaf"); })
      .attr("transform", function(d) { return "translate(" + d.y + "," + d.x + ")"; })

  node.append("circle")
      .attr("r", 2.5);

  node.append("text")
      .attr("dy", 3)
      .attr("x", function(d) { return d.children ? -8 : 8; })
      .style("text-anchor", function(d) { return d.children ? "end" : "start"; })
      .text(function(d) { return d.id.substring(d.id.lastIndexOf(".") + 1); });
});

</script>

steve rickus

unread,
Apr 5, 2017, 3:14:01 PM4/5/17
to d3-js
CSV files are plain text, and do not contain any Excel "properties" like cell color/height/width or font size/color. So if you want to use those properties in your rendering, you will need to find another way to export the spreadsheet that includes those properties as data you can reference.

I have not tried it in a while, but there used to be options for exporting XML (or better yet, JSON). Good luck.

steve rickus

unread,
Apr 5, 2017, 3:18:26 PM4/5/17
to d3-js
Unless, of course, the colors can be derived from the cell value itself? Say, negative numbers in red, or greying out empty cells, for instance. These are easy to accomplish with D3 -- extend your class setting function to include classes based on these "rules", and apply css styling as appropriate.

Alexis Grizard

unread,
Apr 6, 2017, 4:32:49 AM4/6/17
to d3-js
Hi Steve,

Thank you for your answer.

My CSV is organised as per bellow.


Column1                                 Column2 
(name)                                    (Value)
Peter                                        1                              -> Red circle
Peter.Alan                                 3                              -> Yellow circle    
Peter.Alan.James                      1                              -> Red circle
Peter.Alan.James.Paul               2                              -> Green circle
...

I have 800 different names for 7 different values.

I thought it was going to be easier to color the CSV cells first and then export the color to circles.
Apparently not.

Would you have any idea on how to translate for example "If Value = 3 then Alan circle is Yellow"?

Thanks again.

steve rickus

unread,
Apr 6, 2017, 9:00:06 AM4/6/17
to d3-js
So column 2 is a number from 1-7, and you want each number to have a specific color? That is very straightforward to do -- create an array of 8 color names (or hex values) and use the column value as the array index. Not tested, but something like this:

  var colors = ["grey", "red", "orange", "yellow", "green", "cyan", "blue", "purple"];


  node
.append("circle")
     
.attr("r", 2.5)

     
.attr("style", function(d) { return "color:" + colors[d.value]; });


There are other ways of course, using d3 color scales, or adding a class name instead of the style attribute and controlling the color with css. You may want to explore some of those possibilities after getting it working like this. You should also probably do some range checking of the value, so if the number is missing or not between 1-7 it uses 0. This has the added benefit of visually showing those with bad data.
--
Steve

Alexis Grizard

unread,
Apr 6, 2017, 9:51:34 AM4/6/17
to d3-js
Hi Steve,

Thank you for the quick answer.

I attached a picture of the CSV file to make it a bit clearer.
This is the real case with only 4 ranges/colors.

Column 1: Names 
Column2: Span of control

If a person control 0 person (value = 0) then his circle on the chart will be grey.
If a person control 1 to 3 persons (value = 1 to 3) then his circle on the chart will be yellow.
If a person control 3 to 10 persons (value = 3 to 10) then his circle on the chart will be orange.
If a person control 11 to 20 persons (value = 11 to 20) then his circle on the chart will be red.

In that case, Paul and Colin will have a yellow circle
Alan orange and Alex red.

I need to assign colors to values I suppose and then read the values.
Any idea on how to do that?

Thanks,
Alex
Capture.PNG

steve rickus

unread,
Apr 6, 2017, 11:00:43 AM4/6/17
to d3-js
Sure -- you just need a function that takes the span of control value in, and returns a color. How you write that function is up to you (switch statements, if-else ladder, array index lookup, etc). Then you can use the output of that function to set the style for each circle as I did in the previous post.

However, D3 already has these functions built-in, so for my own projects I would use the Threshold Scale object/functions. Set the input domain to [0, 3, 10] and the output range to ["grey", "yellow", "orange", "red"], et voila!

Alexis Grizard

unread,
Apr 6, 2017, 12:05:01 PM4/6/17
to d3...@googlegroups.com
Parfait! 

So if I give it a try, would something like this make sense?

Column 1/Name: Id
Column 2/Span of control: Sc

var color = d3.scaleThreshold()
    .domain([0, 1, 3, 10, 20])
    .range(["grey", "yellow", "orange", "red"]);

var ScById = {};

  circle.forEach(function(d) { ScById[d.id] = +d.Sc; });
  node.append("circle")
     .attr("r", 2.5)
  
     .style("fill", function(d) { return color(ScById[d.id]); });
I m really not sure on how to make the connection between the values and the names.
It might not be a lot of work but as I am new in D3 js it looks like it.

Thanks again


--
You received this message because you are subscribed to a topic in the Google Groups "d3-js" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/d3-js/Aw4wmUW-nVg/unsubscribe.
To unsubscribe from this group and all its topics, send an email to d3-js+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--

Project Engineer

Bilfinger HSG Facility Management Limited

Phone +353 1 215 7032

Mob +353 8 7655 12 34

alexis....@bilfinger.com

 

steve rickus

unread,
Apr 6, 2017, 1:41:12 PM4/6/17
to d3-js
It looks to me like you are over-thinking it...

The domain of the threshold scale lists the points where the colors change. The range lists the colors names to be returned, and should be a list with one more element than the domain. Any value < the first domain value gets the first color, and any value >= the last domain value get the last color:

var color = d3.scaleThreshold()
    .domain([1, 4, 11])
    .range(["grey", "yellow", "orange", "red"]);

color(-1);   // "grey"
color(0);    // "grey"
color(1);    // "yellow"
color(3);    // "yellow"
color(4);    // "orange"
color(10);   // "orange"
color(11);   // "red"
color(20);   // "red"
color(1000); // "red"

You don't need the empty object or forEach section in the middle. Just assign the output of the color() function to the style of the circle:

  node.append("circle")
      .attr("r", 2.5)
      .style("color", function(d) { return colors(d.Sc); });

I'll leave the rest of the testing/tweaking up to you...
Reply all
Reply to author
Forward
0 new messages