Fuzzy plots of ode solutions

Michael Droettboom <mdroe@...86...>
writes:

Passing solid_joinstyle='bevel' does resolve the problem on both 0.91.x
and 0.98.x. Additionally, path simplification (which is a new feature
on 0.98.x) also resolves this problem (set rcParam path.simplify to True).

It seems that agg and pdf have different ways to render small angles
when the join style is 'miter'. Pdf has a limit (settable in the pdf
file) beyond which it reverts to bevel-style angles, agg seems to always
do the miter join but cuts it off at some distance.

Here's a test script, and screenshots of (a part of) the agg and pdf
outputs when the join style is 'miter'.

joinstyle.py (789 Bytes)

agg_miter.png

pdf_miter.png

···

--
Jouni K. Sepp�nen
http://www.iki.fi/jks

This is a very good test to have -- we should add it to backend_driver.py.

FWIW, SVG appears to behave similarly to PDF, and has a "miter-limit" property to control when to bevel vs. miter when the mode is set to "miter". (Though the default threshold appears to be different.) I didn't look into Ps, but it may have a similar configuration.

Agg also has a miter limit (which is not currently settable from Python), but it reverts to what it calls "smart" beveling, rather than regular beveling when below that limit. It does, however, have another miter mode called "miter_join_revert" which doesn't do smart beveling. (Try the "conv_stroke" example in the Agg source). In fact, it has this comment associated with it (agg_math_stroke.h:275):

    // For the compatibility with SVG, PDF, etc,
    // we use a simple bevel join instead of
    // "smart" bevel

I think there is an argument to be made that we should use this mode instead in the Agg backend, to be consistent with PDF and SVG (see patch below).

On a higher level, however, I am a bit concerned about this miter limit concept. It seems a bit dangerous for scientific plots: there is a large change in the look of the corner after only a small change in angle around the miter limit threshold. It may make the data appear to have large changes where in fact the changes are small. This seems like an argument of "bevel" or "round" as the default line join (it is currently "miter"). I also like the idea of "round" join keeping the corner close to the actual data point.

Now, if the user wants miter joins, they can, but I would suggest that we set the miter-limit threshold in all backends high enough such that it "always miters" and "never bevels". I can't see why (for other than artistic purposes), one would want to sometimes miter or bevel depending on angle in a scientific plot. We can expose miter limit as a parameter somehow, but for a default, I think it should be "always miter". What do you think?

Cheers,
Mike

Index: _backend_agg.cpp

···

===================================================================
--- _backend_agg.cpp (revision 6731)
+++ _backend_agg.cpp (working copy)
@@ -209,7 +209,7 @@
   std::string joinstyle = Py::String( gc.getAttr("_joinstyle") );
    if (joinstyle=="miter")
- join = agg::miter_join;
+ join = agg::miter_join_revert;
   else if (joinstyle=="round")
     join = agg::round_join;
   else if(joinstyle=="bevel")

Jouni K. Sepp�nen wrote:

Michael Droettboom <mdroe@...86...>
writes:

Passing solid_joinstyle='bevel' does resolve the problem on both 0.91.x and 0.98.x. Additionally, path simplification (which is a new feature on 0.98.x) also resolves this problem (set rcParam path.simplify to True).
    
It seems that agg and pdf have different ways to render small angles
when the join style is 'miter'. Pdf has a limit (settable in the pdf
file) beyond which it reverts to bevel-style angles, agg seems to always
do the miter join but cuts it off at some distance.

Here's a test script, and screenshots of (a part of) the agg and pdf
outputs when the join style is 'miter'.

  ------------------------------------------------------------------------

------------------------------------------------------------------------

------------------------------------------------------------------------

------------------------------------------------------------------------------
------------------------------------------------------------------------

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Michael Droettboom wrote:

This is a very good test to have -- we should add it to backend_driver.py.

FWIW, SVG appears to behave similarly to PDF, and has a "miter-limit" property to control when to bevel vs. miter when the mode is set to "miter". (Though the default threshold appears to be different.) I didn't look into Ps, but it may have a similar configuration.

Agg also has a miter limit (which is not currently settable from Python), but it reverts to what it calls "smart" beveling, rather than regular beveling when below that limit. It does, however, have another miter mode called "miter_join_revert" which doesn't do smart beveling. (Try the "conv_stroke" example in the Agg source). In fact, it has this comment associated with it (agg_math_stroke.h:275):

    // For the compatibility with SVG, PDF, etc,
    // we use a simple bevel join instead of
    // "smart" bevel

I think there is an argument to be made that we should use this mode instead in the Agg backend, to be consistent with PDF and SVG (see patch below).

On a higher level, however, I am a bit concerned about this miter limit concept. It seems a bit dangerous for scientific plots: there is a large change in the look of the corner after only a small change in angle around the miter limit threshold. It may make the data appear to have large changes where in fact the changes are small. This seems like an argument of "bevel" or "round" as the default line join (it is currently "miter"). I also like the idea of "round" join keeping the corner close to the actual data point.

Now, if the user wants miter joins, they can, but I would suggest that we set the miter-limit threshold in all backends high enough such that it "always miters" and "never bevels". I can't see why (for other than artistic purposes), one would want to sometimes miter or bevel depending on angle in a scientific plot. We can expose miter limit as a parameter somehow, but for a default, I think it should be "always miter". What do you think?

Mike,

Everything you said above sounds right to me, for plotting data--round joins are likely to provide a good combination of aesthetics and faithfulness to the data. Miters are needed for things like arrows (e.g. in quiver), and pcolor patches.

Eric

···

Cheers,
Mike

Index: _backend_agg.cpp

--- _backend_agg.cpp (revision 6731)
+++ _backend_agg.cpp (working copy)
@@ -209,7 +209,7 @@
   std::string joinstyle = Py::String( gc.getAttr("_joinstyle") );
    if (joinstyle=="miter")
- join = agg::miter_join;
+ join = agg::miter_join_revert;
   else if (joinstyle=="round")
     join = agg::round_join;
   else if(joinstyle=="bevel")

Jouni K. Seppänen wrote:

Michael Droettboom <mdroe@...86...>
writes:

Passing solid_joinstyle='bevel' does resolve the problem on both 0.91.x and 0.98.x. Additionally, path simplification (which is a new feature on 0.98.x) also resolves this problem (set rcParam path.simplify to True).
    

It seems that agg and pdf have different ways to render small angles
when the join style is 'miter'. Pdf has a limit (settable in the pdf
file) beyond which it reverts to bevel-style angles, agg seems to always
do the miter join but cuts it off at some distance.

Here's a test script, and screenshots of (a part of) the agg and pdf
outputs when the join style is 'miter'.

  ------------------------------------------------------------------------

------------------------------------------------------------------------

------------------------------------------------------------------------

------------------------------------------------------------------------------
------------------------------------------------------------------------

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

------------------------------------------------------------------------------
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Eric Firing wrote:

Michael Droettboom wrote:

This is a very good test to have -- we should add it to backend_driver.py.

FWIW, SVG appears to behave similarly to PDF, and has a "miter-limit" property to control when to bevel vs. miter when the mode is set to "miter". (Though the default threshold appears to be different.) I didn't look into Ps, but it may have a similar configuration.

Agg also has a miter limit (which is not currently settable from Python), but it reverts to what it calls "smart" beveling, rather than regular beveling when below that limit. It does, however, have another miter mode called "miter_join_revert" which doesn't do smart beveling. (Try the "conv_stroke" example in the Agg source). In fact, it has this comment associated with it (agg_math_stroke.h:275):

    // For the compatibility with SVG, PDF, etc,
    // we use a simple bevel join instead of
    // "smart" bevel

I think there is an argument to be made that we should use this mode instead in the Agg backend, to be consistent with PDF and SVG (see patch below).

On a higher level, however, I am a bit concerned about this miter limit concept. It seems a bit dangerous for scientific plots: there is a large change in the look of the corner after only a small change in angle around the miter limit threshold. It may make the data appear to have large changes where in fact the changes are small. This seems like an argument of "bevel" or "round" as the default line join (it is currently "miter"). I also like the idea of "round" join keeping the corner close to the actual data point.

Now, if the user wants miter joins, they can, but I would suggest that we set the miter-limit threshold in all backends high enough such that it "always miters" and "never bevels". I can't see why (for other than artistic purposes), one would want to sometimes miter or bevel depending on angle in a scientific plot. We can expose miter limit as a parameter somehow, but for a default, I think it should be "always miter". What do you think?

Everything you said above sounds right to me, for plotting data--round joins are likely to provide a good combination of aesthetics and faithfulness to the data. Miters are needed for things like arrows (e.g. in quiver), and pcolor patches.

Good "point" (pun intended). If we change the default from miter, we will need to ensure that arrows etc. are explicitly asking for miter joins.

Cheers,
Mike