views:

1788

answers:

6

A simple XY line graph: The X axis will represent the complete range of possible rating percentages, from 0% on one end to 100% on the other. Specifically, the X value will represent our rating cut-off, or the minimum rating a transaction can have before it is no longer acceptable. The Y axis will show values from 0 to the total number of transactions that have come through. The Y value will represent the total number of transactions that have a rating greater than the current X value (or greater than or equal to the current X value, I haven't decided yet). No transactions will have come through when this graph is first drawn, so the graph will begin at "y=0x".

Let's say the first transaction comes through, with a rating of 40%. The rating of the transaction indicates that this transaction is acceptable if our rating cut-off is less than 40%. (... or less than or equal to 40%. Again, I haven't decided yet).

First, the Y axis will rescale to show the range of 0-1 (since 1 is the total number of transactions). Then the line will be modified to indicate that 0 transactions are acceptable from x=40 or more, and that 1 transaction is acceptable from x=40 or less. This is easy to accomplish in WPF by simply adding two points to the line path - one at (40,0) and the other at (40,1) - and then moving the line's left endpoint to (0,1). The line's right endpoint will remain at (100,0). This process can then be repeated for the second transaction, and so on.

The problem is that we will be dealing with six-digit quantities of transactions. and I want to make sure I am using WPF's hardware accelerated vector drawing capabilities to their fullest extent to ensure the graph doesn’t lag or freeze the rest of the program as it tries to render 300,000 points onto a single line path. Or is WPF supposed to be able to handle numbers like that in a heartbeat? I need to find a way to implement this graph without slowing the application to a halt. I have faith that WPF's vector drawing platform will provide a solution, but I don't know enough about how to exploit WPF to be certain that I am getting the most out of WPF's high-performance rendering capabilities.

+1  A: 

If you aren't using .NET 3.5 SP1 just don't use any of the shader effects. Otherwise there isn't much you need to do as a WPF developer to ensure it uses hardware acceleration.

AgileJon
Okay. But is this workload too much for it? I mean, rendering a model with that many points is quite a bit more than I have ever seen in my (albeit limited) modeling and rendering experience.
Giffyguy
I guess what I'm asking is: Should I go with a line path and add points as transactions come through, or should I be looking at yet another solution?
Giffyguy
Don't you mean bitmap effects? Instead of shader effects?
cplotts
Hmm ... I haven't even considered bitmap effects. I used to be engrossed in bitmap manipulation, back in my earlier days as a C++ 6.0 developer. I like to say I mastered the usage of MFC and GDI. But going back to bitmaps seems like a giant step backwards, when I'm trying to learn the WPF way of doing this rather than GDI. And since WPF provides such simplicity, with the Visual and Shape classes - I guess I may limit myself on how much pain I am willing to endure to speed this up. Trying to render this graph as a bitmap image sounds like WAY more hassle than it's worth.
Giffyguy
Bitmap effects (prior to .NET 3.5 SP1) were the source of performance problems ... since .NET 3.5 SP1 thunks bitmap effects down into actual GPU effects (in most cases) it is less of a problem now ... but then only 2 bitmap effects were offered as baked in GPU effects (drop shadow and blur).
cplotts
I wasn't suggesting the use of bitmap effects and neither was AgileJon (in my understanding). He was just pointing out that they can be a source of performance problems ... since they can at times force software rendering to occur
cplotts
My mistake. I guess I'm not familiar with this usage of the terminology. When I hear the word "bitmap," I assume you mean bitblt() and alphablend() and every other old-school form of high-speed hardware-accelerated bitmap manipulation. But now that I think about it, "bitmap effects" is a clear reference to an "effect" rather than a method of rendering. I'm so concerned about rendering, I completely forgot to consider effects as a performance factor.
Giffyguy
+4  A: 

I do not know the answer, but coding up a quick test shouldn't take much longer than it did for you to post. Also, see this thread for a similar discussion.

PeterAllenWebb
+9  A: 

If you want it to be fast, the best way is to derive from Control and implement OnRender - normally this isn't necessary, but for your application it might be.

Also, let's take a step back - the screen you're rendering to certainly isn't 300k pixels across; before you go to render, reduce the buffer by averaging n nodes into one until you've got something closer to the resolution of the actual device, then draw it on-screen.

