d3noob
d3noob

Reputation: 2151

Looking for a better way to alter the color of axis components in d3.js v4

I want to change the colour of an axis for a simple d3.js (v4) graph. The y axis in the following image is an example of the finished product;

enter image description here

I suspect that the method I am using to achieve this a bit ugly and I believe that there should be an alternative per the description below that I do not yet understand.

The axis component is a combination of text, path and line elements which require alteration of their respective styles (stroke and fill).

At this point the only method I have found to change the colour of the components is by individually setting styles in the <style> section of the code...

.axisRed line{
  stroke: red;
}

.axisRed path{
  stroke: red;
}

.axisRed text{
  fill: red;
}

...and applying that class to the y axis when appending it later in the JavaScript;

  svg.append("g")
      .attr("class", "axisRed")
      .call(d3.axisLeft(y));

Is there a way that I can apply these styles via .style("<some style>", "<some value>") lines while appending the y axis rather than declaring in the <style> section?

An example with code is here.

I have tried trying to address the individual DOM components such as the 'domain' class, but without success. I suspect that I do not understand the hierarchy of the axis component well enough.

Upvotes: 10

Views: 26501

Answers (6)

Klaujesi
Klaujesi

Reputation: 1836

In D3 you have several options to style the elements:

Option A: Using style tag with self-assigned class:

<style>
.axisRed line,
.axisRed path {
  stroke: red;
}
.axisRed text
{
  fill: red;
}
</style>

// assign that class to the y axis
svg.append("g")
  .attr("class", "axisRed")
  .call(d3.axisLeft(y));

Option B: Using style tag with the classes auto-generated by D3:

The axis line is a <path> element with class domain. The ticks are inside a group <g> with class tick, consisting of a <line> element for the tick line and a <text> element for the tick label:

<style>
path.domain,
.tick line {
  stroke: red;
}
.tick text {
  fill: red;
}
</style>

svg.append("g").call(d3.axisLeft(y));

// HTML code generated by D3 (example):
<path class="domain" stroke="currentColor" d="M-6,450.5H0.5V0.5H-6"></path>
<g class="tick" opacity="1" transform="translate(0,414)">
  <line stroke="currentColor" x2="-6" y1="0.5" y2="0.5"></line>
  <text fill="currentColor" x="-9" y="0.5" dy=".32em">50</text>
</g>

Option C: Inline at appending time

In D3 V3 you could do a more compact:

svg.append("line")
   .style({
      fill: "none",
      stroke: "#f00",
      "stroke-width": "10"
    });

But in D3 V4, it doesn't work anymore. So I opened an 'Issue': you can check and follow the progress here: https://github.com/d3/d3-selection/issues/82

** UPDATE ** In V4 you must include selection-multi:

<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://d3js.org/d3-selection-multi.v0.4.min.js"></script>

and then use: styles instead of style and attrs instead attr:

svg.append("line")
   .styles({
      fill:"none",
      stroke:"#f00",
      "stroke-width":"10"
    })

for your example:

svg.selectAll(".domain")
   .styles({ fill:"none", stroke:"#f00",  "stroke-width":"1" });

Now you got a compact way to style your elements.

Extra: you could style and attr any element:

 var svg = d3.select("body").append("svg")
        .attrs({width:600, height:600})
        .styles({
            border:"1px",
            "border-style":"solid",
            "border-color":"#f00"})

Here's the plunker

Upvotes: 18

Robin-Hoodie
Robin-Hoodie

Reputation: 4974

Slightly late to the party but (at least in [email protected]), the stroke of the axis, ticks and tick lines are set to currentColor. This means you can set color on the wrapping g element to anything you like, and the axis, ticks and tick lines will inherit that color.

E.g.

  svg.append("g")
      .style("color", "red")
      .call(d3.axisLeft(y))

Upvotes: 0

Jerry Chong
Jerry Chong

Reputation: 9220

If you are using D3.js V5 with DC.js, then use the following code:

chart.on('pretransition', (chart) => {
    const svg = chart.select('svg');
    svg.selectAll("line").style("stroke", "purple");
    svg.selectAll("path").style("stroke", "green");
    svg.selectAll("text").style("stroke", "blue");
});

Upvotes: 2

Shibin Raju Mathew
Shibin Raju Mathew

Reputation: 930

For v5 you can use below code, Select domain and define stroke for which axis you need and append to svg.

 yAxis = (g) =>
          g
            .attr("transform", `translate(${50} ${0})`)
            .call((g) =>
              g
                .selectAll(".domain")
                .attr("stroke-width", 0.3)
                .attr("stroke", d3.schemePaired[7])
            );

  svg.append("g").call(yAxis);
      

