5
$\begingroup$

From my previous thread where @Alexey Popkov proposed polygon2FilledCurve to remove the outline when exporting to PDF. Now I'm trying to apply that to this but it doesn't work. How can I fix this?

polygon2FilledCurve = # /. {Polygon[pts_ /; Depth[pts] == 3] :> 
      FilledCurve[Thread[Line[pts]]], 
     Polygon[pts_ /; Depth[pts] == 2] :> FilledCurve[Line[pts]]} &;
polygon = {{0, 1}, {1, 3}, {5, 5}, {5, 0}, {-5, 0}, {-5, 5}, {-4, 
    3}, {0, 1}};
image = ListLinePlot[polygon, Filling -> {1 -> Axis}] /. _Line -> 
   Sequence[]

Export["image.pdf", polygon2FilledCurve[image]

This is the image:

enter image description here However, the exported PDF image is not correct.

enter image description here

I'm looking for a solution which work for many types of polygon.

$\endgroup$
2
  • $\begingroup$ @Michael sorry I fogot to add the export code. $\endgroup$
    – hana
    Jul 6 at 0:53
  • $\begingroup$ Thanks!........ $\endgroup$
    – Michael E2
    Jul 6 at 0:54

2 Answers 2

6
$\begingroup$

You need to convert the GraphicsComplex style polygon to a normal, coordinate-point one:

gcpolyToNormal = # /. 
    GraphicsComplex[p_, g_, o___] :> 
     GraphicsComplex[p, 
      g /. Polygon[v_] :> Polygon[v /. i_Integer :> p[[i]]]] &;

polygon2FilledCurve = # /. {Polygon[pts_ /; Depth[pts] == 4] :> 
      FilledCurve /@ Thread[Line[pts]], 
     Polygon[pts_ /; Depth[pts] == 3] :> FilledCurve[Line[pts]]} &;
polygon = {{0, 1}, {1, 3}, {5, 5}, {5, 0}, {-5, 0}, {-5, 5}, {-4, 
    3}, {0, 1}};
image = ListLinePlot[polygon, Filling -> {1 -> Axis}] /. _Line -> 
   Sequence[]
Export["image.pdf", polygon2FilledCurve[gcpolyToNormal@image]]

(I always add "/tmp/" to my test filenames, but it doesn't work on Windows, I think.)

Alternatively, one can fix polygon2FilledCurve for GraphicsComplex:

polygon2FilledCurve = # /. {Polygon[pts_ /; Depth[pts] == 2] :> 
      FilledCurve[Thread[Line[pts]]], 
     Polygon[pts_ /; Depth[pts] == 1] :> FilledCurve[Line[pts]]} &;

But then you have to decide which way you want it. Or one could write a more complicated function that parsed the polygons to see if they were "normal" or GraphicsComplex type.

Here's a way to convert polygons in GraphicsComplex to filled curves without converting them to normal form:

gcpolyToFilledCurved = # /. 
    GraphicsComplex[p_, g_, o___] :> GraphicsComplex[p, g /. {
        Polygon[v : {__Integer}] :> FilledCurve[Line[v]],
        Polygon[v : {{__Integer} ..}] :> 
         FilledCurve[Thread@Line[v]]}] &;

I see @AlexeyPopkov had already posted something like this, plus a fix to the polygon2FilledCurve from the OP. I was called to dinner before I finished my edit.

$\endgroup$
6
  • 2
    $\begingroup$ If you want more rigorous checking, this checks whether the polygon is in the proper form for a GraphicsComplex: gcpolyToNormal = # /. GraphicsComplex[p_, g_, o___] :> GraphicsComplex[p, g /. Polygon[v_?(VectorQ[#, IntegerQ] || AllTrue[#, VectorQ[#, IntegerQ] &] &)] :> Polygon[v /. i_Integer :> p[[i]]]] &; $\endgroup$
    – Michael E2
    Jul 6 at 1:20
  • $\begingroup$ Actually your solution won't do the trick because after applying gcpolyToNormal we have Depth[pts] == 4, and polygon2FilledCurve won't be applied. The same mistake is with your "fix" for polygon2FilledCurve. See also my answer. $\endgroup$ Jul 6 at 3:38
  • $\begingroup$ Please check the output of updated polygon2FilledCurve[gcpolyToNormal@image] - it is as shown in the question due to the reasons explained in my answer. All cases of FilledCurve[Thread@Line[v]] should be replaced with FilledCurve /@ Thread[Line[v]]. $\endgroup$ Jul 6 at 4:20
  • $\begingroup$ Here is what I get: screenshot. $\endgroup$ Jul 6 at 4:27
  • $\begingroup$ @AlexeyPopkov Sorry, I've got bad eyes and misread which thing to fix. $\endgroup$
    – Michael E2
    Jul 6 at 4:29
4
$\begingroup$

The problem arises in the first place because the original version of polygon2FilledCurve used the single-component multi-segment syntax form of FilledCurve instead of its multi-component single-segment syntax form. Also, FilledCurve's filling behavior for overlapping components differs from the one for Polygon, hence for the conversion purposes we must use only the single-component single-segment syntax form. Here is a universal version of polygon2FilledCurve which should work correctly independently of the presence of GraphicsComplex inside of Graphics:

polygon2FilledCurve = # /. 
     g_GraphicsComplex :> (g /. {
         Polygon[pts : {{__Integer} ..}] :> FilledCurve /@ Thread[Line[pts]],
         Polygon[pts : {__Integer}] :> FilledCurve[Line[pts]]}) /.
    {Polygon[pts : {_?(MatrixQ[#, NumericQ] &) ..}] :> FilledCurve /@ Thread[Line[pts]],
     Polygon[pts_ /; MatrixQ[pts, NumericQ]] :> FilledCurve[Line[pts]]} &;

I've updated my answer in the linked thread with this implementation.


More info about the syntax and the use cases of FilledCurve can be found in this answer.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.