Paul Betts
OnRender may be more performant than some approaches ... but be careful about trying to drive WPF in an immediate mode manner (which overriding OnRender might encourage you to do) ... WPF is a retained mode composition system. I myself have been bitten by doing just this.
cplotts
+1 for the idea to minimize the points on the line based on the resolution of the device. Very smart.
cplotts
Reducing the number of points is more of a hack than anything with WPF since the host may be rescaled (zoomed in/out) and the visuals have no way of knowing their true size on the screen.
Hermann
Hermann makes an excellent point. Combined with the fact that the scale of my graph is completely dependent on the accuracy of the point set, I feel like I need to make sure to keep all the points, regardless of final resolution
Giffyguy
If you're zooming in, then many of the points are offscreen; the first thing they teach you in GPU programming is, "The fastest object is the one you *don't* draw". If you're zoomed in, you should be dropping all the points in the buffer that aren't in the visible range, and you *still* might have to reduce it.I'm not saying you should destroy the original buffer, just make a reduced copy before passing it off to the view.
Paul Betts
@Paul Bettts: WPF does that all for you automatically.
Hermann
@Hermann I'll have to look into this visual layer, I could definitely be doing far too much work by hand - thanks for the tip!
Paul Betts
WPF is actually pretty smart about what to render when it comes to Visuals. I've been rendering about 100,000 visuals (rectanles, straingt lines and text) on a chart and the performance is amazing. You can even transform them and the CPU just sleeps because it all runs on the graphics card. It's a known though that WPF has problems with lines. I hope they'll fix that in the future.
Hermann
cplotts linked to http://www.wpftutorial.net/DrawOnPhysicalDevicePixels.html in my question which shows you how to get the final resolution that it's rendered at. Might be useful.
Hermann
+4  A: 

It might be worth having a look at the WPF DynamicDataDisplay library. I've been using it recently and haven't any problems with large amounts of data. It's only an early version (0.3 in fact) so there's not much documentation, but it does have samples showing how to use it. Hopefully that'll be enough to get you started.

The SimulationSample generates lots of data, so that should be a good place to start.

Wilka
Do you know how WPF DynamicDataDisplay is implemented? Does it use Visuals?
Hermann
Interesting, for sure. But so far this sounds like it's more centered around dynamic data rather than dynamic display. I doubt it'll be much use for custom visual output, designed by the data creator.
Giffyguy
+3  A: 

I just stumbled upon this post and am building a line graph control myself that needs to be very performant as we update the points on our lines in a real-time manner.

If performance and number of Visual(s) are what you are after ... I doubt you will find a more performant approach than programming directly against WPF's Visual layer (links: 1, 2). My initial results from using this approach have been very positive.

This will be even more performant than overriding OnRender as it will encourage you to take advantage of WPF's retained mode drawing subsystem (where all the drawing instructions are cached).

That is, if all you have to update is a point on the line, then updating the point will force the line Visual to update but won't force the rest of the graph (axes, gridlines, ...) to update ... as the drawing instructions for these are retained and will be reused (since they aren't updating).

Chapter 14 in Pro WPF in C# 2008 by Matthew MacDonald has a great section (titled 'Visuals') on programming against WPF's Visual layer. Chapter 2 of WPF Control Development Unleashed also has section on page 13 where he discusses how a DrawingVisual approach would be perfect for a charting component. Finally, Charles Petzold wrote a MSDN Magazine article where the best overall solution to a scatter plot was a DrawingVisual approach.

(Now, I know that your question mentioned the axes will also be updating ... and so my answer is really for the general case ... but I still think that this approach will be the most performant ... as only the things that need updating ... will update.)

cplotts
This makes perfect sense, and is a perfect description of the approach that I am currently attempting. The graph I was building back in June was designed using Paul Betts's suggestion. But I've been building another similar graph more recently, and this solution seems to work great. All I do is update only the fewest number of objects possible (in my IValueConverter), and the WPF visual layer seems to be able to handle the rest without incident.
Giffyguy
Wonderful! Glad to hear it!
cplotts
@Giffyguy: Are you still rendering 300,000 data points or have you reduced them? Are these data points all visible on one screen or do you have to scroll?
Hermann
If this approach doesn't work for you, try using an Image control with a dynamically generated DrawingImage. As I mention in http://stackoverflow.com/questions/952657/most-performant-way-to-graph-thousands-of-data-points-with-wpf, Pavan Podila mentions that this approach scales quite well ... and might help you out if you don't have to interact with the points ... and even then you can get smart about it. See page 25 of his WPF Control Development Unleashed book for more info.
cplotts
A: 

IMHO, Paul seems to be on the right track, check out the sections on map smoothing, some of the examples use results from the Florida 2000 election results (~9M votes 18+M total people) for data sets.

Along the lines of the thread from AgileJon, somewhat, I would use simply manually emit a bitmap if no straight forward technique was available to better depect your data set. I render visualizations of scatter plots that are easially 16 000 000 (16 Million+) in seconds, full 32bit ARGB pallette.

You seem to of remarked "But going back to bitmaps seems like a giant step backwards", I would not be so quick to say that, the universe is bound by physical limits.

I referred another post to this codeproject article, which does many tens of thousands of 3D plots + animation etc...

RandomNickName42