Skip to content

Surprising behavior of hatches in fill_between #11418

Open

Description

@mwaskom

Bug report

Hatches are invisible in the output of ax.fill_between when color is specified. They are present when color is absent or when facecolor is used.

I found #9894 which might be related, but seems to be a much narrower

Code for reproduction

import matplotlib.pyplot as plt

f, ax = plt.subplots()
ax.fill_between([0, 1], [0, 1], hatch="//")
f.savefig("test1.png")

f, ax = plt.subplots()
ax.fill_between([0, 1], [0, 1], hatch="//", color="g")
f.savefig("test2.png")

f, ax = plt.subplots()
ax.fill_between([0, 1], [0, 1], hatch="//", facecolor="g")
f.savefig("test3.png")

Actual outcome

test1.png:
test1

test2.png:
test2

test3.png:
test3

Expected outcome

I expected test2.png to have black hatch marks. I think what's happening is that the color= kwarg is being picked up globally by the artist and so the hatches in test2.png are there, they just have the same green color as the background. Unfortunately I don't think any hatch metadata other than the string code gets added to the artist, so I can't check.

Having color= globally change both the face and edge color of the artist makes a certain amount of sense, and I think the hatches are mostly inheriting their attributes from the kwargs that set the edge aesthetics. So I think I understand what's happening, but it took me a long time to figure out why the hatch argument had, apparently, no effect. I'll also note that the hatch demo is using the color= kwarg, but with ax.bar.

Matplotlib version

  • Operating system: MacOS
  • Matplotlib version: 2.2.2
  • Matplotlib backend (print(matplotlib.get_backend())): MacOSX
  • Python version: 3.6
  • Jupyter version (if applicable): NA
  • Other libraries: NA

This is a fresh install from conda to test, but I also saw it on matplotlib 2.2.0.

