"Flash" rendering in the Agg backend

Smart rendering of adjacent, anti-aliased patches is a question which has come up a couple of times in various guises in the past.
It is my understanding that the lack of this functionality led us to disable anti-aliasing for contouring and is the reason the following image has a white stripe around the circle where there should be just a nice blend of the two colors:

import matplotlib.pyplot as plt
import numpy as np

import matplotlib.patches as mpatches
import matplotlib.path as mpath

import matplotlib.collections as mcol

create two paths. One a circle, the other

a square with the same circle cut out.

x = np.linspace(0, np.pi * 2, 1000)

circle_coords = np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))

pth_circle = mpath.Path(circle_coords)

sqr_codes = np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)

sqr_codes[1:5] = mpath.Path.LINETO
sqr_codes[6:] = mpath.Path.LINETO

sqr_coords = np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1], [-1, -1]],
circle_coords[::-1]], axis=0)

sqr_path = mpath.Path(sqr_coords, sqr_codes)

ax = plt.axes()
patches = [mpatches.PathPatch(pth_circle), mpatches.PathPatch(sqr_path)]

col = mcol.PatchCollection(patches,
antialiaseds=True,

                       edgecolors='none',
                       facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02, 0.9)])

ax.add_collection(col)
ax.set_xlim([-1, 1])

ax.set_ylim([-1, 1])
plt.show()

figure_1.png

I know of lots of the workarounds for this (turn off AA, turn on lines, extend the path slightly, set a dark background color) all of which have down-sides, so I’m keen to find a final solution to the problem.

When the two patches marry up perfectly with full anti-aliasing, the antigrain (AGG) community call this “flash” or compound rendering, and this capability was added to Agg 2.4 (which we already ship with mpl).

In order to make full use of the compound rendering technique I believe the drawing pipeline in “_backend_agg.cpp” would need to change, which could be problematic. A less wide-impacting alternative would be to draw all “patches” of a single Collection in the same rasterization step (i.e. just change _draw_path_collection_generic), though this does mean that, as it stands, the result of plt.contourf would not be able to make use of this new functionality - a MEP which changes the return type of plt.contourf to a single Collection might be able to fix that.

I’ve put together a simple example similar to this in C++ using agg (no mpl changes yet), showing the differences in the code needed between the old technique vs the “new” compound renderer (attached).

Ok, so the question to those that have knowledge of the _backend_agg.cpp code (Mike, Eric, JJ + others?):

  • Have you already looked at doing this and determined that this is a non-starter?
  • Do you support adding the ability for the agg backend to draw compound artists (i.e. Collections) in this way rather than treating them as individual primitives in the canvas?
  • Since many of the other backends can’t do flash rendering, would we even want to make this change?
  • SVG in Firefox 10.0.2 has the same problem, it is discussed slightly more in http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  • Acroread has the same problem with PDFs, only to a much lesser extent than in the PNG attached

Thoughts?

bad_paths.1.cpp (2.86 KB)

bad_paths.2.cpp (3.97 KB)

Phil,

Would this greatly slow down the rendering?

Does it work with alpha < 1?

I'm initially not enthusiastic about having contourf return a single Collection, but maybe in practice it would not make much difference. The drawback, apart from code brakeage, is that it would remove the ability to pick out a level for additional customization.

Could this be handled at a subsequent level, by having the renderer able to treat an arbitrary collection of artists as a group?

It seems that contourf is where this "flash" capability would be most important; if it can't be made to work there, I think it might not be worth the trouble to add.

Eric

···

On 2013/03/06 7:06 AM, Phil Elson wrote:

Smart rendering of adjacent, anti-aliased patches is a question which
has come up a couple of times in various guises in the past.
It is my understanding that the lack of this functionality led us to
disable anti-aliasing for contouring and is the reason the following
image has a white stripe around the circle where there should be just a
nice blend of the two colors:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.collections as mcol

# create two paths. One a circle, the other
# a square with the same circle cut out.
x = np.linspace(0, np.pi * 2, 1000)

circle_coords = np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))
pth_circle = mpath.Path(circle_coords)

sqr_codes = np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)
sqr_codes[1:5] = mpath.Path.LINETO
sqr_codes[6:] = mpath.Path.LINETO
sqr_coords = np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1], [-1,
-1]],
                             circle_coords[::-1]], axis=0)
sqr_path = mpath.Path(sqr_coords, sqr_codes)

ax = plt.axes()
patches = [mpatches.PathPatch(pth_circle), mpatches.PathPatch(sqr_path)]
col = mcol.PatchCollection(patches,
                            antialiaseds=True,
                            edgecolors='none',
                            facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1,
0.02, 0.9)])
ax.add_collection(col)
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
plt.show()

I know of lots of the workarounds for this (turn off AA, turn on lines,
extend the path slightly, set a dark background color) all of which have
down-sides, so I'm keen to find a final solution to the problem.

When the two patches marry up perfectly with full anti-aliasing, the
antigrain (AGG) community call this "flash" or compound rendering, and
this capability was added to Agg 2.4 (which we already ship with mpl).

In order to make full use of the compound rendering technique I believe
the drawing pipeline in "_backend_agg.cpp" would need to change, which
could be problematic. A less wide-impacting alternative would be to draw
all "patches" of a single Collection in the same rasterization step
(i.e. just change _draw_path_collection_generic), though this does mean
that, as it stands, the result of plt.contourf would not be able to make
use of this new functionality - a MEP which changes the return type of
plt.contourf to a single Collection might be able to fix that.

I've put together a simple example similar to this in C++ using agg (no
mpl changes yet), showing the differences in the code needed between the
old technique vs the "new" compound renderer (attached).

Ok, so the question to those that have knowledge of the _backend_agg.cpp
code (Mike, Eric, JJ + others?):

  * Have you already looked at doing this and determined that this is a
    non-starter?
  * Do you support adding the ability for the agg backend to draw
    compound artists (i.e. Collections) in this way rather than treating
    them as individual primitives in the canvas?
  * Since many of the other backends can't do flash rendering, would we
    even want to make this change?
      o SVG in Firefox 10.0.2 has the same problem, it is discussed
        slightly more in
        http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
      o Acroread has the same problem with PDFs, only to a much lesser
        extent than in the PNG attached

Thoughts?

I'm trying to compile your examples, but it seems perhaps you forget to include a file -- pixel_formats.hpp? It's not in the agg24 source tree.

Mike

···

On 03/06/2013 12:06 PM, Phil Elson wrote:

Smart rendering of adjacent, anti-aliased patches is a question which has come up a couple of times in various guises in the past.
It is my understanding that the lack of this functionality led us to disable anti-aliasing for contouring and is the reason the following image has a white stripe around the circle where there should be just a nice blend of the two colors:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.collections as mcol

# create two paths. One a circle, the other
# a square with the same circle cut out.
x = np.linspace(0, np.pi * 2, 1000)

circle_coords = np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))
pth_circle = mpath.Path(circle_coords)

sqr_codes = np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)
sqr_codes[1:5] = mpath.Path.LINETO
sqr_codes[6:] = mpath.Path.LINETO
sqr_coords = np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1], [-1, -1]],
circle_coords[::-1]], axis=0)
sqr_path = mpath.Path(sqr_coords, sqr_codes)

