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
Related
Suppose I want to plot histogram for time taken to read each book.
I calculated time to read each book and stored in an array as
const timeToRead = [10,12,8,3,7]
As I gone through different methods on how to plot histogram .... I found that to display data , it should be in range as:
const timeToRead = [0-5,5-10,10-15]
But on basis of my previous data how can I convert it into range, so it can satisfy condition to plot histogram.
Or is there any other method to plot histogram?
Let me know if any further details is need, also if I'm not clear enough do let me know.
How to make histogram
You have to reduce the data you have to get counts of points that go into each bucket.
0-5, 5-10 etc being the buckets.
Now, you could hand-code a reducer for yourself that gives you the count of data points for each of those bins or use something like d3-array package that has tons of stuff to get info out of data.
Here's a quick example.
let bin = d3.bin()
.domain(timeToRead)
.thresholds([0, 5, 10]);
Mode Reading
https://www.npmjs.com/package/d3-array#bin.
https://observablehq.com/#d3/d3-bin#thresholds
I'm using the highcharts library in react.js and it's working great. However, I'm plotting ~15,000 scattered points and it's a bit tricky finding the one I want among all that. I'd like to be able to search for a specific point, since each point has its own unique name property along with its x and y coordinates (not id, but I could put the name as id if that made the solution easier). When the point is found, the graph should zoom in a bit, since at default zoom level there's quite a few overlaps of points so just making it blink/bigger/something wouldn't help much. I've looked through the Highcharts API docs but I can't find anything that will do a manual zoom into specified coordinates.
I found the mapZoom function, but that's only for maps, and... well, this isn't a map. It's a scatter plot.
Also, since this is react, it's a bit tricky to see how I can access the chart object to do stuff with it, since the only time it exists is when it's being returned to be rendered:
var CosinePlot = React.createClass({
componentDidMount: function() {
let chart = this.refs.chart.getChart();
},
render: function() {
return <ReactHighcharts config={plotConfig} isPureConfig={true}/>;
}
});
If you know exact point you want to zoom in, simply get it's x and y. Then zoom into that point using chart.xAxis[0].setExtremes(min, max) and chart.yAxis[0].setExtremes(min, max).
And regarding accessing the chart object, I guess you are using this this wrapper. There is an explanation how to retrieve that chart object here.
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);
My attempts to make my y values scale to logarithmic are turning my data upside-down.
I have vanilla js code and every implementation I read about are tied up in huge libraries of production code, I am not sure how/what to extract, I need some guidance as I could not put my finger on the problem weather it be sum or miss-use of the Math functions.
I am testing this by drawing the y 'data' to canvas (no libraries used) my x axis is constant 2px difference
Math.log uses e (2.718) as default base which is what I have read.. So I should be seeing my price data on a natural log scale but it wont work.
function logScale(data){
var log=data.slice(0);
var i=log.length;
while(i--){
log[i]=Math.log(data[i]); // should be natural but I don't see a change
// log[i]=Math.pow(Math.log(data[i]),10); //upside-down
// log[i]=Math.log(data[i])/Math.LN10; //no visible change when drawn to canvas
}
console.dir(log);
return log;
}
Another attempt from a couple of weeks ago where I am using the data min, max and difference. then removing all the infinity.
function á„logarithm(data){
var Lmax,Lmin,Ldif,Logarithm,infinity;
Lmax=Math.max.apply(this,data);
Lmin=Math.min.apply(this,data);
Ldif=(Lmax-Lmin);
Logarithm=[];
infinity=[];
for(var i=data.length-1;i>=0;i--){
Logarithm[i]=Math.log((data[i]-Lmin)/Ldif);
if(Logarithm[i]===-Infinity){infinity.push(i);}
}
for(var i=0;i<=infinity.length-1;i++){Logarithm.splice(infinity[i],1);}
return Logarithm;
}
The data looks different but still not quite like log scale. It is vertically warped to best describe it.
Please note jsfiddle-ing this won't work as The data is bitcoin prices (real time) so as there is no working code for a log scale there is no good way to show a comparison. Bitcoin or any other exchange data gets served as is so these functions would (if they worked) transfom any data array to log scale.
How do D3 do it? What is wrong with my code?
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