[1.5.1,3.5.1,OSX] Matplotlib version, Python version and Platform (Windows, OSX, Linux ...)
[pip ] How did you install Matplotlib and Python (pip, anaconda, from source ...)
from matplotlib.pyplot import subplots,gca
fig,ax = subplots()
ax.plot(range(0,10),range(0,10))
label_list = list(ax.xaxis.get_ticklabels())
print('First label is :',label_list[0].get_text())
label_list = list(ax.get_xaxis().get_ticklabels())
print('First label is :',label_list[0].get_text())
label_list = list(gca().xaxis.get_ticklabels())
print('First label is :',label_list[0].get_text())
label_list = list(gca().get_xaxis().get_ticklabels())
print('First label is :',label_list[0].get_text())
Returns empty for all calls.
I found quite frustating since testing the code manually in ipython works. While running the source from the shell or with %run in ipython it doesn't. Am I missing some update command before getting the tick labels or mpl is wrongly configured somehow?
I should have elaborated: in interactive mode in ipython, a draw() is automatically triggered after each function that has a plotting action. In non-interactive environments, the draw action is executed only at the end--this saves a lot of run time.
Although I am in an interactive environment (Jupyter notebook with %matplotlib inline)
I had to add a plt.draw() to make it work. Is this how it supposed to be, isn't it a bug?
ax = plt.gca()
plt.plot((0,1),(0,1))
# plt.draw()
ax = plt.gca()
[l.get_text() for l in ax.get_yticklabels()]
just a thought... what if these functions that access values for parameters
that we usually defer until draw time... what if they trigger an internal
draw if things are "stale"? We have this problem too for get_facecolors()
for scalarmappables.
Works for me (on a version close to master, in ipython but without any interactive gui support) with the draw. It's probably not very useful, though, because it is returning labels for ticks that will not, in the end, show up.
At this point the x-ticks are of the format '2015-01', '2015-02' .. and I want to convert them to 'Jan', 'Feb'
To do that I am using this function:
f = lambda x: datetime.datetime.strptime(x, '%Y-%m').strftime('%b')
The strange thing is that if I execute function f (above) as follows:
plt.gca().set_xticklabels([ f(x.get_text()) for x in plt.gca().get_xticklabels()])
The call works correctly if executed in the next cell (cell after the cell with the plt.plot calls) of the notebook. However, if I try to execute it in the same cell that has the plt.plot calls, it does not work as the xticklabels are all emply or blank i.e., ''.
When I tried adding a call to plt.draw() as suggested above, it did not work in both cases - i..e,, did not work for my code nor did it work for the bare-bones example given above.
I'd really like to be able to execute all of this in one cell versus having to split it across two cells and I would really appreciate any help.
To be sure it is clear: getting and setting tick labels directly is almost always a risky operation at best, one that is likely to cause incorrect results. Perhaps it never should have been part of the public API. Since it is, all we can do is urge users to take advantage of Formatters instead.
Not a remotely self-contained one right now - the context of my issue was finding that https://github.com/nschloe/tikzplotlib was not getting the tick labels correct - and I figured I should dump my workaround here until I or someone else has time to look into it further.
What may be relevant is I had already called plt.show(block=False) before setting up my axes - so it's possible that draw saw they were computed, but didn't check if they were stale.
As above, the labels are not calculated until you trigger a draw. i.e. fig.canvas.draw(). Note, confusingly, plt.draw() does not trigger the labels to be computed.
@jklymak Thanks, I thought it doesn't work since some users above also reported issues with it. Is there another way to change the label alignment based on the example I gave other than put a fig.canvas.draw() before the for loop? It is indeed a bit confusing since I'm also running it in an interactive environment. Since this is closed, I assume this will not change in a further update.
Whether things get done when they are called, or on draw, is always a tension in Matplotlib. In this case, changing the limits is relatively expensive so we wait until we have all the information. get_ylim or get_xlim will also call the limit-setting logic.
This is also related to #18408 where we discovered that for some backends fig.canvas.draw() is a no-op and you have to actually run a savefig to get the internal state to update (!!).
... I would expect most folks are not using one of the non-interactive backends except agg. I mean, sure they switch to pdf to write the pdf, but is there some reason to start in pdf? I think a useful restriction back in the day would be to have made some backends transitory in that they only are for printing a "final" version of a plot.
Note that in #6103 (comment) I'm describing using a third-party backend, @nschloe's tikzplotlib - so It would be great if there were at least instructions for backend developers for how to make the tick labels appear.
Activity
efiring commented on Mar 3, 2016
Try putting a pyplot.draw() call after plotting, before trying to get the labels.
ocehugo commented on Mar 3, 2016
Done it. I try that before but maybe I didn't save it. Thanks!
efiring commented on Mar 3, 2016
I should have elaborated: in interactive mode in ipython, a draw() is automatically triggered after each function that has a plotting action. In non-interactive environments, the draw action is executed only at the end--this saves a lot of run time.
ocehugo commented on Mar 3, 2016
I was suspecting something related to this, but rushing I assumed it didnt work.
tacaswell commented on Mar 3, 2016
Closing as this is not a bug per-say, but a fun wart of non-interacitve mode.
oztalha commented on Apr 26, 2017
Although I am in an interactive environment (Jupyter notebook with %matplotlib inline)
I had to add a plt.draw() to make it work. Is this how it supposed to be, isn't it a bug?
story645 commented on Apr 26, 2017
Yup, that's how it's supposed to work.
WeatherGod commented on Apr 26, 2017
story645 commented on Apr 26, 2017
I feel like we should do something about it since this is at least the 3rd bug report about it (#6800, #6638)
sschahal commented on May 15, 2018
I get empty ticks with and without the call to plt.draw() - please help
efiring commented on May 15, 2018
Works for me (on a version close to master, in ipython but without any interactive gui support) with the draw. It's probably not very useful, though, because it is returning labels for ticks that will not, in the end, show up.
What is it that you actually want to do?
sschahal commented on May 15, 2018
Thanks for the prompt response. I am using Jupyter notebooks and my code is as follows:
plt.plot(date_range, min_rec, date_range, max_rec)
plt.fill_between(date_range, min_rec, max_rec, facecolor='blue', alpha=0.25)
At this point the x-ticks are of the format '2015-01', '2015-02' .. and I want to convert them to 'Jan', 'Feb'
To do that I am using this function:
f = lambda x: datetime.datetime.strptime(x, '%Y-%m').strftime('%b')
The strange thing is that if I execute function f (above) as follows:
plt.gca().set_xticklabels([ f(x.get_text()) for x in plt.gca().get_xticklabels()])
The call works correctly if executed in the next cell (cell after the cell with the plt.plot calls) of the notebook. However, if I try to execute it in the same cell that has the plt.plot calls, it does not work as the xticklabels are all emply or blank i.e., ''.
When I tried adding a call to plt.draw() as suggested above, it did not work in both cases - i..e,, did not work for my code nor did it work for the bare-bones example given above.
I'd really like to be able to execute all of this in one cell versus having to split it across two cells and I would really appreciate any help.
phobson commented on May 15, 2018
@sschahal I think you should be using a DateFormatter per this example: https://matplotlib.org/gallery/text_labels_and_annotations/date.html#sphx-glr-gallery-text-labels-and-annotations-date-py
2 remaining items
efiring commented on May 15, 2018
To be sure it is clear: getting and setting tick labels directly is almost always a risky operation at best, one that is likely to cause incorrect results. Perhaps it never should have been part of the public API. Since it is, all we can do is urge users to take advantage of Formatters instead.
sschahal commented on May 15, 2018
Thank you both for your quick responses and help. Greatly appreciated.
eric-wieser commented on Jan 9, 2020
I'm finding that even calling plt.draw() isn't enough to get the labels to compute - I need to call plt.pause(0.01) too.
jklymak commented on Jan 10, 2020
@eric-wieser Can you give us an example?
I actually lean towards the idea that we should populate these when the user asks for them (based on the current viewlims etc) #16141
eric-wieser commented on Jan 10, 2020
Not a remotely self-contained one right now - the context of my issue was finding that https://github.com/nschloe/tikzplotlib was not getting the tick labels correct - and I figured I should dump my workaround here until I or someone else has time to look into it further.
What may be relevant is I had already called plt.show(block=False) before setting up my axes - so it's possible that draw saw they were computed, but didn't check if they were stale.
stevenlis commented on Oct 12, 2020
I'm having some issues with get_text(), for example:
I get nothing by running the above code with get_text(). However, if I just run the code below in a different cell
I will get
jklymak commented on Oct 13, 2020
As above, the labels are not calculated until you trigger a draw. i.e. fig.canvas.draw(). Note, confusingly, plt.draw() does not trigger the labels to be computed.
stevenlis commented on Oct 13, 2020
@jklymak Thanks, I thought it doesn't work since some users above also reported issues with it. Is there another way to change the label alignment based on the example I gave other than put a fig.canvas.draw() before the for loop? It is indeed a bit confusing since I'm also running it in an interactive environment. Since this is closed, I assume this will not change in a further update.
jklymak commented on Oct 14, 2020
Whether things get done when they are called, or on draw, is always a tension in Matplotlib. In this case, changing the limits is relatively expensive so we wait until we have all the information. get_ylim or get_xlim will also call the limit-setting logic.
tacaswell commented on Oct 14, 2020
This is also related to #18408 where we discovered that for some backends fig.canvas.draw() is a no-op and you have to actually run a savefig to get the internal state to update (!!).
jklymak commented on Oct 14, 2020
... I would expect most folks are not using one of the non-interactive backends except agg. I mean, sure they switch to pdf to write the pdf, but is there some reason to start in pdf? I think a useful restriction back in the day would be to have made some backends transitory in that they only are for printing a "final" version of a plot.
tacaswell commented on Oct 15, 2020
We should try to work for all folks not just most folks and we should try to have the same behavior independent of backend choice.
eric-wieser commented on Oct 15, 2020
Note that in #6103 (comment) I'm describing using a third-party backend, @nschloe's tikzplotlib - so It would be great if there were at least instructions for backend developers for how to make the tick labels appear.