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

Horizontal alignment of facet title not working #867

Open
jwhendy opened this issue Sep 1, 2024 · 11 comments
Open

Horizontal alignment of facet title not working #867

jwhendy opened this issue Sep 1, 2024 · 11 comments
Labels

Comments

@jwhendy
Copy link

jwhendy commented Sep 1, 2024

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
Copy link
Author

jwhendy commented Sep 1, 2024

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 has2k1 added the bug label Sep 3, 2024
@has2k1
Copy link
Owner

has2k1 commented Sep 3, 2024

Relevant lines:

self._x = l + w / 2
self._y = b + h / 2

@jwhendy
Copy link
Author

jwhendy commented Sep 3, 2024

@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
Copy link
Owner

has2k1 commented Sep 4, 2024

@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
Copy link
Author

jwhendy commented Sep 5, 2024

@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:

  • add the lookup so that left/center/right = 0/0.5/1
  • self._x = l + w * f
  • I believe self.set_horizontalalignment(anchor) where anchor=ha should work
  • had not gotten to thinking about float ha values yet

@has2k1
Copy link
Owner

has2k1 commented Sep 5, 2024

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
Copy link
Author

jwhendy commented Sep 5, 2024

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

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

  • the general approach seems to work from my limited testing
  • for float values of ha, I made the call that if < 0.5, we should anchor left, otherwise anchor right. Not sure if that's reasonable or how it should work
  • the alignment was dead left/right, which I felt didn't look great. For now I've added a margin variable (maybe pad or padding would be a more accurate name) of 0.05 to keep the text off the edge by w * 0.05. I could see setting this to 0 if ha is a float so the user is given absolute positioning control.
  • I could also see splitting this idea into a positional argument and an explicit anchor point... this would handle use cases where you want e.g. ha=0.8 to put the text far right but left justified.

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
Copy link
Owner

has2k1 commented Sep 9, 2024

Create a PR and we continue there.

@jwhendy
Copy link
Author

jwhendy commented Sep 9, 2024

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

@has2k1
Copy link
Owner

has2k1 commented Sep 10, 2024

Branching off main is the way to go.

@jwhendy
Copy link
Author

jwhendy commented Sep 10, 2024

Thanks for confirming, created!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants