Skip to main content
6 of 14
added 40 characters in body
Alexey Popkov
  • 62.3k
  • 7
  • 154
  • 375

Here I construct a vector figure with transparent (empty) plot markers without plotted lines going through them using Region functionality. 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 ration of the padded plot range (not of the whole figure), as it does the option AspectRatio. The amount of padding may be controlled using the parameners of the padPlotRange function (or, alternatively, the full plot range paddedPlotRange can be set explicitly). The perfect result is achieved when the options AspectRatio -> aspectRatio and PlotRange -> paddedPlotRange, PlotRangePadding -> None are set for the final Graphics.

Input:

data = Table[{x, BesselJ[k, x]}, {k, 0, 4}, {x, 0, 10, 0.5}];
aspectRatio = 1/2;
markers = {"Circle", "ThreePointedStar", "FourPointedStar", 
   "DiagonalFourPointedStar", "FivePointedStar"};
colors = {Blue, Red, Green, Yellow, Orange};
background = Darker@Gray;

Auxiliary functions:

Clear[padPlotRange, rescaleCoords, rescaleCoordsBack, putMarker, createLineWithMarkers]
padPlotRange[xPadding_ : .01, yPadding_ : .02][{{xMin_, xMax_}, {yMin_, yMax_}}] := 
 Module[{xd, yd},
  xd = (xMax - xMin)*xPadding;
  yd = (yMax - yMin)*yPadding;
  {{xMin - xd, xMax + xd}, {yMin - yd, yMax + yd}}
  ]
rescaleCoords[paddedPlotRange_, aspectRatio_][pts_] := 
 Module[{xCoords = pts[[All, 1]], yCoords = pts[[All, 2]], xResc, yResc},       
  xResc = Rescale[xCoords, paddedPlotRange[[1]], {0, 1}];
  yResc = Rescale[yCoords, paddedPlotRange[[2]], {0, aspectRatio}];
  Transpose[{xResc, yResc}]
  ]
rescaleCoordsBack[paddedPlotRange_, aspectRatio_][pts_] := 
 Module[{xCoords = pts[[All, 1]], yCoords = pts[[All, 2]], xResc, yResc},       
  xResc = Rescale[xCoords, {0, 1}, paddedPlotRange[[1]]];
  yResc = Rescale[yCoords, {0, aspectRatio}, paddedPlotRange[[2]]];
  Transpose[{xResc, yResc}]
  ]
putMarker[marker_Polygon][pts_] := 
  Polygon /@ Table[# + vect & /@ marker[[1]], {vect, pts}];
createLineWithMarkers[marker_, pts_, size_ : .02] := 
 Module[{markerPrims, linePrims},
  markerPrims = putMarker[ResourceFunction["PolygonMarker"][marker, size]][pts];
  linePrims = MeshPrimitives[
                     RegionDifference[Line[pts], RegionUnion @@ markerPrims], 1];
  Join[{CapForm[None]}, linePrims, markerPrims]
  ]

Plotting:

dataRange = MinMax /@ Transpose[Flatten[data, 1]];
paddedPlotRange = padPlotRange[.03, .06]@dataRange;
dataResc = rescaleCoords[paddedPlotRange, aspectRatio] /@ data;
primitivesResc = 
  Table[{colors[[i]], AbsoluteThickness[1.5], FaceForm[None], 
    EdgeForm[{colors[[i]], AbsoluteThickness[1.5], JoinForm[{"Miter", 6}]}], 
    createLineWithMarkers[markers[[i]], dataResc[[i]], .02]}, {i, Length[dataResc]}];
primitives = 
  primitivesResc /. (h : Line | Polygon)[pts_] :> 
    h@rescaleCoordsBack[paddedPlotRange, aspectRatio][pts];
pl = Graphics[primitives, AspectRatio -> aspectRatio, 
  ImageSize -> 500, Frame -> True, Background -> background, 
  FrameStyle -> White, ImagePadding -> {{30, 20}, {25, 20}}, 
  GridLines -> Automatic, PlotRange -> paddedPlotRange, 
  PlotRangePadding -> None]

output

Exporting to PDF and looking closer:

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

screenshot

Looks perfect.

Alexey Popkov
  • 62.3k
  • 7
  • 154
  • 375