ax = plt.axes()
patches = [mpatches.PathPatch(pth_circle), mpatches.PathPatch(sqr_path)]
col = mcol.PatchCollection(patches,
antialiaseds=True,
edgecolors='none',
facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02, 0.9)])
ax.add_collection(col)
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
plt.show()

I know of lots of the workarounds for this (turn off AA, turn on lines, extend the path slightly, set a dark background color) all of which have down-sides, so I'm keen to find a final solution to the problem.

When the two patches marry up perfectly with full anti-aliasing, the antigrain (AGG) community call this "flash" or compound rendering, and this capability was added to Agg 2.4 (which we already ship with mpl).

In order to make full use of the compound rendering technique I believe the drawing pipeline in "_backend_agg.cpp" would need to change, which could be problematic. A less wide-impacting alternative would be to draw all "patches" of a single Collection in the same rasterization step (i.e. just change _draw_path_collection_generic), though this does mean that, as it stands, the result of plt.contourf would not be able to make use of this new functionality - a MEP which changes the return type of plt.contourf to a single Collection might be able to fix that.

I've put together a simple example similar to this in C++ using agg (no mpl changes yet), showing the differences in the code needed between the old technique vs the "new" compound renderer (attached).

Ok, so the question to those that have knowledge of the _backend_agg.cpp code (Mike, Eric, JJ + others?):

  * Have you already looked at doing this and determined that this is
    a non-starter?
  * Do you support adding the ability for the agg backend to draw
    compound artists (i.e. Collections) in this way rather than
    treating them as individual primitives in the canvas?
  * Since many of the other backends can't do flash rendering, would
    we even want to make this change?
      o SVG in Firefox 10.0.2 has the same problem, it is discussed
        slightly more in
        http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
      o Acroread has the same problem with PDFs, only to a much lesser
        extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
endpoint security space. For insight on selecting the right partner to
tackle endpoint security challenges, access the full report.
http://p.sf.net/sfu/symantec-dev2dev

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

Thanks for bringing this up -- I was just looking at the test images the other day and was reminded how filled contouring doesn't look as good as it could be.

I had played with the "compound renderer" example in Agg some years ago, but couldn't really understand how it worked, so ultimately gave up on it. I appreciate the research you've done here, because it illustrates pretty clearly what is required. I guess in the actual Agg draw_path_collection renderer, we would have to build a style_handler table dynamically based on the collection and then iterate through it as we draw... At least it's clear now how that could be accomplished.

I wonder, though, and the SVG article you link to hints at this, if we wouldn't be better off just upsampling our Agg rendering instead. The advantage of such an approach would be that the structure or ordering of the drawing wouldn't matter at all -- allaying most of Eric's concerns. It seems like it just overall be "easier" to do the right thing. And it should benefit all things, including other tricky things like quadmeshes, "automatically".

Of course, the downside is a performance hit. Assuming 2x oversampling, it means the screen buffer will be 4x the size, rendering will take "up to" four times as long, and then you have to downsample again (which in the best case would happen in hardware). Compound rendering has a memory penalty, too, of course, since the scanlines for all of the paths have to be stored until finally rendered out simultaneously. Estimating what that overhead is much harder, of course, and is more content dependent, whereas the performance hit upsampling is straightforward and has an obvious upper bound.

I put together a very quick hack on my agg-upsampling branch, which hardcodes the upsampling to 2x in each direction. It currently only works with the GtkAgg backend (even file saving won't work correctly), and I only fixed things up for contour plotting, so images (and probably other things) will be misplaced. But it should give an idea for the performance hit and quality benefit enough to play around with.

Mike

contour.png

···

On 03/06/2013 03:27 PM, Michael Droettboom wrote:

I'm trying to compile your examples, but it seems perhaps you forget to include a file -- pixel_formats.hpp? It's not in the agg24 source tree.

Mike

On 03/06/2013 12:06 PM, Phil Elson wrote:

Smart rendering of adjacent, anti-aliased patches is a question which has come up a couple of times in various guises in the past.
It is my understanding that the lack of this functionality led us to disable anti-aliasing for contouring and is the reason the following image has a white stripe around the circle where there should be just a nice blend of the two colors:

import matplotlib.pyplot as plt
import numpy as np
import matplotlib.patches as mpatches
import matplotlib.path as mpath
import matplotlib.collections as mcol

# create two paths. One a circle, the other
# a square with the same circle cut out.
x = np.linspace(0, np.pi * 2, 1000)

circle_coords = np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))
pth_circle = mpath.Path(circle_coords)

sqr_codes = np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)
sqr_codes[1:5] = mpath.Path.LINETO
sqr_codes[6:] = mpath.Path.LINETO
sqr_coords = np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1], [-1, -1]],
circle_coords[::-1]], axis=0)
sqr_path = mpath.Path(sqr_coords, sqr_codes)

ax = plt.axes()
patches = [mpatches.PathPatch(pth_circle), mpatches.PathPatch(sqr_path)]
col = mcol.PatchCollection(patches,
antialiaseds=True,
edgecolors='none',
facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02, 0.9)])
ax.add_collection(col)
ax.set_xlim([-1, 1])
ax.set_ylim([-1, 1])
plt.show()

I know of lots of the workarounds for this (turn off AA, turn on lines, extend the path slightly, set a dark background color) all of which have down-sides, so I'm keen to find a final solution to the problem.

When the two patches marry up perfectly with full anti-aliasing, the antigrain (AGG) community call this "flash" or compound rendering, and this capability was added to Agg 2.4 (which we already ship with mpl).

In order to make full use of the compound rendering technique I believe the drawing pipeline in "_backend_agg.cpp" would need to change, which could be problematic. A less wide-impacting alternative would be to draw all "patches" of a single Collection in the same rasterization step (i.e. just change _draw_path_collection_generic), though this does mean that, as it stands, the result of plt.contourf would not be able to make use of this new functionality - a MEP which changes the return type of plt.contourf to a single Collection might be able to fix that.

I've put together a simple example similar to this in C++ using agg (no mpl changes yet), showing the differences in the code needed between the old technique vs the "new" compound renderer (attached).

Ok, so the question to those that have knowledge of the _backend_agg.cpp code (Mike, Eric, JJ + others?):

  * Have you already looked at doing this and determined that this is
    a non-starter?
  * Do you support adding the ability for the agg backend to draw
    compound artists (i.e. Collections) in this way rather than
    treating them as individual primitives in the canvas?
  * Since many of the other backends can't do flash rendering, would
    we even want to make this change?
      o SVG in Firefox 10.0.2 has the same problem, it is discussed
        slightly more in
        http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
      o Acroread has the same problem with PDFs, only to a much
        lesser extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
endpoint security space. For insight on selecting the right partner to
tackle endpoint security challenges, access the full report.
http://p.sf.net/sfu/symantec-dev2dev

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

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester
Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the
endpoint security space. For insight on selecting the right partner to
tackle endpoint security challenges, access the full report.
http://p.sf.net/sfu/symantec-dev2dev

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