Activity

  1. mwaskom commented on Jun 11, 2018

    @mwaskom
    Author

    More surprising behavior: whether or not the hatches inherit the alpha= from the main artist varies across output formats. This is consistent across the three examples above but does reveal that the hatches are indeed present but invisible when specifying color:

    f, ax = plt.subplots()
    ax.fill_between([0, 1], [0, 1], hatch="//", color="g", alpha=.5)
    f.savefig("test2.png")
    f.savefig("test2.pdf")
    

    test2.png:
    test2

    test2.pdf:
    screenshot 2018-06-11 14 01 34

  2. jklymak commented on Jun 11, 2018

    @jklymak
    Member

    I think the work around is to call fill_between twice, once for the hatch and once for the facecolor.. I imagine an API proposal for how to make this controlable from the API would be welcome. Note the hatch.linewidth and hatch.color rcParams. You could probably also change those on the fly, though that is kludgey as well.

  3. mwaskom commented on Jun 11, 2018

    @mwaskom
    Author

    To be clear, I can accomplish what I want perfectly fine by using facecolor, but that wasn't obvious and using color just made it seem like hatch was broken somehow.

    Short of adding a whole new set of kwargs that specifically pertain to hatches, I'm not exactly sure how to "solve" the first issue. But it's possible that a situation where the user specifies a hatch and color but not facecolor or edgecolor would be a reasonable place to fire a warning, as (I think?) we can be reasonably certain that the user doesn't mean to be doing that.

    The second issue actually seems more like an actual bug?

  4. jklymak commented on Jun 11, 2018

    @jklymak
    Member

    Right, but sometimes folks want to color the hatch as well, vs using the default color. Calling twice is the workaround for that.

    The second issue seems to definitely be a bug... Adding a pdf tag.

  5. added this to the v3.0 milestone on Jun 11, 2018
  6. mwaskom commented on Jun 11, 2018

    @mwaskom
    Author

    Right, but sometimes folks want to color the hatch as well, vs using the default color. Calling twice is the workaround for that.

    You can also accomplish that with edgecolor (but there's no way to get three distinct colors for the face, edges, and hatches; edgecolor overrides the hatch.color rcParam).

  7. jklymak commented on Jun 11, 2018

    @jklymak
    Member

    Ah, OK, I see. Probably rare that someone wants the edge and the hatch to be different, so thats probaby a decent API.

    Tracking the docs through the color kwarg got me to: https://matplotlib.org/api/collections_api.html#matplotlib.collections.Collection.set_color which is pretty explicit that it'll set the edge and face colors. Where else in the docs should this be specified? FWIW, I'd personally just get rid of the color kwarg, but they outcry would be great!

  8. mwaskom commented on Jun 11, 2018

    @mwaskom
    Author

    Please do not get rid of the color kwarg! It is essential for higher-level APIs like seaborn.FacetGrid.

  9. mwaskom commented on Jun 11, 2018

    @mwaskom
    Author

    If you want to solve this with docs changes then I would suggest more clearly documenting how hatching works. AFAICT there's basically only the hatch demo, which demonstrates (without explication) a usage pattern that produces invisible hatches with fill_between, and then a subsection of the 2.0 release notes that documents how hatches get (some) customization by using the specified edge attributes.

  10. ImportanceOfBeingErnest commented on Jun 11, 2018

    @ImportanceOfBeingErnest
    Member

    a situation where the user specifies a hatch and color but not facecolor or edgecolor would be a reasonable place to fire a warning, as (I think?) we can be reasonably certain that the user doesn't mean to be doing that.

    This is the situation and it gives a perfectly expected result.

    rect = plt.Rectangle((.2,.2),.6,.6, color="g", hatch="\\", fill=False)
    plt.gca().add_patch(rect)
    

    image


    Probably rare that someone wants the edge and the hatch to be different, so thats probaby a decent API.

    This is not rare at all. You would e.g. want a black border and differently colored hatches/faces in a bar plot. Currently it's only solvable by creating the same plot twice.


    In general hatching is very underdevelopped. At one point @tacaswell mentionned that creating a MEP for it would be good; but I guess I forgot about it.

  11. mwaskom commented on Jun 11, 2018

    @mwaskom
    Author

    This is the situation and it gives a perfectly expected result.

    Technically this does involve the user specifying the facecolor because setting fill=False changes its alpha channel:

    rect = plt.Rectangle((0, 0), 1, 1, color="b", fill=False)
    print(rect.get_facecolor())
    print(rect.get_edgecolor())
    
    (0.0, 0.0, 1.0, 0)
    (0.0, 0.0, 1.0, 1)
    

    It's also worth noting that it is possible to get a UserWarning in a similar context:

    UserWarning: Setting the 'color' property will override the edgecolor or facecolor properties

  12. jklymak commented on Jun 11, 2018

    @jklymak
    Member

    In general hatching is very underdevelopped. At one point @tacaswell mentionned that creating a MEP for it would be good; but I guess I forgot about it.

    We have a pretty big API that covers some rare use-cases. i.e. you could imagine a class for hatches where the hatch was an object that you manipulated. But we always have to balance if that extra API is really necessary given the occasional inconvenince of having to do things manually.

  13. tacaswell commented on Jun 11, 2018

    @tacaswell
    Member

    For some fields hatching is not a rare use case (given how quickly it was reported when we broke some things about hatching in 2.0) in some fields.

    You can also accomplish that with edgecolor (but there's no way to get three distinct colors for the face, edges, and hatches; edgecolor overrides the hatch.color rcParam).

    Correct, the work to thread the hatch color through the API to be on the same footing as edge color and face color needs to be done. This includes both the set side to thread it through the plotting methods and the Artists and the backend side so that all of the backends that we ship respect the hatch color correctly.

    As @ImportanceOfBeingErnest mentioned I commented else where this should get a MEP / some planning before the works get started and my rough estimate is that his would take a few weeks of full time effort by someone who knows the MPL code base to implement.

  14. 4 remaining items

  15. mwaskom commented on Jun 13, 2018

    @mwaskom
    Author

    I think 2 might be a bit of a red herring. We should make sure that the API does not lead one to do actions that don't make sense.

    Absolutely. But in the meantime, the current approach is basically a hack that requires some knowledge of the implementation details; doing the most obvious thing fails in a confusing way. First-class support for hatching would be great, but also seems like a lot of work and I haven't seen anyone commit to it. So in the meantime, it might be helpful to give users some more guide rails. With that said I think that being conservative about issuing warnings is usually the right policy so I'm not going to push for it.

    I think I can find time to make some small additions to the hatch demo and solve (1).

  16. mwaskom commented on Jun 13, 2018

    @mwaskom
    Author

    Here's another fun one: it doesn't seem possible to set hatch.linewidth on the fly using a with statement, but hatch.color works fine.

  17. modified the milestones: v3.0, v3.1 on Jun 21, 2018
  18. added
    Difficulty: Hardhttps://matplotlib.org/devdocs/devel/contribute.html#good-first-issues
    on Jun 21, 2018
  19. jklymak commented on Jun 21, 2018

    @jklymak
    Member

    I think I agree that it’d be nice if we had a big API for hatching/stippling. Not going to happen in next 1.5 weeks, and is a bit of an API argument about how to handle. However, I expect we need a FillStyle object similar to a Color object and allow folks to specify that instead of the string shortcuts (which would of course generate a set of default FillStyle objects).

    Not sure if facecolor should be part of the FillStyle. naively, that seems the most complete way to do things.

  20. modified the milestones: v3.1.0, v3.2.0 on Feb 4, 2019
  21. github-actions commented on Jul 22, 2024

    @github-actions

    This issue has been marked "inactive" because it has been 365 days since the last comment. If this issue is still present in recent Matplotlib releases, or the feature request is still wanted, please leave a comment and this label will be removed. If there are no updates in another 30 days, this issue will be automatically closed, but you are free to re-open or create a new issue if needed. We value issue reports, and this procedure is meant to help us resurface and prioritize issues that have not been addressed yet, not make them disappear. Thanks for your help!

  22. added
    keepItems to be ignored by the “Stale” Github Action
    and removed
    status: inactiveMarked by the “Stale” Github Action
    on Jul 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Difficulty: Hardhttps://matplotlib.org/devdocs/devel/contribute.html#good-first-issuesDocumentationbackend: pdfkeepItems to be ignored by the “Stale” Github Actiontopic: hatch

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions