Using the Highstock (Highcharts) library,
I'm wondering, how do I combine A) adding flags as in here (or see fig.1) with B) dynamically updating data, using the addPoint function (ex: series.addPoint([x, y], true, true) see here). There doesn't seem to be a facility for it in the addPoint function.
series : [{
name : 'USD to EUR',
data : data,
id : 'dataseries'
},
{
type : 'flags',
data : [{
x : Date.UTC(2011, 3, 25),
title : 'H',
text : 'Euro Contained by Channel Resistance'
}],
onSeries : 'dataseries',
shape : 'circlepin',
width : 16
}]
fig.1
I have taken a look at this SO question. But is seems to add a flag on an existing dataset. Can I add a data point, and an associated flag at the same time?
Any help's appreciated.
Thanks
=== EDIT ===>
#Sebastian-Bochan
Thanks for responding, and for the working example. However, for some reason, addPoint is not working for my setup.
So take a look at this jsfiddle. What I do is i) setup an initial graph with a call to (chart-fill …), then ii) call (chart-increment …) which adds 1 point, then immediately tries to add 1 flag on that point. The part that isn't working is (-> ($ selector) (.highcharts) (.-series) (nth 9) (.addPoint { :x 1234567 :title "fubar"} true false)). This isn't adding the flag as I'd expect.
I have 11 Series overlaid on top of 5 graphs. This includes one series of type "flag". I thought, maybe with so many Series, there was a problem referencing one of them. But if I look into my series, I can see that the flag is indeed the 9th one.
I'm also using Clojurescript code. But I don't think that's an issue, as the graph otherwise renders properly. Any ideas?
Please take look at example: http://jsfiddle.net/pGpU7/2/
chart.series[0].addPoint([Date.UTC(2012, 1, 5),2],false);
chart.series[1].addPoint({
x: Date.UTC(2012, 1, 3),
title: 'On series'
},true);
Related
I must have lost my google-fu but I can't figure it out.
I create a graph in dygraphs by passing data like :
[
x, [min,avg,max],val1
]
and labels :
["Date","the_bar_value","Val1"]
and {customBars:true} in the options.
Nothing shows.
Is there a way to specify the customBar option by series ?
If not how is one supposed to do what I want to do ? I would like to avoid the solution which is to pass the same value 3 times for each date to the series I want to show as single line.
Here is a jsFiddle that shows the issue : on the second graph there, I would like to show the customBars on the first line but also show the second line.
The option customBars:true can't be set per series, only globally for all series.
You can enable it and set your data either
[
x, [min, avg, max], [val1, val1, val1]
]
or
[
x, [min, avg, max], [null, val1, null]
]
My Y-Axis array :
["1","2","3","4","5","6","7","8","9","10","11","12","13","14","15","16","17","18","19","20","21","22","23","24"]
The chart doesn't show all number, it only shows 1, 3, 5, and so on. 2, 4, 6 is getting skipped. How do I force Highcharts to show all labels?
JFiddle
What you want is to set the label.step to `:
labels: {
step: 1
}
This forces highcharts to render a label for every category/tick.
The default behavior is to remove ticks if they are too close to one another. You can force all ticks by using a tickPositioner, rather than specifying categories:
yAxis: {
title: null,
tickPositioner: function () {
return [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24];
}
},
Note the quotes were removed, i.e. the returned array contains numbers (rather than string literals as was the case in the original question). Not sure why it doesn't work with string literals.
See also http://api.highcharts.com/highcharts#yAxis.tickPositioner
I'm new to JavaScript and HighCharts. I'm sure this is a very simple question, but I got lost.
I want to create a scatter chart with three lines. I need to read data from a text file, and the file looks like this:
x y1 y2 y3
1.02 1.00 6.70 8.19
2.04 1.00 13.30 8.19
3.06 1.00 13.50 8.19
4.08 1.00 9.60 8.19
5.10 1.00 14.60 8.19
6.12 1.00 19.20 8.57
So I need to plot three line with (x and y1), (x and y2), (x and y3)
And this is my HighCharts code:
<script type="text/javascript">
$(document).ready(function() {
var chart1 = new Highcharts.Chart(options);
});
var options = {
chart: {
renderTo: 'container',
type: 'scatter',
zoomType: 'xy'
},
title: {
text: 'Demo'
},
xAxis: {
title: {
enabled: true,
text: 'Time, ns'
},
startOnTick: true,
endOnTick: true,
showLastLabel: true
},
yAxis: {
title: {
text: 'Value'
}
},
series: []
};
$.get('///plot.txt', function(data) {
var lines = data.toString().split('\n');
$.each(lines, function(lineNo, line) {
var item = line.split()});
options.series[0].data[0].push(parseFloat(item[0]));
options.series[0].data[1].push(parseFloat(item[1]));
options.series[1].data[0].push(parseFloat(item[0]));
options.series[1].data[1].push(parseFloat(item[2]));
options.series[2].data[0].push(parseFloat(item[0]));
options.series[2].data[1].push(parseFloat(item[3]));
}, 'text')
var chart1 = new Highcharts.Chart(options);
</script>
I feel I messed up the entire code. I'm sorry but I never wrote JavaScript before. Any help would be hugely appreciated. Thank you in advance.
that's what you want to get : http://jsfiddle.net/z28vy/
Now a few comments
Read doc
You have to look at the HighChart documentation that is quite good, with live example on jsfiddle. Some are quite close to your use case (displaying data from data got with an AJAX call.)
What's peculiar in your need is to get raw text data, which force you into annoying parsing stuff.
Understand what you are doing
Even if your code could end up working, it looks like you are messing a bit with the sync/async story of your javascript. If you are a beginer that's a lot of things to learn at once. Not to mention you are trying to stick to jQuery style with anonymous functions...
Indent !
First thing, I do not know if it is just your post on here, or if you actually write code like that, but indent it properly ! It will show you a lot of problems at a glance. Especially when you are writing enclosed code (for example the success callback function of your ajax call.)
Arrays
Then, just a bit of logic : you have to know that although dynamic, arrays in javascript cannot have random access (read or write) on any non assigned slot. So when you are doing
options.series[0].data[0].push(parseFloat(item[0]));
you should have previously set options.series[0] which you didn't since your options object defines series as an empty array:
series: []
You can do that at the time of your ajax success method, or statically at options definition, depending on the flexibility you need in the number of series accross your use. I prefer you stay simple at first and do :
series: [{
name: 'Serie 1',
data: []
},{
name: 'Serie 2',
data: []
},{
name: 'Serie 3',
data: []
}]
Like that you can access each of your 3 series like you did... well except that you have the same problem with data[0] which does not exist neither for the same reason. Anyway do not bother much because...
First use your API as it goes
The way you add points to your series is far too complex anyway. series has an addPoint() method, just use it ! So instead of
options.series[0].data[0].push(parseFloat(item[0]));
options.series[0].data[1].push(parseFloat(item[1]));
Just do
options.series[0].addPoint([parseFloat(item[0]), parseFloat(item[1])]);
it's already easier to read :)
jQuery is not magical, it is just logical
Now the problem you have is your use of jquery $.each() I do not know if you just did not understand it or if you started to use it, then decided to hard-write your data handling to move on.
$.each(lines, function(lineNo, line) {
var item = line.split()});
options.series[0].data[0].push(parseFloat(item[0]));
options.series[0].data[1].push(parseFloat(item[1]));
As you will clearly see if you start indenting and separate things, you do nothing more than splitting each line for no purpose there.
Just use what you get with your split. If we say we are putting the current serie number in serieIdx :
$.each(lines, function(lineNo, line) {
var item = line.split(' ');
if(item.length==4 && !isNaN(parseFloat(item[0]))) { // skip unwanted line such as header or empty line
chart1.series[serieIdx].addPoint([parseFloat(item[0]), parseFloat(item[serieIdx+1])], false);
}
});
That's it. You just to have to iterate through your 3 series and you are good to go.
A side note about addPoint of serie in HighCharts
Be careful that if you call addPoint with invalid data (such as an array of anything instead of numbers) there is no visible error raised, but it breaks something anyway. In my case, before I added the test
if(item.length==4...
And since I had also at first a '\n' at the end of the last line, the upper split gave me one last empty string, which obviously ended up as en empty items array after the inner split. Which triggered an addPoint([NaN, NaN]) that purely made the lines between dots disappear for the whole graph. Be careful to that !
About the jsfiddle sample
jsfiddle obviously does not allow AJAX get but provide a trick instead : POST data in a json that jsfiddle server will resend back in the answer after the given delay (in my example I put 3 seconds.)
http://jsfiddle.net/z28vy/
I haven't read previous answer, since is pretty long, however I always advice to read tutorial from Highcharts: http://www.highcharts.com/docs/working-with-data/preprocessing-data-from-a-file-csv-xml-json
While generating a track with the help of dygraph library, I have set the legend: always (this display the legend with series name present on that particular track even without mouseover). But when I move to certain graph, the legend changes and shows the value of each series at that particular mouse pointer. I don't want the legend to change and it should just show the series name and not the values. I am using javascript to implement my app. Any way to do the same?
One trick that might be good enough is to supply a custom valueFormatter function for each axis which simply returns an empty string:
axes: {x: {valueFormatter: function (x) {return ''}},
y: {valueFormatter: function (y) {return ''}},
y2: {valueFormatter: function (y2) {return ''}}
}
This prevents the values from being shown, but still switches between line samples and ':' characters depending on the position of the mouse.
At the moment there's no easy way to do this. Your best bets are to either generate the legend yourself using dygraphs' API or to throw a transparent div over your chart which captures all the mouse events.
Well! it might be not a good way but I have found an alternative to do it. Declared a new boolean variable in dygraph.js which checks whether user wish to see x-y values on legend. Using this variable in function generateLegendHTML (defined in legend.js), i have made the control to always go in the first if loop. This makes the dygraph to always show static legend.
You can do the following -
Step 0 - Add a few necessary options and tags -
labelsDiv: document.getElementById("labels"),// in the dygraph options
<div id="labels"></div> <!-- Add this somewhere in your HTML-->
Step 1 - Declare a variable -
var defaultLabelHTML = undefined;
Step 2 - Use drawCallback option -
drawCallback: function(dygraph, is_initial){
if (is_initial)
{
defaultLabelHTML = document.getElementById("labels").innerHTML;
}
},
Step 3 - Use highlightCallback option -
function(e, x, pts, row)
{
document.getElementById("labels").innerHTML = defaultLabelHTML;
}
I've added zooming out to a highcharts application I'm working on, but I've noticed some really bad behavior when zooming back in. If the zoom window includes an area outside the data range of the graph, the resulting zoom level incorrectly ignores that area. Sorry if this is a bit unclear, I'm not certain how to explain it best.
Here's a fiddle showcasing the problem: http://jsfiddle.net/rnAEB/
$(function () {
chart = new Highcharts.Chart({
chart: {
renderTo: "container",
zoomType: "xy"
},
title: {
text: 'Try zooming outside the data range'
},
tooltip: {
headerFormat: '<b>{series.name}</b><br />',
pointFormat: 'x = {point.x}, y = {point.y}'
},
series: [{
data: [1, 2, 4, 8, 16, 32, 64, 128, 256, 512],
pointStart: 1
}]
});
chart.xAxis[0].setExtremes(-10, 20, true);
chart.yAxis[0].setExtremes(-500, 1000, true);
});
Try zooming in to a rectangle from (5, 1000) to (10, -500). The resulting zoom area is around (5, 600) to (10, -100)... this is clearly not what the zoom request asked for.
I've tried hooking into the setExtremes event for the axis, and the bounds when this issue occurs are undefined. I can't figure out how to 'hijack' the setExtremes request to fix the undefined value however. I also cannot recursively call setExtremes from within that event.
Is this intended behavior? I can see why you would only want to zoom where data was - but I'd really like the freedom to zoom to locations where there isn't data for the sake of perspective.
It appears this is intended behavior. Poking around in the highcharts source led me to the Highcharts.Axis.prototype.zoom method which has the following conditional:
// Prevent pinch zooming out of range
if (!this.allowZoomOutside) {
if (newMin <= this.dataMin) {
newMin = UNDEFINED;
}
if (newMax >= this.dataMax) {
newMax = UNDEFINED;
}
}
I've tried setting the 'allowZoomOutside' option using the configuration options, but unfortunately there's no undocumented hook for it that I can figure out (or find in the source).
According to comments in the source, the zoom method is intended to be overridable (they mention stock charts specifically), and I'd rather avoid trying to manually set the 'allowZoomOutside' from outside and hoping it doesn't get wiped by some internal mechanism. Overriding with a version lacking this check works like a charm. Here's an updated fiddle as an example: http://jsfiddle.net/7XHMz/
If anyone can figure out how to properly set the 'allowZoomOutside' option though that's probably going to be the nicest way to do this.
It is related with fact that "started chart" is generated in the own form (min/max values in both axss), then you call setExtrems, which is only event, called one time. So chart cannot "remember" new extremes. So you can define min/max values with numbers form setExtremes, and about events.
http://jsfiddle.net/rnAEB/1/
xAxis:{
min:-10,
max:20
},
yAxis:{
min:-500,
max:1000
},