sveti petar
sveti petar

Reputation: 3797

Remove outline along the axes in d3.js area chart

I've created an area chart with a white fill and red outline:

enter image description here

It works fine, but I would like to get rid of the red outline along the X and Y axes and just leave the outline that represents the actual data. So in the screenshot above I'd like to remove the red lines that track vertically and horizontally along the axes.

My current code:

x.domain(d3.extent(data, function(d) { return d.date; }));
if(full){
    y.domain([0, 1.1*d3.max(data, function(d) { return d.value; })]);
    area.y0(y(0));
} else {
    y.domain([0.98*d3.min(data, function(d) { return d.value; }), 1.02*d3.max(data, function(d) { return d.value; })]);
    area.y0(y(0.98*d3.min(data, function(d) { return d.value; })));
}

g.append("path")
        .datum(data)
        .attr("fill", "#fff")
        .attr("stroke", "#fa0d18")
        .attr("d", area);

g.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x).tickFormat(d3.timeFormat("%m/%d")))
    .selectAll("text")
        .style("text-anchor", "end")
        .attr("dx", "-.8em")
        .attr("dy", ".15em")
        .attr("transform", "rotate(-65)");

g.append("g")
    .call(d3.axisLeft(y))
    .append("text")
    .attr("fill", "#000")
    .attr("transform", "rotate(-90)")
    .attr("y", 6)
    .attr("dy", "0.71em")
    .attr("text-anchor", "end")
    .text("Price ($)");

Is this possible and how?

P.S. Please disregard the grey vertical line in the middle of the screen, it's not relevant here.

Upvotes: 2

Views: 1677

Answers (2)

Mikhail Shabrikov
Mikhail Shabrikov

Reputation: 8509

Currently the red line it is a result of stroke attribute here (you can remove this attribute and see that red line is disappear):

g.append("path")
        .datum(data)
        .attr("fill", "#fff")
        .attr("stroke", "#fa0d18") // <== !!!
        .attr("d", area);

I imitate your problem using this blocks as basis. See hidden snippet below:

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

// 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 area
var area = d3.area()
    .x(function(d) { return x(d.date); })
    .y0(height)
    .y1(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 + ")");

const data = d3.csvParse(dataAsCSV);

// 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 area
  svg.append("path")
     .data([data])
     .attr("class", "area")
     .attr("stroke", "#fa0d18")
     .attr("d", area);

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

// add the Y Axis
svg.append("g")
    .call(d3.axisLeft(y));
.area {
  fill: lightsteelblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>

To draw the red line that represents the actual data you have to make three steps (you have another dataset, so you should use appropriate properties names - value, date as I can see from your code):

1) Remove stroke attribute.

2) Specify the function for line drawing this way:

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

3) And draw the line:

  svg.append("path")
      .data([data])
      .attr('fill', 'none')
      .attr('stroke', '#fa0d18')
      .attr("class", "line")
      .attr("d", valueline);

See result in the hidden demo below:

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

// 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 area
var area = d3.area()
    .x(function(d) { return x(d.date); })
    .y0(height)
    .y1(function(d) { return y(d.close); });
    
// 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 + ")");

const data = d3.csvParse(dataAsCSV);

// 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 area
  svg.append("path")
     .data([data])
     .attr("class", "area")
     .attr("d", area);

  // add the valueline path.
  svg.append("path")
      .data([data])
      .attr('stroke', '#fa0d18')
      .attr('fill', 'none')
      .attr("class", "line")
      .attr("d", valueline);
      
// add the X Axis
svg.append("g")
    .attr("transform", "translate(0," + height + ")")
    .call(d3.axisBottom(x));

// add the Y Axis
svg.append("g")
    .call(d3.axisLeft(y));
.area {
  fill: lightsteelblue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.js"></script>

Upvotes: 3

Komalpreet Singh
Komalpreet Singh

Reputation: 165

You can limit which points are displayed using defined

Every sample gets passed through the function and where it returns false, the points aren't shown...

var line = d3.line()
    .defined(function(d) { 
       return d.x < xMax && dx > xMin && d.y > yMin && d.y< yMax; 
    })
    .x(function(d) { return x(d.x); })
    .y(function(d) { return y(d.y); });

Alternatively, you can use a clip-path like in this example.

https://bl.ocks.org/mbostock/4015254

Upvotes: 0

Related Questions