user8893965
user8893965

Reputation:

How to avoid hardcoding of colors in D3

I've taught myself d3 (still learning), and have a finished visualisation that I'm more than happy with.

But i think (know) that the code can be improved and made more efficient. For instance, use a csv file for the data (don't know where to begin with that). But more specifically, i'd like to know how the hard coded colours can be used directly with d3, but categorised by cancer, diabetes, CHD (exactly how i've hardcoded them). Additionally, rather than use the messy html and css i have for the titles, is there anything that can be done via d3?

I believe i'm pretty good with html and css, but i was a little daunted by d3 and the html/css are inherently mess.

I've attached an image of what it looks like (please ignore the data under South England: I know it's duplicated; I have to replace them with the actual data).

@import url("https://fonts.googleapis.com/css?family=Lato:300");

rect {
  stroke: white;
}
text {
  font-family: "Lato";
  fill: white;
  font-size: 8px;
  text-anchor: middle;
}

svg {
  padding-left: 60px;
  padding-top:17px;
  position: fixed;
}

p {
  font-size: 14px;
}

.p1 {
  position: absolute;
  font-family: "Lato";
  font-size: 17px;
  padding-left: 60px;
}

.p2 {
  position: absolute;
  font-family: "Lato";
  font-size: 17px;
  padding-left: 550px;
}

.p3 {
  position: absolute;
  font-family: "Lato";
  padding-left: 60px;
  padding-top: 35px;
}

.p4 {
  position: absolute;
  font-family: "Lato";
  padding-left: 230px;
  padding-top: 35px;
}

.p5 {
  position: absolute;
  font-family: "Lato";
  padding-left: 380px;
  padding-top: 35px;
}

.p6 {
  position: absolute;
  font-family: "Lato";
  padding-left: 60px;
  padding-top: 390px;
}

.p7 {
  position: absolute;
  font-family: "Lato";
  padding-left: 283px;
  padding-top: 390px;
}

.p8 {
  position: absolute;
  font-family: "Lato";
  padding-left: 553px;
  padding-top: 35px;
}

.p9 {
  position: absolute;
  font-family: "Lato";
  padding-left: 723px;
  padding-top: 35px;
}

.p10 {
  position: absolute;
  font-family: "Lato";
  padding-left: 896px;
  padding-top: 35px;
}

.p11 {
  position: absolute;
  font-family: "Lato";
  padding-left: 552px;
  padding-top: 380px;
}

.p12 {
  position: absolute;
  font-family: "Lato";
  padding-left: 810px;
  padding-top: 380px;
}

<!DOCTYPE html>
<meta charset="utf-8">
<head>
  <title>TreeMap</title>
  <link rel="stylesheet" type="text/css" href="stylesheet.css" />
</head>

<body>
  <svg width="1200" height="720">
    <g></g>
    <section class="container1">
      <p class="p1"> North England </p><p class="p2"> South England </p>
      <p class="p3"> Bradford City </p><p class="p4"> Leeds </p>
      <p class="p5"> Liverpool </p><p class="p6"> Manchester </p>
      <p class="p7"> Sheffield </p><p class="p8"> Brighton </p>
      <p class="p9"> Bristol </p><p class="p10"> Luton </p>
      <p class="p11"> Milton Keynes </p><p class="p12"> Southampton </p>
      <object class="Box" class="cancer"></object>
    </section>
  </svg>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.2.2/d3.min.js"></script>
  <script>
var data = {
  "name": "England",
  "children": [
    {
      "name": "North England",
      "children": [
        {
          "name": "Bradford City",
          "children": [
            {
              "name": "Cancer",
              "value": 1.18,
              "color": "#A8A7A7",
            },
            {
              "name": "CKD",
              "value": 3.21,
              "color": "#2F9599",
            },
            {
              "name": "CHD",
              "value": 2.57,
              "color": "#E8175D",
            },
            {
              "name": "Diabetes",
              "value": 11.92,
              "color": "#474747",
            },
            {
              "name": "Stroke",
              "value": 1.18,
              "color": "#CC527A",
            }
          ]
        },
        {
        "name": "Leeds",
        "children": [
          {
            "name": "Cancer",
            "value": 2.50,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 3.52,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 3.29,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 6.71,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.82,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Liverpool",
        "children": [
          {
            "name": "Cancer",
            "value": 2.50,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 5.90,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 3.71,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 6.70,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.88,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Manchester",
        "children": [
          {
            "name": "Cancer",
            "value": 1.78,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 2.95,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 2.61,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 7.05,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 2.13,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Sheffield",
        "children": [
          {
            "name": "Cancer",
            "value": 2.54,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 4.57,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 3.85,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 7.08,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 2.13,
            "color": "#CC527A",
          }
        ]
      },
    ]
  },
  {
    "name": "South England",
    "children": [
      {
        "name": "Brighton",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 3.21,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 2.57,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 11.92,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.18,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Bristol",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 3.21,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 2.57,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 11.92,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.18,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Luton",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 3.21,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 2.57,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 11.92,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.18,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Milton Keynes",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 3.21,
            "color":"#2F9599",
          },
          {
            "name": "CHD",
            "value": 2.57,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 11.92,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.18,
            "color": "#CC527A",
          }
        ]
      },
      {
        "name": "Southampton",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
            "color": "#A8A7A7",
          },
          {
            "name": "CKD",
            "value": 3.21,
            "color": "#2F9599",
          },
          {
            "name": "CHD",
            "value": 2.57,
            "color": "#E8175D",
          },
          {
            "name": "Diabetes",
            "value": 11.92,
            "color": "#474747",
          },
          {
            "name": "Stroke",
            "value": 1.18,
            "color": "#CC527A",
          }
        ]
      },
      ]
    }
  ]
};

var treemapLayout = d3.treemap()
  .size([1000, 600])
  .paddingTop(20)
  .paddingInner(8);

var rootNode = d3.hierarchy(data)

rootNode.sum(function(d) {
  return d.value;
});

treemapLayout(rootNode);

var nodes = d3.select('svg g')
  .selectAll('g')
  .data(rootNode.descendants())
  .enter()
  .append('g')
  .attr('transform', function(d) {return 'translate(' + [d.x0, d.y0] + ')'})

  nodes
    .append('rect')
    .attr('width', function(d) { return d.x1 - d.x0; })
    .attr('height', function(d) { return d.y1 - d.y0; })
    .attr('opacity', function(d) { return 0.8 /* has to be like d.value / max or so */ })
    .attr('fill', function(d) { if (d.data.color) {
                                  return d.data.color
                                } else {
                                  return "white"
                                }})
  nodes
    .append('text')
    .attr('dx', 10)
    .attr('dy', 8)
        .text(function(d) {
      return d.data.value;
  });


  </script>
</body>

enter image description here

Upvotes: 1

Views: 200

Answers (1)

Mikhail Shabrikov
Mikhail Shabrikov

Reputation: 8509

Normal way for d3 - it is a using ordinal color scale. You should associate names of disease with appropriate colors:

var namesOfDisease = ["Cancer", "CKD", "CHD", "Diabetes", "Stroke"];

var color = d3.scaleOrdinal()
  .domain(namesOfDisease)
  .range(["#A8A7A7", "#2F9599" , "#E8175D", "#474747", "#CC527A"]);

It returns appropriate color when you pass desease name as argument:

console.log(color("Cancer")) // ==> #A8A7A7
console.log(color("CHD")) // ==> #E8175D
console.log(color("Stroke")) // ==> #CC527A

And use this scale for color applying:

...
.attr('fill', function(d) {
    var result = null;

  if (namesOfDisease.indexOf(d.data.name) >= 0) {
    result = color(d.data.name);
  } else {
    result = 'white'
  }

  return result;
})
...

Check demo without hardcoded colors in the hidden snippet:

var data = {
  "name": "England",
  "children": [
    {
      "name": "North England",
      "children": [
        {
          "name": "Bradford City",
          "children": [
            {
              "name": "Cancer",
              "value": 1.18,
            },
            {
              "name": "CKD",
              "value": 3.21,
            },
            {
              "name": "CHD",
              "value": 2.57,
            },
            {
              "name": "Diabetes",
              "value": 11.92,
            },
            {
              "name": "Stroke",
              "value": 1.18,
            }
          ]
        },
        {
        "name": "Leeds",
        "children": [
          {
            "name": "Cancer",
            "value": 2.50,
          },
          {
            "name": "CKD",
            "value": 3.52,
          },
          {
            "name": "CHD",
            "value": 3.29,
          },
          {
            "name": "Diabetes",
            "value": 6.71,
          },
          {
            "name": "Stroke",
            "value": 1.82,
          }
        ]
      },
      {
        "name": "Liverpool",
        "children": [
          {
            "name": "Cancer",
            "value": 2.50,
          },
          {
            "name": "CKD",
            "value": 5.90,
          },
          {
            "name": "CHD",
            "value": 3.71,
          },
          {
            "name": "Diabetes",
            "value": 6.70,
          },
          {
            "name": "Stroke",
            "value": 1.88,
          }
        ]
      },
      {
        "name": "Manchester",
        "children": [
          {
            "name": "Cancer",
            "value": 1.78,
          },
          {
            "name": "CKD",
            "value": 2.95,
          },
          {
            "name": "CHD",
            "value": 2.61,
          },
          {
            "name": "Diabetes",
            "value": 7.05,
          },
          {
            "name": "Stroke",
            "value": 2.13,
          }
        ]
      },
      {
        "name": "Sheffield",
        "children": [
          {
            "name": "Cancer",
            "value": 2.54,
          },
          {
            "name": "CKD",
            "value": 4.57,
          },
          {
            "name": "CHD",
            "value": 3.85,
          },
          {
            "name": "Diabetes",
            "value": 7.08,
          },
          {
            "name": "Stroke",
            "value": 2.13,
          }
        ]
      },
    ]
  },
  {
    "name": "South England",
    "children": [
      {
        "name": "Brighton",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
          },
          {
            "name": "CKD",
            "value": 3.21,
          },
          {
            "name": "CHD",
            "value": 2.57,
          },
          {
            "name": "Diabetes",
            "value": 11.92,
          },
          {
            "name": "Stroke",
            "value": 1.18,
          }
        ]
      },
      {
        "name": "Bristol",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
          },
          {
            "name": "CKD",
            "value": 3.21,
          },
          {
            "name": "CHD",
            "value": 2.57,
          },
          {
            "name": "Diabetes",
            "value": 11.92,
          },
          {
            "name": "Stroke",
            "value": 1.18,
          }
        ]
      },
      {
        "name": "Luton",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
          },
          {
            "name": "CKD",
            "value": 3.21,
          },
          {
            "name": "CHD",
            "value": 2.57,
          },
          {
            "name": "Diabetes",
            "value": 11.92,
          },
          {
            "name": "Stroke",
            "value": 1.18,
          }
        ]
      },
      {
        "name": "Milton Keynes",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
          },
          {
            "name": "CKD",
            "value": 3.21,
          },
          {
            "name": "CHD",
            "value": 2.57,
          },
          {
            "name": "Diabetes",
            "value": 11.92,
          },
          {
            "name": "Stroke",
            "value": 1.18,
          }
        ]
      },
      {
        "name": "Southampton",
        "children": [
          {
            "name": "Cancer",
            "value": 1.18,
          },
          {
            "name": "CKD",
            "value": 3.21,
          },
          {
            "name": "CHD",
            "value": 2.57,
          },
          {
            "name": "Diabetes",
            "value": 11.92,
          },
          {
            "name": "Stroke",
            "value": 1.18,
          }
        ]
      },
      ]
    }
  ]
};

