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

Make legend handling more intuitive and consistent with matplotlib #30

Merged
merged 12 commits into from
Jul 15, 2019

Conversation

lukashergt
Copy link
Collaborator

@lukashergt lukashergt commented Jul 14, 2019

Description

Legend handling is now more intuitive, i.e. can be done in the usual matplotlib fashion.

  • Make the link axes[x][x] = axes[x][x].twin such that the user has direct access to the diagonal axes that have actually been drawn in.

    • axes[x][x].legend() now automatically makes a legend in the diagonal axes.
  • Create the legend proxy already in contour_plot_2d and pass it to ax.patches.

    • axes[x][y].legend() now automatically makes a legend in the 2D 'kde' axes.
    • No need for get_legend_proxy anymore, because matplotlib's own functions can handle this, now:
    handles, labels = axes[x][y].get_legend_handles_labels()
    leg = fig.legend(handles, labels)
    • Flagged get_legend_proxy as deprecated.

Checklist:

  • I have performed a self-review of my own code
  • My code is PEP8 compliant (flake8 anesthetic tests)
  • My code contains compliant docstrings (pydocstyle --convention=numpy anesthetic)
  • New and existing unit tests pass locally with my changes (python -m pytest)
  • I have added tests that prove my fix is effective or that my feature works

Lukas Hergt added 4 commits July 14, 2019 22:04
* At the moment axes[x][x] are empty and axes[x][x].twin are the ones
  that have actually been drawn in. This is rather opaque for the user
  so I think it would make sense to link the diagonal axes to their
  twin: `axes[x][x] = axes[x][x].twin`
  - Now the user can call `axes[x][x].legend()` and gets matplotlib's
    automated legend behaviour for the diagonal plots.
  - Is the original axes needed for something? Then it might be worth
    saving it as `axes[x][x].orig = axes[x][x]` first...

Changes to be committed:
* modified:   anesthetic/plot.py
* modified:   anesthetic/samples.py
* Contour plots are too complex in the scope of matplotlib for the
  purposes of legend handling. Here the contour plots typically only
  draw 2 levels making a simple Rectangle patch a suitable legend
  handle.

* Added legend proxies for contour plots directly to their axes such
  that axes legends can now be drawn simply by calling:
  ```
  axes[x][y].legend()`
  ```

* This also simplifies figure legends because now you can simply do:
  ```
  handles, labels = axes[x][y].get_legend_handles_labels()
  fig.legend(handles, labels)
  ```
  - `get_legend_handles_labels` is matplotlib's standard way of handling
    this sort of thing.
  - This makes the helper function `get_legend_proxy` redundant.

Changes to be committed:
* modified:   anesthetic/plot.py
@lukashergt lukashergt added the enhancement New feature or request label Jul 14, 2019
@lukashergt lukashergt added this to the 1.1 milestone Jul 14, 2019
@lukashergt lukashergt self-assigned this Jul 14, 2019
@lukashergt lukashergt mentioned this pull request Jul 14, 2019
5 tasks
Copy link
Collaborator

@williamjameshandley williamjameshandley left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you also add a test that creates a legend using the new functionality?

@codecov
Copy link

codecov bot commented Jul 15, 2019

Codecov Report

❗ No coverage uploaded for pull request base (master@eefab0a). Click here to learn what that means.
The diff coverage is 80%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master      #30   +/-   ##
=========================================
  Coverage          ?   90.22%           
=========================================
  Files             ?       14           
  Lines             ?      992           
  Branches          ?        0           
=========================================
  Hits              ?      895           
  Misses            ?       97           
  Partials          ?        0
Impacted Files Coverage Δ
anesthetic/samples.py 90.39% <100%> (ø)
anesthetic/plot.py 90.09% <60%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eefab0a...7e1c137. Read the comment docs.

@codecov
Copy link

codecov bot commented Jul 15, 2019

Codecov Report

Merging #30 into master will decrease coverage by 0.11%.
The diff coverage is 83.33%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #30      +/-   ##
==========================================
- Coverage   89.95%   89.84%   -0.12%     
==========================================
  Files          14       14              
  Lines         986      995       +9     
==========================================
+ Hits          887      894       +7     
- Misses         99      101       +2
Impacted Files Coverage Δ
anesthetic/plot.py 89.32% <83.33%> (-0.53%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eefab0a...8909e4f. Read the comment docs.

Lukas Hergt added 2 commits July 15, 2019 11:05
The original axes are where ticks and labels are handled so should not
be discarded in favour of the twin axes. Instead just pass the lines and
patches from the twin on to the original axes for 2D plots.
@lukashergt
Copy link
Collaborator Author

Could you also add a test that creates a legend using the new functionality?

Added a test that checks the handles and labels. Is that what you had in mind?

Lukas Hergt added 2 commits July 15, 2019 12:13
* Remove zorder changes for contour plots.
  - Any legend placed in axes with contour plots got hidden behind the
    contours.
  - Not sure what the original reason for the zorder changes was.

* Set axes in front of axes.twin.
  - Since legends are drawn on axes, they got hidden behind the lines
    and histograms which belonged to the twin axes and thus were in
    front.

Changes to be committed:
* modified:   anesthetic/plot.py
@williamjameshandley
Copy link
Collaborator

Added a test that checks the handles and labels. Is that what you had in mind?

That looks great.

@williamjameshandley
Copy link
Collaborator

One further comment -- If I try calling fig.legend, it produces a large legend for every axis. Is this the expected/desired behaviour?

@lukashergt
Copy link
Collaborator Author

One further comment -- If I try calling fig.legend, it produces a large legend for every axis. Is this the expected/desired behaviour?

Yes, that is the matplotlib behaviour. This happens when you call the figure legend instead of the axis legend. The figure contains all the axes and thus shows all the handles and labels from all the axes.

@williamjameshandley
Copy link
Collaborator

Yes, that is the matplotlib behaviour. This happens when you call the figure legend instead of the axis legend. The figure contains all the axes and thus shows all the handles and labels from all the axes.

So how should we advise users to implement a 'figure legend' in the natural way, namely producing a summary that is not a repeat for each sub-plot?

@lukashergt
Copy link
Collaborator Author

So how should we advise users to implement a 'figure legend' in the natural way, namely producing a summary that is not a repeat for each sub-plot?

See description at the top. I also put this in the deprecation warning for get_legend_proxy.

@williamjameshandley
Copy link
Collaborator

williamjameshandley commented Jul 15, 2019

I'm trying to update the demo.py and demo.ipynb with your changes

prior = nested.set_beta(0)
fig, axes = prior.plot_2d(['ns','tau'])                                                          
nested.plot_2d(axes=axes)
handles, labels = axes['ns']['tau'].get_legend_handles_labels()
leg = fig.legend(handles, labels)

example

But no legend is produced (only an empty top-right box). The handles and labels lists are empty. Do you also get this behaviour?

@lukashergt
Copy link
Collaborator Author

I'm trying to update the demo.py and demo.ipynb with your changes

But no legend is produced (only an empty top-right box). The handles and labels lists are empty. Do you also get this behaviour?

Are you sure they are using this branch?

@lukashergt
Copy link
Collaborator Author

Never mind, you are not passing any labels. Do this:

prior = nested.set_beta(0)
fig, axes = prior.plot_2d(['x0','x1'], label='prior')                                                          
nested.plot_2d(axes=axes, label='posterior')
handles, labels = axes['x0']['x1'].get_legend_handles_labels()
leg = fig.legend(handles, labels)

@williamjameshandley
Copy link
Collaborator

Cool. That seems to have worked. I'll update the plot gallery once version 1.1 is out.

@lukashergt
Copy link
Collaborator Author

You don't care about PEP8 in the demos? (flake8 demo.py)

@williamjameshandley williamjameshandley merged commit 1b4b3e5 into handley-lab:master Jul 15, 2019
@williamjameshandley
Copy link
Collaborator

No, demo.py is for generating the ipython notebook using py2nb. flake8ing it is overkill.

@williamjameshandley
Copy link
Collaborator

(by all means propose a PR that fixes it)

@lukashergt lukashergt deleted the contourf_legend branch July 15, 2019 16:07
This was referenced Jul 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants