Arrows that shimmy

Hi all,
    I' ve been using matplotlib to create some animations and it seems
that the endpoints for arrow polygon lines are being rounded off to
the nearest pixel. At least thats my guess. When viewing an animation
the arrow changes shape and distorts as it moves around. The code
below shows it on my Windows XP system where I'm using Matplotlib
0.91.1, SciPy 0.6.0, Numpy 1.0.4, Python 2.4. (The code is adapted
from examples/animation_blit_tk.py) I've also seen this on my Linux
setup when producing .png's for animation. I think I also remember
noticing circle patches having discrete movements, so it may be more
general than arrows.
    I'm wondering if other's find this to be a problem. Its
distracting in my particular case. What can I do to help change this?
I've been enjoying matplotlib along with basemap for the past two
years and would like to help out if I can.
Norm.

- - - - - -
import matplotlib
matplotlib.use('TkAgg')

import sys
import pylab as p
from matplotlib.patches import Arrow

ax = p.subplot(111)
canvas = ax.figure.canvas

def run(*args):
    background = canvas.copy_from_bbox(ax.bbox)

    while 1:
        canvas.restore_region(background)

        ells = [Arrow(x = i/20.+ (run.cnt+1)/16000.,
                      y = 0.4+ (run.cnt+1)/30000.,
                      dx = 0.04 + 1/200.,
                      dy = 0.06,
                      width=0.03)
            for i in xrange(10)]
        for e in ells:
            ax.add_artist(e)
        for e in ells:
            ax.draw_artist(e)

        canvas.blit(ax.bbox)

        for e in ells:
            e.remove()

        if run.cnt==1000:
            sys.exit()

        run.cnt += 1
run.cnt = 0

p.subplots_adjust(left=0.3, bottom=0.3)
p.grid()
manager = p.get_current_fig_manager()
manager.window.after(100, run)
p.show()
- - - - - -

Norman,

There is code (in 0.91, going back before my time) that rounds the vertices of polygons (which arrows in effect are) to the center of pixels. You can see it here inside RendererAgg::draw_polygon() in _backend_agg.cpp:

   agg::path_storage path;
   for (size_t j=0; j<Npoints; j++) {

     double x = xs[j];
     double y = ys[j];

     //snapto pixel centers
     x = (int)x + 0.5;
     y = (int)y + 0.5;

     if (j==0) path.move_to(x,y);
     else path.line_to(x,y);
   }
   path.close_polygon();

You could comment out these two lines:

     x = (int)x + 0.5;
     y = (int)y + 0.5;

and see if that corrects your wiggliness problem, just to confirm that as the source.

The bigger question is -- there was probably a good reason that this code was put in there in the first place, so it probably isn't a good idea to remove it en masse. It may need to be exposed as an argument so some things get this behavior and others don't. I know that dashed lines that are perpendicular to the edges of the figure (e.g. grid lines) look much worse if they aren't rounded to pixel centers. But in general for polygons, I don't know if that's true.

Now to veer away from your question a little bit -->

On the transforms branch (which is now in SVN head, and not in any release), this behavior has changed. The new heuristic is that if a path (which includes everything including lines and polygons) includes only straight and axis-aligned segments, it is rounded. If it includes any curves or non-axis-aligned segments it is not rounded. This heuristic seems to work quite well in practice, since it includes grid lines, non-rotated rectangles etc., but I am interested in getting feedback from other users if that heuristic fails in any special circumstances.

Cheers,
Mike

Norman Davis wrote:

···

Hi all,
    I' ve been using matplotlib to create some animations and it seems
that the endpoints for arrow polygon lines are being rounded off to
the nearest pixel. At least thats my guess. When viewing an animation
the arrow changes shape and distorts as it moves around. The code
below shows it on my Windows XP system where I'm using Matplotlib
0.91.1, SciPy 0.6.0, Numpy 1.0.4, Python 2.4. (The code is adapted
from examples/animation_blit_tk.py) I've also seen this on my Linux
setup when producing .png's for animation. I think I also remember
noticing circle patches having discrete movements, so it may be more
general than arrows.
    I'm wondering if other's find this to be a problem. Its
distracting in my particular case. What can I do to help change this?
I've been enjoying matplotlib along with basemap for the past two
years and would like to help out if I can.
Norm.

- - - - - -
import matplotlib
matplotlib.use('TkAgg')

import sys
import pylab as p
from matplotlib.patches import Arrow

