I am creating a bar chart using d3. The bar chart accepts negative values. The chart I am creating is based on this chart here, and mostly have similar setup.
The change I like to make is shift the text labels of the y-axis to the absolute left of the chart, but keep the y-axis line at its original spot.
From the above link, the following are the lines of code to render the y-axis (they are at the bottom of the page, almost the last thing of the code)
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + x(0) + ",0)")
.call(yAxis);
Now, if I adjust the above translate line to the following
.attr("transform", "translate(0,0)")
then BOTH the axis line AND the labels will be left aligned. I would like to keep the axis line at its position but move all the labels to the left.
How can I do that?
PS. A solution I thought about is to create second y-axis. The first y-axis is hidden with the labels shown, and is displayed to the left. The second y-axis is shown, but the labels are hidden, and is at the center. However, I do not like this solution, I do not think it is very clean.
Thanks.
Just increase the tick padding:
.tickPadding(width/2 - margin.left);
Related
I have a plunker here - https://plnkr.co/edit/3gikXOR8EydIcA3wcBMb?p=preview
The numbers on the y axis are in the centre of the grid line.
I can change the padding with
.tickPadding(5)
Can I change the vertical position of the numbers so they bottom of the number is on the same level as the grid line.
add a dy attribute to the text items
chart.append("g")
.classed('y-axis', true)
.call(y_axis)
.selectAll('text')
.attr('dy', '-0.3em');
I am new to d3 and svg coding and am looking for a way to rotate text on the xAxis of a chart. My problem is that typically the xAxis titles are longer than the bars in the bar chart are wide. So I'm looking to rotate the text to run vertically (rather than horizontally) beneath the xAxis.
I've tried adding the transform attribute:
.attr("transform", "rotate(180)")
But when I do that, the text disappears altogether. I've tried increasing the height of the svg canvas, but still was unable to view the text.
Any thoughts on what I'm doing wrong would be great. Do I need to also adjust the x and y positions? And, if so, by how much (hard to troubleshoot when I can see it in Firebug).
If you set a transform of rotate(180), it rotates the element relative to the origin, not relative to the text anchor. So, if your text elements also have an x and y attribute set to position them, it’s quite likely that you’ve rotated the text off-screen. For example, if you tried,
<text x="200" y="100" transform="rotate(180)">Hello!</text>
the text anchor would be at ⟨-200,100⟩. If you want the text anchor to stay at ⟨200,100⟩, then you can use the transform to position the text before rotating it, thereby changing the origin.
<text transform="translate(200,100)rotate(180)">Hello!</text>
Another option is to use the optional cx and cy arguments to SVG’s rotate transform, so that you can specify the origin of rotation. This ends up being a bit redundant, but for completeness, it looks like this:
<text x="200" y="100" transform="rotate(180,200,100)">Hello World!</text>
Shamelessly plucked from elsewhere, all credit to author.
margin included only to show the bottom margin should be increased.
var margin = {top: 30, right: 40, bottom: 50, left: 50},
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
.selectAll("text")
.style("text-anchor", "end")
.attr("dx", "-.8em")
.attr("dy", ".15em")
.attr("transform", "rotate(-65)");
One problem with this rotating D3 axis labels is that you have to re-apply this logic each time you render the axis. This is because you do not have access to the enter-update-exit selections that the axis uses to render the ticks and labels.
d3fc is a component library that has a decorate pattern allowing you to gain access to the underling data join used by components.
It has a drop-in replacement for the D3 axis, where axis label rotation is performed as follows:
var axis = fc.axisBottom()
.scale(scaleBand)
.decorate(function(s) {
s.enter()
.select('text')
.style('text-anchor', 'start')
.attr('transform', 'rotate(45 -10 10)');
});
Notice that the rotation is only applied on the enter selection.
You can see some other possible uses for this pattern on the axis documentation page.
I am trying to make a treemap responsive, however, the chart simply drifts off to the left, and to the bottom. As if there is something affecting x0 and y0. The chart does not respond to resizing, however I think this may have something to do with the width and heights... possibly affecting the position of the chart also. Or, is this simply a CSS issue? Very confused with this one. I imagine I am missing something obvious...
Plnkr: https://plnkr.co/edit/U7Zsbjy0zubnMwo1SHg8?p=preview
var svg = d3.select("#graph")
.append("svg")
.attr('width', width + margin.left + margin.right)
.attr('height', height + margin.top + margin.bottom)
.attr('style', 'border:solid 2px blue')
.attr('style', 'padding0px')
.call(responsivefy)
At line 156 you are doing
var newNode = node.enter()
.append("g")
.attr("class", "node");
.attr("transform", "translate("+[fullWidth/2, fullHeight/2]+")")
The last line of that code block is why everything ends up bottom right, you are translating every group to start from the middle of the chart (instead of top left). If you remove it the chart looks ok. Here's your chart with that edited : https://plnkr.co/edit/RUhlH4rwopNKf4iDiUge?p=preview
As for making it responsive, you already set the viewbox attribute on the SVG to make it responsive. You don't need that extra function responsivefy on top of it. You seem like you used this answer for the responsive classes : https://stackoverflow.com/a/25978286/11487 but the order of the nodes in your markup was not quite there.
One thing that's important to note : when you use preserveAspectRatio with "xMinYMin meet" to get a responsive graph, you cannot use width and height instructions.
With that fixed up :
https://plnkr.co/edit/KADSH9GSX1E3lnpmhzjV?p=preview
I am trying to adapt Mike Bostock's Focus+Context via Brushing chart at: bl.ocks.org/mbostock/1667367 to include a drag icon on both vertical lines of the brush rectangle. These should appear once a selection is made and act as a visual cue to shrink or expand the selected/brushed area. I see the placement of the images being dynamic i.e. moving fluidly with the brushed area as opposed to an update after the brushed area is reset. What seems most reasonable to me would be to add an svg image to the context rectangle like so:
//original code
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2 + 7)
//additional code
.append("svg:image")
.attr("xlink:href", "icon.png")
.attr("width", 10)
.attr("height", 10)
.style("opacity",1)
I've tried playing around with the x and y positioning of both images with no luck getting them to appear, but i conceptually see it working as
y axis: height of context chart divided by 2
x axis: each image respectively corresponding to the min and max x values of the brushed area
Any help would be appreciated.
Lars, thanks for the pointer which generally led me in the right direction although I ended up directly adapting from an example at https://engineering.emcien.com/2013/05/7-d3-advanced-brush-styling. That example is a bit more complex so i borrowed from a subset relevant to my purposes.
Steps i followed include
1.) Creating two images appended to the context g element and initializing their position somewhere that doesn't give the impression that the chart is brushed on loading {i put them halfway (vertically) and close together around the end of the context(horizontally)}.
var leftHandle = context.append("image")
.attr("xlink:href", "icon.gif")
.attr("width", 11)
.attr("height", 27)
.attr("x",x2(data[data.length-6].date))
.attr("y", (height2/2)-15);
var rightHandle = context.append("image")
.attr("xlink:href", "icon.gif")
.attr("width", 11)
.attr("height", 27)
.attr("x",x2(data[data.length-1].date))
.attr("y", (height2/2)-15);
2.) Within the brush function, i created a variable to hold brush.extent(), then tied the x attributes of the images to its min and max x values.
var ext = brush.extent();
leftHandle.attr("x",x2(ext[0]));
rightHandle.attr("x",x2(ext[1]));
One things i'm not completely satisfied with is that when i initially created the images after the brush rectangle, they sat on top of it, preventing me from being able to brush if i hovered over the images (which is the intuitive reaction desired). I ended up placing the images behind the rectangle which has a low opacity. Not the 100% accurate visual representation sought, but it works just fine.
in D3, how can I put an axis in the middle, or center, of a graph? The documentation says "only top/bottom/left/right".
I know the dimensions of my graph, let's say it is 400px by 400px. In Protovis I used
vis.add(pv.Rule).bottom(200)
placing an axis 200px up from the bottom. How can I do this in D3?
You can transform the axes whichever way you want. The orientation only refers to which side the ticks and numbers are placed on.
See e.g. http://alignedleft.com/tutorials/d3/axes/
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
where you just need to change the parameter to the transform to get whatever you want.