I'm using jqplot for my chart. As you can see the picture I attached. The data used in chart is 1458 points, and it's look like I have fulfilled the chart with the ball blue color.
I'm looking for a solution to make it look better, even if I use more than 100,000 points.
So, Could you please tell me a good solution to solve this issue? I really appreciate any your idea about it
After replot with _databound min and max
You can get your dataBounds value after rendering using :
var minX = plot.axes.xaxis._dataBounds.min;
var maxX = plot.axes.xaxis._dataBounds.max;
(You can get minY and maxY similarly using yaxis.)
Then you can ask jqplot to use this bounds to plot exact range using :
plot.axes.xaxis.min = minX;
plot.axes.xaxis.max = maxX;
(Again act similarly for yaxis);
Finally, replot your graph : plot.replot();
Your final graph has bounds according to your data values and thus no useless blank on both sides.
Related
im trying to understand what tools i need to use as im new to d3 and didnt find any thing related...
i need a area chart that is like bars but can float and be on multiple values both on the x and y axis.
in this example the values are days but it might be hours/months etc...
need to know the direction i need to go.. / the right term to search...
There's no significant difference between drawing this chart and a normal bar chart.
And you need to define some scales that will map the values in your data to co-ordinates on your chart.
You need to draw some rect shapes.
So, in the above example you would define a time scale that, given an input date, will map that to a certain x co-ordinate on your chart. You can then use that to determine both the x co-ordinate for where the left-hand-side of a rectangle will be, and to work out how wide the rectangle needs to be.
const xScale = d3.scaleTime()
.domain([d3.min(dateValuesInMyDataset, d => d.date), d3.max(dateValuesInMyDataset, d => d.date)])
.range([0, widthOfMyChart]);
The above xScale if given the earliest date in your dataset would return the value 0, because this is the x co-ordinate representing that date.
Similarly, you would want to construct a linear scale which defines how to map the numerical range of values in your dataset, to the y co-ordinates in your chart. Then you can use the scale to determine the y value and height of all of the rectangles in your chart.
There are lots of good examples of this on ObservableHQ.com that you can browse and see the code for.
I am using nvd3 boxplot for my charts. Is there any option to have mean as an asterisk (*) on the boxplot? Can we also have the n value above the top whisker similar to the image below.
This issue has been posted here.
Thanks in advance.
Edit
I would like to add a mean value which I calculate from the data points and not just the center of the box plot. The computed mean may not be in the center of the box plot due to outliers.
You can achieve this by doing the following algorithm:
Get all the rectangles
Find the middle point
Create a text and put it in the above calculated center
Code snippet:
function makeMarkOnMean(){
d3.selectAll(".mean").remove();//remove all * mean markers
//get all the rectangles
d3.selectAll(".nv-boxplot-box")[0].forEach(function(r){
window.setTimeout(function(){
var x = parseFloat(d3.select(r).attr("x")) + d3.select(r).attr("width")/2 - 3; //x position of the star
var y = parseFloat(d3.select(r).attr("y")) + parseFloat(d3.select(r).attr("height"))/2+12;//y position of the star
//now make the star on the above x and y
d3.select(r.parentNode).append("text").attr("class", "mean").style("font-size", "x-large").text("*").style("fill", "red").attr("x",x).attr("y", y);
},500)
});
Working code here.
Well, I'm starting with D3 and I'm trying to create a vertical bar chart.
I really don't know what's happening but some things are not working as expected for me (maybe because I'm just a noob on the matter).
I'm using line scales, works pretty well with axes, but it's miscalculating the height of the bars, for instance the higher values are not displayed (because of the low value of the result).
I've used the d3.max to determine the range. I really don't get what's happening.
var yScaleLeft = d3.scale.linear()
.domain([0, d3.max(stats)])
.range([realHeight, 0]);
.attr("height", function(d) {
return yScaleLeft(d);
});
Here is the code: http://jsfiddle.net/aKhhb/ Look at * Scales * and // Stats bars
(Just forget about the x-alignement of the bars, I will see that later, I want to set its height properly)
Thanks a lot! Y saludos desde Chile :)
The issue is that your input and output ranges are mirrored -- that is, the largest input value maps to the smallest output value. That is fine, but you need to take it into account when calculating the y and height attributes. Essentially, you had the calculations for both reversed.
Fixed fiddle here. I've also fixed the x axis by adding your margin and half of the bar width to the computed x positions. Oh and you don't need parseInt() when doing calculations, only when you actually want to parse an integer from a string.
Following is the stripped down version is what I'm using to generate histograms using d3 and a bit of jQuery.http://bl.ocks.org/4611158
While most of it might seem right, I'm still confused regarding
Why there is no '14' in the x-axis as should have been for the given input in the above example? Instead 13 gets the ordinate of what should have been 14's
In my trials d3.layout.histogram() assigned negative(and hence non-plot table) widths when I try altering the output range of scale to some non-zero value. why is it so? what is the possible workaround?
My main motive to use ordinal scale was to make ticks centrally aligned below the bars, unlike what Mike used in his demo for histograms. I've also made the number of bins equal to the number of ticks in d3.layout.histogram() for the very same purpose. I'm sure there might be a better way around to code what I'm looking for
Also any ideas how to add a 'graph' of indicator lines like its been done in nvd3 visualization (light gray in background )that will make it more pleasing?
There is no 14 and there are two 8s on the x-axis. This is because the bins function will diligently divide the range = 14 - 1 = 13 into 14 intervals as per the API reference:
The bins may be specified as a number, in which case the range of values will be split
uniformly into the given number of bins. Or, bins may be an array of threshold values,
defining the bins; the specified array must contain the rightmost (upper) value, thus
specifying n + 1 values for n bins. ...
Before solving this issue, I am guessing that the second problem you are facing is that if the rangeDefault has negative values, then some values are not plotted. To fix that problem, being unaware of the exact need of it, I will start by removing the following:
rangeDefault[0] = 0; //All histograms start from 0 <-- REMOVED
Then to fix the first problem, use the second form of arguments for binsas shown here:
var bins = [];
for(var ii = settings.range[0], jj = 0; ii <= settings.range[1] + 1; ii++, jj++)
bins[jj] = ii;
var data = d3.layout.histogram()
.bins(bins)(settings.data);
I hope this addresses the primary queries.
Adding the light grey indicator lines is fairly easy, as shown here. The changes were:
vis.css
.y.axis line.tick { opacity: .3; }
vis.js
Moving the axis before the chart in the DOM because of how SVG is laid out affects its z-index:
var gEnter = svg.enter().append("svg").append("g");
gEnter.append("g").attr("class", "x axis");
gEnter.append("g").attr("class","y axis");
gEnter.append("g").attr("class", "bars");
And finally making the major tickSize on the y-axis -(width - margin.right - margin.left):
yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.tickSubdivide(true)
.tickPadding(5)
.ticks(10)
.tickSize(-(width - margin.right - margin.left), 2, 8);
I've created nycMap, a project that uses angularJS (MVC), yeoman (build), d3 (mapping) and geoJSON (geo data).
Everything works very nicely, but I did have to spend quite some time getting the right scale and translation. I was wondering how I can automatically figure out at what scale the map will show its best and what x and y values go into the translation?
'use strict';
japanAndCo2App.controller('MainCtrl', function($scope) {
function makeJapanAll(){
var path, vis, xy;
xy = d3.geo.mercator().scale(16000).translate([-5600,2200]);
path = d3.geo.path().projection(xy);
vis = d3.select("#japanAll").append("svg:svg").attr("width", 1024).attr("height", 700);
d3.json("data/JPN_geo4.json", function(json) {
return vis.append("svg:g")
.attr("class", "tracts")
.selectAll("path")
.data(json.features).enter()
.append("svg:path")
.attr("d", path)
.attr("fill",function(d,i){ return d.properties.color || "transparent"});
});
}
makeJapanAll();
});
(If you are interested in the code, it's all on github. The code for the map is in scripts/controllers/main.js which is the same as shown above.)
I've had the same problems. But it is very easy to do when you have a bounding box, which can be determined from the GeoJSON (like meetamit said), or while creating the GeoJson. And the width of the wanted SVG.
I'll start with the variables lattop, lonleft, lonright, width and height for the bounding box of the geojson and the dimensions of the image. I haven't yet occupied myself with calculating a good height from the difference in latutude. So the height is just estimated to be big enough to fit the image. The rest should be clear from the code:
var xym = d3.geo.mercator();
// Coordinates of Flanders
var lattop = 51.6;
var lonleft = 2.4;
var lonright = 7.7;
var width = 1500;
var height =1000;
// make the scale so that the difference of longitude is
// exactly the width of the image
var scale = 360*width/(lonright-lonleft);
xym.scale(scale);
// translate the origin of the map to [0,0] as a start,
// not to the now meaningless default of [480,250]
xym.translate([0,0]);
// check where your top left coordinate is projected
var trans = xym([lonleft,lattop]);
// translate your map in the negative direction of that result
xym.translate([-1*trans[0],-1*trans[1]]);
var path = d3.geo.path().projection(xym);
var svg = d3.select("body").append("svg").attr("width",width).attr("height",height);
Note, if you go over the date line (180 degrees), you will have to take the overflow into account.
Given this:
xy = d3.geo.mercator().scale(someScale).translate([0, 0]);
someScale is the pixel width of the entire world when projected using the mercator projection. So, if your json data had outlines for the whole world – spanning from lat/lng -180,90 to latLng 180,-90 – and if someScale was 1024, then the world would be drawn such that it exactly fits within a 1024x1024-pixel square. That's what you see on in this Google Maps view (well... sort of... not quite... read on...).
That's not enough though. When the world is drawn at 1024px, without any translation, lat/lng 0,0 (i.e. the "middle" of the world) will sit at the 0,0 pixel of the projected map (i.e. the top left). Under these conditions, the whole northern hemisphere and western hemisphere have negative x or y values, and therefore fall outside the drawn region. Also, under these conditions, the bottom right of the world (i.e. lat/lng -90, 180) would sit at the exact middle of the 1024x1024 square (i.e. at pixel 512,512).
So, in order to center the world in the square described here, you need to translate the map by half its width in the X and Y directions. I.e. you need
xy = d3.geo.mercator().scale(1024).translate([512, 512]);
That'll give you exactly the Google Map view I linked to.
If your json data only has part of the world (like, nyc or NY state) drawing it with this xy projection will render the outlines in the correct geographic position relative to the entire 1024x1024 world-spanning region. So it would appear rather small, with lots of whitespace.
The challenge is how to scale and translate the projection such that the area in question fills up the 1024x1024 square. And... so far I haven't answered this question, but I hope that this explanation points you in the right direction towards figuring out this math. I'll also try to continue the answer later, when I have more time. :/
There's an example here that gets the bounds of countries from geojson and then scales and translates the map to that country. The code is a bit ugly; there're however efforts to make this easier in the future (see this and this issue).