Question

I would like to add a marker for a specific date for a date axis. Please see the line chart below.

My xAxis is drawn by this function, where dateMin and dateMax can be set by the user through the front end (or a brush, etc.).

d3.time.scale.utc().domain([dateMin,dateMax]);

This means the tickValues are calculated automatically.

Now, there is a certain fixed date for our data where there is a cutoff. For example, we may have consolidated figures up to Jan. 31st 2014, and then projected data from February 1st 2014 onwards.

What I need to do is make it visually clear at what date the cutoff point is. I have manually drawn a red vertical line at the date into the JPG below. But how do I do this programatically with d3?

One caveat is that the user might choose a date range (using the brush, etc.) which does not include the cutoff date (say, Jan 1st 2014 to Jan 20th, 2014). In this case, no line should be drawn.

If possible, it would be even better if the actual lines of the line chart would look different from the cutoff date onwards. They could be dotted instead of solid, or their colours could be less saturated (.brighter ?), to make visually clear that the underlying data is not consolidated yet.

Thanks for any hints you can give me.

Sorry I can't post images to StackOverflow yet, hence I uploaded the example here:

Trying out code from the answers

Using the code below, the line and label get drawn, but not at the given x value (cutoffDate), but too "early" on the time scale, approximately on the evening of 2014-01-29.

        var cutoffDate = new Date("2014-02-01T00:00:00Z");

        seriesChart.svg().append("svg:line")
                .attr("x1", xScale(cutoffDate))
                .attr("x2", xScale(cutoffDate))
                .attr("y1", yScale.range()[1])
                .attr("y2", yScale.range()[0])
                .style("stroke", "rgb(225,0,0)")
                .style("stroke-width", "1");

        seriesChart.svg()
                .append("text")
                .attr("text-anchor", "start")
                .attr("x", xScale(cutoffDate))
                .attr("y", 80)
                .text("Projected data");

See the result here: http://i.imgur.com/0PXKFup.jpg

In my original question, I didn't mention I am using seriesChart from dc.js: seriesChart API docs I suppose this does something with the xScale when it composes the seriesChart so setting a value on the xScale later on will result in a shifted display. Will investigate further.

Update: x position fixed

The correct way to append svg elements to a dc.js chart is not to use

chart.svg().append()

but

chart.chartBodyG().append()

This fixes the position offset for custom elements added to the chart. Using this in combination with Lars' answer works.

Was it helpful?

Solution

This would be difficult to achieve with one axis, but easy with separate axes. First, for the dividing line, you can use code like this:

svg.append("line")
   .attr("x1", xScale(cutoffDate))
   .attr("x2", xScale(cutoffDate))
   .attr("y1", yScale.range()[0])
   .attr("y2", yScale.range()[1]);
svg.append("text").attr("x", xScale(cutoffDate) + 10).attr("y", yCoord)
   .text("projected");

To have different styles, use two different axes:

var xScale1 = d3.time.scale().domain([..., cutoffDate]).range([0, 100]),
    xScale2 = d3.time.scale().domain([cutoffDate, ...]).range([100, 200]);
svg.append("g").attr("class", "before")
    .call(d3.svg.axis().scale(xScale1));
svg.append("g").attr("class", "after")
   .attr("transform", "translate(" + xScale1.range()[1] + ",0)")
   .call(d3.svg.axis().scale(xScale2));

Once appended, you can style the axes using the classes or by selecting the individual DOM elements. This means you end up with two scales -- to make using them for computing coordinates easier, you could wrap them:

var xScale = function(x) { return x < cutoffDate ? xScale1(x) : xScale2(x); };

The exact best way to implement this will depend on your specific application, but the above should give you a rough guide how to do it.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top