Wolfram Research

Function Repository Resource:

PolygonMarker (4.0.1) current version: 4.1.0 »

Source Notebook

Create markers carefully designed for creation of publication-quality plots

Contributed by: Alexey Popkov  |  AlexeyPopkov

ResourceFunction["PolygonMarker"]["name"]

returns a unit area Polygon describing the shape "name".

ResourceFunction["PolygonMarker"][{p1,,pn}]

returns a unit area Polygon with shape described by points {p1,,pn} and centroid at {0,0}.

ResourceFunction["PolygonMarker"][shape, size]

returns shape of the specified size.

ResourceFunction["PolygonMarker"][shape,{size,angle}]

returns shape rotated by angle.

ResourceFunction["PolygonMarker"][shape, spec, style]

returns a Graphics object suitable for PlotMarkers where the style of shape is defined by style.

ResourceFunction["PolygonMarker"][All]

returns the list of names of predefined shapes.

Details and Options

The basic usage syntax is ResourceFunction["PolygonMarker"][shape,spec], where shape is the name of a predefined shape or a list of 2D coordinates describing a simple polygon, and spec can be either size or {size, angle}.
The size can be given as a number or in Scaled or Offset form.
The angle in radians determines the angle of counterclocwise rotation of shape about its centroid.
ResourceFunction["PolygonMarker"][shape,spec] returns a Polygon graphics primitive that can be used in Graphics.
ResourceFunction["PolygonMarker"][shape,spec,style], where style is a list of graphics directives applied to shape, returns a Graphics object which can be used as a marker for PlotMarkers.
ResourceFunction["PolygonMarker"][shape,spec,style,options] returns a Graphics object with options applied.
The centroid of Polygon generated by ResourceFunction["PolygonMarker"] is always placed at {0,0} in the internal coordinate system of Graphics.
ResourceFunction["PolygonMarker"][shape,spec,positions], where positions is a list of 2D coordinates, evaluates to Translate[ResourceFunction["PolygonMarker"][shape,spec],positions]. It represents a collection of multiple identical copies of shape with centroids placed at positions.
With an Offset size specification, the plot marker has a fixed size specified in printer's points, independent of ImageSize.
ResourceFunction["PolygonMarker"][shape,size] returns a Polygon with area size2 in the internal coordinate system of Graphics. ResourceFunction["PolygonMarker"][shape,Offset[size]] returns a Polygon with area size2 square printer’s points. The area taken by the boundary of the returned Polygon isn’t taken into account.
ResourceFunction["PolygonMarker"][All] and ResourceFunction["PolygonMarker"][] both return the complete list of names of predefined shapes.

Examples

Basic Examples (6) 

Create a unit area Polygon object of "TripleCross" type rotated counterclockwise by :

In[1]:=
ptc = ResourceFunction["PolygonMarker"]["TripleCross", {1, \[Pi]/6}]
Out[1]=

The centroid of the polygon is placed at {0,0}:

In[2]:=
centroid = RegionCentroid[ptc] // Chop
Out[2]=

Visualize the polygon and its centroid:

In[3]:=
Graphics[{LightBlue, ptc, Red, PointSize[.05], Point[centroid]}, Axes -> True]
Out[3]=

Create a tuned up Graphics marker in one step:

In[4]:=
mtps = ResourceFunction["PolygonMarker"][
  "ThreePointedStar", {Offset[7], 0}, {EdgeForm[Red], FaceForm[None]}]
Out[4]=

This marker is set up to be suitable for PlotMarkers:

In[5]:=
ListPlot[Labeled[#, #, Background -> None] & /@ Table[Prime[n], {n, 10}], PlotMarkers -> {mtps}, PlotRange -> {{0, All}, {0, All}}]
Out[5]=

Get the complete list of built-in named shapes:

In[6]:=
allShapes = ResourceFunction["PolygonMarker"][All]
Out[6]=

Make a Grid of Buttons with the shapes for easy selection:

In[7]:=
Grid[{allShapes[[;; 11]], allShapes[[12 ;; 17]], allShapes[[18 ;; 26]], allShapes[[27 ;; 32]], allShapes[[33 ;; 38]], allShapes[[39 ;;]]} /. shape_String :> Button[Tooltip[
     ResourceFunction["PolygonMarker"][shape, Offset[13], {FaceForm[RandomColor[ColorSpace -> LUVColor]], EdgeForm[{Black, AbsoluteThickness[72/96], JoinForm["Miter"]}]}], Row[{"\"", Style[shape, Bold], "\"", " (click to copy the name)"}]], CopyToClipboard@ToString[shape, InputForm], ImageSize -> {40, 40},
     FrameMargins -> False]]
Out[7]=

Filled markers that pick up PlotStyle and PlotTheme automatically:

In[8]:=
fm[name_String, size_ : 8] := ResourceFunction["PolygonMarker"][name, Offset[size], EdgeForm[]];
In[9]:=
SeedRandom[25];
In[10]:=
ListPlot[Table[Accumulate@RandomReal[1, 10] + i, {i, 6}], PlotMarkers -> fm /@ {"Triangle", "Y", "Diamond", "ThreePointedStar", "FivePointedStarSlim", "TripleCross"}, Joined -> True, PlotStyle -> ColorData[52, "ColorList"], PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {50, 37}, LegendLayout -> (Column[Row /@ #, Spacings -> -1] &)], ImageSize -> 450]
Out[10]=
In[11]:=
SeedRandom[2];
In[12]:=
ListPlot[Table[Accumulate@RandomReal[1, 10] + i, {i, 6}], PlotMarkers -> fm /@ {"Triangle", "LeftTriangle", "Diamond", "ThreePointedStar", "UpTriangleTruncated", "Square"}, PlotTheme -> "Marketing", PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {50, 35}, LegendLayout -> (Column[Row /@ #, Spacings -> -1] &)], ImageSize -> 450]
Out[12]=

Empty markers that pick up PlotStyle and PlotTheme automatically:

In[13]:=
em[name_String, size_ : 7] := ResourceFunction["PolygonMarker"][name, Offset[size],
   {Dynamic@
     EdgeForm[{CurrentValue["Color"], JoinForm["Round"], AbsoluteThickness[2], Opacity[1]}], FaceForm[White]},
   ImagePadding -> 6];
In[14]:=
SeedRandom[2];
In[15]:=
ListPlot[Table[Accumulate@RandomReal[1, 10] + i, {i, 3}], PlotMarkers -> em /@ {"Triangle", "Square", "Diamond"}, Joined -> True, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 25}], ImageSize -> 450]
Out[15]=
In[16]:=
SeedRandom[3];
In[17]:=
ListPlot[Table[Accumulate@RandomReal[1, 10] + i, {i, 3}], PlotMarkers -> em /@ {"Triangle", "Square", "Diamond"}, Joined -> True, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 25}], PlotTheme -> "Marketing", ImageSize -> 450]
Out[17]=

Filled markers with lighter filling colors:

In[18]:=
fm2[name_String, size_ : 9] := ResourceFunction["PolygonMarker"][name, Offset@size, {
    Dynamic@EdgeForm[{CurrentValue["Color"], Opacity[1]}],
    Dynamic@FaceForm@Lighter[CurrentValue["Color"], 0.75]}];

data = Table[{x, BesselJ[k, x]}, {k, 0, 2}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> fm2 /@ {"UpTriangle", "Square", "Circle"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}]
Out[15]=

Scope (3) 

Use the third argument of PolygonMarker to specify the coordinate(s) where the marker should be placed:

In[19]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/e9375601-721a-45cc-a251-c6aad9236633"]
Out[19]=

Construct a list plot directly from graphics primitives:

In[20]:=
data = Table[{x, BesselJ[k, x]}, {k, 0, 3}, {x, 0, 10, 0.5}];
markers = {"Circle", "ThreePointedStar", "FourPointedStar", "FivePointedStar"};
colors = {Blue, Red, Darker@Green, Darker@Yellow};
Graphics[Table[{colors[[i]], Line[data[[i]]], FaceForm[White], EdgeForm[{colors[[i]], AbsoluteThickness[1], JoinForm["Miter"]}], ResourceFunction["PolygonMarker"][markers[[i]], Offset[7], data[[i]]]}, {i, Length[data]}], AspectRatio -> 1/2, ImageSize -> 450, Frame -> True]
Out[16]=

Construct a custom list plot where open plot markers have transparent faces for each other (but not for the lines):

In[21]:=
data = Table[{x, BesselJ[k, x]}, {k, 0, 4}, {x, 0, 10, 0.5}];
markers = {"Circle", "ThreePointedStar", "FourPointedStar", "DiagonalFourPointedStar", "FivePointedStar"};
colors = {Blue, Red, Green, Yellow, Orange};
background = Darker@Gray;
Graphics[{Table[{colors[[i]], AbsoluteThickness[1.5], Line[data[[i]]],
     FaceForm[background], EdgeForm[None], ResourceFunction["PolygonMarker"][markers[[i]], Offset[7], data[[i]]]}, {i, Length[data]}], Table[{FaceForm[None], EdgeForm[{colors[[i]], AbsoluteThickness[1.5], JoinForm["Miter"]}], ResourceFunction["PolygonMarker"][markers[[i]], Offset[7], data[[i]]]}, {i, Length[data]}]}, AspectRatio -> 1/2, ImageSize -> 500, Frame -> True, Background -> background, FrameStyle -> White, ImagePadding -> {{30, 20}, {25, 20}}]
Out[17]=

Neat Examples (5) 

Center markers that pick up PlotStyle and PlotTheme automatically:

In[22]:=
cfm[name_String, size_ : 9] := Show[
   ResourceFunction["PolygonMarker"][name, Offset@size, {
     FaceForm[White],
     Dynamic@
      EdgeForm[{CurrentValue["Color"], AbsoluteThickness[1], Opacity[1]}]}],
   ResourceFunction["PolygonMarker"][name, Offset[size/2], EdgeForm[None]]];

data = Table[{x, BesselJ[k, x]}, {k, 0, 2}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> cfm /@ {"UpTriangle", "Square", "Circle"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 30}], ImageSize -> 450]
Out[15]=

Half-filled markers that pick up PlotStyle and PlotTheme automatically:

In[23]:=
hfm1[name_String, size_ : 9] := Show[
   ResourceFunction["PolygonMarker"][name, Offset@size, {
     FaceForm[White],
     Dynamic@
      EdgeForm[{CurrentValue["Color"], AbsoluteThickness[1], Opacity[1]}]}],
   ResourceFunction["PolygonMarker"][name, Offset@size, EdgeForm[None]] /. {x_?Negative, y_?NumericQ} :> {0, y}];

data = Table[{x, BesselJ[k, x]}, {k, 0, 2}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> hfm1 /@ {"UpTriangle", "Square", "Circle"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 30}], ImageSize -> 450]
Out[15]=
In[24]:=
hfm2[name_String, size_ : 9] := Show[
   ResourceFunction["PolygonMarker"][name, Offset@size, {
     FaceForm[White],
     Dynamic@
      EdgeForm[{CurrentValue["Color"], AbsoluteThickness[1], Opacity[1]}]}],
   Graphics[{EdgeForm[None], Replace[RegionDifference[ResourceFunction["PolygonMarker"][name],
        Rectangle[{-10, -10}, {10, 0}]], p : {x_, y_} :> Offset[size p, {0, 0}], {-2}]}]];

data = Table[{x, BesselJ[k, x]}, {k, 0, 3}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> hfm2 /@ {"Diamond", "Square", "Circle", "RightTriangle"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 30}], ImageSize -> 450]
Out[25]=
In[26]:=
hfm3[name_String, size_ : 9] := Show[
   ResourceFunction["PolygonMarker"][name, Offset@size, {
     FaceForm[White],
     Dynamic@
      EdgeForm[{CurrentValue["Color"], AbsoluteThickness[1], Opacity[1]}]}],
   Graphics[{EdgeForm[None], Replace[RegionDifference[ResourceFunction["PolygonMarker"][name],
        Triangle[{{-10, -10}, {10, 10}, {10, -10}}]], p : {x_, y_} :> Offset[size p, {0, 0}], {-2}]}]];

data = Table[{x, BesselJ[k, x]}, {k, 0, 3}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> hfm3 /@ {"Diamond", "Square", "Circle", "DiagonalFourPointedStar"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 38}], ImageSize -> 450]
Out[5]=