While I cannot say much about the “compound renderering” in Agg as I know little about it, but the upsampling method that Mike mentioned seems quite robust.
Just a quick question, will it affect the rendered quality of AA’ed artists, like texts? What I mean is, drawing texts w/ AA on (in the upsampled canvas) and downsampling the result may give poor quality? But maybe there is a way to adjust how AA is done in the first place.

Maybe what we can try is to upsample only selected artists, similar to rasterization in vector backends or agg_filter. This will likely consume more memory and maybe more CPU, but may give minimal side effects.

While it is not directly related to the current issue, I thought it would be good to have, within a backend, multiple layers to render and the final result is a composite of those layers.

And we may upsample some layers or apply effects selectively. And do the alpha compositing of layers in the end. This will be also useful for animations as we can only update selected layers.

Back to the original issue, I am inclined to play with Mike’s upsamping method to see if it solves the problem without significant side effects.

Regards,

-JJ

···

On Thu, Mar 7, 2013 at 6:54 AM, Michael Droettboom <mdroe@…31…> wrote:

  Thanks for bringing this up -- I was

just looking at the test images the other day and was reminded how
filled contouring doesn’t look as good as it could be.

  I had played with the "compound renderer" example in Agg some

years ago, but couldn’t really understand how it worked, so
ultimately gave up on it. I appreciate the research you’ve done
here, because it illustrates pretty clearly what is required. I
guess in the actual Agg draw_path_collection renderer, we would
have to build a style_handler table dynamically based on the
collection and then iterate through it as we draw… At least
it’s clear now how that could be accomplished.

  I wonder, though, and the SVG article you link to hints at this,

if we wouldn’t be better off just upsampling our Agg rendering
instead. The advantage of such an approach would be that the
structure or ordering of the drawing wouldn’t matter at all –
allaying most of Eric’s concerns. It seems like it just overall
be “easier” to do the right thing. And it should benefit all
things, including other tricky things like quadmeshes,
“automatically”.

  Of course, the downside is a performance hit.  Assuming 2x

oversampling, it means the screen buffer will be 4x the size,
rendering will take “up to” four times as long, and then you have
to downsample again (which in the best case would happen in
hardware). Compound rendering has a memory penalty, too, of
course, since the scanlines for all of the paths have to be stored
until finally rendered out simultaneously. Estimating what that
overhead is much harder, of course, and is more content dependent,
whereas the performance hit upsampling is straightforward and has
an obvious upper bound.

  I put together a very quick hack on my agg-upsampling branch,

which hardcodes the upsampling to 2x in each direction. It
currently only works with the GtkAgg backend (even file saving
won’t work correctly), and I only fixed things up for contour
plotting, so images (and probably other things) will be
misplaced. But it should give an idea for the performance hit and
quality benefit enough to play around with.

  Mike




  On 03/06/2013 03:27 PM, Michael Droettboom wrote:
    I'm trying to compile your examples,

but it seems perhaps you forget to include a file –
pixel_formats.hpp? It’s not in the agg24 source tree.

    Mike



    On 03/06/2013 12:06 PM, Phil Elson wrote:
          Smart rendering of adjacent, anti-aliased patches is a

question which has come up a couple of times in various
guises in the past.

          It is my understanding that the lack of this functionality

led us to disable anti-aliasing for contouring and is the
reason the following image has a white stripe around the
circle where there should be just a nice blend of the two
colors:

              import

matplotlib.pyplot as plt

                              import

numpy as np

                              import

matplotlib.patches as mpatches

                              import

matplotlib.path as mpath

                              import

matplotlib.collections as mcol

                              # create

two paths. One a circle, the other

                              # a

square with the same circle cut out.

                              x =

np.linspace(0, np.pi * 2, 1000)

              circle_coords

= np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))

              pth_circle

= mpath.Path(circle_coords)

              sqr_codes

= np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)

              sqr_codes[1:5]

= mpath.Path.LINETO

              sqr_codes[6:]

= mpath.Path.LINETO

              sqr_coords

= np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1],
[-1, -1]],

circle_coords[::-1]], axis=0)

                              sqr_path

= mpath.Path(sqr_coords, sqr_codes)

                              ax =

plt.axes()

                              patches

= [mpatches.PathPatch(pth_circle),
mpatches.PathPatch(sqr_path)]

                              col =

mcol.PatchCollection(patches,

antialiaseds=True,

edgecolors=‘none’,

facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02,
0.9)])

            ax.add_collection(col)


              ax.set_xlim([-1,

1])

              ax.set_ylim([-1,

1])

            plt.show()
        I know of lots of the workarounds for this (turn off AA,

turn on lines, extend the path slightly, set a dark
background color) all of which have down-sides, so I’m keen
to find a final solution to the problem.

        When the two patches marry up perfectly with full

anti-aliasing, the antigrain (AGG) community call this
“flash” or compound rendering, and this capability was added
to Agg 2.4 (which we already ship with mpl).

        In order to make full use of the compound rendering

technique I believe the drawing pipeline in
“_backend_agg.cpp” would need to change, which could be
problematic. A less wide-impacting alternative would be to
draw all “patches” of a single Collection in the same
rasterization step (i.e. just change
_draw_path_collection_generic), though this does mean that,
as it stands, the result of plt.contourf would not be able
to make use of this new functionality - a MEP which changes
the return type of plt.contourf to a single Collection might
be able to fix that.

        I've put together a simple example similar to this in C++

using agg (no mpl changes yet), showing the differences in
the code needed between the old technique vs the “new”
compound renderer (attached).

      Ok, so the question to those that have knowledge of the

_backend_agg.cpp code (Mike, Eric, JJ + others?):

  •           Have you already looked at doing this and determined
    
    that this is a non-starter?
  •           Do you support adding the ability for the agg backend to
    
    draw compound artists (i.e. Collections) in this way
    rather than treating them as individual primitives in the
    canvas?
  •           Since many of the other backends can't do flash
    
    rendering, would we even want to make this change?
  •             SVG in Firefox 10.0.2 has the same problem, it is
    
    discussed slightly more in http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  •             Acroread has the same problem with PDFs, only to a
    
    much lesser extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)
------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester

Wave™: Endpoint Security, Q1 2013 and “remains a good choice” in the

endpoint security space. For insight on selecting the right partner to

tackle endpoint security challenges, access the full report.

http://p.sf.net/sfu/symantec-dev2dev


Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

I’m trying to compile your examples,
but it seems perhaps you forget to include a file

Sorry, you can find pixel_formats.h in the examples directory. I have a mirror of agg here: https://github.com/pelson/antigrain/tree/master/agg-2.4/examples

My compile steps are:

export AGG_DIR=

g++ -c -O3 -I${AGG_DIR}/include -I${AGG_DIR}/examples -L${AGG_DIR}/src basic_path.cpp -o basic_path.o

g++ -O3 -I${AGG_DIR}/include -L${AGG_DIR}/src basic_path.o -o basic_path -lagg

  > I had played with the "compound renderer" example in Agg some

years ago, but couldn’t really understand how it worked

