I’ve been digging through code and docs, but could not find a definitive answer to this question: is it considered valid to do something like the following:
rect = matplotlib.patches.Rectangle((np.nan, np.nan), 0, 0, facecolor='C0', label='foo')
I’m using this as a bit of a hack to make a patch that is invisible in the plot and does not participate in limit calculations, but does still show up in the legend with an appropriate color and label. It works perfectly (3.10.3) for this use, where alternatives either do not show up in the legend or do not receive the proper color (eg visible=False).
It feels a little hacky in some ways, though it is basically consistent with how other nan/non-finite data are treated in mpl, so maybe it’s fine? I’d just like to get a sense of whether its functioning is intended and correct behavior that should remain stable, or if I’m exploiting some strange corner case bug that may change in the future.
Added context: I’m working with some display code that generates multiple related artists for the same data, and it’s not always clear at creation time which one should be visible and used for the legend. (There’s more to it than that, but this is the essential description of the scenario.) Hence creating a proxy artist for this purpose, but I also want to make sure that it does not influence the behavior of the figure in any other way.
I’m not qualified to comment on whether accepting nans is stable. However, you can make proxy artists and pass them straight to legend without adding them to the plot.
Just following up after I did some more homework on this.
This bit of the documentation for Path seems relevant:
vertices (N, 2) array-like
The path vertices, as an array, masked array or sequence of pairs. Masked values, if any, will be converted to NaNs, which are then handled correctly by the Agg PathIterator and other consumers of path data, such as iter_segments().
This implies that NaN values are expected to be handled by the backend. The various backends that I’ve tried (agg, qtagg, ipympl, svg, pdf, cairo) all seem to behave consistently and skip nan-valued paths.
I guess a refined version of my question is: is this behavior explicit and guaranteed for all backends? (Or, is it supposed to be?)
PathCollections created with scatter now keep track of invalid points. Previously, points with nonfinite (infinite or nan) coordinates would not be included in the offsets (as returned by PathCollection.get_offsets) of a PathCollection created by scatter, and points with nonfinite values (as specified by the c kwarg) would not be included in the array (as returned by PathCollection.get_array)
Such points are now included, but masked out by returning a masked array.
and it seems to me like this handling of invalid points (via nan / masked array) is implemented by the backend, and so should be consistently handled across backends. If so, I think my initial question is answered in the affirmative (using nans for coordinates is okay).
It would be great if someone could confirm whether I have this right.
Follow-up on this: using nan positioning works fine most of the time, but triggers a total failure when saving figures with bbox=’tight’. The problem, I guess, is that the bbox calculation does not have explicit logic to pass over nan values, resulting in nans everywhere.
I was able to work around this by adding proxy.set_in_layout(False). I do suspect though that there’s an opportunity here to make the bbox and data limit calculations internally consistent.