ZedGraph super users, I have done my best working with ZedGraph to make an analog signal chart. I need some help with the finishing touches.
Currently the graph "grows" from the left to the right as new data comes in (No real world data yet, just a random point every timer tick), if the data grows too large for the default zooming options then the data points are "compressed" on the graph and the right hand side shows more white space, and the X axis scales larger.
What I would like is for the data to grow from right to left (Basically "flip" the graph over the Y axis so +x is to the left and -x is to the right?). Also I would like a "sliding window" for the graph to show only the newest data from the source (basically a 5 second sliding window).
Does ZedGraph have the ability to implement either of these features by default?
Otherwise I plan to negate all of the time stamps on the data (I guess and never show the x axis?) so that the data "grows" from right to left as it comes in. For the sliding window, I was going to only keep (5sec/timeBetweenData) # of data points and remove the rest from the LineItem representing the signal and store them (in case I want to show them to the user again). But If I don't have to do that it would be nice.
So to fix this I did end up negating all of the time stamps so that the new data would "enter" the graph on the left and move to the right as it got older.
Then to create the sliding window effect I removed the oldest point in the graph for every point that I added.
Another unforeseen issue was that the GraphPane by default would add some padding in front of and behind the min and max points, so to fix this I found the minimum and maximum points in my curve and set the dimensions of the axis' scales to that.
Related
How can I prevent a WinForms Chart object from autosizing on the X axis when a new tickmark comes up?
A picture, or in this case a gif, is worth a thousand words:
See the little jump when a new gridline, tick, and label show up? Super annoying.
I'm pretty sure that the setting is somewhere in chart1.ChartAreas[0].AxisX but I haven't been able to find anything that prevents this from happening.
Where should I look?
When adding points at some point a new axis label must be added at each new interval. Since it is drawn centered at the value the chart needs to make room for it to both sides. The extra room to the right side then takes a while to be filled with data. This results in the jumps..
In my test the most straightforward solution was to simply omit the last axis label:
Axis ax = chart1.ChartAreas[0].AxisX;
ax.LabelStyle.IsEndLabelVisible = false;
Of course turning it back on when no more points are being added is a good idea.
Another, much more involved solution might be to disable the axis labels altogether and draw them in a xxxPaint event..
I have a FIFO Real Time chart (pretty much taken from their published Example) of a SciChart graph. As it renders, it starts out completely zoomed in very close and as the line is drawn, it zooms out to accommodate the full size of the line.
<s:SciChartSurface.XAxis>
<s:NumericAxis x:Name="axisX" MinHeight="50" AutoRange="Always" AxisTitle="{Binding Path=XAxisTitle}" DrawMinorGridLines="False" DrawMinorTicks="False" TextFormatting="0.##">
<s:NumericAxis.GrowBy>
<s:DoubleRange Max="0.1" Min="0.1" />
</s:NumericAxis.GrowBy>
</s:NumericAxis>
</s:SciChartSurface.XAxis>
However, what I would like is for it to begin zoomed out by a certain amount already - e.g. the X axis would already be displaying from (for example) 0 - 10 and as the line is drawn it proceeds across the screen, only zooming if the line happens to get bigger than the space provided.
I've tried setting the VisibleRangeLimit, but while this does allow me to define the range of the chart area, the zoom doesn't kick in when the curve gets too big (so it literally goes "off the chart")
How can this be accomplished?
The reason for this is the Fifo Example in sciChart WPF uses XAxis AutoRange set to Always to scale the axis to fit the data. When the example starts, even if the Fifo buffer has a capacity of 10,000 points, it has no data in it, hence the axis is scaled small to accommodate the data.
There are two ways around this:
Is to pre-fill your FIFO DataSeries with X=xValue, Y=double.NaN. Given enough values the chart will think it has to draw all these points so the XAxis will scale accordingly
Is to take control of XAxis.VisibleRange yourself (do not use AutoRange). In this case, you need to set XAxis.VisibleRange to a window size to accommodate N points, and as you update data, update the window.
The FAQ 'How to create a StripChart in SciChart' demonstrates technique (2), how to update the visible-range of the XAxis to achieve scrolling behaviour.
Disclosure, I am the tech lead of the SciChart WPF Team
I add points to the chart, using
chart1.Series[0].Points.AddXY(x,y);
Millions of points were added. The chart automatically starts drawing them in the current chartarea. Problem is that, it could take a long time before the program become responsive, and I don't need to see all of them at the beginning.
If I call
chart1.ChartAreas[0].AxisX.ScaleView.Zoom(a, b);
right after adding points, it would not work, because the chartview is still empty yet.
So how can I stop the automatically drawing process?
Just some point of views don't know if it can help of if it is possible but
Maybe reduce decrease value of AxisX maximum can speed up,
Turn off AntiAliasing to none at chart1 can give a try otherwise keep it set All,
Maybe being Drawing Paint can be stopped by catch related Pre Post paint or
other event and return "handled" after enough needed requested point are drawn
Try reduce number of Value to be used at Points array of Series it self and
update this Points array when needed with new points
Regards
Original Question
I'm using Microsoft Chart Control to display some data points as a Line. I have a Legend with custom items used to display calculated information about the line (mean average and others).
Now I've enabled IsUserSelectionEnabled which allows the user to "zoom into" a range of values and I want the legend items to be calculated on only the data points that are currently in view.
I can use the AxisViewChanged event to be notified of the view change, but what I can't figure out is how to enumerate only those DataPoint currently in view.
Update
The zoom isn't going to work for my purpose. What I discovered is that the NewPosition and NewSize properties of the AxisViewChanged event do in fact contain the precise area selected by the user, but the resulting zoom contains points outside of that area. I need more precision than that. What I need are two cursors, but the control only gives you one.
So my question now is: How do I customize this thing to add another cursor? I'm not asking just yet and if I do I'll start a new question.
Though I do still need to figure out how to translate client coords into data coords...
Updated again
I found the coord translation functions right on the Axis. Seems obvious in retrospect.
ChartArea.Axis.PixelPositionToValue (for whichever axis you need)
ChartArea.Axis.ValueToPixelPosition
I would like to know if is there some good web solutions to show charts for "huge data sets", I've tried amcharts and Highcharts Stock (jquery solutions) without success.
At the beginning they were working, but at the moment the "chrome" is telling me that the javascript memory is full and the page crashes.
I've times where I need to show more than 20 lines, each one with more than 100.000 points, so in the end I can have gigantic jquery arrays that sure will crash the internet browser.
At the moment I am open to change to some flash, silverlight or other solution (not java applet because I am using C#).
What do you guys recommend?
UPDATE #1
For example: one purpose of this application is to see ECG channels.
The person will carry a device with several "sensors" (lets define 10 or 12, more or less), the device will save the data each second (or sometimes even in shorter intervals). And there can be cases that the person will use this system for 3 days).
Minimum data:
60 seconds * 60 minutes * 24 hours * 3 days = 259.200 points per line.
8 lines or more => 2.073.600 total points
Usability:
Well, in this health area normally the "readings" will be similar, no highs or lows enough to be recognized in a 3 days data. So for this example the best would be to load the data just when it is needed > the pan/zoom slide is showing just 1hour and when it moves to other, then AJAX get the rest of the DATA. Sure this is the way to go. BUT this is not the only case in my system.
I've other type or devices where the "highs and lows" are HUGE and the user would like to see ALL data in just one "chart" without zoom in. So, in this situations just from a simple look it is easy to see that something happened on the readings, then the user can make zoom in and since the data is already on memory no need to make more AJAX calls and refresh the chart.
Smart way to go: process the data in a way to do "reduce" the number of points when we are looking at a bigger "scale". Sure, this is the wise way to go, but once again, there are times when the result of some processing math will "fake" and hide the real readings and in the end there are some "behaviors" that will not show up on the chart.
So, for now I really need to find a way to display all of this points.
Note: I really appreciate all the feedback of you guys.
I think I'm with Neil here...there must be some way that this data can be processed before display...I mean, how can this amount of data even be displayed in a window? You say a line has 100000 points...if each of those points was unique in the X,Y plane, 100000 points would completely fill a 300x300 display window. 20 lines like this would completely saturate a normal 1024x1280 display.
Presumably, that can't be what you are looking for, so I'm assuming there must be a lot of cases where the points overlap. Preprocessing the data, to eliminate duplicate data points would help reduce the data size considerably.
It's hard to know exactly how this answer fits, or to give more precise instructions without further details, but if you have questions or clarifications, edit your question and I'll modify my answer (or delete it, if I've misinterpreted.)
Response to Edit 1:
I think that the way to approach the thinking for this is to recognize that for any given view, you can only show as many data points as you have horizontal resolution, so you can limit your data download to that.
From what I'm hearing (and I grant that I have very few details) this problem can be reduced to:
Figuring out how many points to get (based on horizontal resolution)
Calculating those points based on the data, horizontal scroll, zoom, and any heuristics.
Dynamically downloading that data
That sounds not too bad, and your original problem (of too much data crashing the system) disappears. That leaves you with secondary problem of how to calculate the height of the downloaded data.
I've other type or devices where the "highs and lows" are HUGE and the
user would like to see ALL data in just one "chart" without zoom in.
So, in this situations just from a simple look it is easy to see that
something happened on the readings...
There are a number of potential difficulties that I can see here...
If the timescale for these events is too short, they won't be visible on a naively drawn graph. If you have 100000 points in a particular line graph and your default viewing area is 1000 pixels wide with no zooming, you're only seeing 1 out of 100 datapoints. If some spike lasts for 10 of the datapoints, for example, unless you do something special, there's a good chance it won't be visible on the graph (so the user won't know to "zoom in" for more resolution). And how do you determine the height at which to plot the point? The actual datapoint at a specific spot? An average of the 100 data points that pixel covers? A rolling average? If don't average, you could miss spikes entirely. If you do average, you could lower the amplitude of the spikes or troughs if they are of short duration.
This, I think (and, again, I'm doing a lot of guesswork) sounds like the real challenge. Trying to find some way to display the graph which will definitely not be able to show all of the data at one time, but may be able to have some way to highlight points of interest dynamically (calculating, noting, and marking peaks and troughs with notations on the graph...things like that.)
Try out the Zoom Line chart from the FusionCharts stables.
I've myself created charts with 27,000 datapoints; and beyond the initial loading times, the chart worked smoothly.
Here is a blog post about the zoom line chart - http://blog.fusioncharts.com/2011/10/stuck-between-massive-historical-data-and-daily-intricacies-zoom-line-chart-to-the-rescue/
As a bonus, you can render the chart in pure JavaScript or Flash.
And it also works well with server-side languages. Check out their docs for more reading material - http://docs.fusioncharts.com/