Agreed. It took the best part of a day to figure out how to do it, given no prior knowledge of Agg. I intend to submit a couple of simpler (GUI-less) examples to be included with the agg repo - and perhaps even write some documentation for this stuff!

Does it work with alpha < 1?

Yes. I’ve attached the two images (converted from ppm to png using gimp + default settings) so that you can see the results. Each shape has an alpha value of 200.

bp.1.separate.pngbp.2.compound.png

HTH

···

On 6 March 2013 20:27, Michael Droettboom <mdroe@…31…> wrote:

  I'm trying to compile your examples,

but it seems perhaps you forget to include a file –
pixel_formats.hpp? It’s not in the agg24 source tree.

  Mike




  On 03/06/2013 12:06 PM, Phil Elson wrote:
        Smart rendering of adjacent, anti-aliased patches is a

question which has come up a couple of times in various
guises in the past.

        It is my understanding that the lack of this functionality

led us to disable anti-aliasing for contouring and is the
reason the following image has a white stripe around the
circle where there should be just a nice blend of the two
colors:

            import

matplotlib.pyplot as plt

                          import

numpy as np

                          import

matplotlib.patches as mpatches

                          import

matplotlib.path as mpath

                          import

matplotlib.collections as mcol

                          # create

two paths. One a circle, the other

                          # a square

with the same circle cut out.

                          x =

np.linspace(0, np.pi * 2, 1000)

                          circle_coords

= np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))

                          pth_circle

= mpath.Path(circle_coords)

                          sqr_codes

= np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)

                          sqr_codes[1:5]

= mpath.Path.LINETO

                          sqr_codes[6:]

= mpath.Path.LINETO

                          sqr_coords

= np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1],
[-1, -1]],

circle_coords[::-1]], axis=0)

                          sqr_path =

mpath.Path(sqr_coords, sqr_codes)

                          ax =

plt.axes()

                          patches =

[mpatches.PathPatch(pth_circle),
mpatches.PathPatch(sqr_path)]

                          col =

mcol.PatchCollection(patches,

antialiaseds=True,

edgecolors=‘none’,

facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02, 0.9)])

          ax.add_collection(col)

                          ax.set_xlim([-1,

1])

                          ax.set_ylim([-1,

1])

          plt.show()
      I know of lots of the workarounds for this (turn off AA, turn

on lines, extend the path slightly, set a dark background
color) all of which have down-sides, so I’m keen to find a
final solution to the problem.

      When the two patches marry up perfectly with full

anti-aliasing, the antigrain (AGG) community call this “flash”
or compound rendering, and this capability was added to Agg
2.4 (which we already ship with mpl).

      In order to make full use of the compound rendering technique

I believe the drawing pipeline in “_backend_agg.cpp” would
need to change, which could be problematic. A less
wide-impacting alternative would be to draw all “patches” of a
single Collection in the same rasterization step (i.e. just
change _draw_path_collection_generic), though this does mean
that, as it stands, the result of plt.contourf would not be
able to make use of this new functionality - a MEP which
changes the return type of plt.contourf to a single Collection
might be able to fix that.

      I've put together a simple example similar to this in C++

using agg (no mpl changes yet), showing the differences in the
code needed between the old technique vs the “new” compound
renderer (attached).

    Ok, so the question to those that have knowledge of the

_backend_agg.cpp code (Mike, Eric, JJ + others?):

  •         Have you already looked at doing this and determined that
    
    this is a non-starter?
  •         Do you support adding the ability for the agg backend to
    
    draw compound artists (i.e. Collections) in this way rather
    than treating them as individual primitives in the canvas?
  •         Since many of the other backends can't do flash rendering,
    
    would we even want to make this change?
  •           SVG in Firefox 10.0.2 has the same problem, it is
    
    discussed slightly more in http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  •           Acroread has the same problem with PDFs, only to a much
    
    lesser extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester

Wave™: Endpoint Security, Q1 2013 and “remains a good choice” in the

endpoint security space. For insight on selecting the right partner to

tackle endpoint security challenges, access the full report.

http://p.sf.net/sfu/symantec-dev2dev


Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Would this greatly slow down the rendering?

That is a million dollar question. Without trying it to see, we could ask the agg mailing list to see if they have any insight.

Personally I’d be surprised if anything we did at the Agg level was a bottleneck given how much python code comes before it - though I admit that doesn’t mean anything in practice…

I wonder, though, and the SVG article you link to hints at this,
if we wouldn’t be better off just upsampling our Agg rendering
instead.

I put together a very quick hack on my agg-upsampling branch,
which hardcodes the upsampling to 2x in each direction.

I’m not a big fan of supersampling (http://en.wikipedia.org/wiki/Supersample_anti-aliasing) - that is essentially implementing a global anti-aliasing scheme which one wouldn’t be able to control on an artist by artist basis (such as fonts) with the overhead cost of increasing the memory highwater by a factor of 5 (as you say for an image of size (n, m) at a minimum the drawing buffer needs to be (2n x 2m) + then downsampled to (n x m)). We might even want to upscale to a factor of 3 or 4 to really get rid of most of the white in this example.

From the linked SVG article:

Perfect antialiasing can be done by rendering complete artwork at a much higher resolution and subsequent downsampling.

I also dispute this claim. Whilst good anti-aliasing can be achieved using supersampling, I believe no matter the size of your bigger draw buffer you will always get a component of background color (white in our case) which goes into the averaging operation and therefore will impact the final pixel color. It is then a compromise between performance vs “good enough” rendering.

Having said all of the above, supersampling would be a nice feature to add to mpl’s Agg backends (and maybe the Cairo backend too) - though I do not believe it is a full solution to this problem.

Cheers,

bp.1.separate.png

bp.2.compound.png

···

On 7 March 2013 09:15, Phil Elson <pelson.pub@…272…149…> wrote:

  > I'm trying to compile your examples,

but it seems perhaps you forget to include a file

Sorry, you can find pixel_formats.h in the examples directory. I have a mirror of agg here: https://github.com/pelson/antigrain/tree/master/agg-2.4/examples

My compile steps are:

export AGG_DIR=

g++ -c -O3 -I${AGG_DIR}/include -I${AGG_DIR}/examples -L${AGG_DIR}/src basic_path.cpp -o basic_path.o

g++ -O3 -I${AGG_DIR}/include -L${AGG_DIR}/src basic_path.o -o basic_path -lagg

  > I had played with the "compound renderer" example in Agg some

years ago, but couldn’t really understand how it worked

Agreed. It took the best part of a day to figure out how to do it, given no prior knowledge of Agg. I intend to submit a couple of simpler (GUI-less) examples to be included with the agg repo - and perhaps even write some documentation for this stuff!

Does it work with alpha < 1?

Yes. I’ve attached the two images (converted from ppm to png using gimp + default settings) so that you can see the results. Each shape has an alpha value of 200.

HTH

On 6 March 2013 20:27, Michael Droettboom <mdroe@…31…> wrote:

  I'm trying to compile your examples,

but it seems perhaps you forget to include a file –
pixel_formats.hpp? It’s not in the agg24 source tree.

  Mike




  On 03/06/2013 12:06 PM, Phil Elson wrote:
        Smart rendering of adjacent, anti-aliased patches is a

question which has come up a couple of times in various
guises in the past.

        It is my understanding that the lack of this functionality

led us to disable anti-aliasing for contouring and is the
reason the following image has a white stripe around the
circle where there should be just a nice blend of the two
colors:

            import

matplotlib.pyplot as plt

                          import

numpy as np

                          import

matplotlib.patches as mpatches

                          import

matplotlib.path as mpath

                          import

matplotlib.collections as mcol

                          # create

two paths. One a circle, the other

                          # a square

with the same circle cut out.

                          x =

np.linspace(0, np.pi * 2, 1000)

                          circle_coords

= np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))

                          pth_circle