Contrast markers that pick up PlotStyle and PlotTheme automatically:

In[27]:=
cfm1[name_String, size_ : 9] := Show[
   ResourceFunction["PolygonMarker"][name, Offset@size, {
     FaceForm[White],
     Dynamic@
      EdgeForm[{CurrentValue["Color"], AbsoluteThickness[1], Opacity[1]}]}],
   Graphics[{EdgeForm[None], Replace[RegionDifference[
       RegionDifference[ResourceFunction["PolygonMarker"][name], Rectangle[{0, 0}, {10, 10}]], Rectangle[{0, 0}, {-10, -10}]], p : {x_, y_} :> Offset[size p, {0, 0}], {-2}]}]];

data = Table[{x, BesselJ[k, x]}, {k, 0, 3}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> cfm1 /@ {"Diamond", "Square", "Circle", "FourPointedStar"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 38}], ImageSize -> 450]
Out[15]=
In[28]:=
cfm2[name_String, size_ : 9] := Show[
   ResourceFunction["PolygonMarker"][name, Offset@size, {
     FaceForm[White],
     Dynamic@
      EdgeForm[{CurrentValue["Color"], AbsoluteThickness[1], Opacity[1]}]}],
   Graphics[{EdgeForm[None], Replace[RegionDifference[
       RegionDifference[ResourceFunction["PolygonMarker"][name], Triangle[{{-10, 10}, {10, 10}, {0, 0}}]], Triangle[{{-10, -10}, {10, -10}, {0, 0}}]], p : {x_, y_} :> Offset[size p, {0, 0}], {-2}]}]];

