Skip to content

Simplify annotation examples. #13515

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

Closed
wants to merge 1 commit into from

Conversation

anntzer
Copy link
Contributor

@anntzer anntzer commented Feb 25, 2019

When xycoords and textcoords use the default of "data" (which is the
same as for text(), for example), don't bother specifying it.

In some other cases, I find it clearer to specify xycoords in
terms of the more general ax.transAxes (i.e. "axes fraction")
or IdentityTransform() (i.e. "figure pixels"), or even
ax.get_yaxis_transform() (i.e. ("axes fraction", "data")) --
transforms are a general, widely used concept, whereas transform strings
only apply to annotate().

PR Summary

PR Checklist

  • Has Pytest style unit tests
  • Code is Flake 8 compliant
  • New features are documented, with examples if plot related
  • Documentation is sphinx and numpydoc compliant
  • Added an entry to doc/users/next_whats_new/ if major new feature (follow instructions in README.rst there)
  • Documented in doc/api/api_changes.rst if API changed in a backward-incompatible way

@@ -92,12 +91,11 @@ def doall():
color=fill_color, alpha=0.5)
plt.annotate(title,
xy=(0.07, baseline - 0.3 * line_axesfrac),
xycoords='data', color=mpl_grey_rvb, weight='bold')
Copy link
Member

Choose a reason for hiding this comment

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

I don't think its helpful to drop all the xycoord='data' calls. Its good for users to understand that there are different co-oridnates that annotate can be expressed in...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But the point is that "data" is the default for annotate() just like it is the default for nearly every other function (e.g. in particular text()).
I purposefully left the xycoords=... in the main annotation demo and tutorials (where the coordinates systems are explained), but outside of them I think these are just noise.
(And again I'd rather have people learn to use ax.transData/ax.transAxes which also works for text(), instead of an annotate()-specific API.)

@jklymak jklymak added this to the v3.2.0 milestone Feb 25, 2019
@ImportanceOfBeingErnest
Copy link
Member

I would agree to roughly half of the changes made here. Certainly

from matplotlib.transforms import blended_transform_factory
reference_transform = blended_transform_factory(ax.transAxes, ax.transData)
ax.annotate(...,  xycoords=reference_transform)

is better written as

ax.annotate(..., xycoords=ax.get_yaxis_transform())

However,

ax.annotate(..., xycoords='figure pixels')

is much better than

from matplotlib.transforms import IdentityTransform
ax.annotate(..., xycoords=IdentityTransform())

In general xycoords="axes fraction" is understandable on a much lower level than xycoords=ax.transAxes. It's not for nothing that the transformation tutorial is categorized as "Advanced", while annotations are one of the most basic things you want to be doing with plots.

Removing the "data" value is ok in all examples which do not explicitely focus on annotations. E.g.

  • examples/showcase/anatomy.py
  • examples/style_sheets/style_sheets_reference.py
  • examples/text_labels_and_annotations/mathtext_examples.py
  • examples/text_labels_and_annotations/usetex_demo.py

However, in cases which show the functionality of annotations, it adds clear value and points the user to the option to use some other coordinates systems as well. I would hence oppose the changes in

  • examples/text_labels_and_annotations/demo_annotation_box.py
  • examples/units/annotate_with_units.py
  • examples/userdemo/annotate_explain.py

Furthermore at least some of the examples

  • examples/userdemo/annotate_simple{*}.py
  • examples/userdemo/annotate_simple_coord{*}.py
  • examples/userdemo/connectionstyle_demo.py
  • examples/userdemo/simple_annotate{*}.py

should keep it. Those are originally part of the annotations guide. It would totally make sense to rework that guide and bring some variety concerning the allowed arguments into it.

@anntzer
Copy link
Contributor Author

anntzer commented Feb 26, 2019

At the risk of sounding like a broken record...

In general xycoords="axes fraction" is understandable on a much lower level than xycoords=ax.transAxes.

In my view, this means that we should rename ax.transAxes to something more transparent, e.g. ax.axes_rel_transform. If the name is good, it should not matter for understandability whether it has quotes around or "ax.<>" (and the latter form is tab-completable!). If someone learns how to use "axes fraction" with annotate(), they've learned, well, how to place an annotation in axes fraction coordinates and nothing else, not even how to do that with text(). If someone learns how to use ax.transAxes (name up to bikeshedding) in annotate(), they're pretty close to also knowing how to do

  • text(.1, .1, "foo", transform=ax.transAxes) (text in relative coordinates)
  • plot([.1, .2], [.1, .1], transform=ax.transAxes) (e.g. for a scale bar)
  • imshow([[0, 1], [2, 3]], extent=(0, .5, 0, .5), transform=ax.transAxes)
  • etc.

@jklymak
Copy link
Member

jklymak commented Feb 28, 2019

The problem is that somehow _AnnotationBase and all its children got a different API convention that also allows strings. So we have an API mixture and in my opinion we should either in the long term:

  1. propagate the string API to other methods
  2. deprecate the string API in all methods. Perhaps adding some better-named helpers (i.e. ax.axes_coords, ax.points_coords) to give the user easy access to the transforms.
  3. status-quo with Annotation and (many) friends having a different API from other artists.

For now, I'm not convinced that just ripping all the string-based examples out of the documentation base is the right thing to do until we decide what to do about the API. If both APIs are staying as-is, then I'm not sure this PR is the way to go....

Copy link
Member

@jklymak jklymak left a comment

Choose a reason for hiding this comment

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

Blocking on strategy discussion, not because I think this is a bad idea.

@ImportanceOfBeingErnest
Copy link
Member

Maybe one can separate between the changes that are a clear improvement of the docs and changes that are controversial? I.e. either remove the offending stuff out of this PR, or open a new PR with the helpful and harmless stuff?

@anntzer
Copy link
Contributor Author

anntzer commented Feb 28, 2019

The "noncontroversial" parts are in #13549.
I would definitely support option 2 in #13515 (comment) (where the string locations don't even necessarily need to be really deprecated, just "soft deprecated" by making them less prominent in the docs). Obviously I'm not your average matplotlib user, but at least personally I had always found annotate() positioning extremely confusing (where do all these strings come from??) until I realized that they were just another way to spell ax.transAxes, etc.
Between strings and ax.transAxes (again, name up to bikeshedding), the latter has two advantages: 1) they are tab-completable, and 2) we need to expose these transforms anyways (well, unless we decide to make them private, but why would we?) so that API is already there.

