views:

1964

answers:

8

I have written a chart that displays financial data. Performance was good while I was drawing less than 10.000 points displayed as a connected line using PathGeometry together with PathFigure and LineSegments. But now I need to display up to 100.000 points at the same time (without scrolling) and it's already very slow with 50.000 points. I was thinking of StreamGeometry, but I am not sure since it's basically the same as a PathGeometry stroring the information as byte stream. Does any one have an idea to make this much more performant or maybe someone has even done something similar already?

EDIT: These data points do not change once drawn so if there is potential optimizing it, please let me know (line segments are frozen right now).

EDIT: I tried StreamGeometry. Creating the graphic took even longer for some reason, but this is not the issue. Drawing on the chart after drawing all the points is still as slow as the previous method. I think it's just too many data points for WPF to deal with.

EDIT: I've experimented a bit and I noticed that performance improved a bit by converting the coordinates which were previously in double to int to prevent WPF anti-aliasing sub-pixel lines.

EDIT: Thanks for all the responses suggesting to reduce the number of line segments. I have reduced them to at most twice the horizontal resolution for stepped lines and at most the horizontal resolution for simple lines and the performance is pretty good now.

+4  A: 

When you start dealing with hundreds of thousands of distinct vertices and vectors in your geometry, you should probably consider migrating your graphics code to use a graphics framework instead of depending on WPF (which, while built on top of Direct3D and therefore capable of remarkably efficient vector graphics rendering, has a lot of extra overhead going on that hampers its efficiency). It's possible to host both Direct3D and OpenGL graphics rendering windows within WPF -- I'd suggest moving that direction instead of continuing to work solely within WPF.

(EDIT: changed "DirectX" in original answer to "Direct3D")

Dathan
Thanks for the suggestion. I'll will certainly look into that in the future, but I don't know anything about other graphics framework so that is not an option for me right now. I was hoping there was a WPF way to solve this. Thanks again.
Hermann
+2  A: 

I believe the only method that might be faster while remaining in the WPF framework would be to override OnRender in a custom control. You can then render your geometry directly to the persisted scene, culling anything out of view. If the user can only see a small part of the data set at a time, culling could be enough on its own.

With this many data points, it's unlikely that the user can see full detail when the entire dataset is in view. So it might also be worthwhile to consider simplifying the dataset for full view and then showing a more detailed view if and when they zoom in.

Edit: Also, give StreamGeometry a shot. Its whole reason for existing is performance, and you never know until you try.

PeterAllenWebb
In overriding OnRender, be careful of trying to drive WPF like an immediate mode drawing system versus the retained mode system that it is. You will lose performance that way.
cplotts
+1 for pointing to more performant ways of doing it.
cplotts
A: 

I haven't worked with WPF (disclaimer), but I suspect that your performance problem is because your code is trying to fit a smooth curved line through all of your data, and the time required increases geometrically (or worse) with the number of data points.

I don't know if this would be acceptable appearance-wise, but try graphing your data by connecting each point to the last with a straight line. This should make the time-to-graph proportional to the number of data points, and with as many points as you have the graph may end up looking exactly the same anyway.

MusiGenesis
No, it's not smooth curving the line through all of the data.
Hermann
Actually, downsampling the points and then using b-splines to smoothly interpolate between them is a common technique for *improving* performance.
Crashworks
+9  A: 

I'd consider downsampling the number of points you are trying to render. You may have 50,000 points of data but you're unlikely to be able to fit them all on the screen; even if you charted every single point in one display you'd need 100,000 pixels of horizontal resolution to draw them all! Even in D3D that's a lot to draw.

Since you are more likely to have something like 2,048 pixels, you may as well reduce the points you are graphing and draw an approximate curve that fits onto the screen and has only a couple thousand verts. If for example the user graphs a time frame including 10000 points, then downsample those 10000 points to 1000 before graphing. There are numerous techniques you could try, from simple averaging to median-neighbor to Gaussian convolution to (my suggestion) bicubic interpolation. Drawing any number of points greater than 1/2 the screen resolution will simply be a waste.

As the user zooms in on a part of a graph, you can resample to get higher resolutions and more accurate curve fitting.

