7

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]
Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
hana
  • 2,388
  • 5
  • 19
  • 1
    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. – Nasser Jun 30 '22 at 07:45
  • 1
    @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. – hana Jun 30 '22 at 07:48

3 Answers3

11

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.

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
11

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:

Alexey Popkov
  • 61,809
  • 7
  • 149
  • 368
6

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]]

Nasser
  • 143,286
  • 11
  • 154
  • 359
  • Nope, I want to make the region inside the markers transparent. – hana Jun 30 '22 at 05:32
  • @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? – Nasser Jun 30 '22 at 05:35
  • @Nasser Maybe the questioner want Clip or UnFill the interior of markers. It is ease implement in PostScript but difficult in Mathematica. – cvgmt Jun 30 '22 at 07:00
  • @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. – Nasser Jun 30 '22 at 07:04
  • @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. – cvgmt Jun 30 '22 at 07:13
  • @cvgmt yes, that is what I wanted. The white color hide the background. I want to see the background. If you use the white fill then you can't see the grid lines there. – hana Jun 30 '22 at 07:27
  • @cvgmt I see. But in the example given, the background of the plot is now white. So it makes no difference using your method if I understand it right. – Nasser Jun 30 '22 at 07:28
  • @Nasser that would hide the grid lines, so they're different when the markers and the grids are overlapping. – hana Jun 30 '22 at 07:29
  • @cvgmt is this the PostScript you're talking about? https://en.wikipedia.org/wiki/PostScript – hana Jun 30 '22 at 07:34
  • @Nasser When we export the plot to svg ,png or pdf, the background color is not white. We can include such svg ,png or pdf to a color background to test such features. – cvgmt Jun 30 '22 at 08:10
  • @cvgmt I just exported the image I showed to pdf and png and also svg, in each case the plot background remained white just as it shows in the notebook itself? May be I misunderstood something. I do understand if one sets the background of the plot explicitly to different color using Background -> Yellow for example, then the markers will remain white,. Yes which is not what the OP wants. – Nasser Jun 30 '22 at 08:19
  • @Nasser Sorry for my poor English :) We can include the output.pdf into TeX to test the feature of Opacity instead of White. \documentclass{article} \usepackage{graphicx} \usepackage{pagecolor} \begin{document} \pagecolor{yellow!30!orange} \includegraphics{output.pdf} \end{document} – cvgmt Jun 30 '22 at 08:40
  • @Nasser is it still confusing? I think I explained above. The problem is when the markers are on the grid lines so if you use white then they will block the grids. – hana Jun 30 '22 at 09:56
  • @cvgmt is this the PostScript you're talking about? https://en.wikipedia.org/wiki/PostScript – hana Jun 30 '22 at 11:28