has2k1 / plotnine

A Grammar of Graphics for Python
https://plotnine.org
MIT License
4.03k stars 217 forks source link

Horizontal alignment of facet title not working #867

Open jwhendy opened 2 months ago

jwhendy commented 2 months ago

I think I ran into the same as #506 . Repro:

import pandas as pd
from plotnine import *

df = pd.DataFrame({'x': [0, 1, 2, 3], 'y': [4, 5, 6, 7], 'facet': ['a', 'a', 'b', 'b']})
p = ggplot(df, aes(x='x', y='y')) + geom_point() + facet_wrap('~facet')
p

Default facet strip_text:

image

Theming element_text to try and apply ha='right', I get the same result:

p + theme(strip_text=element_text(ha='right'))
image

Using ha='left' yields the same:

p + theme(strip_text=element_text(ha='left'))
image

I also tried explicitly using strip_text_x (and strip_text_y, cause why not try it all) and saw no effect. I also tried facet_grid instead of facet_wrap just to be thorough and saw the same behavior as above.

I'm on OS X, with plotnine==0.13.6. I was on 0.13.0 when I wrote this, upgraded, restarted my jupyter kernel, and reproduced again to verify it's not been fixed, at least in the released version.

jwhendy commented 2 months ago

One more interesting finding: on a whim I tried just theme(text=element_text(ha='right')) and it appears to apply to all text except the strip_text (not sure what it's doing to the y-axis label as that moves left; I'd have expected closer to the y-axis if "right" is in the global frame, or to the top if "right" is with respect to the y-axis orientation).

p + theme(text=element_text(ha='right'))

image
has2k1 commented 2 months ago

Relevant lines: https://github.com/has2k1/plotnine/blob/4159f9548fa5f95c02366efc324e88f9ba79af09/plotnine/_mpl/text.py#L67-L68

jwhendy commented 2 months ago

@has2k1 could I try and help with this? If so, I can look around but wondered if you knew off hand somewhere else ha is applied the I can study for reference?

Thanks!

has2k1 commented 2 months ago

@jwhendy, you can if you make sense of it.

Normally matplotlib handles the horizontal alignment and it aligns along an edge. Here we have to repurpose the alignment to be a justification within the strip_box. And for maximum flexibility we have to accommodate alignment values in the [0, 1] range.

For example, ha and va are applied here to align the title, subtitle, caption, axis_title_x and axis_title_y with respect to the plot panels.

We also have to deal with the margin, but that can come later.

jwhendy commented 2 months ago

@has2k1 I admit my experience with more sophisticated/formal python projects is not good. I had some ideas, but struck out even figuring out how to access the ha argument passed via theme(strip_text_x=element_text(ha='right').

I have little/no experience with the **kwargs dict or inheritance like the super() call. I ended up just adding a print(info.ha) to the code when things weren't working like I thought, and even when specifying ha='right' it still prints out as center. How does ha make it to StripText?

I am definitely willing to keep trying, but don't want to burden you with coaching me. I defer to your time and patience :)

From the title alignment, my baby step was going to be:

has2k1 commented 2 months ago

I had some ideas, but struck out even figuring out how to access the ha argument passed via theme(strip_text_x=element_text(ha='right').

The values of info.ha and info.va are not being picked up and passed through. For now assume you have the right ha values and proceed with the rest. As you test you can hard code info.ha = "left", info.ha = 0.2, e.t.c

jwhendy commented 2 months ago

@has2k1 ah, that makes me feel slightly better :)

Here's an first attempt at my fork. Some comments:

Test code, switching line 66 to test:

import pandas as pd
from plotnine import *

df = pd.DataFrame({'x': [0, 1, 2, 3], 'y': [4, 5, 6, 7],
                   'facet': ['abcdef', 'abcdef', 'ghijkl', 'ghijkl']})
p = ggplot(df, aes(x='x', y='y')) + geom_point() + facet_grid('~facet')
p

With info.ha = "left": image

With info.ha = "right": image

With info.ha = 0.8: image

has2k1 commented 1 month ago

Create a PR and we continue there.

jwhendy commented 1 month ago

@has2k1 I drafted it but then paused. I branched off of main; do you want me to rebase on dev before I PR?

has2k1 commented 1 month ago

Branching off main is the way to go.

jwhendy commented 1 month ago

Thanks for confirming, created!