-
-
Notifications
You must be signed in to change notification settings - Fork 7.9k
Create InsetIndicator
artist
#27996
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
Create InsetIndicator
artist
#27996
Conversation
Added a |
IndicateInset
patchInsetIndicator
patch
fce57eb
to
3d725ea
Compare
Perhaps instead of inheriting from |
That sounds like a fairly common use case to me so I think that'd be awesome. Is there an advantage to the rectangle approach/downside to making it a container? |
Not that I can think of. I think I just had in mind from #23424 (comment) that the new object should be a |
Technically artist w/ face color + edgecolor & for the most part I've always thought of it as roughly the MPL abstraction of an area mark b/c that's basically the space of visual encodings we allow/can apply to most of our patch artists: Where size and shape are controlled by the drawing of the shape, while for example the choice of marker determines shape and marker size controls the size. So for what it's worth, I agree w/ your intuition that a container Artist is probably a better abstraction for what's actually going on here. |
3d725ea
to
745c737
Compare
InsetIndicator
patchInsetIndicator
artist
745c737
to
b8d7469
Compare
OK, the One side-effect of this is that we no longer get the axes limits updated around the artist, which is done in matplotlib/lib/matplotlib/axes/_base.py Line 2414 in 1e98377
I guess it would be pretty easy to re-instate that but I'm not sure if it matters. Most of the time there will be a bunch of other artists that this one is indicating. Still to do:
|
b8d7469
to
cbe1aa1
Compare
Added changenotes and directives, though I'm not sure if the behaviour change documentation for |
cbe1aa1
to
9deb35b
Compare
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
This comment was marked as resolved.
I hid the alpha discussion because that was addressed by #28710 and is not needed for the reviewers of this PR. |
It is also used by When you said "container" I was worried you were following what we do with e.g. error bar where we return a |
why did the lower left and upper right segments disappear? |
yeah, that is all a bit tricky. The rectangle would ideally clip to the parent axes; probably easy. The connectors would ideally clip the parent axes as well, but only on the side that links to the rectangle. I'm not aware that we have a way to do that and I'm not sure it's worth the hassle to make it. Either you are doing this for data exploration, in which case a little mess is OK, or you are doing it for a final plot, in which case you can clean up the positions then. |
You mean the connectors? Only 2 of those are visible by default. |
Thanks! Sorry for not checking the docs 🤦♀️ |
9deb35b
to
9134a5c
Compare
for conn in self.connectors or []: | ||
if conn.get_visible(): | ||
drawn = False | ||
for s in _shared_properties: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't it also the case that if the non-shared properties differ, then you can't merge the paths? For example, zorder
isn't listed as shared, but might make a difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I wasn't super-happy about doing this with a hard-coded list, but so far haven't thought of a better way. Very happy to take suggestions/pointers.
... oh I just realised I could use ArtistInspector.get_setters
to make a complete list - maybe that's part of the solution, though we'd have to actively skip comparing some properties like transform 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also just realised that I currently have the zorder going to Rectangle
in the __init__
when it should be getting applied to InsetIndicator
. So I need a better way to keep the properties straight at that end too.
6e106e9
to
143a228
Compare
inset_indicator.rectangle : `.Rectangle` | ||
The indicator frame. | ||
|
||
inset_indicator.connectors : 4-tuple of `.patches.ConnectionPatch` | ||
The four connector lines connecting to (lower_left, upper_left, | ||
lower_right upper_right) corners of *inset_ax*. Two lines are | ||
set with visibility to *False*, but the user can set the | ||
visibility to True if the automatic choice is not deemed correct. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
would it make sense to make this an interpolated doc, even if it's only used in like two places? That way it can be defined in the module? Only thinking about this b/c of how it's being done for colorizer:
matplotlib/lib/matplotlib/colorizer.py
Lines 29 to 34 in cf9a943
mpl._docstring.interpd.update( | |
colorizer_doc="""\ | |
colorizer : `~matplotlib.colorizer.Colorizer` or None, default: None | |
The Colorizer object used to map color to data. If None, a Colorizer | |
object is created base on *norm* and *cmap*.""", | |
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly can do something even more direct but I do not follow this example at all https://matplotlib.org/devdocs/devel/document.html#keyword-arguments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any general guidance about when it makes sense to do this rather than copy/paste? As you say it's only in two places and I am keenly aware that I have a lot more copy/paste going on in the artist's set_*
docstrings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lib/matplotlib/tests/test_inset.py
Outdated
if conn.get_visible(): | ||
# Make one visible connector a different style | ||
conn.set_linestyle('dashed') | ||
conn.set_color('blue') | ||
break |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shouldn't you know which connector this is b/c this is deterministic? basically why loop?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was just too lazy to figure out which index it would be...
e5ad7fc
to
d2cd137
Compare
Is this no longer PoC (as in title)? |
InsetIndicator
artistInsetIndicator
artist
d2cd137
to
adb8a95
Compare
adb8a95
to
4d944bb
Compare
4d944bb
to
b833055
Compare
I just noticed I forgot to update the deprecation warning when the patch became an artist. Now fixed. |
PR summary
#19768 (comment) suggested that we should have some kind of container for the output of
indicate_inset[_zoom]
. #23424 (comment) suggested that it should be drawn as a single path to avoid double-alpha where the box and connectors overlap. This PR is my attempt to implement that.The new artist has convenience methods to update colour/linestyle/etc for the whole thing, but the user can also get hold of individual patches and update styles on those. The current doctrings of
indicate_inset[_zoom]
specifically mention updating the visibility of the connectors, but a user might also reasonably want a different colour or linestyle for the connectors than for the box.The logic from
indicate_inset_zoom
that decided where the box should be is now methodInsetIndicator._bounds_from_inset_ax
so we can reuse it. Whenever theconnectors
attribute is accessed (including at draw) the box bounds and position of connectors (if any) get updated using the current inset axes x- and y-limits. This therefore closes #19768 and we can do things likeStyles for the connectors are now inherited from the parent artist when the connectors are created. This therefore closes #23424. Within the
draw
method, we check which connectors have the same style properties as the rectangle (currently four specific properties - maybe there is a better way). Those that do are drawn with the rectangle as a compound path.This also inadvertently fixes #23425 since I haven't implemented
get_window_extent
orget_tight_bbox
, so constrained layout will get a null tight bbox. I would like advice on whether I should implement one or both of these and what it should include. For the purposes of layout engines is does not seem useful to include the connectors, but maybe there are other uses for these methods?PR checklist