matplotlib / matplotlib

matplotlib: plotting with Python
https://matplotlib.org/stable/
20.29k stars 7.65k forks source link

simpler way to plot open symbols #20360

Open gmamon opened 3 years ago

gmamon commented 3 years ago

Problem

It would be nice to have direct shortcuts for plotting open symbols (e.g. with plt.scatter).

For example,

etc.

story645 commented 3 years ago

agree this would be nice, some related discussion is at xref: #17850

QuLogic commented 3 years ago

With plot, you can do ax.plot(x, y, marker='o', fillstyle='none'), though annoyingly it seems you can't do that with scatter. However, maybe you don't need scatter?

timhoffm commented 3 years ago

17850 is only about consistent rendering.

This is achievable in scatter by plt.scatter(x, y, marker=MarkerStyle('o', fillstyle='none')).

marker (and fillstyle) are internally passed to MarkerStyle.

What is asked here is an extension of the MarkerStyle parser so that MarkerStyle('oo') == Marker('o', fillstyle='none'). This is only about convenience not about new functionality.

First, the fundamental question to answer is if the increased usability outweights the redundancy.

Some additional specific aspects:

QuLogic commented 3 years ago

Is marker='oo' readable enough or is that too cryptic.

This might conflict conceptually with hatching, where doubling the character increases the density, whereas this decreases the ink for the marker.

timhoffm commented 3 years ago

Here it‘s not doubling, but an added o for open (an open square is 'so'). Technically there is no conceptual overlap. The question is rather if 'oo' is readable enough. A more verbose option could be 'o(open)' or 'open-o' or similar.

anntzer commented 3 years ago

annoyingly it seems you can't do that with scatter

Indeed, something like scatter([1, 2], [3, 4], c=[0, 1], fc="none") fails to colormap the edgecolors because edgecolor defaults to "face" and then fc="none" wins against the colormapping provided by c. I actually think that looks like a bug? (it should be possible to colormap ec while having a fixed fc)

story645 commented 3 years ago

Would we also have characters for the half fill styles? If so which?

f[ull], l[eft], r[ight], t[op], b[ottom], n[one]

If it's not overkill to expand to three letters, (or I guess two since none=open?)

anntzer commented 3 years ago

First, the fundamental question to answer is if the increased usability outweights the redundancy.

To be clear, I think the preferred API should not be manipulating MarkerStyles, but really to make fc="none" work (as noted in my message above). I don't think scatter(x, y, marker="o", fc="none") (in fact, that's just scatter(x, y, fc="none") in the common case of circle markers) is really worse than scatter(x, y, marker="oo"), and is likely more legible (and if you start writing "o-open" then the difference in length is even less). (In other words, as things are I am :-1: on "oo" or "o-open". In further other words, I don't think minimization of keystroke count should rank highly in API design. (I'm not saying it doesn't matter at all, either.))


As for making fc="none" work, perhaps the solution would be along the lines of making the default value of ec not be "face" ("match the facecolor"), but rather the new magic value "mapped" (or "data" or whatever), and likewise for fc, meaning "the colormapped color"? (and if no data-to-be-colormapped is set, fallback to some rc such as lines.markerfacecolor or lines.color? (or we would even introduce another rc for that but that seems overkill))

gmamon commented 3 years ago

With plot, you can do ax.plot(x, y, marker='o', fillstyle='none'), though annoyingly it seems you can't do that with scatter. However, maybe you don't need scatter?

This makes me think that plot, scatter and errorbar should be merged into a single Matplotlib.pyplot function.

story645 commented 3 years ago

I'm +1 on the fc='none' proposal cause that's what I've tried first in the past and was frustrated it didn't work.

@gmamon plot, scatter, and errorbar have different semantics, but I agree we should try to standardize the keyword arguments for manipulating markers.

anntzer commented 3 years ago

Actually, looking at the docs of Collection again, I note that it states

If the Collection's .ScalarMappable matrix _A has been set (via a call to .Collection.set_array), then at draw time this internal scalar mappable will be used to set the facecolors and edgecolors, ignoring those that were manually passed in.

which is currently not true (even ignoring the edge case of ec="face"): with pc = scatter([1, 2], [3, 4], ec="r", fc="r"); pc.set_array([0, 1]) the edgecolor is not ignored; colormapping is only applied to the facecolor.

story645 commented 1 year ago

instead of opening a new issue, gonna revive this one. The no fillstyle in scatter is bothering me cause of its inconsistency w/ plot (https://github.com/matplotlib/matplotlib/issues/20360#issuecomment-854166001) so what do folks feel about either:

timhoffm commented 1 year ago

I'm -1 on the original two-char proposals (marker="oo"). - This is too crypitc. I'm -0.3 on an expanded string notation or a tuple (symbol, fillstyle) - This is a new type of API and we already have ways to set fillstyle. I'm +0.5 on scatter growing a fillstyle argument. - This is consistent with plot().