05-07-2009 08:58 AM
hi everyone,
i am struggeling with the need to plot some 20kHz data on a scatterGraph. There should be some light colored plot for the latest data and a dark colored one for the older data. this works quite alright with two different plots with different historyCapacity values, but the old data should stay in the plot no matter how long the daq takes. in other words, i would need an infinite historyCapacity for plotting the old data. the thing is, the app get slower with growing historyCapacity Values.
could it be that the whole plot gets redrawn every time causing the app to slow down when historyCapacity grows?
i have a working version written in c++ (pointers etc.), but i cannot simply reuse it for obvious reasons. i tried a simple rewrite with pointers in c# without success.
i also tried to use the Graphics.drawline method (no plot.append = no historyCapacity), but it is even slower. i wonder how measurement studio manages to achieve reasonable speed with low historyCapacity values...
too bad one cannot learn from the source code. 😞
so, how can i have a fast daq app with an infinite plot of old data?
05-12-2009 04:14 AM
Hi
I don't think the infinite plot of data is possible because you only have a finite RAM where the values are stored.
And of course it will slow down with a lot of values in RAM.
I suggest you better save the date in a file and read it when necessary.
05-12-2009 08:16 AM
hi diana,
thanx for your thoughts! by "endless" I of course only mean "potentially". I thought about doing some kind of canvas.drawline(x,y) thing and the line just stays visible until ich clear the canvas. But this appendXY method in measurement studio seems to be connected to the historCapacity, and that causes the app to slow down if I use large values, i.e. for 20s data.
Did I oversee some possibility to write data to a scatterPlot that stays as long as i want to?!
thanx again,
mael15
05-13-2009 11:08 AM
Hey mael15,
If I understand correctly, you want the ability to have some static historical data showing on one plot, and some dynamic data gathered from a DAQ task showing on the same graph.
If this is not what you are trying to accomplish, do you think you could attach a drawing or screenshot demonstrating what you are trying to achieve?
If this is what you are trying to accomplish, I think it can be done relatively simply by adding another XAxis to the XAxes collection associated with the scatter graph. Then you can set the visible property of the new axis to false, unless of course you want it to be displayed. This will allow you to plot the historic data against one XAxis, and the new dynamic data against the other XAxis. Taking this approach will give the illusion of historical data that persists indefinitely throughout the DAQ task that you need to plot.
Please let us know if you have any further questions!
NickB
National Instruments
05-14-2009 02:23 AM
hi nick,
i just want one point to show the data. it should leave a short trail that moves with the point (like with a low historyCapacity setting) and all data should stay visible no matter how long the measurement goes. the current data could be in a light color and the older in a dark color.
i tried to define my own Graphics object and do simple drawLines() since these lines just stay plotted. i also tried tried to do my custom version of the scatterGraph, but both are just way too slow, even when using pointers in c#.
i must admit i do not understand what you wrote about another xAxis. Would that be different from using two plots using the same axis?
thanx!
05-14-2009 08:09 AM - edited 05-14-2009 08:10 AM
Hey mael15,
The idea behind having two x axes and two plots is so that one plot can be associated with an axis that is configured to update as a strip chart (as I'm only assuming you're using) and the other can be associated with an axis that has a fixed range that never changes, thus persisting on the graph. I took a quick minute to put together an example of what I'm thinking will work for you, hopefully it will meet your needs. The example is attached below, and the important portion of the code can be seen below:
{
InitializeComponent();
// configure the default XAxis to behave as a strip chart
scatterGraph1.XAxes[0].Mode = AxisMode.StripChart;
// create a new XAxis with a fixed range
XAxis fixedXAxis = new XAxis();
fixedXAxis.Mode = AxisMode.Fixed;
fixedXAxis.Range = new Range(0, 10);
fixedXAxis.Visible = false;
// add it to the XAxes collection
scatterGraph1.XAxes.Add(fixedXAxis);
// create a new plot using this new fixed axis
ScatterPlot fixedPlot = new ScatterPlot(scatterGraph1.XAxes[1], yAxis1);
// add the plot to the plots collection
scatterGraph1.Plots.Add(fixedPlot);
// set some line colors
scatterGraph1.Plots[0].LineColor = Color.Coral;
scatterGraph1.Plots[1].LineColor = Color.LightGray;
// plot the historic data
scatterGraph1.Plots[1].PlotXY(historicXData, historicYData);
}
private void timer1_Tick(object sender, EventArgs e)
{
scatterGraph1.Plots[0].PlotXYAppend((double)xVal++, rand.NextDouble() * 10);
}
05-14-2009 08:38 AM - edited 05-14-2009 08:41 AM
hi nick,
thank you for your time and effort.
i probably have described my problem poorly (sorry, i am German and not a native English speaker).
i do not have some kind of historic data that stays the same no matter what the current data does. i just want the current data to leave a "Footprint" on the scattergraph. this "footprint" is exactly what plotxyAppend() does, only that it is connected to the historyCapacity property. so if i have 100 samples/sec and i have historyCapacity = 300, older values disappear after three seconds. i just want older values to stay plotted indefinitely.
i use the scattergraph as some sort of oscilloscope with fixed x and y axis.
i hope this makes my problem clearer?
05-14-2009 06:53 PM
Hey mael15,
Sorry I misunderstood your requirements, I think things are much more clear now. What it sounds like you need are lines to be drawn without persistant data associated with the points. Unfortunately, there is nothing built into the Measurement Studio graphs that enables you to do that. While drawing your own lines may be a possibility, I haven't had time to look into that possibility.
However, to help with the color distinction between the old and new data, you should check out the Measurement Studio help topic Creating a Custom Line Style for the Measurement Studio Windows Forms Graph .NET Controls. If you want more control over the gradient (to make the color change more immediate) you could check out this post.
When I get a couple more minutes, I'll take another look at the possibility of drawing your own lines and get back to you.
NickB
National Instruments
05-15-2009 04:20 AM - edited 05-15-2009 04:25 AM
hi nick,
thanks for trying to solve my problem.
i actually succeeded to draw my own lines by deriving my own scattergraph and doing simple Graphics.drawLines(...), but it is very slow. at least it is too slow for 20k/s data.
the line color is the smallest problem. i am about to give up on this whole scatterGraph thing and try to work with c++. if you find a way, i would be more than happy to continue with c# which is MUCH easier for me.
mael15
05-18-2009 09:19 AM
Hello mael15,
Sorry for the delay in my response. I was recently able to look at the issue you have raised with another colleague, and I have another suggestion for you. Hopefully it will be a little more helpful.
A possiblity would be for you to maintain your own internal bitmap, and draw the plots to this bitmap, instead of to the internal, private, bitmap the ScatterGraph maintains. This would allow you to use the PlotXY method instead of the eventually slower PlotXYAppend method. By never clearing your internal bitmap, the PlotXY method will be sufficient to fake a PlotXYAppend method with an infinite history capacity.
The implementation of this would be something similar to the following:
- Create your own internal bitmap, and graphis object from this bitmap using Graphics.FromImage()
- Handle the BeforeDrawPlot event
-- in this event, create a ComponentDrawArgs object from your graphics object and the Bounds property of the EventArgs
-- call ScatterPlot.Draw(args) with your newly created ComponentDrawArgs
-- call e.Cancel, signifying that you will be responsible for drawing the plot
- Handle the AfterDrawPlotArea event
-- in this event, call e.Graphics.DrawImage(), passing in your own internal bitmap that now has a plot drawn to it
There are of course many other considerations you may wish to make, such as resizing the internal bitmap if the graph size changes, and perhaps checking a boolean flag set in the PlotDataChanged event of the graph - so that you only redraw if the plot data has been updated.
The relevant pieces of code can be found below, and a complete example (minus the aforementioned sanity checking) can be found attached:
private Bitmap bmp;
private Graphics graphics;
public Form1()
{
InitializeComponent();
bmp = new Bitmap(GetPlotGraphicsWidth(scatterGraph1, 0), GetPlotGraphicsHeight(scatterGraph1, 0));
graphics = Graphics.FromImage(bmp);
}
private void scatterGraph1_BeforeDrawPlot(object sender, BeforeDrawXYPlotEventArgs e)
{
ComponentDrawArgs args = new ComponentDrawArgs(graphics, e.Bounds);
scatterPlot1.Draw(args);
e.Cancel = true;
}
private void scatterGraph1_AfterDrawPlotArea(object sender, AfterDrawEventArgs e)
{
e.Graphics.DrawImage(bmp, 0f, 0f);
}
I haven't been able to extensively test the performance of this, but it looks to be faster than PlotXYAppend with a very large history capacity. Please let me know if it does not meet your performance requirements, or other requirements I may not have thought of.
Thanks!
NickB
National Instruments