Add y-axis gridlines to D3 Gantt chart - javascript

What's the best way of adding horizontal gridlines to a d3 gantt chart like in this example? I was originally thinking of making an axis and making the tick marks the length of the chart (as in this example), but this puts them directly in the middle of the chart rectangles.
Is it possible to make the axis ticks into "lanes" around the rectangles, or would it just be easier to plot lines (as done here)?

A solution comes from this issue post on GitHub. Basically just translate the axis group by half the width of the band:
var yScale = d3.scaleBand()
.domain(lanes)
.rangeRound([0, chartHeight], 0.1);
var yGridAxis = d3.axisLeft()
.scale(yScale)
.tickFormat('')
.tickSize(-chartWidth);
chart.append('g')
.attr('class', 'grid')
.attr('transform', function(d) {
return 'translate(0,' + (-yScale.bandwidth()/2) + ')';
})
.call(yGridAxis);

Related

D3 Scatter Plot Not Implementing Zoom Interaction Properly

I am a novice at D3 and I was trying to implement zoom/pan functionality on my scatter plot. Unfortunately, after following a tutorial, whenever I zoom on the visualization, the axes ticks disappear but the visualization doesn't readjust. Could someone explain what I'm doing wrong?
//Adding zoom and pan interaction to visualization
var zoom = d3.zoom()
.scaleExtent([.5, 20])
.extent([0, 0], [width, height])
.on("zoom", zoomed);
// This add an invisible rect on top of the chart area. This rect can recover pointer events: necessary to understand when the user zoom
svg.append("rect")
.attr("width", width)
.attr("height", height)
.style("fill", "none")
.style("pointer-events", "all")
.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')')
.call(zoom);
function zoomed(){
// recover the new scale
var newX = d3.event.transform.rescaleX(xScale);
var newY = d3.event.transform.rescaleY(yScale);
// update axes with these new boundaries
xAxis.call(d3.axisBottom(newX))
yAxis.call(d3.axisLeft(newY))
//update positions
dotGraph.selectAll("circle")
.attr("cx", d => newX(d.installs))
.attr("cy", d => newY(d.reviews));
}
The full code is located here: https://jsfiddle.net/wkLr7hob/
Thanks.
If you comment out the extent portion of your code you'll see the zoom working as expected¹, minus the enforcement of an extent.
You're not providing a valid extent to zoom.extent(), you pass two arrays:
.extent([0, 0], [width, height])
Instead of one [[0,0],[width,height]],
But this still doesn't fix the extent of the zoom behavior, I believe you are looking for translateExtent which limits the panning extent of the chart - however, if we use [[0,0],[width,height]], zooming out to 0.5 is not possible: the extent shown would be greater than the translate extent. So we might as well set the minimum scale to 1.
Doing that we get this.
¹ Also, in the zoom function, you're selecting all circles in dotGraph, but dotGraph is a selection of circles already - so we can drop the selectAll("circle") method in the zoom function. Otherwise the circles won't update.

Brush functionality in my d3 line chart is not working as expected

My implementation for Brush & Zoom functionality in my d3 line chart is not working as expected,
I followed this link - https://bl.ocks.org/EfratVil/92f894ac0ba265192411e73f633a3e2f,
Problems what I am facing is -
chart is not showing all the values, I have 4 data but it only shows 3 data
onClick of dot I am showing the rect which is not moving with the brush functionality
minor thing but chart always goes out of the box
My code sandbox - https://codesandbox.io/s/proud-firefly-xy1py
Can someone point out what I am doing wrong? thanks.
Please suggest me what I am doing wrong, thanks.
Your first point is going behind your clip area. For example, if you right click on the first visible circle and inspect element you will see all 4 circle elements are present in the dom. The first circle element is behind the axis.
This means you have to move your plot to the right. Unfortunately, the way you have coded the chart you have not appended a g element for the main chart and then appended the circles and path to that g element. As a result this has to be done in multiple places.
First we adjust your clip path as:
svg
.append("defs")
.append("SVG:clipPath")
.attr("id", "clip")
.append("SVG:rect")
.attr("width", containerWidth)
.attr("height", height)
.attr("x", 40)
.attr("y", 0);
next we adjust your circles
scatter
.selectAll(".foo")
.data(data)
.enter()
.append("circle")
.attr("class", "foo")
.attr("transform", "translate(40,0)")
and then your line
scatter
.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line)
.attr("transform", "translate(40,0)");
You will have to account for this 40 px translate for your other elements as well. Although I am having a hard time destructuring your svg. I think this should give you the idea though. Check the axis matches the time points as well.
Check the code sand box
Update
To make the rectangles move with the brush, you will have to add code to your brushed const function to recalculate the x, y, width and height using the updated scales.
Update2
After going through the codesandbox presented in the comments I was able to add the code to update the rectangles to the brushed const as below to make the rects also move with the brushing:
// update rectangles
scatter
.selectAll(".rect-elements")
.attr("x", d => {
console.log(d);
return xScale(d.startTime) - 12.5;
})
.attr("y", 0)
.attr("width", 24)
.attr("height", height + 5);
Full working Code Sandbox.