var treemapLayout = d3.treemap()
  .size([1000, 600])
  .paddingTop(20)
  .paddingInner(8);

var rootNode = d3.hierarchy(data)

rootNode.sum(function(d) {
  return d.value;
});

treemapLayout(rootNode);

var namesOfDisease = ["Cancer", "CKD", "CHD", "Diabetes", "Stroke"];

var color = d3.scaleOrdinal()
  .domain(namesOfDisease)
  .range(["#A8A7A7", "#2F9599" , "#E8175D", "#474747", "#CC527A"]);

var nodes = d3.select('svg g')
  .selectAll('g')
  .data(rootNode.descendants())
  .enter()
  .append('g')
  .attr('transform', function(d) {return 'translate(' + [d.x0, d.y0] + ')'})

  nodes
    .append('rect')
    .attr('width', function(d) { return d.x1 - d.x0; })
    .attr('height', function(d) { return d.y1 - d.y0; })
    .attr('opacity', function(d) { return 0.8 /* has to be like d.value / max or so */ })
    .attr('fill', function(d) {
    	var result = null;
      
      if (namesOfDisease.indexOf(d.data.name) >= 0) {
      	result = color(d.data.name);
      } else {
      	result = 'white'
      }
      
      return result;
    })
  nodes
    .append('text')
    .attr('dx', 10)
    .attr('dy', 8)
        .text(function(d) {
      return d.data.value;
  });
