Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Fix errorbar property cycling to match plot. #17930

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

Merged
merged 5 commits into from
Aug 19, 2020

Conversation

QuLogic
Copy link
Member

@QuLogic QuLogic commented Jul 15, 2020

PR Summary

It would not cycle if a color were specified. However, this does not match plot, which does not advance the cycle only if all properties in the cycle are specified. Notably, this means if your property cycle was for line style, specifying a color would ignore the cycle in errorbar, but not in plot.

Fixes #7074.

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/next_api_changes/* if API changed in a backward-incompatible way

@QuLogic QuLogic added this to the v3.4.0 milestone Jul 15, 2020
base_style = next(self._get_lines.prop_cycler)

base_style = self._get_lines._getdefaults(
set(), {**fmt_style_kwargs, **kwargs})
Copy link
Member

Choose a reason for hiding this comment

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

Is this where the property cycler gets implicitly advanced?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I don't really like the private API of a private member, but that's how it is right now.

@jklymak
Copy link
Member

jklymak commented Jul 15, 2020

Is it the case that errorbar was wrong or that the behaviour for plot changed, but it didn't get changed in errorbar? I suspect the latter, in which case this may still get out of sync. Does it make sense to have some sort of helper for this or add the functionality into _get_lines._getdefaults so this doesn't get out of sync in the future?

@QuLogic
Copy link
Member Author

QuLogic commented Jul 17, 2020

I think _get_lines._getdefaults is that helper.

My preferred method would be to use something higher, like _get_lines() directly or _get_lines._makeline(), but we need the property dict to copy to the error bars. I don't think we have an easy way to copy from the Line2D to the error bar line. Though maybe since this is private, I can just make it return both the line and its properties?

@jklymak
Copy link
Member

jklymak commented Jul 17, 2020

I'm not blocking on that comment - just seems if we want the two to have the same behaviour they should have the same method of getting the behaviour...

@QuLogic
Copy link
Member Author

QuLogic commented Jul 18, 2020

Well, it is, sort of. self._get_lines is the object that implements the behaviour. The plot call tree is plot -> self._get_lines() -> self._get_lines._plot_args -> self._get_lines._makeline -> (self._get_lines._getdefaults for kwargs and creates Line2D). Previously, errorbar used the self._get_lines.prop_cycle and only looked for colour; in this PR it uses _getdefaults like plot ultimately does.

I experimented a little bit with calling one of those higher methods and then .update_from(data_line) + overriding any properties after, but this is complicated by the kwarg inheritance in errorbar. It's currently:

  • _getdefaults + fmt_style_kwargs -> base_style
    • + kwargs = plot_line_style -> the main line
    • + e* kwargs - markers/lines = eb_lines_style -> error bars
    • + cap settings - markers/lines = eb_cap_style -> error caps

However, the main line is Line2D while the error bars are LineCollection, so they have different properties and bars.update_from(data_line) doesn't work.

I think at best, we could have _makeline return both the line and its kwargs, which could then be used as base_style, or maybe do that on _plot_args.

@QuLogic
Copy link
Member Author

QuLogic commented Jul 18, 2020

The closest I could do is call self._get_lines._plot_args, as calling self.plot or self._get_lines directly would call _process_unit_info again:

self.axes._process_unit_info(kwargs=kwargs)

or process data
if data is None: # Process dict views
args = [cbook.sanitize_sequence(a) for a in args]
else: # Process the 'data' kwarg.
replaced = [mpl._replacer(data, arg) for arg in args]
if len(args) == 1:
label_namer_idx = 0
elif len(args) == 2: # Can be x, y or y, c.
# Figure out what the second argument is.
# 1) If the second argument cannot be a format shorthand, the
# second argument is the label_namer.
# 2) Otherwise (it could have been a format shorthand),
# a) if we did perform a substitution, emit a warning, and
# use it as label_namer.
# b) otherwise, it is indeed a format shorthand; use the
# first argument as label_namer.
try:
_process_plot_format(args[1])
except ValueError: # case 1)
label_namer_idx = 1
else:
if replaced[1] is not args[1]: # case 2a)
cbook._warn_external(
f"Second argument {args[1]!r} is ambiguous: could "
f"be a format string but is in 'data'; using as "
f"data. If it was intended as data, set the "
f"format string to an empty string to suppress "
f"this warning. If it was intended as a format "
f"string, explicitly pass the x-values as well. "
f"Alternatively, rename the entry in 'data'.",
RuntimeWarning)
label_namer_idx = 1
else: # case 2b)
label_namer_idx = 0
elif len(args) == 3:
label_namer_idx = 1
else:
raise ValueError(
"Using arbitrary long args with data is not supported due "
"to ambiguity of arguments; use multiple plotting calls "
"instead")
if kwargs.get("label") is None:
kwargs["label"] = mpl._label_from_arg(
replaced[label_namer_idx], args[label_namer_idx])
args = replaced

which are not done in errorbar.

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.

This looks good to me - just a small comment...

@QuLogic QuLogic marked this pull request as draft August 14, 2020 20:28
@QuLogic
Copy link
Member Author

QuLogic commented Aug 14, 2020

With #8031 in, I'd like to apply this to the 3D version as well before merging.

@timhoffm
Copy link
Member

This seems rather complete (modulo some restructuring of the clipping). IMHO it would be easier for reviewing to merge this now and do the 3D stuff in a separate PR.

@QuLogic QuLogic force-pushed the errorbar-cycler branch 2 times, most recently from a7c085d to 32c3ece Compare August 19, 2020 00:06
@QuLogic QuLogic marked this pull request as ready for review August 19, 2020 00:08
@QuLogic
Copy link
Member Author

QuLogic commented Aug 19, 2020

Sure, I ran into other issues just doing that directly, so I'll mark this Ready for Review now, and do 3D in a followup PR. Not sure what you mean about clipping though?

@timhoffm
Copy link
Member

Sorry, I meant popping, not clipping.

It would not cycle if a color were specified. However, this does not
match `plot`, which does not advance the cycle only if _all_ properties
in the cycle are specified. Notably, this means if your property cycle
was for line style, specifying a color would ignore the cycle in
`errorbar`, but not in `plot`.

Fixes matplotlib#7074.
Move iterable checks before working on styling.

In the styling section, the lines and caps dictionary modifications are
intermixed, making them a bit confusing. Also do the same marker style
removal from the cap style, which would normally be replaced later.
We can't directly use `self.plot` or `self._get_lines` because they
would do `self._process_unit_info` and/or *data* keyword argument
processing.
@QuLogic
Copy link
Member Author

QuLogic commented Aug 19, 2020

Ah, okay, the last commit should clear that up, I hope.

@timhoffm timhoffm merged commit c7e4448 into matplotlib:master Aug 19, 2020
@QuLogic QuLogic deleted the errorbar-cycler branch August 19, 2020 18:46
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Sep 8, 2020
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Sep 8, 2020
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
@QuLogic QuLogic mentioned this pull request Sep 8, 2020
4 tasks
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Sep 8, 2020
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Feb 4, 2021
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Feb 4, 2021
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Feb 10, 2021
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Feb 17, 2021
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
QuLogic added a commit to QuLogic/matplotlib that referenced this pull request Feb 18, 2021
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
MihaiAnton pushed a commit to MihaiAnton/matplotlib that referenced this pull request Mar 8, 2021
As with 2D before matplotlib#17930, it would not cycle if a color were specified.
However, this does not match `plot`, which does not advance the cycle
only if _all_ properties in the cycle are specified. Notably, this means
if your property cycle was for line style, specifying a color would
ignore the cycle in `errorbar`, but not in `plot`.

This is a 3D version of 149e7fb and
0782c74.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Using a linestyle cycler with plt.errorbar results in strange plots
4 participants