8
$\begingroup$

This is what happens when I use FaceForm[Opacity[0, White]]. The lines go across the markers:

enter image description here

How can I make the markers transparent inside, but so that the lines don't go through them (just connect on both sides of the markers)?

Initially, I used FaceForm[White], but then the grid lines behind the markers are not visible:

enter image description here

data = {Table[{x, 1 + 2 x}, {x, 0, 5, 1}], 
   Table[{x, 1 + x}, {x, 0, 5, 1}]};
markers = {"Circle", "ThreePointedStar"};
colors = {Blue, Red};
Graphics[Table[{colors[[i]], Line[data[[i]]], 
   FaceForm[Opacity[0, White]], 
   EdgeForm[{colors[[i]], AbsoluteThickness[2], JoinForm["Miter"]}], 
   ResourceFunction["PolygonMarker"][markers[[i]], Offset[7], 
    data[[i]]]}, {i, Length[data]}], AspectRatio -> 1/2, 
 ImageSize -> 450, Frame -> True, GridLines -> Automatic]
$\endgroup$
2
  • 1
    $\begingroup$ The grids are blocked if you fill white. True. But to tell you the truth, it looks better this way. I do not think the grid lines showing under the markers will look better. But ofcourse, it is your choice. $\endgroup$
    – Nasser
    Commented Jun 30, 2022 at 7:45
  • 1
    $\begingroup$ @Nasser yes, it looks better but I want to show a bit more information where they intersect so I wanted to do that way. Probably I can try to manually set so that the grids and markers are not overlapping. $\endgroup$
    – hana
    Commented Jun 30, 2022 at 7:48

3 Answers 3

11
$\begingroup$

For creating a vector figure, you can start from the third example under the "Scope" section on the Documentation page for PolygonMarker:

data = Table[{x, BesselJ[k, x]}, {k, 0, 4}, {x, 0, 10, 0.5}];
plotRange = MinMax /@ Transpose[Flatten[data, 1]];
markers = {"Circle", "ThreePointedStar", "FourPointedStar", 
   "DiagonalFourPointedStar", "FivePointedStar"};
colors = {Blue, Red, Green, Yellow, Orange};
background = Darker@Gray;
gr = Graphics[{Table[{colors[[i]], AbsoluteThickness[1.5], 
     Line[data[[i]]]}, {i, Length[data]}],
   Table[{colors[[i]], FaceForm[background], EdgeForm[None], 
     ResourceFunction["PolygonMarker"][markers[[i]], Offset[7], data[[i]]]}, {i, 
     Length[data]}],
   {Gray, CapForm[None], AbsoluteThickness[0.5], 
    Table[{InfiniteLine[{x, 0}, {0, 1}]}, {x, Range[0, 10, 1]}],
    Table[{InfiniteLine[{0, y}, {1, 0}]}, {y, Range[-.4, 1, .2]}]},
   Table[{FaceForm[None], 
     EdgeForm[{colors[[i]], AbsoluteThickness[1.5], JoinForm[{"Miter", 6}]}], 
     ResourceFunction["PolygonMarker"][markers[[i]], Offset[7], data[[i]]]}, {i, 
     Length[data]}]},
  AspectRatio -> 1/2, ImageSize -> 500, Frame -> True, 
  PlotRange -> plotRange, 
  PlotRangePadding -> {Scaled[.025], Scaled[.05]}, 
  Background -> background, FrameStyle -> White, 
  ImagePadding -> {{30, 20}, {25, 20}}, GridLines -> Automatic]

output

Exporting to PDF and looking closer:

Export["plot.pdf", gr] // SystemOpen

screenshot

As you see, the grid lines are over the plotted lines - this is a drawback of this approach. If this drawback is important, try a Region-based approach from the other answer here.

$\endgroup$
11
$\begingroup$

Let us employ the Region-based functionality for constructing a vector figure with transparent (empty) plot markers without plotted lines going through them. The advantage of this approach is that the plot markers are really transparent, as opposed to my previous answer, where the transparency was a simulation. The plotted lines do not go through the markers, because the corresponding portions of them are explicitly removed using RegionDifference. The parameter aspectRatio here defines the aspect ratio of the full plot range area (not of the whole figure), as it does the option AspectRatio. The amount of padding may be controlled using the parameters of the padPlotRange function (or, alternatively, the full plot range fullPlotRange can be set explicitly). The perfect result is achieved when the options AspectRatio -> aspectRatio and PlotRange -> fullPlotRange, PlotRangePadding -> None are set for the final Graphics.

First, define auxiliary functions:

Clear[padPlotRange, createLineWithMarkers, createLegend];
(* Uniformly expands the plotting area, taking into account the aspect ratio *)
padPlotRange[padding_ : .05, aspectRatio_ : 1/GoldenRatio][plotRange_] := 
 Transpose[ScalingTransform[
    1 + 2 {padding, padding/aspectRatio}, Mean /@ plotRange][plotRange\[Transpose]]]
(* Generates graphics primitives representing the lines and the markers *)
createLineWithMarkers[{shape_, spec_ : .02}, pts_, fullPlotRange_, 
   aspectRatio_ : 1/GoldenRatio] := 
  Module[{rt, rtBack, markerPrimsResc, linePrimsResc, ptsResc},
   rt = RescalingTransform[fullPlotRange, {{0, 1}, {0, aspectRatio}}]; 
   rtBack = InverseFunction[rt]; ptsResc = rt[pts];
   markerPrimsResc = ResourceFunction["PolygonMarker"][shape, spec, ptsResc];
   linePrimsResc = 
    MeshPrimitives[RegionDifference[Line[ptsResc], RegionUnion @@ markerPrimsResc], 
      1] /. _MeshPrimitives :> {};
   Join[linePrimsResc, markerPrimsResc] /. (h : Line | Polygon)[ptsResc_] :> 
     h@rtBack[ptsResc]];
