I see how to make stacked bar and column charts in HighCharts. However, I want to be able to put an arrow outside the bar/column to indicate a point in it, similar to this: http://support.sas.com/kb/26/addl/fusion_26104_4_slider_alert.gif
Is this possible in HighCharts? I can't find an example of it.
Of course it is possible.
There are two ways in which you can achieve this.
Use a sctterplot.
In this Approach you build a addl scatterchart series . the value of the scatterchart series will help you to position it like in here http://jsfiddle.net/p2MF6/
{
name: 'indicator',
data: [5],
type: 'scatter',
marker:{
//here you can have your url
symbol: 'circle',
}
}
render a image.
using chart.rendere.image(src,x,y,length,height) you can render any image on the chart.
finding the coordinates is not a big deal.
hope this is what you are looking for
Example for you: http://jsbin.com/oyudan/276/edit
Add triangle and function to change scatter position (if you want to add line to marker, just change returned path):
var chart;
$.extend(Highcharts.Renderer.prototype.symbols, {
'triangle-left': function (a, b, c, d) {
return ["M", a, b + d, "L", a, b, a + c / 2, b + d / 2, "Z"];
}
});
Highcharts.updateMarketMarkers = function (chart,action) {
/* get category width */
var barWidth = chart.series[0].data[0].pointWidth / 2;
for(var i = 0; i < chart.series[2].data.length; i++){
var p = chart.series[2].data[i];
if(p.graphic){
p.graphic[action]({
x: p.plotX - barWidth - p.graphic.r
});
}
}
};
Now add that function to chart, when should be invoked:
chart: {
renderTo: 'container',
type: 'column',
showAxes: false,
events: {
load: function () {
Highcharts.updateMarketMarkers(this, 'attr');
},
redraw: function () {
Highcharts.updateMarketMarkers(this,'attr');
}
}
},
plotOptions: {
series: {
events: {
hide: function(e) {
Highcharts.updateMarketMarkers(this.chart,'animate');
},
show: function() {
Highcharts.updateMarketMarkers(this.chart,'animate');
}
}
},
}
I would use the scatter series approach, as answered above, if you really need a symbol there.
You can also draw a plotLine:
http://api.highcharts.com/highcharts#yAxis.plotLines
This will not include an arrow, of course, but you can draw the line and label in this manner, and IMO the arrow is really not necessary at that point. FWIW
Related
I'm trying to draw a stacked (area) line chart using C3.
My code, as it stands, allows me to create a line chart without stacking :
var chart = c3.generate({
data: {
x: 'x',
url: 'GeneratedData.csv',
type: 'area',
/* groups: [ ['data1', 'data2'] ] */
},
axis : {
x : {
type : 'timeseries',
tick : {
format : "%y-%m-%d"
}
}
}
});
My problem is that the data is generated in such a way that I do not know the name of the columns in advance, so I cannot set their type or group them
(hence the comments around groups: [ ['data1', 'data2'] ])
My CSV looks something like this :
x,LT62Ag,5NwafDw,Pac0dA
2017-01-22,85797,145417,626803
2017-01-23,71837,105246,440776
2017-01-24,77650,108834,442359
...
2017-03-31,87359,102618,467113
How should I proceed to create the groups from the dynamic data to stack the charts ?
You could try adding this to your chart declaration, it'll pull out the names of the data series (apart from x) and turn them into one big group:
onrendered: function () {
var seriesNames = this.data.targets.map (function (d) {
return d.id;
}).filter (function (sname) {
return sname !== "x";
});
this.api.groups ([seriesNames]);
},
Ideally it should be done with the 'oninit' declaration rather than the groups reset on every rendering, but there seems to be some sort of bug that makes the bars go 1 pixel wide when you do that...
I guess a flag that decides whether the groups have already been set could be employed though...
https://jsfiddle.net/1bb60dd9/
I am using the Bubbles plugin with the Flot charting library for JQuery. The data I have is dynamic and can be quite varied within the X, Y, and Z values. The main issue I am having is the size of the bubbles. If the X and Y values are somewhat close to each other but the Z value is much larger the bubble simply takes over the chart. Setting the axis min and max for the X and Y axes helps a bit but not in every case. I have tried to look for other options and settings but did not find anything useful. Is there any type of way to control the size of the bubble?
For instance Flex used to automatically create bubble sizes relative to the screen and axes where Flot seems to always set the bubble size to the same scale as the X and Y values. I have included just a sample of data. I would like to continue to use Flot as the plugin because I have many other chart types in my application and would like to use the same code base. However if there is another plugin that would be better I am open to ideas. Thanks!
https://jsfiddle.net/llamajuana/zd4hd7rb/
var d1 = [[30,339,139856], [30, 445,239823], [30,1506,127331]];
var options = {
series: {
//color: '#CCC',
color: function(x, y, value) {
var red = 55 + value * 10;
return 'rgba('+red+',50,50,1)';
},
bubbles: {
active: true,
show: true,
fill: true,
linewidth: 0,
bubblelabel: {
show: true
},
highlight: {
show: true,
opacity: 0.3
}
}
},
grid:{
hoverable: true,
clickable: true
},
tooltip: {
show: true,
content: "x: %x | y: %y | value: %ct"
}
};
var p4 = $.plot( $("#plot"), [d1], options );
You could try logarithmic scaling.
For the x- and y-axis you can do this using the transform property in the axis options or changing the data before drawing the plot.
For the bubbles you have to do this by hand, either by changing the data before drawing or by replacing the drawbubble function of the bubbles plugin (see the User draw example here).
See this fiddle for the full example. Changes from your fiddle:
1) You could change this directly in the bubbles plugin, if you wanted.
// index of bubbles plugin is dynamic, you better search for it
var defaultBubbles = $.plot.plugins[1].options.series.bubbles.drawbubble;
var logBubbles = function(ctx, serie, x, y, v, r, c, overlay){
defaultBubbles(ctx, serie, x, y, v, Math.log(r), c, overlay);
}
2) In the series options:
xaxis: {
transform: function (v) {
return Math.log(v);
},
inverseTransform: function (v) {
return Math.exp(v);
}
},
yaxis: {
transform: function (v) {
return Math.log(v);
},
inverseTransform: function (v) {
return Math.exp(v);
}
},
3) In the radiusAtPoint() function in the bubbles plugin:
// added Math.log function here too
return parseInt(series.yaxis.scale * Math.log(series.data[radius_index][2]) / 2, 0);
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.
I know the question was already asked before but I am very new to Dygraphs and struggling to find the answer.
I have the following datastructure in javascript:
x , Label1, Label2, label3.... label1_2, label1_3, etc...
new Date(...), 1.23,1.45,.... , .... , ....,
new Date(...), null, null, ......., 1.23,1.434
new Date(....), 1.4656, 1.6765.......,null, null,null
The whole idea is to have a plot on which a certain part of the line is dashed and the remaining part is not. I initially have 7 time series, I splitted each time serie in two (the dashed part and the non-dashed part), now I would like to highlight the whole time series ( so 2 distinct series in terms of Dygraphs the dashed serie, and the non-dashed that I splitted in two) when I pass the mouse over either the dashed region either the non dashed region.
I ve seen that people were stipulating using HihlightCallback but I am struggling to put it in practice.
What I have for the moment:
data =[new Date(), ..,..,.,,.,,.]
labels= {'A','B', ..... }
series= {'A': {strokePattern: [10, 20] }, 'B': .......}
g = new Dygraph( demo, data, {width: 1000,height: 700,labelsDivStyles: { 'textAlign': 'right' }, labels: labels,series:series, visibility: visibility, gridLineColor: 'red', gridLinePattern: [5,5], highlightCircleSize: 2,strokeWidth: 1, strokeBorderWidth: 1,highlightSeriesOpts: { strokeWidth: 3,strokeBorderWidth: 1,highlightCircleSize: 5}});
I believe my structure should be as follows:
g.updateOptions({ highlightCallback: function(event, x, points, row, seriesName) {
//1)here I need to somehow reference the other series whose label is situated N columns from the highlighted serie ( I can also reference it by its name).
// 2) Hilight the other serie
}});
I tried many different syntaxe but nothing seems to be working properly.
Could anyone please help me on this I am lost.
Here is what I would like to achieve :
http://www.google.co.uk/publicdata/explore?ds=k3s92bru78li6_#!ctype=l&strail=false&bcs=d&nselm=h&met_y=ggxwdn_ngdp&scale_y=lin&ind_y=false&rdim=world&idim=world:Earth&idim=country:AR:DZ:AU:AZ&ifdim=world&tstart=343382400000&tend=1574064000000&hl=en_US&dl=en_US&ind=false
Thanks a lot!
If I understand correctly, you've set up something like this: jsbin
Typically you style the highlighted series using highlightSeriesOpts, but that comes with the assumption that there's only a single highlighted series.
If you want to model the data this way (as separate series for actual & projected), you'll need to style the series yourself using highlightCallback. There are a few gross things about this which I'll mention below, but this is doable.
Demo: jsbin
g = new Dygraph(document.getElementById("graph"),
"X,Y,Y projected,Z,Z projected\n" +
"2006,0,,3,\n" +
"2008,2,,6,\n" +
"2010,4,,8,\n" +
"2012,6,,9,\n" +
"2014,8,8,9,9\n" +
"2016,,10,,8\n" +
"2018,,12,,6\n" +
"2020,,14,,3\n",
{
colors: ['blue', 'blue', 'red', 'red'],
series: {
'Y': { },
'Y projected': { strokePattern: [5, 5] },
'Z': { },
'Z projected': { strokePattern: [5, 5] }
},
highlightCallback: function(_, _, _, row, seriesName) {
update(seriesName, row);
},
unhighlightCallback: function() {
update();
},
highlightSeriesOpts: {},
highlightSeriesBackgroundAlpha: 1.0
});
function update(selectedSeries, row) {
var newOptions = {};
var seriesNames = g.getLabels().slice(1);
seriesNames.forEach(function(label) {
newOptions[label] = {strokeWidth: 1};
});
if (selectedSeries == 'Y' || selectedSeries == 'Y projected') {
newOptions['Y'] = newOptions['Y projected'] = {strokeWidth: 3};
} else if (selectedSeries == 'Z' || selectedSeries == 'Z projected') {
newOptions['Z'] = newOptions['Z projected'] = {strokeWidth: 3};
}
g.updateOptions({series: newOptions});
if (typeof(row) !== 'undefined') {
g.setSelection(row);
}
}
The idea is that you call updateOptions in your highlightCallback, setting the strokeWidth property for each series according to whether it (or its paired series) is selected.
There are a few gross things about this:
You have to set highlightSeriesOpts for the seriesName parameter to be passed to highlightCallback.
You need to counteract the default fading behavior of highlightSeriesOpts by setting highlightSeriesBackgroundAlpha.
Calling updateOptions clears the selection, so you have to call setSelection explicitly to re-select.
If you're willing to model the measured & projected values as a single series, then you can accomplish this more cleanly by writing a custom plotter which switches from solid to dashed lines at some point.
Here's a demo: jsbin
g = new Dygraph(document.getElementById("graph"),
"X,Y,Z\n" +
"2004,0,3\n" +
"2006,2,6\n" +
"2008,4,8\n" +
"2010,6,9\n" +
"2012,8,9\n" +
"2014,10,8\n" +
"2016,12,6\n" +
"2018,14,3\n",
{
plotter: function(e) {
var ctx = e.drawingContext;
ctx.beginPath();
ctx.moveTo(e.points[0].canvasx, e.points[0].canvasy);
for (var i = 1; i < e.points.length; i++) {
var p = e.points[i];
ctx.lineTo(p.canvasx, p.canvasy);
if (p.xval == 2014) {
ctx.stroke();
ctx.beginPath();
ctx.moveTo(p.canvasx, p.canvasy);
ctx.setLineDash([5]);
}
}
ctx.stroke();
ctx.setLineDash([]);
},
highlightSeriesOpts: {
strokeWidth: 3
}
});
Because your data is a single series, you no longer need to highlight multiple series simultaneously and hence you can use highlightSeriesOpts.
I use Flot library for charting, I need to present a bars chart and there one special series which should be distinguished, giving it a certain color would be best option.
I've already did so in previous charts giving the color parameter to the series pushed to the data but it's not working here.
Bar for 21 should be in red and it's not.
First I tried the usual:
series.push({
color: 'anyHexColorCode',
data: [[parseFloat(k).toFixed(9).toString(),respuesta['puntos'][k]]]
})
In a loop I checked for the wished value and gave that a different color, same as I also do in the current function I got shown below.
This is how I'm sending to plot:
function plotInterpolacion(respuesta) {
clearCharts()
var series = []
var colorsList = ['#8B0000','#FFA614']
alert("La aproximación para x=" + $("#a").val() + " es igual a: " + respuesta['aproximacion'])
var xs = Object.keys(respuesta['puntos']).sort().forEach(function (k,i) {
if (k == respuesta['aproximacion']) {
series.push({
color: 0,
data: [[parseFloat(k).toFixed(9).toString(),respuesta['puntos'][k]]]
})
}
else {
series.push({
color: 1,
data: [[parseFloat(k).toFixed(9).toString(),respuesta['puntos'][k]]]
})
}
})
$.plot($("#bars"), series, {
bars: {
show:true,
align: "center",
barWidth: 0.6
},
xaxis: {
mode: "categories",
tickLength:0
},
colors: colorsList
})
}
In that example, bar for 21 should be in red.
This is what respuesta['puntos'] looks like:
"puntos": {
"18.0": 79.0,
"17.8": 72.0,
"21.0": 184.0000000000009
}
I have added jquery.colorhelpers.js flot plugin but it didn't make any difference.
The barWidth is expressed in axis units. So with a barWidth of 0.5, and only 0.2 x-units between the first and second bars, they will of course overlap.
A series can have only one color, and all of your bars are in the same series. If you want them to have different colors, split them into separate series.
Use the array directly when you are giving the color to data set? Like this:
color:colorsList[0]
http://jsfiddle.net/Margo/ZRkJN/4/