Yes. This is a long-known issue in librsvg-based viewers. The SVG spec
allows for clip paths defined after their reference. Only librsvg gets
this wrong.
@WeatherGod: Sorry, it's not a trivial fix because it means we have to go
from stream-based writing (which is important for web servers and
minimizing memory usage) to random-access (or at least multi-pass) writing.
@mdboom, forgive my ignorance on the particulars of the svg backend, but
what is the limitation that forces us to write the clipping path
definitions after all of their references? Do we need to write out the
other artists first to get the clip or something? Just curious.
Yes. This is a long-known issue in librsvg-based viewers. The SVG spec
allows for clip paths defined after their reference. Only librsvg gets
this wrong.
@WeatherGod: Sorry, it's not a trivial fix because it means we have to go
from stream-based writing (which is important for web servers and
minimizing memory usage) to random-access (or at least multi-pass) writing.
To provide some SVG user agents with an opportunity to implement efficient implementations in streaming environments, creators of SVG content are encouraged to place all elements which are targets of local IRI references within a ‘defs’ element which is a direct child of one of the ancestors of the referencing element.
which we are doing (assuming I am understanding 'one of the ancestors' correctly to include the root node).
I suspect that this is the reason that we emit all of the clip paths at the end. The clip urls are shared with in a figure (which is the correct thing to do). The first time we see each clip path it is generated and stashed for later re-use. If the <def> block always needs to be a child on an ancestor of the element, it is used in then it is not safe to emit the clip path where you first see it (as there may be less nested use of it later) and we don't know what the clip paths will be until we walk the full artist tree once.
Conversely, there is no other explicit requirement that it must come before so it is allowed to come after.
And the failure to render with libQtSvg is expected as it only supports a very minimal set of svg (SVG 1.2 tiny) which it is my understanding does not support clipping.
@rsmith31415 and @tacaswell, I guess I'll just write a script to do it. It's far from ideal but is probably the best option at this point.
It would be nice if there was a fix to matplotlib for this but doing so would violate the end-to-end principle, so maybe that's not the best approach. However, practically speaking, how long is going to take to get it fixed in librsvg and widely deployed? It seems like applying a workaround in Matplotlib is likely to solve the problem faster for Linux users, so that is the trade-off more or less.
I have no idea how responsive the librsvg developers are or even how big of a fix this is for them. The bug has been known for a while, but apparently in never made it upstream until last night.
@abreslow If you want to make that a function to put into matplotlib.cbook I think that would be useful, call it something like fix_svg_for_librsvg(fin, fout).
It looks like librsvg 2.40.12 fixes this bug!!! That was a long time coming. Glad we stuck to our guns! The relevant entry in the librsvg CHANGELOG:
References to objects/filters/URIs/etc. are now handled lazily. Also, there is a general-purpose cycle detector so malformed SVGs don't cause infinite loops. Work by Benjamin Otte.
Benjamin Otte: beverage of your choice if I ever meet you. This is a big thing.
Reacted by Courtney B, Thomas A Caswell and Christian Heider Lindbjerg
Activity
tacaswell commented on Apr 15, 2015
90% this is a veiwer issue, not a MPL issue.
WeatherGod commented on Apr 15, 2015
True, but it does seem fairly trivial to fix, though. Just write out the
clipping path earlier, IIUC. We can't fight the whole world.
On Wed, Apr 15, 2015 at 2:12 PM, Thomas A Caswell notifications@github.com
wrote:
mdboom commented on Apr 15, 2015
Yes. This is a long-known issue in librsvg-based viewers. The SVG spec
allows for clip paths defined after their reference. Only librsvg gets
this wrong.
@WeatherGod: Sorry, it's not a trivial fix because it means we have to go
from stream-based writing (which is important for web servers and
minimizing memory usage) to random-access (or at least multi-pass) writing.
On Wed, Apr 15, 2015 at 2:12 PM Thomas A Caswell notifications@github.com
wrote:
tacaswell commented on Apr 15, 2015
I just checked and this renders correctly in both chromium and firefox.
WeatherGod commented on Apr 15, 2015
@mdboom, forgive my ignorance on the particulars of the svg backend, but
what is the limitation that forces us to write the clipping path
definitions after all of their references? Do we need to write out the
other artists first to get the clip or something? Just curious.
On Wed, Apr 15, 2015 at 2:16 PM, Michael Droettboom <
notifications@github.com> wrote:
tacaswell commented on Apr 28, 2015
@rsmith31415 http://www.w3.org/TR/SVG/struct.html#SVGElement It says the svg element may contain any number of any (of a long list) of elements types in any order.
The section of defs http://www.w3.org/TR/SVG/struct.html#DefsElement says:
which we are doing (assuming I am understanding 'one of the ancestors' correctly to include the root node).
I suspect that this is the reason that we emit all of the clip paths at the end. The clip urls are shared with in a figure (which is the correct thing to do). The first time we see each clip path it is generated and stashed for later re-use. If the <def> block always needs to be a child on an ancestor of the element, it is used in then it is not safe to emit the clip path where you first see it (as there may be less nested use of it later) and we don't know what the clip paths will be until we walk the full artist tree once.
Conversely, there is no other explicit requirement that it must come before so it is allowed to come after.
It appears that this got reported upstream to ubuntu (https://bugs.launchpad.net/ubuntu/+source/librsvg/+bug/1207538) but was never bumped up to actual upstream (which I just fixed as https://bugzilla.gnome.org/show_bug.cgi?id=748565).
I am closing this as this is pretty clearly a bug in librsvg as the svgs render correctly in:
there is nothing in the spec which says this can't be done, and there are major benefits to doing svg writing in a streaming fashion.
The emitted svg render badly with 2 svg libraries (librsvg and libQtSvg)
due to upstream bugs.
tacaswell commented on Apr 28, 2015
And the failure to render with libQtSvg is expected as it only supports a very minimal set of svg (SVG 1.2 tiny) which it is my understanding does not support clipping.
abreslow commented on Apr 28, 2015
@rsmith31415 and @tacaswell, I guess I'll just write a script to do it. It's far from ideal but is probably the best option at this point.
It would be nice if there was a fix to matplotlib for this but doing so would violate the end-to-end principle, so maybe that's not the best approach. However, practically speaking, how long is going to take to get it fixed in librsvg and widely deployed? It seems like applying a workaround in Matplotlib is likely to solve the problem faster for Linux users, so that is the trade-off more or less.
tacaswell commented on Apr 28, 2015
I have no idea how responsive the librsvg developers are or even how big of a fix this is for them. The bug has been known for a while, but apparently in never made it upstream until last night.
@abreslow If you want to make that a function to put into matplotlib.cbook I think that would be useful, call it something like fix_svg_for_librsvg(fin, fout).
mdboom commented on Jan 12, 2016
It looks like librsvg 2.40.12 fixes this bug!!! That was a long time coming. Glad we stuck to our guns! The relevant entry in the librsvg CHANGELOG:
Benjamin Otte: beverage of your choice if I ever meet you. This is a big thing.