Highcharts with custom scaling in upper regions - javascript
I would like to know how to achieve a custom scale for a chart in Highcharts. I want to display a boxplot which has very high whiskers. The normal values to display are between 500 and 1000 but there are some anomalies which are about 6000 on y-axis. This is causing the whole chart to be squeezed and the scaling is so small that you can't determine the boxplots correctly. I would like to increase the tick-size between 1000 and 6000 to decrease the heigt of the chart.
Highcharts provides breaks functionality that seems to be ideal for your case: https://api.highcharts.com/highcharts/yAxis.breaks
Another approach is to change the yAxis type to logarithmic: https://api.highcharts.com/highcharts/yAxis.type
EDIT
The discussion in the comments section reveals that the OP needs rather custom y axis formatting than breaks functionality.
Here's how to approach this issue:
The problem here is that axes in Highcharts can only have either constant or logarythmic scales. Your example shows irregular scale - the values are not in constant or logarythmic order ([0, 3, 10, 30, 150]).
Here's what I've done to mimic that kind of look and behaviour:
I set tickPositions to [0, 1, 2, 3, 4] - these are the actual values that appear on the chart. As you can see the distance between all these numbers is constant: 1.
Then I used formatter to display corresponding number from ranges array for each label.
yAxis: {
tickPositions: [0, 1, 2, 3, 4],
labels: {
formatter: function() {
return ranges[this.pos];
}
}
},
Before I passed the data to the chart constructor I converted all the values so that they're between 0 and 4:
series: [{
data: [2, 120].map(function(val) {
var range = findRange(val);
var y = range.index + (val - range.low) / (range.high - range.low);
return {
y: y,
originalValue: val
};
})
}]
Finally I used originalValue property in tooltip.format string to print to the user the number before the conversion.
tooltip: {
pointFormat: "<span style='color:{point.color}'>\u25CF</span> {series.name}: <b>{point.originalValue}</b><br/>"
},
This example is simplified to the line series case but can be easily adjusted to boxplot series. The code serves only for the example purposes and should be improved - it's easy to cause an error within it.
Live working demo: https://jsfiddle.net/kkulig/ytjz1jej/
API references:
https://api.highcharts.com/highcharts/tooltip.pointFormat
https://api.highcharts.com/highcharts/yAxis.tickPositions
https://api.highcharts.com/highcharts/xAxis.labels.formatter
Related
weird series sorting problem in Highcharts bar chart
Full code example here: https://jsfiddle.net/_dario/o6nugkrw/24/ I have a data series structured like this (from an API call): { "mango": 12736, "orange": 8906, "banana": 8404, "2020": 8239, "blackberry": 7703, "pear": 7297, "raspberry": 6895, "apple": 6432, "kiwi": 6202, "tomato": 6189, "1995": 6123, "kumquat": 6038, "melon": 5982, "strawberry": 5973, "pineapple": 5441 } The sorting order is value high to low, regardless of the label. These are to be plotted in an Highcharts horizontal bar chart. Notice there are two numeric (string, though) labels: "1995" and "2020". This specific data format is then parsed for Highcharts: //--previous highcharts options series: Object.keys(data).map((s, index) => { let arr = new Array(length).fill(null, 0, length); arr[index] = data[s]; return { name: s, data: arr, tooltip: { headerFormat: '' }, } }), //--subsequent highcharts options as per the jsfiddle example (https://jsfiddle.net/_dario/o6nugkrw/24/), the sorting order along the Y axis in the chart is different, and no matter what the order the data is presented in, the two "numeric" labels always stay on top and are sorted differently (by numeric value). I found no reference in the Highcharts docs about this and would like to have them treated as "words" like the others and sorted accordingly. I believe the error might be in the parsing above, but cannot find it.
C3 Bar Graph x-axis labels are too congested
I have created a Bar graph using C3 JS plugin, The graph is working fine but the problem is with the x-axis labels looks too congested like as shown below Working JSFiddle My Code is as given below var chart = c3.generate({ bindto: "#chart", data: { x : 'x', columns: [ ['x', "2016-04-01","2016-04-08","2016-04-15","2016-04-22","2016-04-29","2016-05-06","2016-05-13","2016-05-20","2016-05-27","2016-06-03","2016-06-10","2016-06-17","2016-06-24","2016-07-09","2016-07-10","2016-07-11","2016-07-12","2016-07-13","2016-07-15","2016-07-16","2016-07-17","2016-07-18","2016-07-19","2016-07-20","2016-07-21","2016-07-22","2016-07-23","2016-07-24","2016-07-25","2016-07-26","2016-07-27","2016-07-28","2016-07-29","2016-07-30","2016-07-31","2016-08-01","2016-08-02","2016-08-03","2016-08-04","2016-08-05","2016-08-06","2016-08-07","2016-08-08","2016-08-09","2016-08-10","2016-08-11","2016-08-12","2016-08-13","2016-08-14","2016-08-15","2016-08-16","2016-08-17","2016-08-18","2016-08-19","2016-08-20","2016-08-21","2016-08-22","2016-08-23","2016-08-24","2016-08-25","2016-08-26","2016-08-27","2016-08-28","2016-08-29","2016-08-30","2016-08-31","2016-09-01","2016-09-02","2016-09-03","2016-09-04","2016-09-05","2016-09-06","2016-09-07","2016-09-08","2016-09-09","2016-09-10","2016-09-11","2016-09-12","2016-09-13","2016-09-14","2016-09-15","2016-09-16","2016-09-17","2016-09-18","2016-09-19","2016-09-20","2016-09-21","2016-09-22","2016-09-23","2016-09-24","2016-09-25","2016-09-26","2016-09-27","2016-09-28","2016-09-29","2016-09-30","2016-10-01","2016-10-02","2016-10-03","2016-10-04","2016-10-05","2016-10-06","2016-10-07","2016-10-08","2016-10-09","2016-10-10","2016-10-11","2016-10-12","2016-10-13","2016-10-14","2016-10-15","2016-10-16","2016-10-17","2016-10-18","2016-10-19","2016-10-20","2016-10-21","2016-10-22","2016-10-23","2016-10-24","2016-10-25","2016-10-26","2016-10-27","2016-10-28","2016-10-29","2016-10-30","2016-10-31","2016-11-01","2016-11-02","2016-11-03","2016-11-04","2016-11-09"], ['pv1', 2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2500,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2696,2748,2748,2694,2694,2694,2694,2694,2694,2694,2668,2668,2668,2668,2576,2572,2572,3043,3084,3084,3084,3084,3084,3156,3521,3521,3550,3542,3542,3573,3580,3629,3579,3584,3542,2757,2791,2696,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3415,3414,3414,3414,3414,3414,3414,3414,3414,3414,3414,3414,3414,3414,3369,3376,3371,3373,3371,3379,3363,3373,3347,3348,3382,3402,3410,3434,2579,2579,2369], ['pv2', 1750,1750,1750,1750,1825,1850,1975,2150,2375,2425,2475,2500,2500,2087,2087,2087,2087,2091,2087,1767,1767,1767,1633,1498,1498,1642,1637,1633,1609,1841,1713,1702,1862,1888,1888,1888,1949,1976,1977,2014,2014,2014,1946,1966,1973,2224,2252,2318,2318,2318,2327,2373,2513,2535,2543,2534,2539,2823,2849,2990,3142,3142,3108,2513,2687,2678,2856,2860,2861,2862,2866,2869,2870,2875,2874,2874,2874,2879,2885,2886,2883,2889,2896,2895,2899,2903,2909,2911,2913,2913,2913,2916,2922,2933,2937,2943,2942,2943,2947,1811,1826,1837,1840,1840,1841,1843,1511,1854,1853,1851,1852,1853,1849,1852,1874,1857,1883,1886,1888,1904,1903,1924,1947,2060,2068,2068,2082,1582,1344,836,839,788] ], type: 'bar' }, axis: { x: { type: 'category', tick: { rotate: -60, multiline: false }, height: 130 } } }); Can anyone please tell me some solution for this What I did to solve it I have used timeseries type instead of category type, after that the label issue got resolved but the graph was been plottted with more white spaces for the month of march like as shown below Working JSFiddle
You can use c3's tick count setting for this, so here we say 20 labels. However there is an added gotcha in that ticks that now resolve to a fractional category value won't show - i.e. the 2nd equally spaced tick out of 20 may be the 2.6667th element in the x category axis - so you need to have a little format function that adjusts for this, otherwise you just get the end and start labels. (Or you could figure out a tick count that divides into your data count + 1 as a whole number.) tick: { format: function (x) { var cats = this.api.categories(); return cats[Math.round(x)]; }, count: 20, rotate: -60, multiline: false }, http://jsfiddle.net/fz0t10yb/7/
One of the possible solution could be to use x-axis labels at required indexes only & leaving others blank. ['x', "2016-04-01","","","","2016-04-29","","","",...] ['pv1', 2500,2500,2500,2500,2500,2500,2500,2500,...] ['pv2', 1750,1750,1750,1750,1825,1850,1975,2150,...] You can position labels so that it would capture the date and at same time it looks good also.
How to draw a pie with logarithmic scale in HighCharts?
I need to draw a pie (or a donut, or an half donut, I think that it's the same process) in Highcharts. The problem is that the data are heavily biased, i.e. one slice has size = 3 and the second one has size = 1000. the final result is a pie with a giant slice and a slice almost invisible. Is there a way to print the size of the slices in a logarithmic way (as for the axis charts)?
A pie chart does not use axis, so setting its type to logarithmic will not work. What you can do is transforming your data and preserving the "real" value so it can be displayed in a tooltip, data labels, etc. var data = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512], logData = data.map(function (value) { return { y: Math.log(value) / Math.LN10, realY: value // store a pure value }; }); // later in chart options tooltip: { pointFormat: 'x = {point.x}, y = {point.realY}' // access the pure value in a tooltip } Comparison pie charts with transformed data and with "pure" data: http://jsfiddle.net/rz9899j8/
c3 scaling similar to d3?
I have used c3 to make some graphs and am impressed with its ease of use. However, I'm not sure if it is possible to a 3 value scaling like you can in d3 like the code below: var yScale= d3.scale.linear() .domain([0,100,500]) .range([height, height - 20, 0]); so then i can make my graphs scaled mainly for values below 100 since this is where the majority of values will be and I don't want the bars scale to be skewed by values exceeding 100. Is it possible to do something like this in c3? or do I need to use d3 to get this sort of scaling? Thanks
You could use a scale to map the value and scale.invert to get all the labels. For example... var myScale = d3.scale.linear().domain([0, 5, 50]).range([0, 40, 50]); var chart = c3.generate({ data: { columns: [ ['A', 3, 2, 1, 4, 1.5, 42.5].map(function (value, index) { return index ? myScale(value) : value; })], type: 'spline' }, tooltip: { format: { value: function (value) { return parseFloat(myScale.invert(value).toFixed(5)); } } }, axis: { y: { tick: { format: function (d) { return myScale.invert(d) } } } } }); The parseFloat and toFixed is to get rid of precision problems when you convert back and forth. Fiddle - http://jsfiddle.net/rujx39fw/ There is a similar issue on the c3 github at https://github.com/masayuki0812/c3/issues/252. It was closed with a similar workaround (there is a linked question too - that was closed by referencing this workaround) There is also a related question you may be interested in at https://github.com/masayuki0812/c3/issues/971 that suggests another option, if you are feeling adventurous.
How to duplicate Y Axis on JQuery Flot
I'm being able to use JQuery Flot, and it's a very nice tool. However, I could not find a GOOD solution for my problem. I want to duplicate Y axis, so I can display 1 on the left and 1 on the right, so the users, when comparing data from the rightmost side of the chart, won't have to scroll through the leftmost side of the chart. I'm assuming they will be accessing it through a smartphone. JQuery Flot allows multiple axis, but for each axis, I would need a different set of data, as in this example: http://people.iola.dk/olau/flot/examples/multiple-axes.html But I don't want to duplicate the data. Can't I just 'tell' Flot to duplicate the yaxis using the same set of data?
You can use the hooks functionality to force flot to show the second yaxis even though it has no data series assigned to it: // hook function to mark axis as "used" // and assign min/max from left axis pOff = function(plot, offset){ plot.getYAxes()[1].used = true; plot.getYAxes()[1].datamin = plot.getYAxes()[0].datamin; plot.getYAxes()[1].datamax = plot.getYAxes()[0].datamax; } $.plot("#placeholder2", [ { data: d2 } ], { hooks: { processOffset: [pOff] }, yaxes: [ {}, {position: 'right'} // add second axis ] }); Depending on how your axis is configured though, this might be messy. You'll have to steal parameters from the left axis to get it to work (as I've done above with datamin/datamax). If it was my code, I'd go with your duplicate data approach. You aren't really duplicating anything, just assigned the same array to two series. I'd then configure the 2nd series to simply not draw. var d2 = [[0, 3], [4, 8], [8, 5], [9, 13]]; // use the same data but toggle off the lines... $.plot("#placeholder", [ { data: d2 }, {data: d2, yaxis: 2, lines: {show: false}} ], { yaxes: [ {}, {position: 'right'} ] }); Here's a fiddle demonstrating the two approaches.