Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic dodging mechanism #558

Merged
merged 12 commits into from
Sep 17, 2024
Merged

Generic dodging mechanism #558

merged 12 commits into from
Sep 17, 2024

Conversation

jkrumbiegel
Copy link
Member

Fixes #393

This PR adds the keywords xdodge and ydodge to mapping which, like other hardcoded mappings (layout, row, col, group) are not tied to any Makie attributes in particular. Instead, these modify any AesX or AesY columns, respectively, when they are used. This allows generic dodging of things like scatters or errorbars:

df = (
    x = [1, 1, 2, 2],
    y = 1:4,
    err = [0.5, 0.4, 0.7, 0.6],
    group = ["A", "B", "A", "B"],
)

data(df) *
    (
        mapping(:x, :y, :err, xdodge = :group, color = :group) * visual(Errorbars) +
        mapping(:x, :y, xdodge = :group, color = :group) * visual(Scatter)
    ) |> draw(scales(DodgeX = (; width = 0.2)))
image

The width of the dodging can be controlled with a scale attribute:

mapping(
    repeat(string.('A' .+ (0:9)), inner = 20),
    randn(200),
    xdodge = repeat(["X", "Y"], 100),
    strokecolor = repeat(["X", "Y"], 100),
) * visual(Scatter, strokewidth = 2, color = :transparent) |>
    draw(scales(DodgeX = (; width = 0.5)))
image

Caveats / remaining design problems

The most common scenario is errorbars on barplots, I think. However, barplots implement their own dodging via the dodge keyword. (There are a couple recipes that have dodge implemented, rainclouds, crossbars, violins...) And the width does not depend on the dodging scale but on the plot's own width setting as well as gap and dodge_gap. So one can have mismatched dodging:

df = (
    x = [1, 1, 2, 2],
    y = 1:4,
    err = [0.5, 0.4, 0.7, 0.6],
    group = ["A", "B", "A", "B"],
)

data(df) *
    (
        mapping(:x, :y, dodge = :group, color = :group) * visual(BarPlot) +
        mapping(:x, :y, :err, xdodge = :group) * visual(Errorbars)
    ) |> draw(scales(DodgeX = (; width = 0.2)))
image

One could use xdodge for barplot as well, but then this can conflict with the width setting from barplot, which would then not be adjusted for anymore (barplot wouldn't know that dodging is going on)

df = (
    x = [1, 1, 2, 2],
    y = 1:4,
    err = [0.5, 0.4, 0.7, 0.6],
    group = ["A", "B", "A", "B"],
)

data(df) *
    (
        mapping(:x, :y, xdodge = :group, color = :group) * visual(BarPlot, width = 1) +
        mapping(:x, :y, :err, xdodge = :group) * visual(Errorbars)
    ) |> draw(scales(DodgeX = (; width = 0.2)))
image

Note that in this particular case, if width = 1 wasn't set, the plot would look ok, but that might not always be the case if enough categories are missing, so it's too brittle I think.

image

So ideally, I think the width for widthless plots (scatter, errorbars, etc.) could be inferred from plots with width that are also using the dodge scale. So if a barplot is in the mix, the width would be picked up from it somehow. This adds a small layer of complexity on top of the processing pipeline but might be manageable.

@jkrumbiegel
Copy link
Member Author

Going the width inference route now, to make the super common case of barplots + errorbars easier. The widthless errorbars can now infer the necessary width from the barplots in a sort of preprocessing step before entries are computed.

df = (
    x = [1, 1, 2, 2],
    y = 1:4,
    err = [0.5, 0.4, 0.7, 0.6],
    group = ["A", "B", "A", "C"],
)

data(df) *
    (
        mapping(:x, :y, dodge = :group, color = :group) * visual(BarPlot, gap = 0.5) +
        mapping(:x, :y, :err, dodge_x = :group) * visual(Errorbars)
    ) |> draw
image

@jkrumbiegel jkrumbiegel marked this pull request as ready for review September 17, 2024 10:25
@jkrumbiegel jkrumbiegel merged commit 2ab0756 into master Sep 17, 2024
6 checks passed
@jkrumbiegel jkrumbiegel deleted the jk/generic-dodge branch September 17, 2024 10:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Dodge in scatter,lines
1 participant