ax = p.subplot(111)
canvas = ax.figure.canvas

def run(*args):
    background = canvas.copy_from_bbox(ax.bbox)

    while 1:
        canvas.restore_region(background)

        ells = [Arrow(x = i/20.+ (run.cnt+1)/16000.,
                      y = 0.4+ (run.cnt+1)/30000.,
                      dx = 0.04 + 1/200.,
                      dy = 0.06,
                      width=0.03)
            for i in xrange(10)]
        for e in ells:
            ax.add_artist(e)
        for e in ells:
            ax.draw_artist(e)

        canvas.blit(ax.bbox)

        for e in ells:
            e.remove()

        if run.cnt==1000:
            sys.exit()

        run.cnt += 1
run.cnt = 0

p.subplots_adjust(left=0.3, bottom=0.3)
p.grid()
manager = p.get_current_fig_manager()
manager.window.after(100, run)
p.show()
- - - - - -

-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://ad.doubleclick.net/clk;164216239;13503038;w?http://sf.net/marketplace
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
matplotlib-users List Signup and Options

--
Michael Droettboom
Science Software Branch
Operations and Engineering Division
Space Telescope Science Institute
Operated by AURA for NASA

For subpixel accuracy in rendering, agg antialiasing causes different
line segments to appear different in their thicknesses if they do not
have the same subpixel values. Maxim wrote the following essay on the
subject:

http://antigrain.com/tips/line_alignment/line_alignment.agdoc.html#PAGE_LINE_ALIGNMENT

For this reason, to preserve visible consistency of the segments, I
have several parts in the agg code which snaps the vertices ot the
pixel centers. I have never found a solution that seems to work in
all cases, since removing the snapto code will cause the
inconsistencies referred to above. I think should probably be a
graphics context property (which could get the information from an
artist property) so at least the user could control it when needed.

JDH

···

On Jan 9, 2008 9:11 AM, Michael Droettboom <mdroe@...86...> wrote:

You could comment out these two lines:

     x = (int)x + 0.5;
     y = (int)y + 0.5;

and see if that corrects your wiggliness problem, just to confirm that
as the source.

The bigger question is -- there was probably a good reason that this
code was put in there in the first place, so it probably isn't a good
idea to remove it en masse. It may need to be exposed as an argument so
some things get this behavior and others don't. I know that dashed
lines that are perpendicular to the edges of the figure (e.g. grid
lines) look much worse if they aren't rounded to pixel centers. But in
general for polygons, I don't know if that's true.

Hi John, Hi Mike,

I commented out the two lines in draw_polygon() and am now getting
very smooth arrow movement in my animations. It looks GREAT!

I've got my system here now set up so I can easily turn the rounding
on and off, by switching the PATH, and will watch the results so I can
understand more about this issue. The more I understand, the harder it
looks.

Being able to control this as a property of an artist would definitely
work easily enough for my scenario.

I'll also give the new hueristic in SVN a try and see how it works for me.

Thanks for all the help!

···

On Jan 9, 2008 11:53 AM, John Hunter <jdh2358@...287...> wrote:

On Jan 9, 2008 9:11 AM, Michael Droettboom <mdroe@...86...> wrote:

> You could comment out these two lines:
>
> x = (int)x + 0.5;
> y = (int)y + 0.5;
>
> and see if that corrects your wiggliness problem, just to confirm that
> as the source.
>
> The bigger question is -- there was probably a good reason that this
> code was put in there in the first place, so it probably isn't a good
> idea to remove it en masse. It may need to be exposed as an argument so
> some things get this behavior and others don't. I know that dashed
> lines that are perpendicular to the edges of the figure (e.g. grid
> lines) look much worse if they aren't rounded to pixel centers. But in
> general for polygons, I don't know if that's true.

For subpixel accuracy in rendering, agg antialiasing causes different
line segments to appear different in their thicknesses if they do not
have the same subpixel values. Maxim wrote the following essay on the
subject:

http://antigrain.com/tips/line_alignment/line_alignment.agdoc.html#PAGE_LINE_ALIGNMENT

For this reason, to preserve visible consistency of the segments, I
have several parts in the agg code which snaps the vertices ot the
pixel centers. I have never found a solution that seems to work in
all cases, since removing the snapto code will cause the
inconsistencies referred to above. I think should probably be a
graphics context property (which could get the information from an
artist property) so at least the user could control it when needed.

JDH