d3 resizes path (gains 10 px width) on update - why? - javascript

TL;DR: Why does the line graph path in the fiddle example grow 10 px width when updated?
Long version: I am building a little microeconomic simulation in d3, trying to illustrate price elasticity. Here's a fiddle (which doesn't actually illustrate elasticity, it's just a dummy to try to get the graph working). The idea is you adjust the price (the height of the price bars by pulling with the mouse), and the demand line graph updates.
The only trouble is that when it updates, the line graph <path> seems to grow 10px. (you can verify this in your browser inspector - it should go from 408px to 418px). I don't know why this is happening.
I don't believe an extra point is being added, merely that the path is being "stretched" horizontally. The relevant update function uses the the original data as the input to the x.axis domain - so I don't see why the data points should be mapped differently to the x range.
//...extract of the update function
var demandData = demandForecastData.map( function(d, i){
return [ d[0], d[1] + somestuff ];
});
updateDemand(demandData);
Can someone clever tell me what's going on?

You set margins as so:
//svg margins for axis labelling, etc
var margin = {top: 20, right: 40, bottom: 30, left: 40}
But upon drawing it you decrease the right margin by 10:
//graph the bar chart
var margin = {top: 20, right: 30, bottom: 30, left: 40}
just update it to right: 40 and it's fixed.

Related

How to fix graph so it doesn't write over itself when resizing

I am trying to make my graph resize with the window when changed. I put my code that makes the graph in a function and added an event listener that calls the main function with updated height and width variables when added however it doesn't remove the already added in bars, lines, axes, labels, etc. causing an effect where the graph rescales properly but doesn't remove all the old stuff so I end up with hundreds of bars on my graph.
I tried just putting in a white rectangle each time the window resizes, however it takes too long for the graph to load in such a way that it flickers while resizing and doesn't look good.
Also to note: I have the function chart() run on load in my HTML file. Here is a link to what it looks like:
https://imgur.com/iuDXjpC
var margin = {top: 10, right: 70, bottom: 100, left: 70},
w = window.innerWidth,
h = window.innerHeight;
var topBottom = margin.top + margin.bottom;
var leftRight = margin.left + margin.right;
var mid = {x: w/2, y:h/2};
var svg = d3.select("#svgDiv")
.append("svg")
.attr("width",w)
.attr("height",h)
.attr("margin","auto");
function chart(){
w = window.innerWidth;
h = window.innerHeight;
d3.csv("test.csv").then(function(dataset) {
part where I make the graph
}
}
window.addEventListener("resize",chart);
Should I just remove everything and redraw it whenever 'chart()' is called? or should I better optimize my code and then just put a white rectangle over old window sizes so that the one that is desired is on top.
If you're going to use resize events, you can do two things. Either remove all children of svg before drawing (svg.selectAll("*").remove();) anything, or, if you want to optimize the code, split the loading and handling of the data and the drawing of the chart into two parts.
First, when you load the data, store it as a variable and use the .data attribute to add/remove SVG nodes based on it. For example, if you have three bars in the data, you add the rect nodes here, but don't do anything about their placement.
Then, inside the function that is also called on resize, you first take the xScale and yScale variables and call .range() with the new size. Take the variable you assigned the three rect nodes to, and set their x, y, width, and height attributes based on their values as you loaded them in the first part. Note that all these values are indirectly based on the values you passed to xScale and yScale .range() function.
I can't help you more specifically without seeing more code, so I hope this helps.

D3 graph shows zero in y axis

Hello i was plotting D3 line graph with brush and zoom
i was able to do it but in y-axis of the graph the values shows zero even after data having some values
and one more problem is mouse-hover even is not firing properly on circles due to pointer-events: all; on .zoom class
adding fiddle here
Set margin left more, 60 instead 20 and you will be happy:)
margin = {top: 20, right: 20, bottom: 110, left: 60},

How to minimize whitespace around Baidu's echarts