data = Table[{x, BesselJ[k, x]}, {k, 0, 3}, {x, 0, 10, 0.5}];

ListPlot[data, PlotMarkers -> cfm2 /@ {"Diamond", "Square", "Circle", "DiagonalFourPointedStar"}, Joined -> True, Frame -> True, Axes -> False, ImageSize -> 450, PlotRangePadding -> {Scaled[.05], Scaled[.1]}, PlotLegends -> PointLegend[Automatic, LegendMarkerSize -> {40, 30}], ImageSize -> 450]
Out[29]=

Create an auxiliary function that (approximately) converts a simple glyph into a set of points suitable for PolygonMarker:

In[30]:=
pts[l_String] := First[Cases[
    ImportString[
     ExportString[Style[l, FontFamily -> "Verdana", FontSize -> 20], "PDF"], If[$VersionNumber >= 12.2, {"PDF", "PageGraphics"}, {"PDF", "Pages"}]], c_FilledCurve :> c[[2, 1]], Infinity]];

Show a set of markers in use, including some created from glyphs:

In[31]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/1dbd30f5-2df7-41fc-aae8-8ef69f4962e5"]
Out[31]=

Black-and-white plot, where the markers overlap considerably:

In[32]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/bf1dacda-8397-4d8d-82ba-6d09a3fda804"]
Out[28]=

Use the resource functions RoundedPolygon and NotchedPolygon to make markers:

In[33]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/cb4fd2c9-cc66-4d1b-b2ec-60a2e493f956"]
Out[33]=

Version History

  • 4.1.0 – 08 July 2022
  • 4.0.1 – 28 February 2022
  • 4.0.0 – 31 January 2022
  • 3.0.1 – 16 August 2021

Source Metadata

Related Resources

Author Notes

The original (author’s) version of the package which contains all the general-purpose functions used to generate the shapes can be found at https://github.com/AlexeyPopkov/PolygonPlotMarkers.

License Information