So here's the scenario:
I set xAxis: axisLeft().tickSize(-width), same for the yAxis, this makes a grid out of axis:
Is it possible to make a grid out of tick lines and at the same time make them point at tick values like this?
(in this example I set manualy x1 value to the tick line).
You cannot have both the ticks going inside and outside using tickSize. A positive value will make the ticks grow outside, and a negative value will make the ticks grow inside the plotting area.
But there are different ways to have both inside and outside ticks. My favourite one is creating a separate set of lines (the gridline) without using the axis generator (see my answer here: https://stackoverflow.com/a/38329969/5768908). This is more complicated but has the advantage of allowing you to set them a different colour, stroke-width, opacity etc.
A simpler approach, that doesn't allow such customisations, is translating the ticks to the left. In this demo, I'm setting the tickSize:
.tickSize(width + someValue)
And then moving them to the left:
.attr("transform", "translate(-someValue, 0)");
Check the demo:
var svg = d3.select("body").append("svg");
var data = d3.range(10);
var yScale = d3.scaleLinear().domain([0,10]).range([140,10]);
var yAxis = d3.axisLeft(yScale).tickSize(-256).tickPadding(10);
var gY = svg.append("g").attr("class", "y axis").attr("transform", "translate(50,0)").call(yAxis);
d3.selectAll(".y.axis .tick line").attr("transform", "translate(-6,0)");
.y.axis .tick line{
stroke: #999
}
<script src="https://d3js.org/d3.v4.min.js"></script>
Related
I am new to d3v4 and working on a chart where i need to show little rectangle on certain date matching to its title on yaxis. The problem i am facing is rectangles in the chart area not drawing equal to the yaxis point labels, i have tried changing the y value by hardcoding, it works fine but the point is the number of data object will change in real time like it could be any number of objects in an array. Here is the plunker
To draw the graph dynamically with limited data objects i've created few buttons on top of chart so that rectangles in the chart can draw equal to y-axis labels.
Any help is much appreciated.
You are using a band scale: that being the case, you should not change the y position, which should be just...
.attr('y', function(d) {
return yScale(d.title);
})
.. and you should not hardcode the height: use the bandwidth() instead:
.attr('height', yScale.bandwidth())
The issue now is setting the paddingInner and paddingOuter of the scale until you have the desired result. For instance:
var yScale = d3.scaleBand().domain(data.map(function(d) {
return d.title
}))
.range([height - 20, 0])
.paddingInner(0.75)
.paddingOuter(.2);
Here is the plunker with those changes: https://plnkr.co/edit/ZxGCeDGYwDGzUCYiSztQ?p=preview
However, if you still want (for whatever reason) hardcode the height or the width of the rectangles, use a point scale instead, and move the y position by half the height.
I have a line chart in D3 as seen here:
I am attempting to extend the x-axis to be the same size as the y-axis tick width. Currently I am setting the ranges as follows:
// set the ranges
var x = d3.scaleTime().range([20, width - 20]);
var y = d3.scaleLinear().range([height, 0]);
This achieves my desired effect of pushing the plot in from the left and right sides but does not extend the x-axis. I'm sure there has to be a way to add padding to the plot without changing the ranges but I can't seem to figure out how?
There's no easy way to add padding to a linear scale.
However, in your case, since your x axis is presenting categorical data (days of the week), you can use a d3.scalePoint and configure its outer padding with the padding function.
I tried http://bl.ocks.org/godds/ec089a2cf3e06a2cd5fc
However, I found when I used the brush, the main part of the stacked bar is out of boundary. How to fix it?
I think here is the reason:
some bars should not be shown in the main part but they are still in the scope of svg
Thank you for your help!
These types of zoom literally are just geometric zooms, all the bars are still being drawn, it's just that the vast majority are off-screen, some are within the chart limits and a few lie in the axis gap in-between which are the ones that look awkward.
Make a svg clip, and add it to the right 'g' element to get rid of this effect:
svg.append("defs").append("clipPath")
.attr("id", "myclip")
.append ("rect")
.attr({x: 0, width: width, y: margin.top, height: height});
... and later on in the code
// draw the bars
main.append("g")
.attr("clip-path", "url(#myclip)")
.attr("class", "bars")
After reading the spec and this question I've understood, that the rendering order is actually a timing order.
The sub-elements of an <svg> are ordered in the z-axis regarding the timing of the rendering, meaning the element, which has been rendered first lies on bottom, the lastly rendered element on top of all others in the same area.
Is this differently for group elements (<g>)?
If you look at this code (a JsFiddle) and the outcome, the helper lines (<line> elements) lie above the graph lines (<path> elements). The helper lines are grouped within the axis group, each graph line would be drawn in a separate group.
But the axes are rendered first, at least the function addYAxis is called before handleLine runs. What am I missing here?
Note: in this answer, dealing with the rendering of red circles and blue squares in a chart, is stated, that
In this case the red circle will be visible above the blue square even though the blue square was created last. This is because the circle and the square are children of different group elements, which are in a pre-defined order.
But I don't get, why this is possible and how I can set this pre-defined order.
Ok if you want the axis lines to be behind the line charts.
First make a x-axis group and y axis group then make the line group.
This ensures the oder is preserved.
Inside your setSVG function do:
parts.svg.append('defs').append('clipPath') //add a clip
.attr('id', lineWrapperId)
.append('rect')
.attr({
width: basics.width + 'px',
height: basics.height + 'px'
});
parts.svg.append('g') // add x axis g
.attr('class', 'x-axis');
parts.svg.append('g') // add y axis g
.attr('class', 'y-axis');
//finally add line group
parts.pathFrame = parts.svg.append('g') // add lines group
.attr('clip-path', 'url(#' + lineWrapperId + ')')
.attr('class', 'line-wrapper');
Now when you make your x axis select its group and make the axis like below in function addXAxis and addYAxis:
if (!parts.axisX) {
parts.axisX = d3.select(".x-axis") //selectin the x axis group
.attr({
'class': 'x-axis',
transform: 'translate(0,' + (basics.height - basics.margin) + ')'
})
.call(xAxis); // leave out tick sizes for now
} else {
parts.axisX = d3.select('g.x-axis')
.call(xAxis);
}
Working example here
I have a D3 project where I'm drawing a time axis along the left side of the screen. I want to have it smoothly transition on window resize so I'm using D3 transitions. However the axis setup appears to be changing the "dy" attribute on the tick labels immediately causing the tick labels to jump downward and then transition back into their normal place any time the SVG is transitioned. Is there any way to set the "dy" attribute of the tick text as part of the axis call or a better way to transition?
My initial (one-time) axis setup:
var timeScale = d3.time.scale().domain([minTime, maxTime]);
var yAxis = d3.svg.axis().scale(timeScale).tickFormat(d3.time.format("%-m/%-d %-I:%M%p")).orient("right");
I have a function to update/transition the SVG elements I'm using. The first time the SVG is drawn init is set to true, false afterwards.
function updateSVG(init) {
...
timeScale.rangeRound([topPadding, svgHeight]);
// Use a transition to update the axis if this is an update
var t = (init) ? svgContainer : svgContainer.transition().duration(750);
// {1}: Create Y axis
t.select("g.axis").call(yAxis);
// {2}: Move Y axis labels to the left side
t.selectAll("g.tick > text")
.attr("x", 4)
.attr("dy", -4);
...
}
On an update at {1} tick labels all have a "dy" attribute of "-4" from the previous attr() call. At {2} applying the axis resets the "dy" attribute of these elements to a default of ".32em" after which they transition slowly back to "-4" causing them to jitter up and down as the window is resized and the axis is redrawn.
Here is a working JSFiddle that demonstrates the jump on the y-axis when the Result box is resized, resize just by a few pixels and it should be obvious: http://jsfiddle.net/YkDk4/1/
Just figured this out. By applying a "transform" attribute instead of a "dy" attribute the axis call() does not overwrite the value. So:
t.selectAll("g.tick > text")
.attr("x", 4)
.attr("dy", -4);
becomes:
t.selectAll("g.tick > text")
.attr("x", 4)
.attr("transform", "translate(0,-4)");
and everything transitions smoothly.
According to the bug fix made in response to this problem with the text-anchor attribute:
How to tweak d3 axis attributes when transition is present?
It looks like the dy attribute is supposed to update immediately during transitions...but it's not.
In any case, the easiest solution is simply to take the dy update OUT of the transition and apply it directly:
t.select(".y")
.call(yAxis);
chartSvg.selectAll(".y g.tick > text")
.attr("dy", -4);
That should avoid the "bounce".