I'm trying to incorporate Baidu's echarts (which look really good). However, there is a lot of whitespace around the actual graph when one doesn't set a title nor uses their toolbar. Is there a way to have the graph/chart use more of the canvas?
My current solution to add an extra inside the container one and then set it's width and height to be be bigger by the margins I want to remove and the offset it by setting 'top' and 'left' to negative values of the respective margins. Not elegant and more importantly, not robust, but it works for the moment.
In ECharts 4, 5
As mentioned by some other posters, the correct way to get rid of the whitespace is to change options.grid.
https://echarts.apache.org/en/option.html#grid
grid: {
left: 0,
top: 0,
right: 0,
bottom: 0
}
In ECharts 4, the names of the grid properties have been changed to left, right, top, and bottom.
Thanks to the answers above for pointing me in the right direction!
Further, changing the option.legend, as suggested above, had no effect on my chart.
You can use the properties defined on the grid (x, y, x2 and y2).
These properties are mentioned on the documentation: http://echarts.baidu.com/doc/doc-en.html#Grid
In ECharts 3 you can use the options grid.left, grid.top, grid.right and/or grid.bottom. According to the documentation, left and right default to 10%, and top and bottom default to 60 (px).
Documentation: https://ecomfe.github.io/echarts-doc/public/en/option.html#grid.
const option = {
// these are the grid default values
grid: {
top: 60,
bottom: 60,
left: '10%',
right: '10%',
},
// your other options...
}
Adding values to your themes grid object, like so:
var theme = {
grid: {
x: 40,
y: 20,
x2: 40,
y2: 20
}
}
legend: {
padding: 0,
itemGap: 0,
data: [' ', ' ']
},
In here we can just simply remove the padding of the legend. even though you are not specifying one, it is taking the default values. Unfortunately, eCharts doesn't give flexible option of setting chartArea through options.
In google Charts you can mention it 100% and it'll cover all the available area. I tried the above mentioned work around and could cover a bit more space after that.
in Echart u can make chart/graph with combination of the chart, and thre is too many config for every charts section, like legend, etc... just have look at their api documantation on their web site and Example page (Combinations part)

Snap SVG : Fixed bottom and animate height only

I need to animate the height of a rectangle in SVG with the bottom fixed. I am using Snap SVG library.
jsFiddle of what I have tried.
If the y parameter is not added, the rectangle's height animates to the top. So to fix the bottom, I have animated the y parameter too, but then I didn't get the bottom fixed.
Please share your thoughts to fix the bottom and animate the height only.
How about this...
var s = Snap("#svg");
rect = s.rect(10, 5, 50, 100);
rect.attr({
fill: '#fc0'
});
rect.animate({
y:100,
height: 5
}, 1500, mina.easein);
If you change the height from 100 to 5 you must change the y by 95 in the opposite direction for the bottom to appear fixed.

Add some gap in between legend and the chart

In my fiddle here, I want to add some gap in between the legends at the top and the chart, so as to look better.
I tried:
d3.select(".nv-linesWrap").style("padding-top","50px");
but it didnt work.
How do I fix this?
jsFiddle
take a look at xTicks attributes in line 102.
.attr('transform', function(d,i,j) { return 'translate (-10, 40) rotate(-90 0,0)' });
There you can translate and rotate your scalevalues.
In your case, just raise the value of the second translate paramater (40->60).
And a tipp:
play around with those attributes, the first rotateparameter to "-45" makes it really better to read, so you dont have to turn your head every time ;)
//EDIT (Wrong solution)
the legendwrap has the same function and an equal behaviour of the translate function.
Just insert following in line 110:
d3.select(".nv-legendWrap")
.style("float", "right")
.attr("transform", "translate(0,-75)");
Maybe you now have to resize your whole SVG Container where the whole chart is placed
//EDIT2 (Improvement)
to resize the whole Chart (or margin-top+25) i used the following way: just put this part after your legendWrap.
d3.select(".nv-wrap.nv-lineChart").attr("transform", "translate(100,75)");
You can control the distance of the chart legend from chart as follows:
chart.legend.margin({
top: 0,
bottom: 10,
left: 0,
right: 0
});
Please modify the top / bottom values as required.
Note that by default nvd3 uses following values: {top: 5, right: 0, bottom: 5, left: 0}
For introducing space between individual legends there is no direct way as this is not controlled by CSS property and is hard-coded within nvd3 itself.
In nvd3 legend.js line 120:
seriesWidths.push(nodeTextLength + 128); // 28 is ~ the width of the circle plus some padding
You can increase this 28 value to increase space between legends.

Categories