proplot-dev / proplot

🎨 A succinct matplotlib wrapper for making beautiful, publication-quality graphics
https://proplot.readthedocs.io
MIT License
1.11k stars 102 forks source link

Prevent shared-label algorithm from ignoring/overwriting distinct axis labels #384

Open pulkin opened 2 years ago

pulkin commented 2 years ago

Description

Cannot create a subplot label.

Steps to reproduce

import proplot as p
fig, ax = p.subplots(
        array=[
            (1, 1, 1),
            (1, 1, 1),
            (1, 1, 1),
            (2, 2, 2),
            (3, 3, 3),
            (4, 4, 4),
            (5, 6, 7),
            (8, 9, 10),
        ],
        refwidth=2.5, refheight=1.25, refnum=1,
        abc="(a)", abcloc='ul', sharex=True, sharey=True, titleloc='uc',
        hspace=[None, None, None, 0, 0, None, None],
        wspace=None)
ax[1:4].format(xlabel="ok xlabel", ylabel="ok ylabel")
ax[4:].format(xlabel="ok xlabel", ylabel="not ok ylabel")
fig.savefig("test_proplot.png")

Expected behavior: not ok ylabel should be visible

Actual behavior: not ok ylabel is absent

Proplot version

0.9.5.post332 3.5.2

syrte commented 2 years ago

Try set p.subplots(..., sharey=False, ...)?

pulkin commented 2 years ago

Try set p.subplots(..., sharey=False, ...)?

Labels re-appear in multitudes (i.e. expected behavior).

pulkin commented 2 years ago

The problem is this code: https://github.com/proplot-dev/proplot/blob/29bc955ec79c2a384c8e5a20f81173874e099c22/proplot/figure.py#L1185-L1206 ax._get_span_axes(pos, panels=False) returns every axes adjacent to the left edge: 1, 2, 3, 4, 5, 8 to share the same y axis label. I patched it like this:

...
            axs = ax._get_span_axes(pos, panels=False)  # returns panel or main axes
            if any(getattr(ax, '_share' + x) for ax in axs):
                continue  # nothing to align or axes have parents
            _ref_label_text = getattr(ax, x + 'axis').label.get_text()  # PATCH
            axs = list(_ax for _ax in axs if getattr(_ax, x + 'axis').label.get_text() == _ref_label_text)  # PATCH
            seen.update(axs)
...

And the desired effect is kinda achieved.

pulkin commented 2 years ago

There might be another issue on top of this: super-label coordinates are computed incorrectly in ._get_align_coord. The computation is based on some intermediate alignment of axes which is changed afterwards. If I do this

for i in ax:
    pos = i.get_subplotspec().get_position(fig)
    print(f"{i=} {pos=}")

before and after figure is printed I get different results.

lukelbd commented 1 year ago

Thanks for the report and PR #385 -- will take a closer look when I can. Agree this makes sense -- the shared label algorithm should only consider subplots with identical labels. The sharing algorithm is pretty klunky right now.