setting tickslabel in matplotlib disables mouse cursor position - python

Whenever I plot something in matplotlib, moving the mouse over the plot shows at the bottom the x and y position of the cursor. This is very convenient when exploring data.
Now, If I set the ticklabels to something else, the x position of the cursor at the bottom of the plot is empty, while the gui keeps track of the y position. Is there a way to keep getting the x position?
This is a simple example of this happening:
import numpy as np
fig, ax = plt.subplots()
x=np.linspace(0,np.pi)
y=np.sin(x)
ax.plot(x,y)
ax.set_xticks([0,np.pi/2,np.pi])
ax.set_xticklabels(['0','pi/2','pi'])
plt.show()

No, there is no easy way to do this.
When you set the labels with a list of strings you set the xaxis.major_formatter to be FixedFormatter (doc) which has some peculiar behavior to make it work (it always returns '', unless you give it a third argument which given when it labels the x-axis, but not otherwise). The marking of where the cursor is is generated using the major_formatter and when you call a FixedFormatter it returns '', which is what is displayed.
If you really want this, you have to write your own call back, see Color values in imshow for matplotlib? for a starting point. (or subclass axes and re-implement format_coord (around line 2903 in axes.py in current matplotlib master branch)

Related

How does matplotlib 1.5.3's tight_layout() interact with subplots_adjust()?

I am using Matplotlib 1.5.3 in Python 3. I have a 3x3 subplot structure, or more generically an unspecified subplot structure that I'm trying to add a color bar to. As per this thread, an apparently good way to do this is to distort the subplots with subplots_adjust(), and add the colorbar as a new axes. Except, I have tight_layout() enabled, and that totally messes with things. Here is the function that, based on what I have read about subplots_adjust(), should work:
import matplotlib.pyplot as plt
def add_colorbar(last_im):
SPACE = 0.2 # portion of final width reserved for colorbar and its padding
PADDING = 0.5 # portion of reserved space reserved for padding
fig = plt.gcf()
# expand image to make room for colorbar
w,h = fig.get_size_inches()
fig.set_size_inches((w/(1-SPACE), h))
# shrink right side of subplot to create empty space on
# right hand side
fig.subplots_adjust(right=0.9*(1-SPACE)) # 0.9 being the original value
# create colorbar axes, place in empty space with padding
cbax = fig.add_axes([1-SPACE*(1-PADDING/2), 0.15,
SPACE*(1-PADDING), 0.7])
fig.colorbar(last_im, cax=cbax)
But the subplot configuration is kept centered, so this creates basically no space, and the color bar is drawn straight over the subplots. I have also tried using plt.tight_layout(rect=[0, 0, 1-SPACE, 1]) instead of subplots_adjust(), but this seems to do even less than the subplots_adjust() statement, and messes with basically just the sizes of the individual subplots. It seems neither of these functions work as advertised for me. What am I missing? Faulty plot shown below, with plot titles censored to be on the safe side.
Alternatively, I'd be fine with a solution for adding a colorbar that will generically work for a figure with any subplot configuration, but I'd prefer to understand the baffling behavior of subplots_adjust() and the tight_layout() rect.
EDIT: Problem ended up being that I made tight_layout() calls erroneously after running add_colorbar(). Correct behavior is observed now that I have removed the calls.

PyPlot coordinate reader ruined when changing axis labels

Generally when plotting with pyplot we have the current (x,y) values at the bottom right:
But, what happens if you relabel? Code:
import matplotlib.pyplot as plt
plt.ion()
plt.draw()
plt.plot([(i,i) for i in range(10)])
plt.gca().set_xticklabels((1,2,3,4,5,6,7,8,9,10))
plt.draw()
You get:
As you see the x value is ruined, that is, is no longer displayed. This may make sense for non- numeric labeling, and may be difficult to handle, but this actually happened to me while working with a twin axis, which I need to be a transformation of the first. If I relabel the twin the coordinates do not appear as well, even though the main axis is untouched. Is there a way to retrieve coordinate display capability?. If someone feels a code to produce and alter a twin axis is necessary let me know.
When set_xticklabels is used, it will overwrite the formatter used. So it has to be set again:
plt.gca().xaxis.set_major_formatter(FormatStrFormatter('%.5f'))
If you want to display the values transformed somehow, then you have to use FuncFormatter, which accepts a function of tick and position, and returns the label. Read about it here. To combine it with nice scalar formatting (in the link as well) you can use something like:
plt.gca().xaxis.set_major_formatter(FuncFormatter(
lambda t,p,f=yourfunc: ScalarFormatter().format_data_short(f(t))))
You probably want to initialize the ScalarFormatter outside.

draw order of grid lines and data in pyplot [duplicate]

This question already has answers here:
Matplotlib: draw grid lines behind other graph elements
(7 answers)
Closed 7 years ago.
I've got a library function which plots data into a pyplot figure containing several subplots.
I just added grid lines to all of the subplots but they overlay the actual data but I would prefer them to be in the background.
I've tried changing the order in which the plotting and ax.plot() ax.grid() commands are executed but that has no influence.
Is there a way to force the grid into the background?
Related bonus question: I'm also using axhline to designate the x=0 line but it always assumes the grid colour even though it is being specified in a different one ...
The way the code currently works:
def plot_the_things(fig=None):
# in case no figure is provided, make a new one,
# otherwise add to the existing one
plot_fig=fig if fig else plt.figure()
#[...some calculations of data ...]
plot_ax1 = plot_fig.add_subplot(3,3,1)
plot_ax1.axhline(y=0, ls='-', color='0.5')
plot_ax1.plot(self.diff_3[:,0],self.diff_3[:,1])
# [...setting labels, adapt axes limits in case the new data needs wider ones..]
plot_ax1.grid(b=True, which='major', axis='both', c='0.75', ls='-', linewidth=1)
# this is repeated in similar fashion for the other axes -- there are 9 of
# them, each plotting something different in a different axes
This function is called several times over. More precisely: It's actually part of a class. I have multiple instances of this class and call all of them, passing in the same figure object. Each instance then draws its own data, which works fine, and even the axhline() was shown properly (below the data!) but after I put in the command to add the grid, it always shows up on top of the data and covers the axhline, which is annoying.
... any way to fix this?
(I think I could and maybe should also move all the things that only need to run once to a place where they aren't repeatedly executed but time and mental resources are scant right now, so I went with the quickest way that worked... but I wouldn't expect this to change anything)
Use the zorder kwarg to your plot and axhline calls. The grid is plotted at zorder=2.5, so place the axhline and plot above this:
plot_ax1.axhline(y=0, ls='-', color='0.5', zorder=3)
plot_ax1.plot(self.diff_3[:,0],self.diff_3[:,1], zorder=4)
plot_ax1.grid(b=True, which='major', axis='both', c='0.75', ls='-', linewidth=1)
More info: here, and here.

turn off axis border for polar matplotlib plot

I have a polar axes in matplotlib that has text which extends outside of the range of the axes. I would like to remove the border for the axis -- or set it to the color of the background so that the text is more legible. How can I do this?
Simply increasing the size of the axes is not an acceptable solution (because the figure is embeddable in a GUI and it becomes too small if this is done). Changing the color of the background to be black so that the border is not visible is also not an acceptable solution.
A considerable amount of code that does various parts of plotting things is omitted, but here is the generation of the figure and axes itself:
import pylab as pl
fig = pl.figure(figsize=(5,5), facecolor='white')
axes = pl.subplot(111, polar=True, axisbg='white')
pl.xticks([])
pl.yticks([])
pl.ylim(0,10)
# ... draw lots of things
Just add this line: axes.spines['polar'].set_visible(False) and it should go away!
eewh, all the anatomy terms.
A more general way (independent of coordinate systems) is:
axes.axis("off")

Using matplotlib, how do I whiten the background of the axis label?

Is there a way to whiten out the background of the axis label so that when it crosses the axis line itself, the latter does not run through it?
For example, this script (the best I managed so far)
#!/usr/bin/python
import matplotlib.pyplot as plt
xx=[1,2,3]
yy=[2,3,4]
dy=[0.1,0.2,0.05]
fig=plt.figure()
ax=fig.add_subplot(111)
ax.errorbar(xx,yy,dy,fmt='ro-',ms=6,elinewidth=4)
ax.set_xlim([0.,3.4])
ax.set_ylim([0.,4.4])
ax.set_xlabel(r'$T/t$',fontsize=16)
ax.set_ylabel(r'$S(\mathbf{Q})L^{1+\eta}$',fontsize=16)
# position the axis labels
ax.xaxis.set_label_coords(1,0)
ax.yaxis.set_label_coords(0.1,0.93)
ax.yaxis.get_label().set_rotation('horizontal')
ax.yaxis.get_label().set_backgroundcolor('w')
#ax.yaxis.get_label().set_zorder(222) #doesn't do the trick
plt.show()
produces almost what I'm looking for, but still the y-axis runs over the label: .
By default, the left spine has a zorder of 2.5. For some reason this seems to cause problems; maybe there's something in the code which only works if they're integral? Anyway, if you add
ax.spines['left'].set_zorder(2)
or more generally
ax.spines['left'].set_zorder(ax.yaxis.get_label().get_zorder()-1)
before the show, it should work. Also, set_ylabel returns the ylab object itself, so if you use "ylab = ax.set_ylabel(stuff)" you can avoid all the ax.yaxis.get_label() calls later.
Does this link help you?
http://matplotlib.sourceforge.net/faq/howto_faq.html#automatically-make-room-for-tick-labels
You can simply shift the y-axis to the right to allows some space for the $S(\mathbf{Q})L^{1+\eta}$ mark be fully placed before the axis line.

Categories

Resources