I have a filled line graph and I am trying to set a clip-path. Right now the filled area descends below the graph border and into the axis notations.
Here is a JS fiddle of my code: http://jsfiddle.net/HgP6D/6/
Even setting the clip-path to a small value doesn't seem to change anything:
// Add the clip path.
g.append("clipPath")
.attr("id", "rect")
.append("rect")
.attr("width", 100)
.attr("height", 100)
Anyone have any idea? Thanks.
I don't know about the clip path, but this fixes the area so it doesn't descend below 0:
var area = d3.svg.area()
.interpolate( "monotone" )
.x(function(d,i) { return x(i); })
.y0(-y(0))
.y1(function(d) { return -y(d); })
Related
Im creating a mekko chart and wanted to rotate the legends on x axis.
Example of what i did: https://codepen.io/fabioTester/pen/JjYeJEv
I want to rotate the elements with class "labelTitle" on the example...
I tried using the following code to rotate:
// rotation code
svg.selectAll(".month .labelTitle")
.attr("transform", function (d) {
return "translate(0) rotate(-25)"
});
I'm guessing my issue is the calculation of the translate, but can't figure out how to fix it.
Thanks in advance for any suggestions.
I noticed the labels seem to rotate around a point that is quite far away from their actual position, so a small increase in rotation would quickly rotate them out of sight.
If you set the transform-origin of every individual label to its x and y position, it will rotate the individual labels around that point instead.
svg
.selectAll(".month")
.append("text")
.text(function (d) {
return d.key;
})
.attr("x", 5)
.attr("y", function (d) {
return height - (margin * 2);
})
.attr('transform-origin', `5 ${height - (margin * 2)}`)
.attr("class", "labelTitle");
svg.selectAll('.labelTitle')
.attr('transform', d => 'translate(0, 10), rotate(25)')
I also noticed the y-value of your labels didn't respect the margin, so I fixed that as well.
I came up with the following codepen: https://codepen.io/pitchblackcat/pen/OJyawaV
It seems like you forgot to append deg to rotate's value.
Try this:
// rotation code
svg.selectAll(".month .labelTitle")
.attr("transform", function (d) {
return "translate(0) rotate(-25deg)"
});
The names of the legend don't fully show.They are cut off, if I increase the width, the bars just grow bigger. How can I accommodate more space for my legend?
I tried appending the legend to the 'svg' tag instead of the 'g' tag but still not the desired results. I even plotted the axis, bars and legend on the 'svg' tag but its still not working.
javascript
const g= svg.append('g')
.attr("transform", `translate(${margin.left},${margin.top})`)
const xAxis= g.append('g')
.call(d3.axisBottom(x).tickSizeOuter(0))
.attr("transform", "translate(0," + innerHeight + ")")
const yAxis= g.append('g')
.call(d3.axisLeft(y).tickSizeOuter(0))
//stack the data? --> stack per subgroup
var stackedData = d3.stack()
.keys(subgroups)
(data)
var legend = g.append('g')
.attr('class', 'legend')
.attr('transform', `translate(${210},${20})`);
legend.selectAll('rect')
.data(subgroups)
.enter()
.append('rect')
.attr('x', 0)
.attr('y', function(d, i){
return i * 20;})
.attr('width', 14)
.attr('height', 14)
.attr('fill', function(d, i){
return color(i);
});
legend.selectAll('text')
.data(subgroups)
.enter()
.append('text')
.text(function(d){
return d;
})
.attr('x',18)
.attr('y', function(d, i){
return i * 18;
})
.attr('text-anchor', 'start')
.attr('alignment-baseline', 'hanging');
//below is my plotted data
telescope,allocated,unallocated
IRSF,61,28
1.9-m,89,0
1.0-m,64,23
// width=300 and heigh=300 for svg
I want to show the full names of the legends just next to the right of the bars for the graph.
Link to the graph is here.
How do I solve the problem?
Your issue is that the SVG's width is too narrow to accomodate showing all of the legend texts.
If your graph follows D3 conventions, space for elements that are auxilliary to graph itself (axis names, ticks, legends, etc.) is made using an margin object. Although I can't see how your graph is made, it looks like yours is setup to use a margin object as well. Following D3 conventions the margin values are fixed, which would explain why changing the width value just makes the bars wider yet still doesn't make space for the legend texts.
Therefore, locate the margin object and change its right value to something higher. Inspecting your example, it looks like doubling it should do it.
Hope this helps!
I have been looking into this d3.js block Timeline with Zoom. However, I am not able to figure out how the zoom function is actually implemented. Could somebody help me understand?
Frankly, there is no zoom happening.
var brush = d3.svg.brush()
.x(x)
.on("brush", display);//this calls display function on brush event drag.
Inside display function.
minExtent = brush.extent()[0],//this give the brush extent min
maxExtent = brush.extent()[1],//this give the brush extent max
Based on the max and min of the brush filter the data:
visItems = items.filter(function(d) {return d.start < maxExtent && d.end > minExtent;});
Reset the domain with the brush's max and min.
x1.domain([minExtent, maxExtent]);
Select all rectangles in the upper area not having the brush associate data to the DOM.
update it with the new scale values
rects = itemRects.selectAll("rect")
.data(visItems, function(d) { return d.id; })
.attr("x", function(d) {return x1(d.start);})
.attr("width", function(d) {return x1(d.end) - x1(d.start);});
create any new rectangles if the data is present but DOM is not present.
rects.enter().append("rect")
.attr("class", function(d) {return "miniItem" + d.lane;})
.attr("x", function(d) {return x1(d.start);})
.attr("y", function(d) {return y1(d.lane) + 10;})
.attr("width", function(d) {return x1(d.end) - x1(d.start);})
.attr("height", function(d) {return .8 * y1(1);});
Remove all the rectangle outsside the brush extent or not in the filtered item list visItems
rects.exit().remove();
Exactly the same for labels as done for rectangles above.
Hope this clears all your doubts.
I'm not sure but I think this is just a trick with D3 scales.
What happens is that it gets the selection below (which is a projection a 100% of with from time 0 to time 100) and plots into a new scale from time 50 to time 80 with the same width.
This will make the scale change in a way that looks like you zoomed on that time moment in time.
I'm new to D3.js and using following example from D3.js to create a simple dashboard for one of my web application.
http://bl.ocks.org/NPashaP/96447623ef4d342ee09b
My requirement is to rotate top value labels of each bar vertically by 90 degrees.
I changed following method by adding "transform" attribute. Then the labels do not align properly.
//Create the frequency labels above the rectangles.
bars.append("text").text(function(d){ return d3.format(",")(d[1])})
.attr("x", function(d) { return x(d[0])+x.rangeBand()/2; })
.attr("y", function(d) { return y(d[1])-5; })
.attr("text-anchor", "middle")
.attr("transform", function(d) { return "rotate(-90)" });
I tried to find a solution for long time but couldn't. Links to my codes are given below.
https://jsfiddle.net/vajee555/7udmyj1k/
Can anybody please give me an idea how to archive this?
Thanks!
EDIT:
I have solved the problem here.
http://jsfiddle.net/vajee555/7udmyj1k/5/
Remember that when you rotate an element, the x and y coordinates are changed: they are no longer with respect to that of the chart, but with respect to the new rotated orientation of the element. Therefore, you will need to compute the x and y attributes differently.
By rotating -90deg, your x axis will be flipped to y, and the y will be flipped to -x:
I have made some small pixel adjustments to make it appear aesthetically pleasing, such as the +8 I have added to the y coordinate and the +5 I have added to the x coordinate, but the fine tuning is up to you.
// Create the frequency labels above the rectangles.
bars.append("text").text(function(d){ return d3.format(",")(d[1])})
.attr('transform', 'rotate(-90)')
.attr("y", function(d) { return x(d[0]) + x.rangeBand()/2 + 4; })
.attr("x", function(d) { return -y(d[1]) + 5; });
Also, change how the coordinates are calculated in the hG.update() function:
// transition the frequency labels location and change value.
bars.select("text").transition().duration(500)
.text(function(d){ return d3.format(",")(d[1])})
.attr("x", function(d) { return -y(d[1]) + 5; });
See working fiddle here: https://jsfiddle.net/teddyrised/7udmyj1k/2/
//Create the frequency labels above the rectangles.
bars.append("text").text(function(d){ return d3.format(",")(d[1])})
.attr("x", function(d) { return x(d[0])+x.rangeBand()/2; })
.attr("y", function(d) { return y(d[1])-5; })
.attr("text-anchor", "middle")
.attr("transform", "rotate(-90,0,0)" );
Change the last line as above.
I have a simple bar chart drawn in d3, with vertical bars: http://jsfiddle.net/philgyford/LjxaV/2/
However, it's drawing the bars down, with the baseline at the top of the chart.
I've read that to invert this, drawing up from the bottom, I should change the range() on the y-axis. So, change this:
.range([0, chart.style('height')]);
to this:
.range([chart.style('height'), 0]);
However, that looks like it's drawing the inverse of the chart - drawing in the space above each of the bars, and leaving the bars themselves (drawn from the bottom) transparent. What am I doing wrong?
Per the d3 basic bar chart :
http://bl.ocks.org/mbostock/3885304
You are correct in inverting the range.
Additionally, your rectangles should be added like this:
.attr('y', function(d) { return y(d.percent); } )
.attr('height', function(d,i){ return height - y(d.percent); });
The x and y coordinates for svg start in the top left. You want the y to start on the bottom. The code below assumes you're appending to some function along the lines of:
svg.selectAll('rect')
.data(dataset)
.enter()
.append('rect')
To make the bar plot act as you desire, set the y attribute to begin at distance data[i] above the axis:
.attr('y', function(d) { return height - d; })
Then, you must make the distance extend the remaining data[i] to the axis.
.attr('height', function(d) { return d; })
And that's it!
Setting the y attribute seems to work:
.attr('y', function(d){ return (height - parseInt(y(d.percent))); })
jsfiddle here