= mpath.Path(circle_coords)

                          sqr_codes

= np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)

                          sqr_codes[1:5]

= mpath.Path.LINETO

                          sqr_codes[6:]

= mpath.Path.LINETO

                          sqr_coords

= np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1],
[-1, -1]],

circle_coords[::-1]], axis=0)

                          sqr_path =

mpath.Path(sqr_coords, sqr_codes)

                          ax =

plt.axes()

                          patches =

[mpatches.PathPatch(pth_circle),
mpatches.PathPatch(sqr_path)]

                          col =

mcol.PatchCollection(patches,

antialiaseds=True,

edgecolors=‘none’,

facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02, 0.9)])

          ax.add_collection(col)

                          ax.set_xlim([-1,

1])

                          ax.set_ylim([-1,

1])

          plt.show()
      I know of lots of the workarounds for this (turn off AA, turn

on lines, extend the path slightly, set a dark background
color) all of which have down-sides, so I’m keen to find a
final solution to the problem.

      When the two patches marry up perfectly with full

anti-aliasing, the antigrain (AGG) community call this “flash”
or compound rendering, and this capability was added to Agg
2.4 (which we already ship with mpl).

      In order to make full use of the compound rendering technique

I believe the drawing pipeline in “_backend_agg.cpp” would
need to change, which could be problematic. A less
wide-impacting alternative would be to draw all “patches” of a
single Collection in the same rasterization step (i.e. just
change _draw_path_collection_generic), though this does mean
that, as it stands, the result of plt.contourf would not be
able to make use of this new functionality - a MEP which
changes the return type of plt.contourf to a single Collection
might be able to fix that.

      I've put together a simple example similar to this in C++

using agg (no mpl changes yet), showing the differences in the
code needed between the old technique vs the “new” compound
renderer (attached).

    Ok, so the question to those that have knowledge of the

_backend_agg.cpp code (Mike, Eric, JJ + others?):

  •         Have you already looked at doing this and determined that
    
    this is a non-starter?
  •         Do you support adding the ability for the agg backend to
    
    draw compound artists (i.e. Collections) in this way rather
    than treating them as individual primitives in the canvas?
  •         Since many of the other backends can't do flash rendering,
    
    would we even want to make this change?
  •           SVG in Firefox 10.0.2 has the same problem, it is
    
    discussed slightly more in http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  •           Acroread has the same problem with PDFs, only to a much
    
    lesser extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester

Wave™: Endpoint Security, Q1 2013 and “remains a good choice” in the

endpoint security space. For insight on selecting the right partner to

tackle endpoint security challenges, access the full report.

http://p.sf.net/sfu/symantec-dev2dev


Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Could this be handled at a subsequent level, by having the renderer able
to treat an arbitrary collection of artists as a group?

If there were no significant slowdown (who knows, there might even be a speedup…) then it would be fantastic to apply compound rasterization to all artists of the same zorder. That would involve a little work (but is certainly doable) and would mean that no changes to contourf would be needed. My original pragmatic solution of applying compound rasterization to just collections is probably easier but the overall benefits is diminished a little (we would then need to make further changes if we wanted contourf to benefit).

Would this greatly slow down the rendering?

I’m happy to look into this over the next week or so to try to get a feel for performance + what other drawbacks might be lurking (e.g. what happens when artists are drawn on top of each other - is the draw order preserved?). Mike, if you decide to look into compound rasterization further, please let me know and we can coordinate our efforts. I’ll feed back any progress or findings here.

Thanks for your thoughts on this so far.

Cheers,

bp.1.separate.png

bp.2.compound.png

···

On 7 March 2013 09:41, Phil Elson <pelson.pub@…149…> wrote:

Would this greatly slow down the rendering?

That is a million dollar question. Without trying it to see, we could ask the agg mailing list to see if they have any insight.

Personally I’d be surprised if anything we did at the Agg level was a bottleneck given how much python code comes before it - though I admit that doesn’t mean anything in practice…

I wonder, though, and the SVG article you link to hints at this,
if we wouldn’t be better off just upsampling our Agg rendering
instead.

  > I put together a very quick hack on my agg-upsampling branch,

which hardcodes the upsampling to 2x in each direction.

