I have generated some charts in d3.js. I use the following code to calculate the values to put in my y axis which works like a charm.
var s = d3.scale.linear().domain([minValue, maxValue]);
var ticks = s.nice().ticks(numberOfPoints);
However I now have to write python code using pycairo which generates clones of the d3.js charts on the server side.
My question is does anybody know the logic used in the above code, or something that can give similar results, so that I can replicate it in python to get nice values to use in my y axis?
D3 is open source, so you can look up the implementation. It basically boils down to rounding the extreme values:
domain[i0] = nice.floor(x0);
domain[i1] = nice.ceil(x1);
Related
Needed a faceted visualization for my personal project. Was looking for options over the web, found out https://github.com/chartshq/muze suits my purpose.
Though I was able to get started pretty early using their documentation, I faced a roadblock soon. Looks like the documentation in progress.
Here is a scaled down sample of what I have achieved so far
https://jsfiddle.net/q8w47vt1/
Promise.all([
fetch('https://raw.githubusercontent.com/chartshq/muze/master/examples/data/cars.json'),
fetch('https://raw.githubusercontent.com/chartshq/muze/master/examples/data/cars-schema.json')]).then((response) => {
Promise.all(response.map(_ => _.json())).then((res) => {
const data = res[0]
const schema = res[1];
let DataModel = muze.DataModel;
let rootData = new DataModel(data, schema);
let env = muze();
let canvas = env.canvas();
canvas
.rows(['Origin', 'Acceleration'])
.columns(['Cylinders'])
.data(rootData)
.width(500)
.height(500)
.title('Acceleration by Cylinders by Origin')
.subtitle('For years 1970 - 1982')
.mount('#chart-container');
});
});
But, I wanted my visualization to have the axis on the right hand side and facet on the left of the plot and not on the left hand side. I tried a couple of ways to do it but was unable to achieve the result.
Spent some time looking at the code, but couldnt figure out much, as I didnt have time to go through the codebase.
Can anyone help me on this? Dont want to raise issue right at this point of time, as I am not sure its a valid feature or not!
Welcome to stackoverflow :)
Changing the position of axis can be done like below
canvas.rows([[], ['Origin', 'Acceleration']])
You can find the documentation here
While the above configuration will serve your purpose to have the axis on the right hand side, it will shift the faceting to the right as well. You can choose to have your facets on the left-hand side of the canvas, while maintaining the axes to the right by providing the configuration as provided below:
canvas.rows([['Origin'],['Acceleration']])
Basically, the first array for the rows API provides the left hand side of the visualization and the second array provides the right hand side. If only a single array is provided, Muze automatically puts all the facets and axes to the left hand side of the visualization.
However, this may not be valid in some cases(specially, when you have only provided only dimensions to the API).
So, you may wish to checkout the documentation to understand how this API works for a better understanding here
This is what I have so far: https://gist.github.com/daluu/fc1cbcab68852ed3c5fa and http://bl.ocks.org/daluu/fc1cbcab68852ed3c5fa. I'm trying to replicate Excel functionality.
The line fits the default histogram just fine as in the base/original http://bl.ocks.org/daluu/f58884c24ff893186416. And I'm able to sort the histogram in descending frequency, although in doing so, I switched x scales (from linear to ordinal). I can't seem to map the line to the sorted histogram correctly at this point. It should look like the following examples in terms of visual representation:
the Excel screenshot in a comment in my gist referenced above
the pareto chart sorted histogram in this SO post
the pareto chart (similar to but not exactly a sorted histogram) made with d3 here
What's the best design approach to get the remaining part working? Should I have started with a single x scale and not need to switch from linear to ordinal? If so, I'm not sure how to apply the histogram layout correctly using an ordinal scale or how not to use a linear x scale as a source of input to the histogram layout and still get the desired output.
Using the same ordinal scale with the code I have so far, the line looks ok but it's not the curve I am expecting to see.
Any help appreciated.
The main issue with the line is that the cumulative distribution needs to be recalculated after the bar is sorted, or if you're gunning for a static pareto chart, the cumulative distribution needs to be calculated in the target sort order. For this purpose i've created a small function to do this calculation:
function calcCDF(data){
data.forEach(function(d,i){
if(i === 0){
d.cum = d.y/dataset.length
}else{
d.cum = (d.y/dataset.length) + data[i-1].cum
}
})
return data
}
In my case, i'm toggling the pareto sort on/off and recalculating the d.cum property each time. One could theoretically create two cumulative dist properties to start with; i.e. d.cum for a regular ordered distribution and say d.ParetoCum for the sorted cumulative, but i'm using d.cum on a tooltip and decided against that.
Per the axis, i'm using a single ordinal scale which i think is cleaner, but required some work on getting the labels to be meaningful for number ranges since tick-marks and labels no longer delineate the bins as one would get with a linear scale. My solution here was to just use the number range as the tick mark e.g. "1 - 1.99" and add a function to alternate tickmarks (got that solution a while ago from Alternating tick padding in d3.js).
For the bar sorting, i'm using this d3 example as a reference in case you need to understand in the context of a simpler/smaller example.
See this fiddle that incorporates all of the above. If you want to use it, i would suggest adding a check to avoid the user being able to toggle off both bars and line (left a note in the code...should be trivial)
Instead of sorting the y.
data.sort(function(a,b){ return b.y - a.y;});
you should be sorting the x
data.sort(function(a,b){ return a.x - b.x;});
Working code here
Let me explain my situation.
First, I have chosen to use Dimple because I am new with d3, and I see dimple as a way to progressively get more familiar with d3 (but still produce interesting plots).
I want to plot a multiple line graph.
Each line represents the power demand at a location during the day.
The data is coming from a Python algorithm under the following shape:
{ time:[00:00:00...23:59:59], locationName1:[power values], ..., locationNameN:[]}
In order to plot it, I transformed it into a flat format, and so I wrote a piece of code to create a csv file such as there are 3 columns:
"Time,Location,Power_Demand"
"00:00,Home,1000"
"...,...,..."
My csv file is approximately 0.14MB
I use the following script to plot my result:
var svg = dimple.newSvg("#chartContainer", 1500, 800);
d3.csv("data.csv", function (data) {
var myChart = new dimple.chart(svg, data);
myChart.setBounds(100, 100, 1000, 620)
var x = myChart.addTimeAxis("x", "Time", "%H:%M:%S", "%H:%M");
x.addOrderRule("Time");
var y = myChart.addMeasureAxis("y", "Power_Demand");
y.overrideMax = 300000;
y.overrideMin = 0;
var s = myChart.addSeries(["Location"], dimple.plot.line);
myChart.addLegend(130, 10, 400, 35, "right");
myChart.draw();
});
It takes approximately 1 minutes to draw.
My main question is: why is it that slow ? Is it my JavaScript code ?
In the end it's just 5 curves with 1439 points each... it should be quick.
(ps: I have also been a bit disappointed that working with a non-flat JSON object is not easier)
Alright, turned out that trying to follow this dimple example http://dimplejs.org/examples_viewer.html?id=lines_horizontal_stacked
made me format my data in a weird way without questioning it.
I have decided to use http://bl.ocks.org/mbostock/3884955 instead and realized that I could also write my data under this flat format:
Time,Location1,Location2,...,LocationN
00:00,power value1.1,power value2.1,...,power valueN.1
The result is instantaneous.
Not using Dimple was a little bit harder at first, but worth it in the end.
I am sure that my JavaScript code using dimple wasn't the good way to proceed (probably because I am new to it). But still it's a bit disappointing that there are no examples using a simpler dataset on the dimple page. As a result it turns out to be confusing to use a very simple dataset (according to me).
I have a set of data for dates. What value should I provide the X axis values? How do I make Rickshaw display the X data values as dates?
I looked around the docs and examples and cannot find anything.
I've just started using Rickshaw and was in the exact situation.
But, before I go any further, Rickshaw documentation is virtually nonexistent which is very upsetting because the performance of Rickshaw compared to other JS graphing libraries is outstanding.
The best way to find examples is to dig into the source code and example code on their github page try to make sense of things (not the way documentation should be).
That being said, let's try and build a strong base of questions/answers here on StackOverflow!
So, back to the question :) It looks like you've already found your own solution to the question, but I'll provide my solution as well.
Rather than using Rickshaw.Graph.Axis.Time, I've used Rickshaw.Graph.Axis.X and set the tickFormat accordingly.
var data = [ { x: TIME_SINCE_EPOCH_IN_SECONDS, y: VALUE },
{ x: NEXT_TIME_SINCE_EPOCH_IN_SECONDS, y: NEXT_VALUE } ]
var xAxis = new Rickshaw.Graph.Axis.X({
graph: graph,
tickFormat: function(x){
return new Date(x * 1000).toLocaleTimeString();
}
})
xAxis.render();
toLocaleTimeString() can be any of the Javascript date functions, such as toLocaleString(), toLocaleDateString(), toTimeString(), or toUTCString(). Obviously, because the tickFormat takes a function as an argument one can supply their own formatter.
Koliber, I'd be interested to understand your answer if you could provide more detail as well.
Additional to Lars' reply, I found by default Rickshaw is calling
.toUTCString(x.value*1000) //(just ctrl+F to find where =) ).
In my case, I saw different time label on X between Graphite and Rickshaw for this reason, and it works beautifully once I changed it to
.toLocaleString(x.value*1000).
Plus, you may need modify this in two places : Rickshaw.Graph.Axis.Time and the ...HoverDetails
I have finally figured out that the X axis values should be epoch time values. Then, using the code from the examples I was able to show a proper time scale.
I still have a problem because I would like to show the tick marks on weeks on the X axis. However, setting timeUnit to 'week' causes JavaScript errors. It works with other time units though.
None of this worked for me. What worked with angularjs was:
'x' : d3.time.format.iso.parse(date).getTime(), 'y' : 10
This is a little tricky,
I'd like to generate some graph lines for a frequency spectrum.
e.g.
See how the x-axis graph lines change logarithmically in this way...
What i need is the maths to do this above. And then a way to plot x coordinates accurately upon it.
I want to be plotting frequencies between 20Hz to 16000Hz across the x-axis in this way.
(I'm not too worried about the drawing part I can use canvas, i'm just stuck on the maths)
I think i would then need a function to convert say 1525Hz into px (or%) to be plotted on it.
Many thanks
i'd use something like this (live example on jsFiddle):
var min_f = Math.log(20) / Math.log(10),
max_f = Math.log(16000) / Math.log(10),
range = max_f - min_f,
position_px = (Math.log(frequency) / Math.log(10) - min_f) / range * width_px