Crashworks
Thanks, I was thinking about that two. The problem I have is that the data points are not spaced apart equally on the x-axis (they are based on time). There might be several points at point x, but y may be different. I also don't know how clean the filtering will be since I don't know the resolution the points will be rendered at since it's all vector graphics in WPF.
Hermann
+1 for a great and common sense idea.
cplotts
PresentationSource.FromVisual(visual).CompositionTarget.TransformToDevice.M11 will get you the factor to convert from logical units to device units. See http://www.wpftutorial.net/DrawOnPhysicalDevicePixels.html for more info.
cplotts
Wow, great link, thanks so much!
Hermann
+2  A: 

This is a very good question, and at it's heart begs the question "Can any user make practical use of, or business descisions from, a screen containing 100,000 discrete points?".

Following best practice in GUI design philosphy, the answer should be No, which would lead me to question whether there isn't a different way to meet the requirement for the application.

If there really is a bona-fide case for displaying 100,000 points on screen, with no scrolling, then using an off-screen buffer is the way to go. Composite your image to a bitmap, than whack that bitmap onto your Window / Page as needed. This way the heavy lifting is only done once, after which the hardware acceleration can be used every time the window needs to be drawn.

Hope this helps.

Mark
Thanks, good idea. I will try that if I have performance issues in the future, it seems to be ok now having reduced the number of points.
Hermann
+2  A: 

I don't know how well it scales, but I've had some success using ZedGraph in WPF (WinForms control inside a WindowsFormsPresenter). I'm surprised no one mentioned it yet. It's worth taking a look at, even if you're not planning on using it for your current project.

ZedGraph

Good luck!

Pwninstein
I always love me some ZedGraph
Michael Haren
Funny you mention ZedGraph because this is a WPF port of what I used to do in ZedGraph. ZedGraph was pretty good at this chart, but performance was unacceptable for other charts I needed.
Hermann
Don't you mean WindowsFormsHost ... as the way to interop the Windows Forms graphing component? +1 for the idea to interop in something more performant. Realize, though, that this approach will limit you in how you can compose WPF things on top of the Windows Forms graphing component. This is how our current application does things and it works rather well ... but now we want to start composing things on top of our graphing component ... and this is leading us to rewrite our graphing component in WPF.
cplotts
Whatever the Windows Forms interop component is for WPF is called is what I meant :) Good catch! (+1)
Pwninstein
A: 

Just ran into this question, but as I mentioned in this thread, the most performant approach might be to program against WPF's Visual layer.

Everything Visual in WPF eventually goes against this layer ... and so it is the most lightweight approach of them all.

See this and this for more info. Chapter 14 of Matthew MacDonald's Pro WPF in C# 2008 book also has a good section on it.

As another reference ... see Chapter 2 of Pavan Podila's book WPF Control Development Unleashed. On page 13, he discusses how DrawingVisuals would be an excellent choice for a charting component.

Finally, I just noticed that Charles Petzold wrote an MSDN Magazine article where the best overall (performant anyway) solution (to a scatter plot) was a DrawingVisual approach.

cplotts
For the record, I like many of the suggestions above ... especially downsampling the number of points. Obviously, that approach could be used in conjunction with programming against the Visual layer.
cplotts
I use Visuals for everything in my application and I did a quick implementation of lines with Visuals, but it made no difference. I am going to do it properly again soon and see if there is really no difference. Thanks for the link to the other thread!
Hermann
You're using DrawingVisual? That's odd that should have given a huge performance boost ...
cplotts
I know it's strange. It do have insanely good performance on other charts with more DrawingVisuals that this one, but for some reason when it comes to lines that are very close to each other WPF just can't handle it, but as I said, I need to re-implement it properly to make a final assessment. I have read in another article (http://techzone.enterra-inc.com/architecture/cartographical-objects-visualization-using-wpf/) though where the author also noticed that WPF was particularly bad at drawing lines performance-wise.
Hermann
A: 

Another idea would be to use the Image control with the Source property set to a DrawingImage that you've dynamically created.

According to Pavan Podila in WPF Control Development Unleashed, this approach can be very helpful when you have thousands and thousands of visuals that don't need any interactivity. Check out page 25 of his book for more info.

cplotts
Unfortunately, while the lines do not change, I do need interactivity. Thanks for the tip though.
Hermann