I’m not a big fan of supersampling (http://en.wikipedia.org/wiki/Supersample_anti-aliasing) - that is essentially implementing a global anti-aliasing scheme which one wouldn’t be able to control on an artist by artist basis (such as fonts) with the overhead cost of increasing the memory highwater by a factor of 5 (as you say for an image of size (n, m) at a minimum the drawing buffer needs to be (2n x 2m) + then downsampled to (n x m)). We might even want to upscale to a factor of 3 or 4 to really get rid of most of the white in this example.

From the linked SVG article:

Perfect antialiasing can be done by rendering complete artwork at a much higher resolution and subsequent downsampling.

I also dispute this claim. Whilst good anti-aliasing can be achieved using supersampling, I believe no matter the size of your bigger draw buffer you will always get a component of background color (white in our case) which goes into the averaging operation and therefore will impact the final pixel color. It is then a compromise between performance vs “good enough” rendering.

Having said all of the above, supersampling would be a nice feature to add to mpl’s Agg backends (and maybe the Cairo backend too) - though I do not believe it is a full solution to this problem.

Cheers,

On 7 March 2013 09:15, Phil Elson <pelson.pub@…149…> wrote:

  > I'm trying to compile your examples,

but it seems perhaps you forget to include a file

Sorry, you can find pixel_formats.h in the examples directory. I have a mirror of agg here: https://github.com/pelson/antigrain/tree/master/agg-2.4/examples

My compile steps are:

export AGG_DIR=

g++ -c -O3 -I${AGG_DIR}/include -I${AGG_DIR}/examples -L${AGG_DIR}/src basic_path.cpp -o basic_path.o

g++ -O3 -I${AGG_DIR}/include -L${AGG_DIR}/src basic_path.o -o basic_path -lagg

  > I had played with the "compound renderer" example in Agg some

years ago, but couldn’t really understand how it worked

Agreed. It took the best part of a day to figure out how to do it, given no prior knowledge of Agg. I intend to submit a couple of simpler (GUI-less) examples to be included with the agg repo - and perhaps even write some documentation for this stuff!

Does it work with alpha < 1?

Yes. I’ve attached the two images (converted from ppm to png using gimp + default settings) so that you can see the results. Each shape has an alpha value of 200.

HTH

On 6 March 2013 20:27, Michael Droettboom <mdroe@…31…> wrote:

  I'm trying to compile your examples,

but it seems perhaps you forget to include a file –
pixel_formats.hpp? It’s not in the agg24 source tree.

  Mike




  On 03/06/2013 12:06 PM, Phil Elson wrote:
        Smart rendering of adjacent, anti-aliased patches is a

question which has come up a couple of times in various
guises in the past.

        It is my understanding that the lack of this functionality

led us to disable anti-aliasing for contouring and is the
reason the following image has a white stripe around the
circle where there should be just a nice blend of the two
colors:

            import

matplotlib.pyplot as plt

                          import

numpy as np

                          import

matplotlib.patches as mpatches

                          import

matplotlib.path as mpath

                          import

matplotlib.collections as mcol

                          # create

two paths. One a circle, the other

                          # a square

with the same circle cut out.

                          x =

np.linspace(0, np.pi * 2, 1000)

                          circle_coords

= np.array(zip(*[np.sin(x) * 0.8, np.cos(x) * 0.8]))

                          pth_circle

= mpath.Path(circle_coords)

                          sqr_codes

= np.repeat(mpath.Path.MOVETO, len(circle_coords) + 5)

                          sqr_codes[1:5]

= mpath.Path.LINETO

                          sqr_codes[6:]

= mpath.Path.LINETO

                          sqr_coords

= np.concatenate([[[-1, -1], [-1, 1], [1, 1], [1, -1],
[-1, -1]],

circle_coords[::-1]], axis=0)

                          sqr_path =

mpath.Path(sqr_coords, sqr_codes)

                          ax =

plt.axes()

                          patches =

[mpatches.PathPatch(pth_circle),
mpatches.PathPatch(sqr_path)]

                          col =

mcol.PatchCollection(patches,

antialiaseds=True,

edgecolors=‘none’,

facecolors=[(0, 0.0, 0.0, 0.9), (0.1, 0.1, 0.02, 0.9)])

          ax.add_collection(col)

                          ax.set_xlim([-1,

1])

                          ax.set_ylim([-1,

1])

          plt.show()
      I know of lots of the workarounds for this (turn off AA, turn

on lines, extend the path slightly, set a dark background
color) all of which have down-sides, so I’m keen to find a
final solution to the problem.

      When the two patches marry up perfectly with full

anti-aliasing, the antigrain (AGG) community call this “flash”
or compound rendering, and this capability was added to Agg
2.4 (which we already ship with mpl).

      In order to make full use of the compound rendering technique

I believe the drawing pipeline in “_backend_agg.cpp” would
need to change, which could be problematic. A less
wide-impacting alternative would be to draw all “patches” of a
single Collection in the same rasterization step (i.e. just
change _draw_path_collection_generic), though this does mean
that, as it stands, the result of plt.contourf would not be
able to make use of this new functionality - a MEP which
changes the return type of plt.contourf to a single Collection
might be able to fix that.

      I've put together a simple example similar to this in C++

using agg (no mpl changes yet), showing the differences in the
code needed between the old technique vs the “new” compound
renderer (attached).

    Ok, so the question to those that have knowledge of the

_backend_agg.cpp code (Mike, Eric, JJ + others?):

  •         Have you already looked at doing this and determined that
    
    this is a non-starter?
  •         Do you support adding the ability for the agg backend to
    
    draw compound artists (i.e. Collections) in this way rather
    than treating them as individual primitives in the canvas?
  •         Since many of the other backends can't do flash rendering,
    
    would we even want to make this change?
  •           SVG in Firefox 10.0.2 has the same problem, it is
    
    discussed slightly more in http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  •           Acroread has the same problem with PDFs, only to a much
    
    lesser extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester

Wave™: Endpoint Security, Q1 2013 and “remains a good choice” in the

endpoint security space. For insight on selecting the right partner to

tackle endpoint security challenges, access the full report.

http://p.sf.net/sfu/symantec-dev2dev


Matplotlib-devel mailing list

Matplotlib-devel@lists.sourceforge.net

https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

At first glance, I would be concerned about how this scales with the
number of paths (well, the number of vertices, really). With
regular path rendering in Agg, the time grows exponentially with the
number of vertices in the path, which is why we’ve put so much
effort into path simplification etc. If we use this to render a
contour with many levels, does it start to break down at some point?
The last buffer can in many cases be done in the GPU, so there isn’t
necessarily an additional main memory buffer… But that’s a minor
point.
Maybe it would be useful to quantify the amount of error between the
two approaches. At a certain point, it gets below the level of
perception and we can probably say it’s “good enough”.
While I understand the performance implications, I like the fact
that it is bounded.
I agree. It’s perhaps worth determining how much worse it is and
how good is “good enough”.
I think we agree there is a tradeoff here. On the one hand, there
is a mathematically perfect solution that requires some rather
pervasive refactoring of the code and permanent care in how plots
are constructed to ensure it’s running optimally, and an
exponentially growing performance curve as the complexity of the
plot increases. On the other, is a suboptimal end result that
requires minimal changes, and a well-defined and upper bound
performance penalty.
I think to really determine where on the tradeoff we want to be,
some more experiments comparing the quality of the end result of the
two approaches would be helpful.
Mike

···

On 03/07/2013 04:41 AM, Phil Elson
wrote:

Would this greatly slow down the rendering?

          That is a million dollar question. Without trying it to

see, we could ask the agg mailing list to see if they have
any insight.

          Personally I'd be surprised if anything we did at the

Agg level was a bottleneck given how much python code
comes before it - though I admit that doesn’t mean
anything in practice…

          > I wonder, though, and the SVG article you link to

hints at this, if we wouldn’t be better off just
upsampling our Agg rendering instead.

          > ...

          > I put together a very quick hack on my agg-upsampling

branch, which hardcodes the upsampling to 2x in each
direction.

I’m not a big fan of supersampling (http://en.wikipedia.org/wiki/Supersample_anti-aliasing )

  • that is essentially implementing a global anti-aliasing
    scheme which one wouldn’t be able to control on an artist by
    artist basis (such as fonts) with the overhead cost of
    increasing the memory highwater by a factor of 5 (as you say
    for an image of size (n, m) at a minimum the drawing buffer
    needs to be (2n x 2m) + then downsampled to (n x m)).
        We might even want to upscale to a factor of 3 or 4 to

really get rid of most of the white in this example.

From the linked SVG article:

        > Perfect antialiasing can be done by rendering

complete artwork at a much higher resolution and subsequent
downsampling.

      I also dispute this claim. Whilst good anti-aliasing can be

achieved using supersampling, I believe * no matter the size
of your bigger draw buffer* you will always get a
component of background color (white in our case) which goes
into the averaging operation and therefore will impact the
final pixel color. It is then a compromise between performance
vs “good enough” rendering.

      Having said all of the above, supersampling would be a nice

feature to add to mpl’s Agg backends (and maybe the Cairo
backend too) - though I do not believe it is a full solution
to this problem.

Cheers,

On 7 March 2013 09:15, Phil Elson <pelson.pub@…149…>
wrote:

                  > I'm trying to compile your

examples, but it seems perhaps you forget to
include a file

                Sorry, you can find pixel_formats.h in the examples

directory. I have a mirror of agg here: https://github.com/pelson/antigrain/tree/master/agg-2.4/examples

My compile steps are:

                export AGG_DIR=<path to antigrain

checkout>

                g++ -c -O3 -I${AGG_DIR}/include

-I${AGG_DIR}/examples -L${AGG_DIR}/src
basic_path.cpp -o basic_path.o

                g++ -O3 -I${AGG_DIR}/include -L${AGG_DIR}/src

basic_path.o -o basic_path -lagg

                > I had played with the "compound renderer"

example in Agg some years ago, but couldn’t really
understand how it worked

            Agreed. It took the best part of a day to figure out how

to do it, given no prior knowledge of Agg. I intend to
submit a couple of simpler (GUI-less) examples to be
included with the agg repo - and perhaps even write some
documentation for this stuff!

              > Does it work with alpha < 1?
            Yes. I've attached the two images (converted from ppm

to png using gimp + default settings) so that you can
see the results. Each shape has an alpha value of 200.

HTH

On 6 March 2013 20:27, Michael Droettboom <mdroe@…31…>
wrote:

                      I'm trying to compile your examples, but it

seems perhaps you forget to include a file –
pixel_formats.hpp? It’s not in the agg24
source tree.

                      Mike




                          On 03/06/2013 12:06 PM, Phil Elson wrote:
                                Smart rendering of adjacent,

anti-aliased patches is a question
which has come up a couple of times
in various guises in the past.

                                It is my understanding that the lack

of this functionality led us to
disable anti-aliasing for contouring
and is the reason the following
image has a white stripe around the
circle where there should be just a
nice blend of the two colors:

                                    import

matplotlib.pyplot as plt

                                                                          import numpy as

np

                                                                          import

matplotlib.patches as mpatches

                                                                          import

matplotlib.path as mpath

                                                                          import

matplotlib.collections as mcol

                                                                          # create two

paths. One a circle, the other

                                                                          # a square with

the same circle cut out.

                                                                          x =

np.linspace(0, np.pi * 2, 1000)

                                                                          circle_coords =

np.array(zip(*[np.sin(x) * 0.8,
np.cos(x) * 0.8]))

                                                                          pth_circle =

mpath.Path(circle_coords)

                                                                          sqr_codes =

np.repeat(mpath.Path.MOVETO,
len(circle_coords) + 5)

                                                                          sqr_codes[1:5] =

mpath.Path.LINETO

                                                                          sqr_codes[6:] =

mpath.Path.LINETO

                                                                          sqr_coords =

np.concatenate([[[-1, -1], [-1,
1], [1, 1], [1, -1], [-1, -1]],

circle_coords[::-1]], axis=0)

                                                                          sqr_path =

mpath.Path(sqr_coords,
sqr_codes)

                                  ax = plt.axes()

                                                                          patches =

[mpatches.PathPatch(pth_circle),
mpatches.PathPatch(sqr_path)]

                                                                          col =

mcol.PatchCollection(patches,

antialiaseds=True,

edgecolors=‘none’,

facecolors=[(0, 0.0, 0.0, 0.9),
(0.1, 0.1, 0.02, 0.9)])

                                  ax.add_collection(col)

                                                                          ax.set_xlim([-1,

1])

                                                                          ax.set_ylim([-1,

1])

                                  plt.show()
                              I know of lots of the workarounds for

this (turn off AA, turn on lines,
extend the path slightly, set a dark
background color) all of which have
down-sides, so I’m keen to find a
final solution to the problem.

                              When the two patches marry up

perfectly with full anti-aliasing, the
antigrain (AGG) community call this
“flash” or compound rendering, and
this capability was added to Agg 2.4
(which we already ship with mpl).

                              In order to make full use of the

compound rendering technique I believe
the drawing pipeline in
“_backend_agg.cpp” would need to
change, which could be problematic. A
less wide-impacting alternative would
be to draw all “patches” of a single
Collection in the same rasterization
step (i.e. just change
_draw_path_collection_generic), though
this does mean that, as it stands, the
result of plt.contourf would not be
able to make use of this new
functionality - a MEP which changes
the return type of plt.contourf to a
single Collection might be able to fix
that.

                              I've put together a simple example

similar to this in C++ using agg (no
mpl changes yet), showing the
differences in the code needed between
the old technique vs the “new”
compound renderer (attached).

                            Ok, so the question to those that have

knowledge of the _backend_agg.cpp code
(Mike, Eric, JJ + others?):

  •                                 Have you already looked at doing
    
    this and determined that this is a
    non-starter?
  •                                 Do you support adding the ability
    
    for the agg backend to draw compound
    artists (i.e. Collections) in this
    way rather than treating them as
    individual primitives in the canvas?
  •                                 Since many of the other backends
    
    can’t do flash rendering, would we
    even want to make this change?
  •                                   SVG in Firefox 10.0.2 has the
    
    same problem, it is discussed
    slightly more in http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  •                                   Acroread has the same problem
    
    with PDFs, only to a much lesser
    extent than in the PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

                  Symantec Endpoint Protection 12 positioned as A

LEADER in The Forrester

                  Wave(TM): Endpoint Security, Q1 2013 and "remains

a good choice" in the

                  endpoint security space. For insight on selecting

the right partner to

                  tackle endpoint security challenges, access the

full report.

                  [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)

                  _______________________________________________

                  Matplotlib-devel mailing list

                  Matplotlib-devel@lists.sourceforge.net

                  [https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

In my quick hack, I render the text at the final output resolution,
it gets upsampled onto the “larger” canvas, and then downsampled
back. (All this just because it was the easiest hack). The end
result is definitely fuzzier. So we’d have to explore how we do
text rendering in the new paradigm, particularly wrt hinting (which
already contains a lot of cleverness).
That’s an interesting idea.
Yes – I’ve thought we might need this for a while. Cairo has a
very useful API – “push_group”/“pop_group” and friends – that push
layers on and off a stack. It would solve some of the alpha
blending problems we have because, for example, an entire contour
set could be rendered on a single layer and then alpha composited at
once on the layer below. Another side effect of that API is that it
makes “stamping” things (as we do in draw_marker) possible without
each of the backends having to understand so much about what a
marker is as we have now.
Cheers,
Mike

···

On 03/06/2013 08:28 PM, Jae-Joon Lee
wrote:

While I cannot say much about the “compound
renderering” in Agg as I
know little about it, but the upsampling method
that Mike mentioned seems quite robust.
Just
a quick question, will it affect the rendered quality of
AA’ed artists, like texts? What I mean is, drawing texts w/
AA on (in the upsampled canvas)
and downsampling the
result may give poor quality? But maybe there is a way to
adjust how AA is done in the first place.

          Maybe what we can

try is to upsample only
selected artists, similar to rasterization in vector backends or
agg_filter. This will likely consume more memory and maybe
more CPU, but may give minimal side effects.

          While it is not

directly related to the current issue, I thought it would
be good to have, within a backend, multiple layers to render and the final result
is a composite of those layers.

And we may upsample some layers or apply
effects selectively. And do the alpha compositing of
layers in the end. This will be also useful for
animations as we can only update selected layers.

        Back to

the original issue, I am inclined to play with Mike’s
upsamping method to see if it solves the problem without
significant side effects.

Regards,

-JJ

      On Thu, Mar 7, 2013 at 6:54 AM, Michael

Droettboom <mdroe@…31…>
wrote:

            Thanks for bringing this up -- I was just looking at

the test images the other day and was reminded how
filled contouring doesn’t look as good as it could be.

            I had played with the "compound renderer" example in Agg

some years ago, but couldn’t really understand how it
worked, so ultimately gave up on it. I appreciate the
research you’ve done here, because it illustrates pretty
clearly what is required. I guess in the actual Agg
draw_path_collection renderer, we would have to build a
style_handler table dynamically based on the collection
and then iterate through it as we draw… At least it’s
clear now how that could be accomplished.

            I wonder, though, and the SVG article you link to hints

at this, if we wouldn’t be better off just upsampling
our Agg rendering instead. The advantage of such an
approach would be that the structure or ordering of the
drawing wouldn’t matter at all – allaying most of
Eric’s concerns. It seems like it just overall be
“easier” to do the right thing. And it should benefit
all things, including other tricky things like
quadmeshes, “automatically”.

            Of course, the downside is a performance hit.  Assuming

2x oversampling, it means the screen buffer will be 4x
the size, rendering will take “up to” four times as
long, and then you have to downsample again (which in
the best case would happen in hardware). Compound
rendering has a memory penalty, too, of course, since
the scanlines for all of the paths have to be stored
until finally rendered out simultaneously. Estimating
what that overhead is much harder, of course, and is
more content dependent, whereas the performance hit
upsampling is straightforward and has an obvious upper
bound.

            I put together a very quick hack on my agg-upsampling

branch, which hardcodes the upsampling to 2x in each
direction. It currently only works with the GtkAgg
backend (even file saving won’t work correctly), and I
only fixed things up for contour plotting, so images
(and probably other things) will be misplaced. But it
should give an idea for the performance hit and quality
benefit enough to play around with.

            Mike




                On 03/06/2013 03:27 PM, Michael Droettboom wrote:
                  I'm trying to compile your examples, but it

seems perhaps you forget to include a file –
pixel_formats.hpp? It’s not in the agg24 source
tree.

                  Mike



                  On 03/06/2013 12:06 PM, Phil Elson wrote:
                        Smart rendering of adjacent, anti-aliased

patches is a question which has come up a
couple of times in various guises in the
past.

                        It is my understanding that the lack of this

functionality led us to disable
anti-aliasing for contouring and is the
reason the following image has a white
stripe around the circle where there should
be just a nice blend of the two colors:

                            import matplotlib.pyplot

as plt

                          import numpy as np

                                                          import matplotlib.patches

as mpatches

                                                          import matplotlib.path as

mpath

                                                          import

matplotlib.collections as mcol

                                                          # create two paths. One a

circle, the other

                                                          # a square with the same

circle cut out.

                                                          x = np.linspace(0, np.pi
  • 2, 1000)

                                                            circle_coords =
    

np.array(zip(*[np.sin(x) * 0.8,
np.cos(x) * 0.8]))

                                                          pth_circle =

mpath.Path(circle_coords)

                                                          sqr_codes =

np.repeat(mpath.Path.MOVETO,
len(circle_coords) + 5)

                                                          sqr_codes[1:5] =

mpath.Path.LINETO

                                                          sqr_codes[6:] =

mpath.Path.LINETO

                                                          sqr_coords =

np.concatenate([[[-1, -1], [-1, 1], [1,
1], [1, -1], [-1, -1]],

circle_coords[::-1]], axis=0)

                                                          sqr_path =

mpath.Path(sqr_coords, sqr_codes)

                          ax = plt.axes()

                                                          patches =

[mpatches.PathPatch(pth_circle),
mpatches.PathPatch(sqr_path)]

                                                          col =

mcol.PatchCollection(patches,

antialiaseds=True,

edgecolors=‘none’,

facecolors=[(0, 0.0, 0.0, 0.9), (0.1,
0.1, 0.02, 0.9)])

                          ax.add_collection(col)

                          ax.set_xlim([-1, 1])

                          ax.set_ylim([-1, 1])

                          plt.show()
                      I know of lots of the workarounds for this

(turn off AA, turn on lines, extend the path
slightly, set a dark background color) all of
which have down-sides, so I’m keen to find a
final solution to the problem.

                      When the two patches marry up perfectly with

full anti-aliasing, the antigrain (AGG)
community call this “flash” or compound
rendering, and this capability was added to
Agg 2.4 (which we already ship with mpl).

                      In order to make full use of the compound

rendering technique I believe the drawing
pipeline in “_backend_agg.cpp” would need to
change, which could be problematic. A less
wide-impacting alternative would be to draw
all “patches” of a single Collection in the
same rasterization step (i.e. just change
_draw_path_collection_generic), though this
does mean that, as it stands, the result of
plt.contourf would not be able to make use of
this new functionality - a MEP which changes
the return type of plt.contourf to a single
Collection might be able to fix that.

                      I've put together a simple example similar

to this in C++ using agg (no mpl changes yet),
showing the differences in the code needed
between the old technique vs the “new”
compound renderer (attached).

                    Ok, so the question to those that have knowledge

of the _backend_agg.cpp code (Mike, Eric, JJ +
others?):

  •                         Have you already looked at doing this and
    
    determined that this is a non-starter?
  •                         Do you support adding the ability for the
    
    agg backend to draw compound artists (i.e.
    Collections) in this way rather than
    treating them as individual primitives in
    the canvas?
  •                         Since many of the other backends can't do
    
    flash rendering, would we even want to make
    this change?
  •                           SVG in Firefox 10.0.2 has the same
    
    problem, it is discussed slightly more in
    http://www.svgopen.org/2002/papers/sorotokin__svg_secrets/
  •                           Acroread has the same problem with PDFs,
    
    only to a much lesser extent than in the
    PNG attached

Thoughts?

------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)
------------------------------------------------------------------------------
Symantec Endpoint Protection 12 positioned as A LEADER in The Forrester Wave(TM): Endpoint Security, Q1 2013 and "remains a good choice" in the endpoint security space. For insight on selecting the right partner to tackle endpoint security challenges, access the full report. [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
[https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)

        Symantec Endpoint Protection 12 positioned as A LEADER in

The Forrester

        Wave(TM): Endpoint Security, Q1 2013 and "remains a good

choice" in the

        endpoint security space. For insight on selecting the right

partner to

        tackle endpoint security challenges, access the full report.

        [http://p.sf.net/sfu/symantec-dev2dev](http://p.sf.net/sfu/symantec-dev2dev)

        _______________________________________________

        Matplotlib-devel mailing list

        Matplotlib-devel@lists.sourceforge.net

        [https://lists.sourceforge.net/lists/listinfo/matplotlib-devel](https://lists.sourceforge.net/lists/listinfo/matplotlib-devel)