rect {
  stroke: white;
}
text {
  font-family: "Lato";
  fill: white;
  font-size: 8px;
  text-anchor: middle;
}

svg {
  padding-left: 60px;
  padding-top:17px;
  position: fixed;
}

p {
  font-size: 14px;
}

.p1 {
  position: absolute;
  font-family: "Lato";
  font-size: 17px;
  padding-left: 60px;
}

.p2 {
  position: absolute;
  font-family: "Lato";
  font-size: 17px;
  padding-left: 550px;
}

.p3 {
  position: absolute;
  font-family: "Lato";
  padding-left: 60px;
  padding-top: 35px;
}

.p4 {
  position: absolute;
  font-family: "Lato";
  padding-left: 230px;
  padding-top: 35px;
}

.p5 {
  position: absolute;
  font-family: "Lato";
  padding-left: 380px;
  padding-top: 35px;
}

.p6 {
  position: absolute;
  font-family: "Lato";
  padding-left: 60px;
  padding-top: 390px;
}

.p7 {
  position: absolute;
  font-family: "Lato";
  padding-left: 283px;
  padding-top: 390px;
}

.p8 {
  position: absolute;
  font-family: "Lato";
  padding-left: 553px;
  padding-top: 35px;
}

.p9 {
  position: absolute;
  font-family: "Lato";
  padding-left: 723px;
  padding-top: 35px;
}

.p10 {
  position: absolute;
  font-family: "Lato";
  padding-left: 896px;
  padding-top: 35px;
}

.p11 {
  position: absolute;
  font-family: "Lato";
  padding-left: 552px;
  padding-top: 380px;
}

.p12 {
  position: absolute;
  font-family: "Lato";
  padding-left: 810px;
  padding-top: 380px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>
<svg width="1200" height="720">
    <g></g>
    <section class="container1">
      <p class="p1"> North England </p><p class="p2"> South England </p>
      <p class="p3"> Bradford City </p><p class="p4"> Leeds </p>
      <p class="p5"> Liverpool </p><p class="p6"> Manchester </p>
      <p class="p7"> Sheffield </p><p class="p8"> Brighton </p>
      <p class="p9"> Bristol </p><p class="p10"> Luton </p>
      <p class="p11"> Milton Keynes </p><p class="p12"> Southampton </p>
      <object class="Box" class="cancer"></object>
    </section>
  </svg>

Upvotes: 1

Related Questions