You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The Axes methods are just thin wrappers around the Axis methods.
The kwargs are Text properties.
Issue
The Axes API feels a bit odd. AFAICS set_xticklabels does not make much sense without set_xticks before; otherwise how do I know that the labels will be at the correct places and that I have the right number of labels for the ticks.
maybe even with ticks=None to be compatible with the pyplot API - though I don't know if one needs the ability to set ticks without positions.
Soft-deprecate set_xticklabels. It's too widely used to be deprecated, but we shouldn't have two equal ways here.
Optionally add the minor kwarg to pyplot.xticks; it's not strictly necessary because pyplot may have less functionality than the OOP interface; but it doesn't hurt either.
The proposed signature would be an API-change because the minor argument might have been passed positionally. Thus, we should start with _make_keyword_only on that parameter.
Alternatively, one could allow the ticks argument to also be a dict (or a list of pairs -- i.e., something that you can call dict() on) mapping values to labels. I think the API may be nicer? ax.set_xticks({1: "a", 2: "b"}); ax.set_xticks({x: to_label(x) for x in positions})
I thiink this doesn't need a deprecation period (because even now you can't do ax.set_xticks({1: "a", 2: "b"}) -- set_xticks won't convert the dict to a list only using the keys (not having a deprecation period is a minor nicety, but I don't think we should decide on the API just based on that if another one is clearly better).
A mapping is indeed a neat API for this and has a number of advantages.
My main concern is that we do not have this kind of API in Matplolib so far, AFAIK. We always pass multiple lists; e.g. legend(handles, labels). In particular also the direct analogon pyplot.xticks(ticks, labels). I assume that's an inherited Matlabism.
So, this is also a question of API consistency and if we want to change the paradigm here and if we plan to do this elsewhere.
If ticks=None was the default and allowed to just change tick properties (label rotation!) easily, that would be amazing. I have been using matplotlib for years, but still need to google how to rotate the ticklabels when I need to: something like plt.setp(ax.get_xticklabels(), rotation=45) is not super intuitive imo.
Indeed it would be good to first/simultaneously clarify what the desired interface for changing ticklabel properties should be. Currently we have
ax.set_{x,y}ticklabels() Does take text properties. Drawback: Sets the formatter to a FixedFormatter.
plt.{x,y}ticks() Does take text properties. Drawback: is pyplot-only.
ax.tick_params() Looks like the canonical function for this, yet it only takes a subset of required parameters (no alignment, no fontproperties, etc.)
fig.autofmt_xdate() takes rotation and alignment, but only applies to the lower subplot's xaxis.
plt.setp(ax.get_{x,y}ticklabels(), ...) - General purpose, works with everything (except for rotation on polar plots), but requires pyplot, is not very discoverable, and people seem to not like it for some reason.
If one goes for making ax.set_{x,y}ticklabels() or ax.set_{x,y}ticks the canonical interfaces for setting ticklabel properties, it might be confusing how it would set or not set the locators and formatters depending on the input.
I guess this sort of points to the fact that the tick labels should really be a single collection object (a TextCollection -- yes, this doesn't exist (yet)) so that one can have methods on it to set its properties globally. Of course this doesn't really make sense with the current design where each Tick owns its own Text and Line2D, but see also the discussion at #5665 (comment).
I want to add something which I'm not sure whether it's a bug or intentional. Let me know if I should open a new issue for this.
pyplot.xticks has both ticks and labels as optional. I wanted to add just the labels while maintaining the ticks (this is a use case where the OP doubted one would need). However, this returns an error as the code is as follows:
if ticks is None and labels is None:
locs = ax.get_xticks()
labels = ax.get_xticklabels()
elif labels is None:
locs = ax.set_xticks(ticks)
labels = ax.get_xticklabels()
else:
locs = ax.set_xticks(ticks)
labels = ax.set_xticklabels(labels, **kwargs)
Thus, my use-case would go to the else, but the ticks would be None, which can't happen. This could be fixed by change the upper code with something similar to:
locs = ax.set_xticks(ticks) if ticks else ax.get_xticks()
labels = ax.set_xticklabels(labels, **kwargs) if labels else ax.get_xticklabels()
Or, if one liners are a no go, one can add an extra elif for this specific case.
Let me know if you agree with this being an issue and/or if I should create a separate issue in github for this. Thanks.
PS: The same problem exists in yticks.
Edit: format
@bluetrickpt In any case, this needs action because plt.xticks(labels=['a', 'b', 'c']) yields a quite cryptic TypeError: object of type 'NoneType' has no len(). The question is if it should work or error out with a better message.
What is your use case for only changing the label texts without caring about their position? In particular, how do you know that the labels will be at the correct places and that you the right number of labels for the ticks?
@bluetrickpt In any case, this needs action because plt.xticks(labels=['a', 'b', 'c']) yields a quite cryptic TypeError: object of type 'NoneType' has no len(). The question is if it should work or error out with a better message.
What is your use case for only changing the label texts without caring about their position? In particular, how do you know that the labels will be at the correct places and that you the right number of labels for the ticks?
My use case is for multiple boxplots or bar plots in the same figure, in where I know exactly how many boxplots or bars I'm plotting. The xticks are always range(n), where n is the number of boxplots or bars to put in the plot.
Here's an example of such use case:
But in reality, any case in where you do plt.plot(y), xticks get set as range(len(y)). So in all these cases I would assume that only setting the labels is needed.
Activity
bhuvanshukla commentedon Aug 8, 2019
And similarly for
from mpl_toolkits.mplot3d import Axes3Dthese 3d plots too, keeping in mind thez-axisespecially. :)anntzer commentedon Aug 8, 2019
Alternatively, one could allow the ticks argument to also be a dict (or a list of pairs -- i.e., something that you can call
dict()on) mapping values to labels. I think the API may be nicer?ax.set_xticks({1: "a", 2: "b"});ax.set_xticks({x: to_label(x) for x in positions})I thiink this doesn't need a deprecation period (because even now you can't do
ax.set_xticks({1: "a", 2: "b"})-- set_xticks won't convert the dict to a list only using the keys (not having a deprecation period is a minor nicety, but I don't think we should decide on the API just based on that if another one is clearly better).timhoffm commentedon Aug 8, 2019
A mapping is indeed a neat API for this and has a number of advantages.
My main concern is that we do not have this kind of API in Matplolib so far, AFAIK. We always pass multiple lists; e.g.
legend(handles, labels). In particular also the direct analogonpyplot.xticks(ticks, labels). I assume that's an inherited Matlabism.So, this is also a question of API consistency and if we want to change the paradigm here and if we plan to do this elsewhere.
anntzer commentedon Aug 8, 2019
It's quite likely this comes from MATLAB, like many other bad ideas :/
Phlya commentedon Aug 9, 2019
If
ticks=Nonewas the default and allowed to just change tick properties (label rotation!) easily, that would be amazing. I have been using matplotlib for years, but still need to google how to rotate the ticklabels when I need to: something likeplt.setp(ax.get_xticklabels(), rotation=45)is not super intuitive imo.ImportanceOfBeingErnest commentedon Aug 9, 2019
Indeed it would be good to first/simultaneously clarify what the desired interface for changing ticklabel properties should be. Currently we have
ax.set_{x,y}ticklabels()Does take text properties. Drawback: Sets the formatter to a FixedFormatter.plt.{x,y}ticks()Does take text properties. Drawback: is pyplot-only.ax.tick_params()Looks like the canonical function for this, yet it only takes a subset of required parameters (no alignment, no fontproperties, etc.)fig.autofmt_xdate()takes rotation and alignment, but only applies to the lower subplot's xaxis.plt.setp(ax.get_{x,y}ticklabels(), ...)- General purpose, works with everything (except for rotation on polar plots), but requires pyplot, is not very discoverable, and people seem to not like it for some reason.If one goes for making
ax.set_{x,y}ticklabels()orax.set_{x,y}ticksthe canonical interfaces for setting ticklabel properties, it might be confusing how it would set or not set the locators and formatters depending on the input.anntzer commentedon Aug 9, 2019
I guess this sort of points to the fact that the tick labels should really be a single collection object (a TextCollection -- yes, this doesn't exist (yet)) so that one can have methods on it to set its properties globally. Of course this doesn't really make sense with the current design where each Tick owns its own Text and Line2D, but see also the discussion at #5665 (comment).
y9c commentedon Aug 19, 2019
set_xticklabelsandget_xticklabelsare also confusing. The argminor=Trueworks for both, but notwhich='minor'.rscmendes commentedon Nov 18, 2019
I want to add something which I'm not sure whether it's a bug or intentional. Let me know if I should open a new issue for this.
pyplot.xtickshas both ticks and labels as optional. I wanted to add just the labels while maintaining the ticks (this is a use case where the OP doubted one would need). However, this returns an error as the code is as follows:Thus, my use-case would go to the else, but the ticks would be None, which can't happen. This could be fixed by change the upper code with something similar to:
Or, if one liners are a no go, one can add an extra elif for this specific case.
Let me know if you agree with this being an issue and/or if I should create a separate issue in github for this. Thanks.
PS: The same problem exists in yticks.
Edit: format
timhoffm commentedon Nov 24, 2019
@bluetrickpt In any case, this needs action because
plt.xticks(labels=['a', 'b', 'c'])yields a quite crypticTypeError: object of type 'NoneType' has no len(). The question is if it should work or error out with a better message.What is your use case for only changing the label texts without caring about their position? In particular, how do you know that the labels will be at the correct places and that you the right number of labels for the ticks?
rscmendes commentedon Nov 24, 2019
My use case is for multiple boxplots or bar plots in the same figure, in where I know exactly how many boxplots or bars I'm plotting. The xticks are always range(n), where n is the number of boxplots or bars to put in the plot.
Here's an example of such use case:

But in reality, any case in where you do plt.plot(y), xticks get set as range(len(y)). So in all these cases I would assume that only setting the labels is needed.
timhoffm commentedon Nov 24, 2019
Thanks, that's indeed a valid case and should work. Are you willing to provide a PR?
rscmendes commentedon Nov 24, 2019
Definitely. I'll do it the next few days.
QuLogic commentedon Aug 18, 2021
The first two items were actually duplicated in #19016 and fixed in #20047; I'm not sure what we want to do about the third item.
timhoffm commentedon Aug 21, 2021
I have no strong opinion, maybe we should briefly discuss that in the dev call.