mpl1 draft

Peter Wang wrote:

Ah! and some good math implementation -- What does Chaco do for that?

We've also had this discussion internally a bit. It usually concludes with us wishing that someone would just port jsmath to Python, or implement Knuth's TeX layout rules in Python. :slight_smile:

It looks like jsmath uses the TeX layout rules, so those are the same thing. If you can do it in JS, you sure should be able to do it in Python!

> Currently Chaco2 doesn't have a math markup mechanism, but it was

fairly trivial for me to port mpl's mathtext to Chaco1. I didn't bother moving that to Chaco2 because I really wanted to figure out a way to do "real" TeX layout that would still fit into the interactive model.

That would be nice. I agree, the Math-as-bitmap approach really isn't the way to go, but it does work OK in the meantime!

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...236...

I took a look at examples on the jsmath webpage, and it looks like the
square-root
placement is glitchy (Firefox on WinXP). If it really is TeX's rules
I wonder what the problem is. Maybe fonts on my end?

--bb

···

On 7/25/07, Chris Barker <Chris.Barker@...236...> wrote:

Peter Wang wrote:
> We've also had this discussion internally a bit. It usually
> concludes with us wishing that someone would just port jsmath to
> Python, or implement Knuth's TeX layout rules in Python. :slight_smile:

It looks like jsmath uses the TeX layout rules, so those are the same
thing. If you can do it in JS, you sure should be able to do it in Python!

"""
\begin{minipage}{3cm}
Multi line \\ tick marker
\end{minipage}

x\\,e^\{x\} \\underset\{x \\rightarrow 0\}\{\\thicksim\} x
% That one probably does not run without \usepackage{amsmath} in the preamble

Velocity [{\small m$\cdot$s$^{-1}$}]

\begin{eqarray}
\Phi(v_z) & = &
\int_{z=0}^l
\int_{v_r=0}^{v_c}
\underbrace{v_r \,n \,B_T(v_r, v_z)}_{\text{\parbox{17ex}{\tiny
flux per surface element}}}
\;\times
\underbrace{
\begin{cases}
1 \text{~\small if z/v\_z&lt;\\tau} \\
0 \text{~\small elsewhere}
\end{cases}
\!\!\!\!\!\!
}_{\text{Capture condition}}
\times \;
\underbrace{2 \pi v_r dv_r}_{\text{\parbox{7ex}{\tiny
polar coord.}}} \,
\underbrace{2\pi\, r_c}_{\text{\parbox{11ex}{\tiny 2D-MOT perimeter}}}
dz
\\
& = & 4\pi^2\,v_c^3\, r_c \; n \,
(\pi v_\text{max}^2)^{-\slantfrac{3}{2}}
e^{-v_z^2 /v_\text{max}^2} \big(
e^{-\Gamma_\text{coll} \tau} - e^{-\Gamma_\text{coll} l/ v_z}
\big)
\frac{v_z}{\Gamma_\text{coll}}
\end{eqnarray}
"""

And many more. As you can see this is mainly advanced math with sometimes
some ugly solutions (the parboxes in the underbraces, hum...), but it
works it LaTeX, and I am happy to have this familiar language at hand
when doing figures.

Ga�l

···

On Wed, Jul 25, 2007 at 03:25:36PM +0900, Bill Baxter wrote:

> Well I want TeX. I want to be able to do my TeX hacks on my figures. And
> I do believe there is a lot of work to be done before you can do better
> than TeX.

What kind of TeX hacks do you want to use on figures? My TeX hacks
include mostly things like using negative vspace to squeeze more text
into a 6-page paper.

Chris Barker wrote:

Peter Wang wrote:
  

Ah! and some good math implementation -- What does Chaco do for that?
      
We've also had this discussion internally a bit. It usually concludes with us wishing that someone would just port jsmath to Python, or implement Knuth's TeX layout rules in Python. :slight_smile:
    
It looks like jsmath uses the TeX layout rules, so those are the same thing. If you can do it in JS, you sure should be able to do it in Python!

I currently have a branch (mathtext_mgd), where I am implementing the TeX layout model in Python. It does not attempt to reimplement the whole kit-and-kaboodle (especially the parser and macros etc.), just the box model and some of the math layout algorithms, so it won't support the kind of things Gael is suggesting. But the existing adjacency model was becoming somewhat of a dead end wrt implementing new features like fractions and radicals. Stay tuned -- the code is already beyond feature parity with the old implementation, so I expect to merge this back into the trunk soon.

Cheers,
Mike

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. It looks very clean and is an impressive piece of
work. I'll agree with your assessment above that from a code reading
perspective, this looks a bit more digestible that what I have done
using traits. 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 also would like to hear more
about the "hard to optimize" part, because that is not intuitively
clear to me.

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.
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)?. 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.

As for code readability, I'll also add that as a traits newbie, I am
probably making things harder than necessary. But there are a lot of
gotchas with traits usage, particularly in the area of instantiation,
because you can easily get bitten by shared class level data
structures, especially in the presence of sync_traits.

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. 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. 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. But at the end of the day, I think the
*notification* aspect of traits is the killer feature.

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. I am glad
you interpreted my mpl1 sketch in the right vein, as a lab in which
people can advocate ideas as working code. Much more productive than
lots of emails, I think. Hopefully next week we can come to some
consensus and start merging our two lines.

PS: I'm not ignoring you either Peter, but I won't be able to get to
all your questions and comments until a bit later; as you know the
harder problems take longer to address

···

On 7/24/07, Ken McIvor <mcivor@...227...> wrote:

Since my original comment about traits I have been working hard to
put my money where my mouth is. Attached is an experimental
rendering system with an alternative transform architecture that does
not require attribute change notification. Please let me know what
you think, everybody.

One thing that is convenient when working with Traits, is that there
already are established coding conventions. The problem when coding with
metaclasses is that it is easy to prduce very beautiful code that is hard
to read for the newcomer (I have fallen in that trap). Traits are nothing
more but a metaclass, they also have this problem. But if they become
wildy used this problem goes away.

Ga�l

···

On Wed, Jul 25, 2007 at 12:09:01PM -0500, John Hunter wrote:

As for code readability, I'll also add that as a traits newbie, I am
probably making things harder than necessary. But there are a lot of
gotchas with traits usage, particularly in the area of instantiation,
because you can easily get bitten by shared class level data
structures, especially in the presence of sync_traits.

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. :wink:

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

···

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. :wink:

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

···

Sent via BlackBerry from T-Mobile
-----Original Message-----
From: Ken McIvor <mcivor@...227...>
Date: Fri, 27 Jul 2007 17:35:05
To:John Hunter <jdh2358@...149...>
Cc:matplotlib development list <matplotlib-devel@lists.sourceforge.net>
Subject: Re: [matplotlib-devel] mpl1 draft

On Jul 25, 2007, at 12:09 PM, John Hunter wrote: