Skip to content
This repository

NF - Left and right side axes titles #1644

Merged
merged 1 commit into from about 1 year ago

8 participants

Andrew Dawson Damon McDougall Varoquaux Phil Elson Michael Droettboom Eric Firing Benjamin Root Martin Spacek
Andrew Dawson

Add left and right side titles to axes, in addition to the existing title which is in the center.

There are many instances in which one would like to display title on the left and right sides of the top of an axes rather than in the center (e.g., title on the left side and some relevant statistic on the right side). This PR adds two new titles to matplotlib axes to allow this (in addition to the existing title functionality).

A quick example:
lrtitles

lib/matplotlib/pyplot.py
... ...
@@ -1185,7 +1185,43 @@ def title(s, *args, **kwargs):
1185 1185
     draw_if_interactive()
1186 1186
     return l
1187 1187
 
  1188
+def lefttitle(s, *args, **kwargs):
  1189
+    """
  1190
+    Set the left-side title of the current axis.
1
Damon McDougall Collaborator

I think I would prefer current axes rather than current axis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
lib/matplotlib/pyplot.py
((22 lines not shown))
1188 1206
 
  1207
+def righttitle(s, *args, **kwargs):
  1208
+    """
  1209
+    Set the right-side title of the current axis.
1
Damon McDougall Collaborator

I think I would prefer current axes rather than current axis.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Damon McDougall
Collaborator

This is a nice addition to matplotlib's feature set. Furthermore, it is very well documented and succinctly coded. Your effort and time taken to produce this work is greatly appreciated. I am especially impressed with the fact you have gone above and beyond by providing an example and tests, including a test with tight_layout. Excellent work.

Would you be able to address the (few) nitpicks I have with a couple of the docstrings? Also, for this to merge cleanly it needs to be rebased onto the current master branch.

Andrew Dawson

@dmcdougall I would prefer current axes to current axis in the docstrings too, but I chose to be consistent with the matplotlib.pyplot.title docstring. I think they should all use current axes, and am happy to make this change if you agree.

Varoquaux
Collaborator

I'm actually :-1: on such a feature. There are already way too many methods for a normal human being to remember on the axes class (the class itself takes around 7kloc, and the file contains more than 400methods), and adding more doesn't seem to me like a good idea. I think it makes much more sense to add a well documented argument to set_title.

Andrew Dawson

Sure you could move the existing title. The problem I am trying to solve is when more than one title is required. I want to make it easy to produce a plot like:

title_example

[This graphic was produced with the NCAR command language (NCL)]

In my experience this type of labelling requirement is fairly common and supported out of the box so to speak in other packages (e.g., NCAR Command Language, the Climate Data Analysis Tools). My aim here is to make life easy for those users wishing to switch to matplotlib from another plotting package.

Varoquaux
Collaborator

If I understand correctly, what you are trying to do is to position axis label differently than what is done right now in matplotlib, and not position the title differently. So in any case, the name is quite wrong IMO.
Maybe set_xlabel and set_ylabel should be able to do that.

Also, I think trying to mimic other packages is not a good way to go: to quote someone; "I realize that
trying to imitate another package squashes much innovation and does not lead to well-designed or Pythonic solutions.". I think it is a good idea to make life easier for people wanting to switch from another plotting package to matplotlib. I just don't think that adding many methods is the right way to go. Cluttering the API with many methods just makes it harder for everyone (including matplotlib developpers) to know which one to use: it is a common complaint that matplotlib has too many methods. Let's try to improve the one that exists, instead of adding others.

I here express my personal point of view. I've been contributing to matplotlib only for a few of months now, and I am not sure what I said here corresponds to matplotlib's philosophy.

Andrew Dawson

If I understand correctly, what you are trying to do is to position axis label differently than what is done right now in matplotlib, and not position the title differently. So in any case, the name is quite wrong IMO.
Maybe set_xlabel and set_ylabel should be able to do that.

You have misunderstood. These are titles, performing the same function as a centred title, but in a different location!

As a matplotlib user I became fed-up of adding custom text/annotations to serve this purpose and felt that it is something matplotlib should be able to handle. I understand that it is sometimes confusing for new users to see all these methods, that is why I added an example.

I know there are a lot of methods in the axes API, but surely it is not sensible to reject new features that users would like to use because the class is "full"...

Phil Elson
Collaborator

Personally it has my :+1: - my only reservation is whether to go for left_title instead of lefttitle (my preference is probably the former, but I think is also probably the least consistent).

As for @NelleV 's concerns - I fully see what your saying, but for me these functions make more sense than many of the others which exist in pyplot / on an Axes and I genuinely believe that the proposed changes are beneficial in the context provided.

@NelleV - I'm very pleased we are able to share our opinions freely, challenge the status quo and openly disagree with one another - I think it makes for a very healthy atmosphere and long may it continue!

Andrew Dawson

@pelson I wasn't sure about lefttitle vs left_title. My opinion was that although left_title is more readable, lefttitle appears to be more consistent with the rest of the naming in matplotlib. This can of course up for debate should anyone feel differently.

