I am looking at a simple Rickshaw chart with data from a JSON file.
d3.json(data, function(error, json) {
var graph = new Rickshaw.Graph( {
element: document.getElementById(chart_id),
renderer: 'line',
series: [
{name: 'myseries',
data: json[0].data}
]
})
graph.render();
});
I would like to access the graph after it has been rendered. Since the graph is created within a callback function I cannot simply return the handle. Also document.getElementById(chart_id) does not have a chart attribute.
My goal is to, for example, allow users to specify a certain range for multiple charts at the same time (e.g. last 5 years) without having to adjust the RangeSlider for each one of them. With access to the chart I could then do
new_rng = [new_min,new_max]
graph.window.xMin = new_rng[0]
graph.window.xMax = new_rng[1]
$('#' + slider_id).slider('option', 'values',new_rng)
Any ideas?
I think this is a similar problem to the one I encountered with a xively feed where the data is not returned when the graph is rendered. Here's my post.
Multiple calls to xively.feed.history()
Related
I'm using Echarts v5.2.2 (in an Angular project, with ngx-echarts) to render a line chart using multiple series. I have a listener for the 'highlight' event. This event is giving me an object with a batch of seriesIndex and dataIndex but it doesn't provide the color of each series.
Is there a way to get the colors that were dynamically assigned by echarts?
This is what I'm trying to implement:
Listen when the mouse pointer snapped into a graph line point.
Doing this via this.chartInstance.on('highlight', this.handleShowTip);.
Use the batch of seriesIndex & dataIndex where the mouse pointer snapped to render a table using color, x & y value as columns (the table is placed outside the graph.
I understand that I could use the tooltip's formatter option with a callback function which will provide the series colors in its arguments... and I could broadcast these arguments outside my graph component to render what I need anywhere I want, but this does not feel correct (a formatter is aimed to return HTML or string) and I wonder if there's a better way to get the generated series colors.
Thank you!
The Echarts uses a built-in palette based on the theme. The easiest way to get a set of colors is this:
myChart.getOption().color
To get the colors that are mapped to the series, you can do the following:
myChart.getModel().getSeries().map(s => {
return {
seriesIndex: s.seriesIndex,
seriesColor: myChart.getVisual({
seriesIndex: s.seriesIndex
}, 'color')
}
})
And the result will be something like this:
[
{
"seriesIndex":0,
"seriesColor":"#5470c6"
},
{
"seriesIndex":1,
"seriesColor":"#91cc75"
},
{
"seriesIndex":2,
"seriesColor":"#fac858"
},
{
"seriesIndex":3,
"seriesColor":"#ee6666"
},
{
"seriesIndex":4,
"seriesColor":"#73c0de"
}
]
I have the following error: TypeError: Cannot read property 'skip' of undefined.
I have a method which builds a chart in my app. That happens OnInit
var ctx = document.getElementById("myChart");
var chartInstance = new Chart(ctx);
var myChart = new Chart(ctx, {
type: 'line',
data: {
labels :this.equity,
datasets: [{
data: this.equity
}]
}
});
}
this.equity is an array of values that I calculate on the client side using data from the server. That is the list that I filter later on.
Everything builds smoothly untill I start filtering. The chart is built upon values in a list. I have coded a filter that filters the list with various options. At the end of each filtering I call the method above again to rebuild the chart.
Now here is where strange things start to happen. The chart rebuilds smoothly. I filter many times with different options and then at some point boom I get this error! It doesn't occur at some particular moment when I'm pressing on the filter, it just occurs.
I think it is because every time I create a new chart object and supply it with new values. The variable for the values is the same as for the old object and that causes an error because at some point Angular checks out the old object and it has already got a new list of values which doesn't match the old list.
Has this hapened to anyone? Does anybody now how do I null out the old chart object at the point when I create a new chart object so this possibly solves? Thanks!
Try destroying the old chart instance before creating a new one, using the destroy() method.
...
if (myChart) myChart.destroy();
myChart = new Chart(ctx, {
type: 'line',
...
...
make sure the myChart variable is globally accessible
However, a better approach would be to update your chart using the update() method, when you add/update any data in your chart, instead of creating a new instance of chart everytime.
I am plotting a point graph and the graph should get update with new data for every 5 secs. Here min and max range are always fixed
Currently, when I get new data from server, I do merge the new data to the existing source.data and plotting the complete graph.
So, I dont want to redraw the complete data again and again. As the length of the source.data is increasing, performance is going down . So instead of redraw complete data, can I add only the new data to the existing graph
Please find the source code here
var source = [
{
data: [],
show: true,
label: "Constellation",
name: "Constellation",
color: "#0000FF",
points: {
show: true,
radius: 2,
fillColor: '#0000FF'
},
lines: {
show: false
}
}
]
var options = {...}
$.getJSON(URL , function(data) {
...
$.merge(source[0].data, new_data);
plotObj = $.plot("#placeholder", source, options);
}
Follow this steps:
plotObj.setData(newData);
plotObj.setupGrid(); //if you also need to update axis.
plotObj.draw(); //to redraw data
Another usefull method is getData(). With this method you can get the current data.
var data = plotObj.getData();
Your method of calling $.plot over and over should be avoided. It used to leak memory (not sure if it still does).
That said, #Luis is close, but let's put it all together. To add data to an existing plot do this:
var allData = plotObj.getData(); // allData is an array of series objects
allData[seriesIndex].data.push([newXPoint,newYPoint]);
plotObj.setData(allData);
plotObj.setupGrid(); // if axis have changed
plotObj.draw();
It should be noted that this does redraw the entire plot. This is unavoidable with HTML5 canvas. BUT flot draws extremely fast, you'll barely notice it.
I have inherited a project that is using Highcharts.
The previous dev used the .addSeries method to add all of the series to each chart that was being rendered. From what I've read of Highcharts, it seems like .addSeries is really for adding data dynamically.
The data that is being used to populate the charts are coming from an AJAX request. The old dev's approach was to get the data, render the chart, and then add a series using .addSeries. I was thinking that it might be better to update options.series and then pass the whole thing along to new Highcharts.Chart() for rendering, taking the .addSeries out of the equation.
However, since I'm new with Highcharts, I was hoping to get some feedback on what the better method would be.
You're on a good path, though your question suggests you may simply be looking for preference over a strict right/wrong answer.
From what I've seen, unless you have interactions on the page that would trigger a need to update your chart after it's been drawn, the benefit to using addSerie would be to add some visual flare. Using addSerie, your charts will visually draw themselves in front of the visitor - vs them already being drawn. (I believe HighCharts demo site has some good examples of this.)
I also recently inherited a HighCharts project and am generating a new Highcharts.Chart() using dynamic data by parsing the AJAXed data on the fly. The good news is that all of the charts still have nice visual flare (flare is important) since they don't draw until the AJAXed data is fully loaded. This snippet illustrates how I've been loading dynamic charts, parsing the JSON data on the fly:
$(function () {
var visitsChart;
$(document).ready( function() {
$.getJSON('/json-data-url', function(json){
var visitsChart = new Highcharts.Chart({
chart: {
renderTo: 'visitsContainer',
type: 'spline',
},
title: {
text: 'Test Widget'
},
series: [{
name: 'Speed',
data: [parseInt(json.visits)],
}],
...
});
});
});
});
I won't lie ... I had a few minutes of hair pulling when I got started but now I wish I had more time to work with Highcharts as it's quite fun once you get on a roll. Hope this helps.
I am using jqPlot javascript library ( http://www.jqplot.com/ ) for graphs and charts in one of my application.
In my application, there are 5-6 pages where this library is used. But I would like to discuss one particular case here.
On 1 of page, I am loading 3 charts. Data for these 3 charts is populated from database tables.
There is different set of queries for each chart. So, populated data for each chart is different too.
Once I have populated data, I have to process it, before providing its input to chart.
What is the problem then:
Problem that I am facing is it takes lots of time for page to render on browser (which is quiet obvious, as first it will form query, then fire that query against database tables, get the data, process on data and give to chart)
One of my friend suggested to implement following thing using ajax. I really liked his solution.
This is what I intend to do:
I would create a page, which will load all the required js/css files for jqPlot library.
There will be 3 sections on that page, where I would put some GIF images indicating that some process is going on (say ajax-loader.gif)
Once page is loaded, it will fire 3 ajax call, one at a time, to fetch each chart.
My Question Is how can I load chart from data received from ajax-call?
jqplot puts data and creates chart in following way (look at example below)
<script class="code" type="text/javascript">
$(document).ready(function(){
var plot2 = $.jqplot ('chart2', [[3,7,9,1,4,6,8,2,5]], {
// Give the plot a title.
title: 'Plot With Options',
// You can specify options for all axes on the plot at once with
// the axesDefaults object. Here, we're using a canvas renderer
// to draw the axis label which allows rotated text.
axesDefaults: {
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
},
// An axes object holds options for all axes.
// Allowable axes are xaxis, x2axis, yaxis, y2axis, y3axis, ...
// Up to 9 y axes are supported.
axes: {
// options for each axis are specified in seperate option objects.
xaxis: {
label: "X Axis",
// Turn off "padding". This will allow data point to lie on the
// edges of the grid. Default padding is 1.2 and will keep all
// points inside the bounds of the grid.
pad: 0
},
yaxis: {
label: "Y Axis"
}
}
});
});
</script>
Since you're using jQuery, you'd use the jQuery Ajax method to fetch the chart data after the page has loaded.
In your success function, your JS code (on the browser) receives the data from your server. Once you have the data, make the call to $.jqplot -- passing in the data you've just received.
To initially show the busy gif, just use the img element as the static content of the chart2 div which will later be the graph's container.
Some tips:
Some browsers don't do well at handling an animated gif while running a js program. So you may want to try a text message ("Loading chart...") in addition to the rotating gif. -- Or update the text messages. Eg start with "Fetching chart data from server" then update to "Processing chart data" once your success function has been called.
Rather than starting all 3 Ajax calls at once, experiment with having the success function for the first chart initiating the second Ajax call. (In addition to it charting the data.)
If you have problems with your Ajax calls, Google for examples and ask a separate question on SO if you still have problems.