Plot text at location

@piever How can I set the location of text in AoG?

using AlgebraOfGraphics
using CairoMakie
using DataFrames

n = 500
df = DataFrame(x=1:n, y= collect(1:2:2n) .+ 10randn(n))
df = transform(df, :y => ByRow(x-> x%10==0 ? string(x) : "") => :txt)

data(df) * mapping(:x, :txt, position=:y) * visual(CairoMakie.Text) |> draw

MethodError: no method matching layout_text

There isn’t really a good way to do that at the moment, but it is a planned feature, see Remaining gallery items · Issue #159 · JuliaPlots/AlgebraOfGraphics.jl (

This ties a bit into the larger problem, what to do when plotting function positional arguments don’t conform to x,y,z. Text is one of the only plotting functions where the data positions are given in an attribute, not positional args. Maybe we should change that recipe if this turns out to be a major problem for downstream packages like AoG.

I usually think of geom_text and geom_label as a scatterplot with a different marker shape, so making text conform to the scatter specification would make sense to me.

Yes that could be a good option, I thought the same

Yes, the two main issues are

  1. unusual argument order and
  2. the categorical conversion pipeline gets in the way

To clarify problem 2. a bit, AoG always converts columns to numeric values before plotting. There are rare cases where plotting recipes accept lists of non numeric fields. One is plotting geometries (which are special cased in AoG) and the other is labels in a Text or Annotations plot, which would also need to be special cased.

If we changed the signature to annotations(x, y, labels), or even better annotations(x, y, label=labels), it should be easy enough to special case it and avoid the categorical conversion.

OTOH, scatter(x, y, marker=labels) would be a bit problematic from the AoG perspective, because it would be ambiguous with plotting a categorical variable with different markers. I think it’s better if it is clear from the keyword name that it should receive arbitrary strings.

I think the idea was not to use scatter, just the same argument order with x, y and marker for scatter is similar to string for text


This would be an opportunity to introduce a markermap analogous to colormap. That way, annotations(x,y, labels=labels) could be implemented as scatter(x, y, markers=labels, markermap=unique(labels)). That is, it’s just a categorical variable, and the marker chosen for each value is determined by the markermap to be equal to the text of each label. Then no special casing is necessary.