backend change needed: render patch without boundary

I see only advantages and no disadvantages whatsoever to

    > this change; am I missing something?

The only potential problem with this is that a linewidth=0 is
postscript actually means something -- it tells the rendering device
to draw the thinnest possible line. The change you propose could
potentially break some code where people are relying on this. This
would not be the end of the world as long as we announce it.

Alternatively, we could support 'None' for the facecolor and edgecolor. This
is a little difficult, unfortunately, since None is overloaded to
mean "do the default". The hack workaround we use here is to set
'None' (the string) rather than None itself. Ugly, yes.

The real root of the problem is that

        renderer.draw_polygon(gc, rgbFace, tverts)

is overloaded to support edge and face drawing in one function call.
This is a hold-over from the bad-old-days where pcolor and friends use
polygons for every face, and I wanted to save the function call by
putting both edge and face drawing in one call.

One might rather have at the Artist level

    if facecolor!='None':
        gc.set_foreground(facecolor)
        renderer.draw_polygon(gc, tverts, fill=False)

    if edgecolor!='None'
        gc.set_foreground(edgecolor)
        renderer.draw_polygon(gc, tverts, fill=False)

or have booleans in the patch object if this is too ugly.

This is cleaner in my view than using linewidth=0 but I don't feel
strongly. However, it would require changing *every* backend. Argg

JDH

I would be surprised if anyone is relying on this behavior. I think I remember
reading in a book on postscript that use of this feature is discouraged.

···

On Thursday 25 May 2006 14:30, John Hunter wrote:

    > I see only advantages and no disadvantages whatsoever to
    > this change; am I missing something?

The only potential problem with this is that a linewidth=0 is
postscript actually means something -- it tells the rendering device
to draw the thinnest possible line. The change you propose could
potentially break some code where people are relying on this. This
would not be the end of the world as long as we announce it.

John Hunter wrote:

mean "do the default". The hack workaround we use here is to set
'None' (the string) rather than None itself. Ugly, yes.

and really, really prone to error. If you need to use a string, use something else, like perhaps "transparent"

The real root of the problem is that

        renderer.draw_polygon(gc, rgbFace, tverts)

is overloaded to support edge and face drawing in one function call.

That's actually a good thing. I like to think of a polygon with a border a single object, and it can dome in handy if you want to do something like draw a polygon with a border that is semi-transparent. drawing the fill and the stroke independently doesn't work right. I was recently messing around with this in Cairo, and it's a pain int eh *&^, but it can be done right, but it's up to the back-end to figure out how.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer
                                         
NOAA/OR&R/HAZMAT (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@...236...

John,

I have been poking around in the backends and above, and it looks to me like _backend_agg.cpp already implements the solution I was moving towards (at least in draw_poly_collection), at the backend level: let alpha==0 suppress rendering. This behavior can be added to the backends one at a time without breaking anything. (The backends that don't presently support alpha at all, like ps, will need a little more work than the ones that do, but I think it is still pretty simple.) Then at the higher levels it is just a matter of letting "facecolor='No'" set the alphas of the rgba array to zero, etc. I am inclined to let linewidth=0 do the same thing as edgecolor='No', simply because it is easy and to me a very intuitive way of saying "Don't draw the boundary"; but this is a minor detail.

Darren noticed that because of the edge-drawing problem, ps and svg backends were making unusable colorbars for image-type plots, so I put a quick hack into the ps backend to make it work until the more general solution is put into place.

Eric

John Hunter wrote:

···

"Eric" == Eric Firing <efiring@...229...> writes:

    > I see only advantages and no disadvantages whatsoever to
    > this change; am I missing something?

The only potential problem with this is that a linewidth=0 is
postscript actually means something -- it tells the rendering device
to draw the thinnest possible line. The change you propose could
potentially break some code where people are relying on this. This
would not be the end of the world as long as we announce it.

Alternatively, we could support 'None' for the facecolor and edgecolor. This
is a little difficult, unfortunately, since None is overloaded to
mean "do the default". The hack workaround we use here is to set
'None' (the string) rather than None itself. Ugly, yes.

The real root of the problem is that

        renderer.draw_polygon(gc, rgbFace, tverts)

is overloaded to support edge and face drawing in one function call.
This is a hold-over from the bad-old-days where pcolor and friends use
polygons for every face, and I wanted to save the function call by
putting both edge and face drawing in one call.

One might rather have at the Artist level

    if facecolor!='None': gc.set_foreground(facecolor)
        renderer.draw_polygon(gc, tverts, fill=False)

    if edgecolor!='None'
        gc.set_foreground(edgecolor)
        renderer.draw_polygon(gc, tverts, fill=False)

or have booleans in the patch object if this is too ugly.

This is cleaner in my view than using linewidth=0 but I don't feel
strongly. However, it would require changing *every* backend. Argg

JDH

Thank you for doing that. I need to use the svg backend to make plots for my
poster. I was thinking about how to change the svg backend, and setting the
alpha to zero may create a problem. For example, I create an svg file with
mpl, and import it into inkscape. Then I print the document to my postscript
printer, which does not support alpha, and therefore some unexpected lines
show up on the printed page. Its a corner case, but I bet a fair number of
people will get nailed by it.

Darren

···

On Saturday 27 May 2006 04:29, Eric Firing wrote:

Darren noticed that because of the edge-drawing problem, ps and svg
backends were making unusable colorbars for image-type plots, so I put a
quick hack into the ps backend to make it work until the more general
solution is put into place.

Here's a hack that works for me:

$ svn diff
Index: lib/matplotlib/backends/backend_svg.py

···

On Saturday 27 May 2006 09:06, Darren Dale wrote:

On Saturday 27 May 2006 04:29, Eric Firing wrote:
> Darren noticed that because of the edge-drawing problem, ps and svg
> backends were making unusable colorbars for image-type plots, so I put a
> quick hack into the ps backend to make it work until the more general
> solution is put into place.

Thank you for doing that. I need to use the svg backend to make plots for
my poster. I was thinking about how to change the svg backend, and setting
the alpha to zero may create a problem. For example, I create an svg file
with mpl, and import it into inkscape. Then I print the document to my
postscript printer, which does not support alpha, and therefore some
unexpected lines show up on the printed page. Its a corner case, but I bet
a fair number of people will get nailed by it.

===================================================================
--- lib/matplotlib/backends/backend_svg.py (revision 2417)
+++ lib/matplotlib/backends/backend_svg.py (working copy)
@@ -71,20 +71,25 @@
         else:
             dashes = 'stroke-dasharray: %s; stroke-dashoffset: %f;' % (
                 ' '.join(['%f'%val for val in seq]), offset)
+
+ linewidth = gc.get_linewidth()
+ if linewidth:
+ return 'style="fill: %s; stroke: %s; stroke-width: %f; ' \
+ 'stroke-linejoin: %s; stroke-linecap: %s; %s opacity: %f; ' \
+ '%s"' % (fill,
+ rgb2hex(gc.get_rgb()),
+ linewidth,
+ gc.get_joinstyle(),
+ _capstyle_d[gc.get_capstyle()],
+ dashes,
+ gc.get_alpha(),
+ clippath,)
+ else:
+ return 'style="fill: %s; opacity: %f; ' \
+ '%s"' % (fill,
+ gc.get_alpha(),
+ clippath,)

- return 'style="fill: %s; stroke: %s; stroke-width: %f; ' \
- 'stroke-linejoin: %s; stroke-linecap: %s; %s opacity: %f; ' \
- '%s"' % (
- fill,
- rgb2hex(gc.get_rgb()),
- gc.get_linewidth(),
- gc.get_joinstyle(),
- _capstyle_d[gc.get_capstyle()],
- dashes,
- gc.get_alpha(),
- clippath,
- )
-
     def _get_gc_clip_svg(self, gc):
         cliprect = gc.get_clip_rectangle()
         if cliprect is None:
@@ -144,10 +149,10 @@
         y = self.height-y-h
         im.write_png(filename)

- imfile = file (filename, 'r')
- image64 = base64.b64encode (imfile.read())
- imfile.close()
- os.remove(filename)
+ imfile = file (filename, 'r')
+ image64 = base64.b64encode (imfile.read())
+ imfile.close()
+ os.remove(filename)
         lines = [image64[i:i+76] for i in range(0, len(image64), 76)]

         self._svgwriter.write (

Darren,

Thanks. I expect that a slight modification of your patch will fit in perfectly with what I have in mind, and it is particularly helpful because I know next to zip about svg--and about most of the other backend output formats.

I think you misunderstood what I was suggesting; it was not that alpha would be zero in the svg output, but rather that the backend would use alpha==0 in the line color (or gc.alpha) as a flag to not output the stroke command, in the same way as I started using linewidth for this. In the same way, alpha==0 in the facecolor would turn off output of the fill command. So, even if you start with svg and then go to postscript, the result should be correct.

It is all a little kludgy. Some things use rgb, some use rgba; some alpha values are ignored completely. The GraphicsContextBase has alpha but GraphicsContextPS does not. The gc seems to have *almost* all the information that gets passed down to the lowest-level renderer functions, but lacks the face color; etc. A more thorough rewrite could clean up a lot of things, but as John noted it would require simultaneously modifying the entire set of backends. Instead, my intention is to make small changes that move towards a greater degree of consistency but without breaking anything. This does not preclude a more extensive refactoring in the future; if anything, it should facilitate it.

Eric

Darren Dale wrote:

···

On Saturday 27 May 2006 09:06, Darren Dale wrote:

On Saturday 27 May 2006 04:29, Eric Firing wrote:

Darren noticed that because of the edge-drawing problem, ps and svg
backends were making unusable colorbars for image-type plots, so I put a
quick hack into the ps backend to make it work until the more general
solution is put into place.

Thank you for doing that. I need to use the svg backend to make plots for
my poster. I was thinking about how to change the svg backend, and setting
the alpha to zero may create a problem. For example, I create an svg file
with mpl, and import it into inkscape. Then I print the document to my
postscript printer, which does not support alpha, and therefore some
unexpected lines show up on the printed page. Its a corner case, but I bet
a fair number of people will get nailed by it.

Here's a hack that works for me:

$ svn diff
Index: lib/matplotlib/backends/backend_svg.py

--- lib/matplotlib/backends/backend_svg.py (revision 2417)
+++ lib/matplotlib/backends/backend_svg.py (working copy)
@@ -71,20 +71,25 @@
         else:
             dashes = 'stroke-dasharray: %s; stroke-dashoffset: %f;' % (
                 ' '.join(['%f'%val for val in seq]), offset)
+
+ linewidth = gc.get_linewidth()
+ if linewidth:
+ return 'style="fill: %s; stroke: %s; stroke-width: %f; ' \
+ 'stroke-linejoin: %s; stroke-linecap: %s; %s opacity: %f; ' \
+ '%s"' % (fill,
+ rgb2hex(gc.get_rgb()),
+ linewidth,
+ gc.get_joinstyle(),
+ _capstyle_d[gc.get_capstyle()],
+ dashes,
+ gc.get_alpha(),
+ clippath,)
+ else:
+ return 'style="fill: %s; opacity: %f; ' \
+ '%s"' % (fill,
+ gc.get_alpha(),
+ clippath,)

- return 'style="fill: %s; stroke: %s; stroke-width: %f; ' \
- 'stroke-linejoin: %s; stroke-linecap: %s; %s opacity: %f; ' \
- '%s"' % (
- fill,
- rgb2hex(gc.get_rgb()),
- gc.get_linewidth(),
- gc.get_joinstyle(),
- _capstyle_d[gc.get_capstyle()],
- dashes,
- gc.get_alpha(),
- clippath,
- )
-
     def _get_gc_clip_svg(self, gc):
         cliprect = gc.get_clip_rectangle()
         if cliprect is None:
@@ -144,10 +149,10 @@
         y = self.height-y-h
         im.write_png(filename)

- imfile = file (filename, 'r')
- image64 = base64.b64encode (imfile.read())
- imfile.close()
- os.remove(filename)
+ imfile = file (filename, 'r')
+ image64 = base64.b64encode (imfile.read())
+ imfile.close()
+ os.remove(filename)
         lines = [image64[i:i+76] for i in range(0, len(image64), 76)]

         self._svgwriter.write (

-------------------------------------------------------
All the advantages of Linux Managed Hosting--Without the Cost and Risk!
Fully trained technicians. The highest number of Red Hat certifications in
the hosting industry. Fanatical Support. Click to learn more
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=107521&bid=248729&dat=121642
_______________________________________________
Matplotlib-devel mailing list
Matplotlib-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-devel

Darren,

One more thing: please go ahead and commit your svg patch.

Thanks.

Eric

···

Here's a hack that works for me:

$ svn diff
Index: lib/matplotlib/backends/backend_svg.py

--- lib/matplotlib/backends/backend_svg.py (revision 2417)
+++ lib/matplotlib/backends/backend_svg.py (working copy)
@@ -71,20 +71,25 @@