@anntzer anntzer mentioned this pull request Mar 20, 2019
6 tasks
When xycoords and textcoords use the default of "data" (which is the
same as for text(), for example), don't bother specifying it.

In some other cases, I find it clearer to specify xycoords in
terms of the more general `ax.transAxes` (i.e. "axes fraction")
or `IdentityTransform()` (i.e. "figure pixels"), or even
`ax.get_yaxis_transform()` (i.e. `("axes fraction", "data")`) --
transforms are a general, widely used concept, whereas transform strings
only apply to annotate().
@anntzer anntzer force-pushed the annotation-examples branch from bd298e9 to 2bf2894 Compare July 16, 2019 22:55
@anntzer anntzer mentioned this pull request Jul 16, 2019
6 tasks
@tacaswell tacaswell modified the milestones: v3.2.0, v3.3.0 Sep 5, 2019
@QuLogic QuLogic added the status: needs comment/discussion needs consensus on next step label Apr 1, 2020
@jklymak jklymak dismissed their stale review April 4, 2020 21:42

stale!

@QuLogic QuLogic modified the milestones: v3.3.0, v3.4.0 May 1, 2020
@jklymak jklymak marked this pull request as draft August 24, 2020 14:23
@QuLogic QuLogic modified the milestones: v3.4.0, v3.5.0 Jan 21, 2021
@QuLogic QuLogic modified the milestones: v3.5.0, v3.6.0 Aug 23, 2021
@timhoffm timhoffm modified the milestones: v3.6.0, unassigned Apr 30, 2022
@story645 story645 removed this from the unassigned milestone Oct 6, 2022
@story645 story645 added this to the needs sorting milestone Oct 6, 2022
@github-actions
Copy link

github-actions bot commented Jun 1, 2023

Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you need a review or guidance to move the PR forward! If you do not plan on continuing the work, please let us know so that we can either find someone to take the PR over, or close it.

@github-actions github-actions bot added the status: inactive Marked by the “Stale” Github Action label Jun 1, 2023
@anntzer
Copy link
Contributor Author

anntzer commented Jun 4, 2023

I've changed my mind, the string args can be quite nice to work with in practice. Some other parts of the PR have now been merged separately anyways.

@anntzer anntzer closed this Jun 4, 2023
@anntzer anntzer deleted the annotation-examples branch June 4, 2023 15:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation status: inactive Marked by the “Stale” Github Action status: needs comment/discussion needs consensus on next step status: needs rebase
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants