Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork7.9k
Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor#29133
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
Although some tests are failing, I can't determine the cause; For example, test_bbox_inches_tight in test_bbox_tight fails, even though old/new images appear equal. |
rcomer commentedNov 13, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
The easiest test to debug might be |
lib/matplotlib/axes/_axes.py Outdated
edgecolor = kwargs.pop('edgecolor', color) | ||
facecolor = (facecolor if facecolor is not None | ||
else "b" if mpl.rcParams['_internal.classic_mode'] |
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 guess you made "b" the default in classic mode for consistency withscatter
. However this is not the established behaviour forbar
and setting it to blue is likely the cause of at least some of your test failures. Forscatter
it will only be there for consistency with old Matplotlib versions. I think we should just use theget_next_color_func
here.
lib/matplotlib/axes/_axes.py Outdated
@@ -2320,7 +2320,59 @@ def _convert_dx(dx, x0, xconv, convert): | |||
# we do by default and convert dx by itself. | |||
dx = convert(dx) | |||
return dx | |||
@staticmethod | |||
def _parse_bar_color_args(kwargs, get_next_color_func): |
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.
According to#12739 the method for parsingscatter
color arguments was made static so that we could have unit tests specifically for that method. Do you plan to write similar tests here? If not, this could be an ordinary method and we would not need to pass theget_next_color_func
but just accessself._get_patches_for_fill.get_next_color
directly.
Edit: looking at the discussion in#12739 I think it is not advisable to write such tests but just test the publicbar
function.
@rcomer thx for the review, I'll fix it as soon as possible. prob later today |
@rcomer test_bar_color_cycle passed as you said. Others still failed. |
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
rcomer commentedNov 15, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Here are the before and after of that So it seems the edgecolor has changed from black to blue. Note you can download all the test images under "Artifacts" on theTest Summary Page. However those zip files are large so it may be more efficient to run the tests locally and inspect the images you produce that way. |
Lucx33 commentedNov 20, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@timhoffm thx for the review, commited it. All tests in test_axes passed except for I can commit this to the PR if you think it's okay. |
Lucx33 commentedNov 20, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
@rcomer In |
Other tests fails for the same reason as both tests above. |
I do not think we really wantedgecolor to matchcolor by default: if I takethe grouped bar example and
we see that the shorter bars now overlap the larger ones, which is not visually appealing. This does not happen if the edgecolor is left off |
Indeed. Currently, |
@Lucx33 please add a test for the new behaviour. |
@rcomer Is this test good enought? |
lib/matplotlib/axes/_axes.py Outdated
@@ -2378,6 +2428,9 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", | |||
color : :mpltype:`color` or list of :mpltype:`color`, optional | |||
The colors of the bar faces. |
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.
Thecolorsofthebarfaces. | |
Thecolorsofthebarfaces.Thisisanaliasfor*facecolor*. | |
Ifbotharegiven,*facecolor*takesprecedence. |
@@ -2378,6 +2428,9 @@ def bar(self, x, height, width=0.8, bottom=None, *, align="center", | |||
color : :mpltype:`color` or list of :mpltype:`color`, optional | |||
The colors of the bar faces. | |||
facecolor : :mpltype:`color` or list of :mpltype:`color`, optional | |||
The colors of the bar faces. |
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.
Thecolorsofthebarfaces. | |
Thecolorsofthebarfaces. | |
Ifboth*color*and*facecoloraregiven,*facecolor*takesprecedence. |
lib/matplotlib/tests/test_axes.py Outdated
for bar in bars: | ||
assert to_rgba(bar.get_facecolor()) == to_rgba('red') | ||
ax.cla() |
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.
You don't need to clear in between, which unfortunately is a relatively expensive action. Instead I'd do
# case 1: no color specified bars = ax.bar([1, 2, 3], [4, 5, 6]) [...] # case 2: Only 'color' bars = ax.bar([11, 12, 13], [4, 5, 6], color='red') [...] # case 3: Only 'color' bars = ax.bar([21, 22, 23], [4, 5, 6], color='red') [...] # case 4: 'facecolor' and 'color' bars = ax.bar([1, 2, 3], [4, 5, 6], color='red', facecolor='green') [...]
Putting the no color case first ensures noting is messing with the colorcycle.
Optional: You could usehttps://matplotlib.org/stable/api/_as_gen/matplotlib.colors.same_color.html#matplotlib.colors.same_color for the asserts.
@timhoffm thx for the review, commited it. |
Uh oh!
There was an error while loading.Please reload this page.
Co-authored-by: Tim Hoffmann <2836374+timhoffm@users.noreply.github.com>
Is there anything else I can do to help with the merge? |
timhoffm commentedNov 27, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
No, we just need a second approval from another core developer. Note for other reviewers: The win10 test failure is the flaky determinism check and not related to this PR. |
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.
Thanks@Lucx33, I just have one small comment. Otherwise this looks good to me.
Uh oh!
There was an error while loading.Please reload this page.
Lucx33 commentedNov 30, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Messed up my commit by changing wrong file manually but fixed already |
@rcomer Changed blue as you said |
7025fb9
intomatplotlib:mainUh oh!
There was an error while loading.Please reload this page.
…color handling in plt.bar with precedence and sequence support for facecolor and edgecolor
Thanks@Lucx33 and congratulations on your first Matplotlib PR! I hope we hear from you again. |
…133-on-v3.10.xBackport PR#29133 on branch v3.10.x (Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor)
PR summary
This PR introduces the
_parse_bar_color_args function
, which provides consistency in color bar arguments by establishing a parameter precedence, "similar" to the one used inscatter
:facecolor: facecolor -> color -> 'b' if in classic mode else the result of
get_next_color_func()
edgecolor: edgecolor -> color -> None
This ensures that when edgecolors is not explicitly defined, it tries color. Additionally, this change allows facecolor to accept sequences of colors, ensuring consistency in argument handling, as issued in#29090. The tests are consistent with examples in#29072.
Examples:
plt.bar([1, 2, 3], [1, 2, 3], color=['none', 'C2', 'none'], edgecolor=['C1', 'C2', 'C3'])
plt.bar([1, 2, 3], [1, 2, 3], color=['none', 'C2', 'none'])
plt.bar([1, 2, 3], [1, 2, 3])
plt.bar([1, 2, 3], [1, 2, 3],facecolor=('none', 'C2', 'none'))
plt.bar([1, 2, 3], [1, 2, 3], color=('C1', 'C2', 'C3'), facecolor=('none', 'C2', 'none'))
PR checklist