I found some strange things when trying zedGraph to chart dinamic data:
1) It chart it normally, then slower, slower and jerkily. Then I stop device and charting, and try to move horizontal scroll - it's almost impossible 'cause it moves too slowly and I need to wait several minutes for one mouse move. Why does it occur and how to fix it?
2) What occurs with the RollingPairList if it overflows? As I understood it is just clears and starts with the new data. Is it possible to allocate the memory dinamically (for example use List<PointPair> instead of PointPair[], and is it quick to change this in the zedGraph source? )
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've looked at this, and I think you are correct. RollingPointPairList was intended to avoid memory allocation and garbage collection issues for large datasets. However, since PointPair is a class (reference type instead of value type) -- it gets complicated. It is constrained by the fact that ZedGraph must receive a PointPair from the IPointList index property.
I think the way to fix this is to use the RollingPointPairList.Add( x, y, z ) method for adding points. With some minor mods, this method could avoid creating a new PointPair instance if the current position in the RollingList already contains a PointPair (in this case, just copy in the x, y, z value types).
How exactly do you get your new data points? Would Add( x, y, z ) work for you?
To answer #2 above, the RollingPointPairList cannot overflow -- new points replace older ones. Using the List<PointPair> would not help in this case. However, the modified Add( x, y, z ) logic would insure that each "space" in the list would only have memory allocated for it one time. Does this seem reasonable?
John
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for your answering, John!
There is the listening device, that contains a microphone and a analog-data converter, that produce the data with adjustable sample rate. So I need to display that data on the zedGraph. Default it generates ten points per event (the device software generates events when new data is available), the sample rate is about 1000 points per second. The problem is that the zedGraph becomes working too slowly in several minutes (1-2). I need it too work properly for 5 minutes at least. So I need to fix this problem. I can post the source if you want.
Thank you beforehand!
Dmitry.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I found out some facts about my problem: the device generates event and push all the data it contains. Each time it generates the event it contains more points than previous one, 'cause zedGraph works slower and next time it contains much more points and so on. So the problem I think in the fact that zedGraph charts the graph slower than the points arrive and the process and the delay increase dramatically.
So I need you advice: can I somehow faster the graph, or is it valuable to create my own simple component just to chart these data?
Dmitry
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I need help!!! There are only general help in the article on fastering the graph. So I need to know if I can quickly modify (simplify or smth else) the zedgraph to work faster.
I need only following features:
1) dinamic charting data (with the scrolling ability when stopped)
2) showing scale marks (even can be rejected)
3) printing parts of graph
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
It sounds like there's several things you can do to help.
1) Try the latest CVS version of the code. I have modified the RollingPointPairList so that the Add( x, y ) and Add( x, y, z ) methods only create a PointPair if one does not already exist in the RollingPointPairList. If one exists, it just copies the (x,y,z) values into the existing PointPair. This avoids any memory allocation.
2) Make sure that you don't use Refresh(). Instead, use Invalidate() for your form. Refresh() insists on an immediate redraw, which can cause a backlog of data. Invalidate() can be called as often as you like, and the redraw won't happen until the cpu is available.
3) If you are reloading all of the data at every timestep, skip any points that were previously loaded. For example, assume you have data for time=50 through time=100 already plotted. When you reload the data, you get data for time=50 through time=105. Skip the old points, and only Add() the points for time=101 to time=105.
4) Consider adding a timer event so that the data are not reloaded quite so often.
John
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you, John!
I'll try to get latest CVS code.
I'm posting the code of my charting function, in hope that you could see any opportunities to improve it.
public void Chart(short[] data)
{
try
{
This function should perform fast enough to to keep pace with the device (to prevent accumulating data and timely increasing the length of the function input that increase the time it performs and so on)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The problem remains - it work too slow with files from CVS (PointPairList and RollingPointPairList). May be it is needed to create special branch for dinamic data charting, 'cause currently zedGraph is not available to charting data with sample rate 1000 samples per second. Or may be I can not reach smth important about this....?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm using ZedGraph to build a similar project as yours, and I think it's important to ONLY keep visible points in your PointList. That is, if there're only 500 points visible in your chart but you have 20000 points in your PointList, those invisible points will delay the refresh dramatically.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Could you suggest any idea how to keep only visible points into the zedGraph pointPair list but have the ability to scroll all points? Do I need to implement scroll by myself or is there any way to do it with the help of the zedGraph? Ivan, do you implement the scrolling ability in your project?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Ivan, I read your topic in this thread so some questions is obvious. :)
Have you solved the problem of the charting speed complittely? And how did you calculate the actual count of visible points?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes I implemented scrolling feature in my project. In my case, the data file might end up with several hundred MB, so I have to use file mapping technic to access the data. You might want to google "file mapping" if you havn't used it before.
I didn't use the built-in Scrollbar of zedgraph, instead I used its Pan function. The code is something like:
// Turn on horizontal Pan and Zoomthis.zedGraph.IsEnableHPan=true;this.zedGraph.IsEnableVPan=false;this.zedGraph.IsEnableHZoom=true;this.zedGraph.IsEnableVZoom=false;// Hide built-in scrollbarszedGraph.IsShowHScrollBar=false;// Drag the right mouse button to panthis.zedGraph.IsShowContextMenu=false;this.zedGraph.PanButtons=MouseButtons.None;this.zedGraph.PanModifierKeys2=Keys.None;this.zedGraph.PanButtons2=MouseButtons.Right;
When new data arrives, they are writen to the buffer file first, and inform the control to update. The updating procedure, as I've mentioned, only updates the visible points to speed up the renderring.
Once the user pans or zooms the graph, normally some more data will become visible (and some become hiden of coz), an OnViewportChanged() function will be called. In this function, you can read those points that newly revealed, and put their values in your "visible" PointList.
Normally the refreshing rate in my project is about 5~10 times per second, which is good enough in my project. I don't know what your expectation is, but if you need a very high refreshing rate, I think you might as well implement your own charting control.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thanks a lot!
As I understood the OnVewportChanged function is your own deal. So if I calculate N visible points I'll create PointPairList(N) and will keep it full of visible points. But how you work with span: do you use your own event that refreshes points in the pointList as if the new data available? I think out that the same thing I can do with the HScrollBar native windows control (instead of zedGraph's).
Default sampleRate of the project is 1000 points/per seconds, but device generates event as it could and push all available points.
I'll try to use your suggestions first, 'cause I'm not strong in graphics. :)
And have you looked in my Printing thread, could you suggest smth?
Thank you!
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Yes OnViewportChange is my own function, it's designed to be called everytime the visible span changes (e.g. user zoom / pan / scroll the scrollbar, etc., but essentially, the viewport changes only when the Min and Max properties of the XAxis change)
I think you got my point that only update (and store) those visible points. But plz keep in mind that the count of visible point will be changed when the chart is zoomed in/out. So you might want to deal with it in the zoom event handler.
Another suggestion is to abandon the whole PointList object and create a new one when its point count changes. Dont try to re-use the points, it normally takes more time to handle the expanding / shrinking things -- just dispose it and leave it to the GC. But this might depends on your own IPointList implementation.
Using native scrollbar will be a good idea, I thought of it before but i don't have enough screen space to hold them :) so I turn to zedgraph's build-in pan & zoom mechanism eventually.
pointsPerUnit is how many points are there in a single integer unit of XAxis. For example, from x=0.0 to x=1.0 there're 5 points, then pointsPerUnit = 5; I guess normally this value should be 1. I think it's different from points_per_pixel, because the zedgraph don't use pixel as XAxis' unit -- it's resizable and scalable afterall, right?
Sorry I haven't looked into your thread about printing. I haven't implemented printing feature in my project so far. I'm sure i can learn sth from you by then :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Thank you for your answer. I hope I haven't irritated you much already. :)
So how you generate your input points for graph charting? Is it previously set to needed count accordingly visible_points_count? What do you do if the input points' count exceeds the visible_points_count of the graph control? (some point just won't be visible at all while charting).
And why did you implement your own PointList, why not RollingPointPairList(visible_points_count)?
What about my xAxis - native values are small doubles (if SampleRate = 1000 so second_per_point = 0,001). I think it will be better to bring it to integer values, but I need to show native marks on the axis.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
You're welcome, I got a lot of help from this forum here, so i guess it's my turn to give out sth :)
Yes, some points will never be visible if the visible count is less than the input point's count, unless the user scrolls back to history data. I don't care about those points, I just update the visible ones.
I didn't use RollingPointPairList becoz I didn't know about it by then...
As for the "navtive values " of your XAxis. I don't think it is a problem (perhaps i just didnt get your point). Or maybe you can have a look at the Scale.ScaleFormatEvent event. This enables your program to display anything you like on the scale.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I implemented my own PoinPairList class implementing the IPointList and IPointListEdit, with fixed capacity = visible_points_count, and keep it with new points (shifted previous back if new points count less then visible points count), but there was nothing in the ZedGraph pane... Nothing rendered...
Then I tryed to use RollingPointPair list as it is for dinamic graphs like mine, but nevertheless it keep only in the first part of the graph (for example, if the capacity is 3000, it keeps x values from 1 to 3000 but y values are actual) but I put there actual X and y points. As I shift forvard xMax and xMin it just become invisible after xMin = 3000.
Could you clarify me the way to use the RollingPointPairList object (2 John Champion)?
And could you please post some peace of code you refresh the PointPairList keeping only visible points and keeping the xAxis moving forvard (2 ivan).
I tried to use just PointPairList but nothing happened... :(
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Additional to previous post.
I fill the RollingPointPairList, then assign XMin and XMax to new values (XMax = (last point in list)'s xValue), then call Invalidate. Then working, it shows only xAxis changin but no graph after several seconds. The question is: HOW TO MAKE ZED GRAPH SHOWING POINTS THAT ARE IN THE RollingPointPairList always?
I almost blast my brains thinking about it... :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Have you called AxisChange() method before Invalidate()?
It's quite strange if the xaxis updated while nothing display in the chart, are you sure the points' Y != 0 (if you use a symbol on the curve it will be more obvious)?
I didn't find RollingPointPairList in zedgraph 4.3.5, I guess that's why I didn't use it. So what version are you using?
Nevertheless, i'm not sure it's necessary to use RollingPointPairList here. I haven't seen its source code but I suspect that it's using a List or sth to store the data, which means it might have quite a lot things to do everytime you Add() a single point. In the case of high data rate, this can be too expensive.
Basically, what I do in my project is:
1) Make sure the X and Y axis are both "normal" type, that is, not any "ordinal" type.
2) Add a curve that have visible_point_count (say 500 points);
------ above is a one-time initialization -------------
3) When data arrives, they are firstly saved to a big buffer file (append mode)
4) Read the last 500 points from the buffer file and use their values to replace those in the curve PointList.
5) Change the XAxis.Max to the last point's X value, and XAxis.Min = XAxis.Max - visible_point_count * point_per_unit.
6) Call ZedGraphControl's AxisChange() and Invalidate() method.
Hope these helps
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I use the 5.2 version (latest that in the download section). There is the PointPairList class "for dinamic data charting" but it works unexpectedly (as I posted previously).
So now I write charting event that put only 3000 points into the PointList, do not move the XMin and XMax axis [0;3000], but calculate the new values for the marks (scaleFormatEvent - thank you :). It seems to work without any visible delays.
When I changed XMax for example to my last X point value and XMin = XMax - delta, it worked strange - kept to chart last Y values but the X values became in the [0;3000] range... (?)
So I decide not to affect this values. :)
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I found some strange things when trying zedGraph to chart dinamic data:
1) It chart it normally, then slower, slower and jerkily. Then I stop device and charting, and try to move horizontal scroll - it's almost impossible 'cause it moves too slowly and I need to wait several minutes for one mouse move. Why does it occur and how to fix it?
2) What occurs with the RollingPairList if it overflows? As I understood it is just clears and starts with the new data. Is it possible to allocate the memory dinamically (for example use List<PointPair> instead of PointPair[], and is it quick to change this in the zedGraph source? )
I've looked at this, and I think you are correct. RollingPointPairList was intended to avoid memory allocation and garbage collection issues for large datasets. However, since PointPair is a class (reference type instead of value type) -- it gets complicated. It is constrained by the fact that ZedGraph must receive a PointPair from the IPointList index property.
I think the way to fix this is to use the RollingPointPairList.Add( x, y, z ) method for adding points. With some minor mods, this method could avoid creating a new PointPair instance if the current position in the RollingList already contains a PointPair (in this case, just copy in the x, y, z value types).
How exactly do you get your new data points? Would Add( x, y, z ) work for you?
To answer #2 above, the RollingPointPairList cannot overflow -- new points replace older ones. Using the List<PointPair> would not help in this case. However, the modified Add( x, y, z ) logic would insure that each "space" in the list would only have memory allocated for it one time. Does this seem reasonable?
John
Thank you for your answering, John!
There is the listening device, that contains a microphone and a analog-data converter, that produce the data with adjustable sample rate. So I need to display that data on the zedGraph. Default it generates ten points per event (the device software generates events when new data is available), the sample rate is about 1000 points per second. The problem is that the zedGraph becomes working too slowly in several minutes (1-2). I need it too work properly for 5 minutes at least. So I need to fix this problem. I can post the source if you want.
Thank you beforehand!
Dmitry.
I found out some facts about my problem: the device generates event and push all the data it contains. Each time it generates the event it contains more points than previous one, 'cause zedGraph works slower and next time it contains much more points and so on. So the problem I think in the fact that zedGraph charts the graph slower than the points arrive and the process and the delay increase dramatically.
So I need you advice: can I somehow faster the graph, or is it valuable to create my own simple component just to chart these data?
Dmitry
I need help!!! There are only general help in the article on fastering the graph. So I need to know if I can quickly modify (simplify or smth else) the zedgraph to work faster.
I need only following features:
1) dinamic charting data (with the scrolling ability when stopped)
2) showing scale marks (even can be rejected)
3) printing parts of graph
It sounds like there's several things you can do to help.
1) Try the latest CVS version of the code. I have modified the RollingPointPairList so that the Add( x, y ) and Add( x, y, z ) methods only create a PointPair if one does not already exist in the RollingPointPairList. If one exists, it just copies the (x,y,z) values into the existing PointPair. This avoids any memory allocation.
2) Make sure that you don't use Refresh(). Instead, use Invalidate() for your form. Refresh() insists on an immediate redraw, which can cause a backlog of data. Invalidate() can be called as often as you like, and the redraw won't happen until the cpu is available.
3) If you are reloading all of the data at every timestep, skip any points that were previously loaded. For example, assume you have data for time=50 through time=100 already plotted. When you reload the data, you get data for time=50 through time=105. Skip the old points, and only Add() the points for time=101 to time=105.
4) Consider adding a timer event so that the data are not reloaded quite so often.
John
Thank you, John!
I'll try to get latest CVS code.
I'm posting the code of my charting function, in hope that you could see any opportunities to improve it.
public void Chart(short[] data)
{
try
{
This function should perform fast enough to to keep pace with the device (to prevent accumulating data and timely increasing the length of the function input that increase the time it performs and so on)
The problem remains - it work too slow with files from CVS (PointPairList and RollingPointPairList). May be it is needed to create special branch for dinamic data charting, 'cause currently zedGraph is not available to charting data with sample rate 1000 samples per second. Or may be I can not reach smth important about this....?
Hi ziggy,
I'm using ZedGraph to build a similar project as yours, and I think it's important to ONLY keep visible points in your PointList. That is, if there're only 500 points visible in your chart but you have 20000 points in your PointList, those invisible points will delay the refresh dramatically.
Thank you, Ivan.
But what did you do with scroll? User need to have the ability to sroll recorded graph to examine it.
Could you suggest any idea how to keep only visible points into the zedGraph pointPair list but have the ability to scroll all points? Do I need to implement scroll by myself or is there any way to do it with the help of the zedGraph? Ivan, do you implement the scrolling ability in your project?
Ivan, I read your topic in this thread so some questions is obvious. :)
Have you solved the problem of the charting speed complittely? And how did you calculate the actual count of visible points?
Hi ziggy, sorry for the late response.
Yes I implemented scrolling feature in my project. In my case, the data file might end up with several hundred MB, so I have to use file mapping technic to access the data. You might want to google "file mapping" if you havn't used it before.
I didn't use the built-in Scrollbar of zedgraph, instead I used its Pan function. The code is something like:
When new data arrives, they are writen to the buffer file first, and inform the control to update. The updating procedure, as I've mentioned, only updates the visible points to speed up the renderring.
Once the user pans or zooms the graph, normally some more data will become visible (and some become hiden of coz), an OnViewportChanged() function will be called. In this function, you can read those points that newly revealed, and put their values in your "visible" PointList.
Normally the refreshing rate in my project is about 5~10 times per second, which is good enough in my project. I don't know what your expectation is, but if you need a very high refreshing rate, I think you might as well implement your own charting control.
To calculate the actual count of visible points:
int pointCount = (int)((pane.XAxis.Max - pane.XAxis.Min) / pointPerUnit)
Thanks a lot!
As I understood the OnVewportChanged function is your own deal. So if I calculate N visible points I'll create PointPairList(N) and will keep it full of visible points. But how you work with span: do you use your own event that refreshes points in the pointList as if the new data available? I think out that the same thing I can do with the HScrollBar native windows control (instead of zedGraph's).
Default sampleRate of the project is 1000 points/per seconds, but device generates event as it could and push all available points.
I'll try to use your suggestions first, 'cause I'm not strong in graphics. :)
And have you looked in my Printing thread, could you suggest smth?
Thank you!
pointPerUnit = points_per_pixel?
Yes OnViewportChange is my own function, it's designed to be called everytime the visible span changes (e.g. user zoom / pan / scroll the scrollbar, etc., but essentially, the viewport changes only when the Min and Max properties of the XAxis change)
I think you got my point that only update (and store) those visible points. But plz keep in mind that the count of visible point will be changed when the chart is zoomed in/out. So you might want to deal with it in the zoom event handler.
Another suggestion is to abandon the whole PointList object and create a new one when its point count changes. Dont try to re-use the points, it normally takes more time to handle the expanding / shrinking things -- just dispose it and leave it to the GC. But this might depends on your own IPointList implementation.
Using native scrollbar will be a good idea, I thought of it before but i don't have enough screen space to hold them :) so I turn to zedgraph's build-in pan & zoom mechanism eventually.
pointsPerUnit is how many points are there in a single integer unit of XAxis. For example, from x=0.0 to x=1.0 there're 5 points, then pointsPerUnit = 5; I guess normally this value should be 1. I think it's different from points_per_pixel, because the zedgraph don't use pixel as XAxis' unit -- it's resizable and scalable afterall, right?
Sorry I haven't looked into your thread about printing. I haven't implemented printing feature in my project so far. I'm sure i can learn sth from you by then :)
Thank you for your answer. I hope I haven't irritated you much already. :)
So how you generate your input points for graph charting? Is it previously set to needed count accordingly visible_points_count? What do you do if the input points' count exceeds the visible_points_count of the graph control? (some point just won't be visible at all while charting).
And why did you implement your own PointList, why not RollingPointPairList(visible_points_count)?
What about my xAxis - native values are small doubles (if SampleRate = 1000 so second_per_point = 0,001). I think it will be better to bring it to integer values, but I need to show native marks on the axis.
You're welcome, I got a lot of help from this forum here, so i guess it's my turn to give out sth :)
Yes, some points will never be visible if the visible count is less than the input point's count, unless the user scrolls back to history data. I don't care about those points, I just update the visible ones.
I didn't use RollingPointPairList becoz I didn't know about it by then...
As for the "navtive values " of your XAxis. I don't think it is a problem (perhaps i just didnt get your point). Or maybe you can have a look at the Scale.ScaleFormatEvent event. This enables your program to display anything you like on the scale.
I implemented my own PoinPairList class implementing the IPointList and IPointListEdit, with fixed capacity = visible_points_count, and keep it with new points (shifted previous back if new points count less then visible points count), but there was nothing in the ZedGraph pane... Nothing rendered...
Then I tryed to use RollingPointPair list as it is for dinamic graphs like mine, but nevertheless it keep only in the first part of the graph (for example, if the capacity is 3000, it keeps x values from 1 to 3000 but y values are actual) but I put there actual X and y points. As I shift forvard xMax and xMin it just become invisible after xMin = 3000.
Could you clarify me the way to use the RollingPointPairList object (2 John Champion)?
And could you please post some peace of code you refresh the PointPairList keeping only visible points and keeping the xAxis moving forvard (2 ivan).
I tried to use just PointPairList but nothing happened... :(
Additional to previous post.
I fill the RollingPointPairList, then assign XMin and XMax to new values (XMax = (last point in list)'s xValue), then call Invalidate. Then working, it shows only xAxis changin but no graph after several seconds. The question is: HOW TO MAKE ZED GRAPH SHOWING POINTS THAT ARE IN THE RollingPointPairList always?
I almost blast my brains thinking about it... :)
Any answer? :)
Have you called AxisChange() method before Invalidate()?
It's quite strange if the xaxis updated while nothing display in the chart, are you sure the points' Y != 0 (if you use a symbol on the curve it will be more obvious)?
I guess you'd have read this article:
http://zedgraph.org/wiki/index.php?title=Display_Dynamic_or_Real-Time_Data
I didn't find RollingPointPairList in zedgraph 4.3.5, I guess that's why I didn't use it. So what version are you using?
Nevertheless, i'm not sure it's necessary to use RollingPointPairList here. I haven't seen its source code but I suspect that it's using a List or sth to store the data, which means it might have quite a lot things to do everytime you Add() a single point. In the case of high data rate, this can be too expensive.
Basically, what I do in my project is:
1) Make sure the X and Y axis are both "normal" type, that is, not any "ordinal" type.
2) Add a curve that have visible_point_count (say 500 points);
------ above is a one-time initialization -------------
3) When data arrives, they are firstly saved to a big buffer file (append mode)
4) Read the last 500 points from the buffer file and use their values to replace those in the curve PointList.
5) Change the XAxis.Max to the last point's X value, and XAxis.Min = XAxis.Max - visible_point_count * point_per_unit.
6) Call ZedGraphControl's AxisChange() and Invalidate() method.
Hope these helps
I use the 5.2 version (latest that in the download section). There is the PointPairList class "for dinamic data charting" but it works unexpectedly (as I posted previously).
So now I write charting event that put only 3000 points into the PointList, do not move the XMin and XMax axis [0;3000], but calculate the new values for the marks (scaleFormatEvent - thank you :). It seems to work without any visible delays.
When I changed XMax for example to my last X point value and XMin = XMax - delta, it worked strange - kept to chart last Y values but the X values became in the [0;3000] range... (?)
So I decide not to affect this values. :)