Using arbitrary polygons as markers in Makie.jl

Hi,

I know I can make any polygon as a vector of Point2f0 and plot it with poly!. However what I’d like to do is use this polygon as a marker for a scatter plot.

is this possible? how? I couldn’t find something in the docs. (BTW the it would be really helpful if the docs have a plot that shows all available markers, this docstring: http://makie.juliaplots.org/stable/abstractplotting_api.html#AbstractPlotting.available_marker_symbols-Tuple{} could be used to produce an actual plot)

2 Likes

You mean something like this :

Legend · Makie.jl (juliaplots.org)

There, the last entry is a poly marker [scatter].

No, that’s not what I’m looking for. This adds a polygon as an entry to a legend. I want to scatter plot markers whose shape is a polygon.

Here the marker attribute is listed for available types. Example gallery has some marker examples with symbols, unicode character and an image.

The plots you cite are outdated w.r.t. current Makie so I’m not sure how trustworthy they are. They are also not what I am expecting. I am expecting something like this: matplotlib.markers — Matplotlib 3.3.3 documentation , which is the first hit I get after googling “matplotlib available marker types”

1 Like

if you check the help for scatter, it says that

?marker
.
marker            HyperSphere{2,T} where T
.
.

which suggest one should define custom markers as in here [including polygons]
https://juliageometry.github.io/GeometryBasics.jl/stable/

I did try some, but unfortunately none of them worked. No errors, but not points [markers] were plotted. Probably someone else, that knows better the internals could help here.

It looks like marker doesn’t accept a Polygon, but it works if you make a Mesh from it:

p = Polygon([Point2f0(0), Point2f0(1), Point2f0(1,0)]);
meshscatter(rand(Point2f0, 10), marker=GeometryBasics.mesh(p), color=:red)

Looks like shading is on by default even for 2D plots, so you might want to add shading=false.

3 Likes

@sijo suggests what I’d do! :wink:

2 Likes

I’m making a plotting framework for Agents.jl where users can plot their agents as scatter markers. It is convenient for us to do everything with scatter and forward splatted keywords to scatter.

Doesn’t it make more sense if scatter could accept a Polygon directly as a marker, instead of me writing an if clause? It might be that more people in the future will want to scatter plot something with arbitrary polygons.

2 Likes

Hello,
I believe this question was answer in Slack [black hole], could you please share the solution here.

1 Like

I think we settled on doing poly(vector_of_polygons). The only thing is that it’s currently buggy to add vertices to these polygons interactively. But in the use case that we talked about, only the rotation and size was changed.

1 Like

poly was indeed the solution. Here are a few examples using it:

Flocking, Bacteria Growth.

For the animations to work we provide the markers to an observable (source), and introduced some helper functions.

2 Likes

This solution works nicely, but as with the poly solution, I’m wondering if there’s a way to change the space-units from data to pixel. When you zoom in on a regular scatter-marker the size of the marker doesn’t change, which is great. I would have liked to be able to create a custom marker (from a polygon) that behaves similarly.

For more context

I’m trying to create and use a new rotated drop-shaped marker, which works really well following the docs https://makie.juliaplots.org/stable/documentation/recipes/index.html#multiple_argument_conversion_with_convert_arguments:

using CoordinateTransformations, Rotations

struct DirectedDrop{T<:AbstractVector}
  c::T
  θ::Float64
end

function Makie.convert_arguments(::PointBased, x::DirectedDrop)
  f = Translation(x.c) ∘ LinearMap(Angle2d(x.θ))
  n = 64
  ([f(Point2f(cos(t), sin(t)*sin(t/2)^2)) for t in range(0, 2π, n + 1)[1:end-1]], )
end

c = Point2f(2,3)
dd = Node(DirectedDrop(c, 0.0))
poly(dd, axis = (aspect = DataAspect(), ))

My question is, what is the best way to plug in the whole interplay between MarkerSpace versus DataSpace? And as a side-question, in the decomposition of my DirectedDrop, what is the correct way to specify the number of vertices I use to create the drop (right now, I just have it hard-coded to 64)?

Actually, there’s a much simpler solution to this. I could use a unicode droplet character and then simply:

n = 10
scatter(rand(Point2f0, n), marker='↓', rotation = 2π*rand(n))

where the ↓ would be replaced by say something like 🌢. But currently I couldn’t find any droplet charachters that rendered correctly on my figure (I’m just getting the empty rectangle symbol).

maybe this will help you if you look into the markershape attribute in the table.

Series Attributes · Plots (juliaplots.org)

Your reply isn’t even about Makie.jl though…

2 Likes