(* Generates graphics primitives representing a legend *)
createLegend[markerSpecs_, labels_, {verticalStep_, labelStep_, lineLength_ : .06}, 
   legendPosition_, styles_, fullPlotRange_, aspectRatio_ : 1/GoldenRatio] := 
  Module[{rt, shifts, protect},
   rt = RescalingTransform[{{0, 1}, {0, aspectRatio}}, fullPlotRange];
   Table[Join[styles[[i]],
      MeshPrimitives[
        RegionDifference[Line[{{-lineLength/2, 0}, {lineLength/2, 0}}], 
         ResourceFunction["PolygonMarker"] @@ markerSpecs[[i]]], 1] /. _MeshPrimitives :> {},
      {ResourceFunction["PolygonMarker"] @@ markerSpecs[[i]], Text[protect@labels[[i]], {labelStep, 0}]}] /.
     {protect[l_] :> l, {x_?NumericQ, y_?NumericQ} :>
        (rt[{x, y} + {0, (Length[markers] - i) verticalStep} + legendPosition])},
    {i, Length[markers]}]];

Input:

(* The data set to plot *)
data = Table[{x, BesselJ[k, x]}, {k, 0, 4}, {x, 0, 10, 0.5}];
(* Labels for the legend *)
labels = Table[Style[Subscript[J, n][z], 15], {n, 0, 4}];
(* Aspect ratio of the whole plot area (doesn't include ImagePadding) *)
aspectRatio = 1/2;
(* Plot markers *)
markers = {"Circle", "ThreePointedStar", "FourPointedStar", "DiagonalFourPointedStar", 
   "FivePointedStar"};
(* Colors for the lines&markers *)
colors = {LightBlue, Red, Green, Yellow, Orange};
(* Backgound image *)
background = 
  Polygon[ImageScaled /@ {{0, 0}, {1, 0}, {1, 1}, {0, 1}}, VertexColors -> 
    RGBColor /@ {{0, 0, 1, .9}, {0, 1, 0, .9}, {1, 0, 0, .9}, {1, 1, 0, .9}}];

Plotting:

(* Determine the range of the input data *)
dataRange = MinMax /@ Transpose[Flatten[data, 1]];
(* Expand the plot area to fit all the graphics elements. 
This value must be specified as the value for PlotRange *)
fullPlotRange = padPlotRange[.04, aspectRatio]@dataRange;
(* Define full specifications for the markers *)
markerSpecs = Table[{markers[[i]], .02}, {i, Length[data]}];
(* Define styles for the lines and the markers *)
plotStyles = 
  Table[{colors[[i]], AbsoluteThickness[1.5], CapForm[None], FaceForm[None], 
    EdgeForm[{colors[[i]], AbsoluteThickness[1.5], JoinForm[{"Miter", 6}]}]}, {i, 
    Length[data]}];
(* Generate graphics primitives representing the lines and the markers,
along with the corresponding styling directives *)
plotPrimitives = 
  Table[Join[plotStyles[[i]], 
    createLineWithMarkers[markerSpecs[[i]], data[[i]], fullPlotRange, aspectRatio]], {i, 
    Length[data]}];
(* Generate graphics primitives representing the legend *)
legendPrimitives = 
  createLegend[markerSpecs, labels, {.045, .08, .06}, {.85, .29}, plotStyles, 
   fullPlotRange, aspectRatio];
(* Construct a Graphics object from the set of graphics primitives *)
pl = Graphics[{plotPrimitives, legendPrimitives}, PlotRange -> fullPlotRange, 
  AspectRatio -> aspectRatio, ImageSize -> 500, Frame -> True, FrameStyle -> White, 
  ImagePadding -> {{25, 5}, {15, 5}}, GridLines -> Automatic, GridLinesStyle -> Black, 
  Prolog -> background]

output

Exporting to PDF and looking closer:

Export["plot.pdf", pl] // SystemOpen

screenshot

Looks perfect.


Strongly related:

$\endgroup$
6
$\begingroup$

How can I make the markers transparent inside but the lines don't go through it

You mean like this? If not, will delete this

Mathematica graphics

Just changed FaceForm[Opacity[0, White]] to FaceForm[Opacity[1, White]]

$\endgroup$
14
  • $\begingroup$ Nope, I want to make the region inside the markers transparent. $\endgroup$
    – hana
    Commented Jun 30, 2022 at 5:32
  • $\begingroup$ @hana I am having hard time understanding what you want then. Can you draw by on paper how one of the markers will look like then and scan the image? You said you do not want the other lines to show below the markers and the above does it. How else will it look like otherwise? $\endgroup$
    – Nasser
    Commented Jun 30, 2022 at 5:35
  • $\begingroup$ @Nasser Maybe the questioner want Clip or UnFill the interior of markers. It is ease implement in PostScript but difficult in Mathematica. $\endgroup$
    – cvgmt
    Commented Jun 30, 2022 at 7:00
  • $\begingroup$ @cvgmt Ok, thanks. But how would it look different than the above is what I do not see now. i.e. Assuming your method can be done in Mathematica, will the end result look different? I never used Clip and Unfill, so may be if you know how to do, that will be good to see. $\endgroup$
    – Nasser
    Commented Jun 30, 2022 at 7:04
  • $\begingroup$ @Nasser When we put the picture onto some color background, the clip or unfill part just the background color instead of white. That is their difference. $\endgroup$
    – cvgmt
    Commented Jun 30, 2022 at 7:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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