Varoquaux
Collaborator

As @pelson and @dmcdougall both seem to agree on the fact that these features should go in, here are my remarks.

I agree with @pelson on the fact that the attribute lefttitle should be replaced by left_title.

Also, because there is a get_lefttitle method, maybe the attribute should be private: this would help not to clutter the API. I have mixed feeling about this, because the get methods are not pythonic, and the attribute title is public.

Last but not least, I'm currently working on MEP10, which reformats the documentation and I would greatly appreciate if these new methods' documentation could follow this convention (numpy's documentation convention). I can submit a PR on your branch to do this, if you prefer.

examples/pylab_examples/titles_demo.py
... ...
@@ -0,0 +1,15 @@
  1
+#!/usr/bin/env python
  2
+"""
  3
+matplotlib can display plot titles above axes in the center, to the left and
2
Varoquaux Collaborator
NelleV added a note January 16, 2013

I find this part of the documentation confusing. I think the term "axes" should be dropped here, because it can refer both to the matplotlib object, and the mathematical object "axis". (If I am not mistaken, in english, axes is the plural of axis)

Andrew Dawson
ajdawson added a note January 16, 2013

I agree axes can be confusing, as here it is in the axes object sense. Since this is in a docstring of an example which will have the example plot above it, I thought it did not matter so much...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Phil Elson
Collaborator

Also, because there is a get_lefttitle method, maybe the attribute should be private: this would help not to clutter the API. I have mixed feeling about this, because the get methods are not pythonic, and the attribute title is public.

Agreed. The get_ set_ approach is a major bug-bear of mine too, so your not alone on making these stylistic compromises and feeling bad about it :smile: .

I think the term "axes" should be dropped here, because it can refer both to the matplotlib object, and the mathematical object "axis"

Again, agreed. Sadly we have Axes objects which represent a sub area of the figure with its own coordinate system (on which you add lines, contours, images etc.) - in many ways, this is the "plot" area where it is possible to have multiple Axes or plots per figure. Axes objects contain at least two Axis objects, which represent the numbers, tick marks and gridlines of the x and y axes. We are where we are (FWIW I don't like it either), and this terminology is engrained into mpl - I don't think we should avoid using it.

Damon McDougall
Collaborator

This needs rebasing and force-pushing.

Once this is in a state where @NelleV, @ajdawson, and @pelson are mostly in agreement I think it can be merged.

Michael Droettboom
Owner

I'm only skimming these PRs, but as a sanity check: does this have any relationship to #1519?

Andrew Dawson

@mdboom The short answer is no.

Eric Firing
Owner

I'm late in commenting, but I think @NelleV was suggesting the the user interface could be handled by adding a kwarg to the Axes.set_title() and get_title() methods:

gca().set_title("Middle") # default is loc="center"
gca().set_title("Left", loc="left")
gca().set_title("Right"), loc="right")

instead of adding two new methods. This seems to me like a reasonable, and possibly superior, alternative, that would not require huge changes to the PR. Was it considered and rejected?
Or how about adding a single method like this:

gca().set_titles("Left", "Middle", "Right") # sets all three
gca().set_titles("", "Middle", "Right") # erases any left title, sets others
gca().set_titles(None, "Middle") # Sets only center, leaves sides alone

or another modification of set_title() or a variation on set_titles():

gca().set_title("Middle", left="Left", right="Right")
Benjamin Root
Collaborator
Andrew Dawson

I'm going to modify to use Axes.set_title and Axes.get_title only and use a keyword argument loc to control which title is being worked with as @efiring suggested. I can make Axes.lefttitle into Axes._left_title (and equivalent for right) so that they do not clutter the API, but I'll have to leave Axes.title as it is part of the public API already. Any comments on this? If not I will update soon and the discussion can begin again :smile:

Damon McDougall
Collaborator

The only draw-back I see is how to handle setting the text properties independently.

Yes. How do we do this and allow the user to set, say, the left title without having to set the main (middle) title.

Benjamin Root
Collaborator
Andrew Dawson

@WeatherGod I think I have set those artists already so I think it is fine.

However, I have just thought, if we don't use separate methods for each title won't we lose the ability to use setp/getp to handle these properties?

Andrew Dawson

Also, if mpl does move to properties (ongoing discussion on dev mailing list), wont we need a separate getter/setter for each title? I'm now a bit unsure about using only one method to control 3 separate titles...

Eric Firing
Owner
Damon McDougall
Collaborator

How do we move forward? I think the idea of the keyword argument in lieu of [gs]etters as suggested by @NelleV and @efiring is great. However, I'd rather not lose the flexibility of setting the properties of each text instance separately.

Andrew Dawson

How do we move forward? I think the idea of the keyword argument in lieu of [gs]etters as suggested by @NelleV and @efiring is great.

From my perspective as a user I'd prefer to keep these as separate methods, it makes it very clear where to find the functionality I'm after. However, with my software engineering hat on I can see that using a keyword argument loc in set_title might be cleaner, although I am still concerned that it does depart somewhat from the established system of being able to retrieve and set properties using getp/setp...

However, I'd rather not lose the flexibility of setting the properties of each text instance separately.

If we went for keyword argument to set_title there would be no loss of generality regarding being able to set each title's properties separately, so don't worry about that. We just won't be able to do it using setp.

Varoquaux
Collaborator

I think MEP13 needs to be taken in account here: https://github.com/matplotlib/matplotlib/wiki/MEP13

I have been totally swamped with meetings and teaching, so I did not have the time to look at what the MEP implied, so maybe someone else can review.

Andrew Dawson

Yes MEP13 is what I was referring to earlier (before it became MEP13). I think MEP13 implies that each title should be a property, that is have its own getter/setter methods. Of course MEP13 is still preliminary but it would be worth bearing in mind.

Damon McDougall
Collaborator

If we went for keyword argument to set_title there would be no loss of generality regarding being able to set each title's properties separately, so don't worry about that. We just won't be able to do it using setp.

Ahhh! There's still an axes.Axes.left_title, say. I see. Personally, I have never used [gs]etp. Now, I know that's not gospel to remove or not cater for it, but it does influence my opinion nonetheless; I still prefer the kwarg approach.

Andrew Dawson

OK I've decided to go with the kwarg approach. This means that the left and right titles will not be able to be used with getp/setp, but in turn no new methods have been added to the matplotlib API. If in the future MEP13 is applied, then the Axes.set_title method can be broken down into separate properties for each title, which won't be too much work as the underlying instance variables for each title are still present.

@NelleV: I have used the new numpy docstring format to Axes.set_title and pyplot.title, but I'm a little unsure of some things like the current state of cross referencing in the docs. Could you review please.

@dmcdougall: I'll squash these commits if this latter method is accepted, but it probably needs rebasing before merge anyway.

Damon McDougall
Collaborator

I think this new implementation is cleaner.

@pelson @NelleV @efiring @WeatherGod You guys have made comments on this PR. What do you think of this new approach?

doc/users/whats_new.rst
... ...
@@ -49,6 +49,13 @@ using Inkscape for example, while preserving their intended position. For
49 49
 `svg` please note that you'll have to disable the default text-to-path
50 50
 conversion (`mpl.rc('svg', fonttype='none')`).
51 51
 
  52
+Left and right side axes titles
  53
+-------------------------------
  54
+Andrew Dawson added the ability to add axes titles flush with the left and
  55
+right sides of the top of the axes using :func:`~matplotlib.pyplot.lefttitle`
1
Eric Firing Owner
efiring added a note January 19, 2013

This whats_new entry will need updating for the new implementation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Eric Firing
Owner

I think there is no perfect solution, and we could discuss it endlessly; but this one looks good enough to go with it. It represents the addition of a very useful feature in a way that is non-disruptive and, as far as I can see, that doesn't interfere with any future direction in which we might decide the API should involve. (I haven't actually tested the code myself.)

Phil Elson
Collaborator

:+1:

lib/matplotlib/tests/test_text.py
... ...
@@ -146,4 +146,14 @@ def test_contains():
146 146
         vl = ax.viewLim.frozen()
147 147
         ax.plot(x, y, 'o', color=color)
148 148
         ax.viewLim.set(vl)
149  
-    
  149
+
  150
+
  151
+@image_comparison(baseline_images=['titles'])
  152
+def test_titles():
  153
+    # left and right side titles
  154
+    fig = plt.figure()
  155
+    ax = plt.subplot( 1, 1, 1 )
2
Varoquaux Collaborator
NelleV added a note January 21, 2013

PEP8 nitpick: you've got extra spaces after and before (, )

Andrew Dawson
ajdawson added a note January 21, 2013

Fixed. Also fixed in the test I copy-and-pasted this line from.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Varoquaux
Collaborator

LGTM

Damon McDougall
Collaborator

This needs another rebase.

Andrew Dawson NF - Left and right side axes titles
Add left and right side titles to a set of axes, in addition to the
existing title which is in the center.
917f3ae
Andrew Dawson

@dmcdougall this is rebased onto the current master and squashed into a single commit.

Damon McDougall dmcdougall merged commit 2f86924 into from January 25, 2013
Damon McDougall dmcdougall closed this January 25, 2013
Damon McDougall
Collaborator

Cheers @ajdawson.

Martin Spacek

I've discovered that this PR is responsible for the complete breakage of the qt4_editor reported in #1714. Specifically, Axes.get_title now returns a matplotlib.text.Text instance instead of a simple Python string as before. Was this intentional, to conform with MEP13 or something? Other than the call in figureoptions.py, were all calls to Axes.get_title changed accordingly? This will break a lot of user code that taps into the MPL API, won't it? Shouldn't this change have been documented in api_changes.rst?

Andrew Dawson

This was not intentional and should be fixed.

Andrew Dawson ajdawson deleted the branch July 18, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Showing 1 unique commit by 1 author.

Jan 22, 2013
Andrew Dawson NF - Left and right side axes titles
Add left and right side titles to a set of axes, in addition to the
existing title which is in the center.
917f3ae
Something went wrong with that request. Please try again.