On Jul 25, 2007, at 12:09 PM, John Hunter wrote: > > Hi Ken -- sorry for the radio silence, I'm not intentionally ignoring > you. Real life has made some demands on my time of late, and probably > will until next week, but I was able to download, read through and > test your code.
I appreciate you making the time to take a look at my code in spite of it. > But I don't think that closes the book on the subject -- for > example, I have realized I am introducing too much complexity and > trait forwarding, and I think I know a way to work around this, so > I will be hacking through my version one more time while at the > same time taking a closer look at yours. I'd hardly expect it to close the book on the subject. Although it functions as a proof-of-concept, my rendering model needs more work before it can handle special cases like the blended affine transformation to plot an axis. I've been thinking about how best to accomplish this and will try to have something for you to look at by early next week. Please drop me a line when you're satisfied with your changes to mpl1.py, as I'm looking forward to seeing them. > I also would like to hear more about the "hard to optimize" part, > because that is not intuitively clear to me. Moving to a rendering model when the primitives modify the CTM instead of replacing it with a pre-calculated value removes the dependency between primitives and their containers. A Primitive object, like a Path, may be reused and shared between renderers. The native version of a Primitive object is stored by the Primitive object itself, so it can be reused by any Canvas that draws the Primitive. This also means that you incur very little cost in clearing a Renderer and then repopulating it with existing Primitives. An Artist-level implementation of z-order could leverage this to avoid having to sort primitives by z-order every time a figure is rendered. Since primitives modify graphics state instead of replacing it wholesale the it's easier for the Canvas to push as few changes to the backend as possible. For example, if none of the child primitives of a ScaledView have their own transforms then the CTM only gets modified once when the ScaledView is rendered. The same is true for all of the other graphics state parameters, like linewidth and strokecolor. This saves on unnecessary backend overhead (e.g. creating the same agg.trans_affine repeatedly). It could also lead to tighter PDF and EPS output. Finally, the Renderer class is canvas-independent so it can be used to draw on multiple canvases during the course of its lifetime. I hope this will substantially simplify the process of saving a figure that was drawn interactively. I'm also contemplating making Renderers able to contain child Renderers so parts of a figure can be selectively updated. For example, drawing the non-Axis children of an Axes by using a subrenderer could further improve animation performance. > I confess to being a meta-class ignoramus, so I am intrigued to study > how you handled the canvas primitive cache problem using meta classes. I hate to disappoint you, but metaclasses aren't involved. Right now the caching is implemented cooperatively by Canvas and CanvasPrimitive to reduce duplicate code. CanvasPrimitive.get_canvas_primitive() handles the caching logic and calls CanvasPrimitive.create_canvas_primitive() to create a new native object if necessary. Subclasses of CanvasPrimitiveoverride create_canvas_primitive() to delegate the call to the appropriate method of Canvas, e.g. Path.create_canvas_primitive() returns the result of Canvas.create_canvas_path(). Subclasses of Canvas that do not cache Primitives should not override the create_canvas_xxx() methods. > How for example, if one modifies a Rectangle object which embodies a > path primitive, would the canvas get the notification to update it's > internal path representation (egg the agg_path_storage)?. Native canvas objects are always created at render-time, so rectangle would just update its associated Path instance when its bounds changed. The next time the Path is drawn, Canvas.draw_path() would call CanvasPrimitive.get_canvas_primitive() and end up with a new AGG path. That being said, it might be more efficient if all Rectangles share one Path that draws a unit square and change its size by updating the CTM. > With traits, I use the trait event handling mechanism so that when > any of > the box properties (left, width, top, etc...) are modified, the > PathPrimitiveAgg would get a callback. So when the user does > > rect.left = 0.1 > > the agg path knows to update itself. This is pretty cool. Yes it is, and I agree that mpl1 should have an attribute-based API for modifying plot object parameters. > vis-a-vis properties vs traits, I second Peter's comment that once > you've written 8,000 setters and getters and manually constructed > properties, you'll probably evolve toward something like traits, w/o > all the features. This is a library that has been bug and performance > vetted in production applications for years, so we should seriously > consider it as a properties alternative. Traits does look excellent at what it does, but I'm still of the opinion that the cost of adding a large external dependency that is not available in Debian or Ubuntu outweighs the benefits of replacing vanilla properties with traits. > I strongly encourage you to download Fernando's mplconfig sandbox > stuff and try the edit_traits demo in the presence of a wx enabled > traits. I'll give it a try. > He is somewhat blown away by the fact that he got a sophisticated, > nested GUI dialog w/o writing *any* code. Since you are a > committed wx user, you might find this particularly appealing. No one's committed me yet, mwahaha! Actually, that feature does little to advance my primary use case for mpl, embedding plots in applications. I my experience you have to put enough effort into making the plots look good that you don't want users to be able to edit them at runtime. That being said, I wouldn't be surprised to learn that others' experiences differ. > But at the end of the day, I think the *notification* aspect of > traits is the killer feature. I know, and I still think that for matplotlib it's a bad Software Engineering move due to the implicit inter-object dependencies it creates. I can't see why drawing plots should require that much "spooky action at a distance". I could be wrong, but for now I'll keep working to find a way that doesn't. > I think your approach of working on a display PDF renderer interface > is also a good one, for several reasons. It uses an established > specification instead of a home grown one, and it makes it easier for > us to consider things like integrating with Kiva or Chaco. It's nice to hear you like it. Those are two of the specific goals I have in mind. I also like the idea of having a generic retained drawing system available in Python. > I am glad you interpreted my mpl1 sketch in the right vein, as a > lab in which > people can advocate ideas as working code. Well, I'm glad you've taken my criticisms of mpl1.py in the spirit they were intended in. I also appreciate you taking the time to review the code I submitted instead of just telling me how very nice and convenient traits are. ;-) > Hopefully next week we can come to some consensus and start merging > our two lines. That sounds like a plan. I'll try to make some progress on the blended affines for drawing axis tickmarks and the Artists layer. Ken ------------------------------------------------------------------------- This SF.net email is sponsored by: Splunk Inc. Still grepping through log files to find problems? Stop. Now Search log events and configuration files using AJAX and a browser. Download your FREE copy of Splunk now >> http://get.splunk.com/ _______________________________________________ Matplotlib-devel mailing list Matplotlib-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-devel