Upvotes: 3

Rohit Rane
Rohit Rane

Reputation: 2930

How about some thing like this incase you don't want to use style tag:

 svg.append("g")
      .attr("class", "axisRed") // don't need this anymore but just re-suing your code
      .call(d3.axisLeft(y))
      .select("path")
      .attr("stroke","red")

Upvotes: 0

Mark
Mark

Reputation: 108522

To style them inline, just keep a reference to the added axis and select the components:

  // Add the Y Axis
  var axis = svg.append("g")
    .call(d3.axisLeft(y));

  axis.selectAll("line")
    .style("stroke", "purple");

  axis.selectAll("path")
    .style("stroke", "green");

  axis.selectAll("text")
    .style("stroke", "blue");

Full example:

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

<body>

  <!-- load the d3.js library -->
  <script src="https://d3js.org/d3.v4.min.js"></script>
  <script>
    // set the dimensions and margins of the graph
    var margin = {
        top: 20,
        right: 20,
        bottom: 30,
        left: 50
      },
      width = 960 - margin.left - margin.right,
      height = 500 - margin.top - margin.bottom;

    // parse the date / time
    var parseTime = d3.timeParse("%d-%b-%y");

    // set the ranges
    var x = d3.scaleTime().range([0, width]);
    var y = d3.scaleLinear().range([height, 0]);

    // define the line
    var valueline = d3.line()
      .x(function(d) {
        return x(d.date);
      })
      .y(function(d) {
        return y(d.close);
      });

    // append the svg obgect to the body of the page
    // appends a 'group' element to 'svg'
    // moves the 'group' element to the top left margin
    var svg = d3.select("body").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
      .append("g")
      .attr("transform",
        "translate(" + margin.left + "," + margin.top + ")");

    var data = [{
      "date": "1-May-12",
      "close": "58.13"
    }, {
      "date": "30-Apr-12",
      "close": "53.98"
    }, {
      "date": "27-Apr-12",
      "close": "67.00"
    }, {
      "date": "26-Apr-12",
      "close": "89.70"
    }, {
      "date": "25-Apr-12",
      "close": "99.00"
    }, {
      "date": "24-Apr-12",
      "close": "130.28"
    }, {
      "date": "23-Apr-12",
      "close": "166.70"
    }, {
      "date": "20-Apr-12",
      "close": "234.98"
    }, {
      "date": "19-Apr-12",
      "close": "345.44"
    }, {
      "date": "18-Apr-12",
      "close": "443.34"
    }, {
      "date": "17-Apr-12",
      "close": "543.70"
    }, {
      "date": "16-Apr-12",
      "close": "580.13"
    }, {
      "date": "13-Apr-12",
      "close": "605.23"
    }, {
      "date": "12-Apr-12",
      "close": "622.77"
    }, {
      "date": "11-Apr-12",
      "close": "626.20"
    }, {
      "date": "10-Apr-12",
      "close": "628.44"
    }, {
      "date": "9-Apr-12",
      "close": "636.23"
    }, {
      "date": "5-Apr-12",
      "close": "633.68"
    }, {
      "date": "4-Apr-12",
      "close": "624.31"
    }, {
      "date": "3-Apr-12",
      "close": "629.32"
    }, {
      "date": "2-Apr-12",
      "close": "618.63"
    }, {
      "date": "30-Mar-12",
      "close": "599.55"
    }, {
      "date": "29-Mar-12",
      "close": "609.86"
    }, {
      "date": "28-Mar-12",
      "close": "617.62"
    }, {
      "date": "27-Mar-12",
      "close": "614.48"
    }, {
      "date": "26-Mar-12",
      "close": "606.98"
    }];

    // format the data
    data.forEach(function(d) {
      d.date = parseTime(d.date);
      d.close = +d.close;
    });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) {
      return d.date;
    }));
    y.domain([0, d3.max(data, function(d) {
      return d.close;
    })]);

    // Add the valueline path.
    svg.append("path")
      .data([data])
      .attr("class", "line")
      .attr("d", valueline)
      .style("fill", "none")
      .style("stroke", "steelblue");

    // Add the X Axis
    svg.append("g")
      .attr("transform", "translate(0," + height + ")")
      .call(d3.axisBottom(x));

    // Add the Y Axis
    var axis = svg.append("g")
      .call(d3.axisLeft(y));

    axis.selectAll("line")
      .style("stroke", "purple")

    axis.selectAll("path")
      .style("stroke", "green")

    axis.selectAll("text")
      .style("stroke", "blue")
  </script>
</body>

Upvotes: 15

Related Questions