Scale / Redraw d3.js gridlines on zoom / drag

I just started using d3.js yesterday and i have some trouble getting my stuff done.
For now I created a chart with two y axes, each showing some values and an x axis showing dates.
On click on the values on the y axes, I display the corresponding horizontal grid lines.
My problem is, that when zooming in or out, or dragging, the gridlines (horizontal and vertical) don't scale correctly with the axes values, they just don't move at all.
I searched a lot this afternoon and found some examples how to do it, but none of them seem to work with the code i already have.
I presume, that the logic should be added to the zoom behavior but i'm not sure
// x axis gridlines
function make_x_gridlines() {
return d3.axisBottom(x)
.ticks(5)
}
// add the X gridlines
let xGrid = svg.append("g")
.attr('class', 'grid')
.attr("id", "grid")
.attr("transform", "translate(0," + height + ")")
.call(make_x_gridlines()
.tickSize(-height)
.tickFormat("")
)
//zoom behavior
function zoomed() {
.. some behavior ..
//redraw gridlines here?
.. some behavior ..
}
Please see this fiddle for the whole thing.
I called the second y axis (right) zAxis even if it's not a z axis.
Help would really be greatly appreciated.
The axes are working when you zoom. That's because, in the function zoomed() you are updating the scales.
So in order to make the grids zoom, you just need to update its scales too. Put this code inside the function zoomed() and it should work.
xGrid.call(
d3.axisBottom(x)
.scale(d3.event.transform.rescaleX(x))
.ticks(5)
.tickSize(-height)
.tickFormat("")
)
Now you just need to replicate this scale update to all other grids. Sorry that I couldn't give you a complete answer, but I don't have much time right now.
Now, in my opinion, you should not have the function make_gridlines() because it is really simple, and when you're working on lots of updates on different places it confuses me.
So, instead of calling make_gridlines() you call d3.axisBottom(x).ticks(5).
(Note that I'm new to d3 and js, so I'm recommending this based on my little experience and knowledge)

add y axis label to NVD3 Multi-Bar Chart

I'm trying to add axis labels to a NVD3 Multi-Bar Chart, but it only seems to work for the x axis. Is there any way around this?
I have set up an example here: http://jsfiddle.net/msts1jha/2/
var chart = nv.models.multiBarChart();
chart.xAxis
.tickFormat(d3.format(',f'));
chart.yAxis
.tickFormat(d3.format(',.1f'));
chart.xAxis.axisLabel("x axis");
chart.yAxis.axisLabel("y axis");
Your yAxis is hidden, set the left margin on your chart, and it will work.
Try this :
var chart = nv.models.multiBarChart().margin({left: 100});
More info regarding margins have a look here
Hope it helps

d3.js: show only part of data on xAxis

I'm using a linear scale chart with zoom/pan functionality to display a large dataset (500+ points). Here's the code I use to construct the x-scale:
x = d3.scale.linear()
.domain([0, data.length-1])
.range([0, w]);
This way all data is squeezed into the chart making it impossible to view the details like in the top part of the image:
I'd like to display the data similar to the bottom chart (and let the user scroll to see more of the data using the pan functionality).
One way to do this is to manipulate the domain of the X scale such that it maps the zoom boundaries to be the min/max domain values that map to the 0-width values of the range. You can then use a clip path to clip/hide that parts of the plot that are drawn outside of the X scale range.
It might make more sense with a jsFiddle example: http://jsfiddle.net/reblace/8TmM9/
In this example, there are 10 squares that are always being drawn. You can inspect the dom to see what I'm talking about. But, there is a clip path that is only wide enough for you to see 4 of them at a time. The X scale maps the input values of 0-9 to the output coordinates. The range is set as 0 to the width required to draw all 10 of the squares, and the domain is set as [0, 9].
var xScale = d3.scale.linear()
.domain(d3.extent(data))
.range([0, width]);
...
var svg = d3.select('#chart').append('svg')
.attr('width', clipWidth)
.attr('height', clipHeight);
svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", clipWidth)
.attr("height", clipHeight);
...
var g = svg.append("g");
g.selectAll("rect")
.data(data).enter().append('rect')
.attr("class", "area").attr("clip-path", "url(#clip)")
.attr('x', xScale)
.attr('width', rectWidth)
.attr('height', rectHeight)
.style('fill', d3.scale.category20());
Initially, this will draw the first four rectangles in the visible pane. By manipulating the domain so that it is instead [1,10] or [2,11] or even [-1, 8], we can effectively shift the drawn elements left and right so that a different span of the plot is drawn in the visible area.
// Pan Left
xScale.domain([xScale.domain()[0] - 1, xScale.domain()[1] - 1]);
// Pan Right
xScale.domain([xScale.domain()[0] + 1, xScale.domain()[1] + 1]);
This technique is identical whether you are doing it with squares or plots.
Mike Bostock has an example that does this with plots in the manner you are attempting here as well: Focus+Context http://bl.ocks.org/mbostock/1667367

Categories

Resources