I have a plot with an Axes, and I call:
axes.set_xscale('log')
After that I cannot see any tick label along the x axis, when I use axes.set_xticks(my_ticks). Without the log I can see the tick labels.
How can I show my ticks on the log scale?
axes.set_xticks(my_ticks) sets the position of the ticks, it normally automatically updates the tick labels, but it seems it doesn't. You can use set_xticklabels() to set them yourself.
You can use tick_params() to change properties of the ticks (like length, color etc) themselves.
Related
I'm making a plotting app which should, through a tkinter gui, allow the user to create plots to graph spectral data, and modify the plots.
I'm trying to make it so the user can change the limits of the x and y axes after data has been plotted. Looking through the mpl docs, it seems like the obvious solution is to use the set_xlim and set_ylim methods. However, if these methods are invoked after a line is plotted, the line can no longer be seen, and there are no intermediate axis ticks. Through my other widgets, I know the lines are still contained in the lines attribute of the axis object, they just aren't visible.
My question is, is there a way to 'set' the the axes after a line has been plotted, so that the data will adjust to it, i.e be visible after adjusting the axes, and have ticks like it did before being adjusted? I'll show images of the graph to illustrate my situation. The class definitions are rather long, so I'll just show the use of set_xlim and set_ylim
The plot before changing the axis limits:
The plot after changing the x limits:
if all(entry.get() for entry in {self.lxlimEntry, self.rxlimEntry}):
self.master.controller.get_plots()[self.plotVar.get()].axes[0].set_xlim(self.lxlimEntry.get(), self.rxlimEntry.get())
if all(entry.get() for entry in {self.lylimEntry, self.rylimEntry}):
self.master.controller.get_plots()[self.plotVar.get()].axes[0].set_ylim(self.lylimEntry.get(), self.rylimEntry.get())
The Entry widgets are contained in a Toplevel, instantiated by a page of the application (master), and the Entries are where the user inputs the new x and y limits. The controller is the App backend.
I've got scatter plot with colorbar which I save as PNG image. I need the plot to be of a certain figsize but adding colorbar scales original plot.
import pylab as plt
plt.figure(figsize=FIGSIZE)
plt.scatter(X, Y, c=Z, s=marker_size, norm=LogNorm(), vmin=VMIN, vmax=VMAX, cmap=CMAP,rasterized=True,lw=0,)
CB = plt.colorbar(ticks=TICKS, format=FORMAT)
How could I save original plot (with figsize set as above) and colorbar as two separate images?
The obvious answer is "plot your colorbar separately". You need to create a new figure window and plot your colorbar there, in order to prevent your first figure from being distorted. Small example:
import matplotlib.pyplot as plt
import numpy as np # only for dummy data
X,Y = np.mgrid[-2:3,-2:3]
Z = np.random.rand(*X.shape)
FIGSIZE = (2,3)
plt.figure(figsize=FIGSIZE)
mpb = plt.pcolormesh(X,Y,Z,cmap='viridis')
# plot the original without a colorbar
plt.savefig('plot_nocbar.png')
# plot a colorbar into the original to see distortion
plt.colorbar()
plt.savefig('plot_withcbar.png')
# draw a new figure and replot the colorbar there
fig,ax = plt.subplots(figsize=FIGSIZE)
plt.colorbar(mpb,ax=ax)
ax.remove()
plt.savefig('plot_onlycbar.png')
# save the same figure with some approximate autocropping
plt.savefig('plot_onlycbar_tight.png',bbox_inches='tight')
Consider the following four figures that were produced (click to view properly):
The first is a saved version of the figure without a call to colormap. This is fine, this is what you want to preserve. The second figure shows what happens if we call colorbar without any extra fuss: it takes some space from the original figure, and this is what you want to prevent.
You have to open a new figure (and axes) using plt.subplots, with the size of your original figure. This way you can be sure that the produced colorbar will be the same size as if it was drawn in your original figure. In the above setup I let matplotlib determine the size of the colorbar itself; but then afterward we need to delete the auxiliary axes that would pollute the resulting plot. (The other option would be to create a single axes in the new figure manually, with the expected size of the colorbar. I suspect this is not a feasible course of action.)
Now, as you can see in the third plot, the empty space left after the deleted axes is clearly visible in the resulting plot (but the size of the colorbar is perfect, correspondingly). You can either cut this white space off manually in post-production, or use something that autocrops your colorbar image.
I also included a version of the plot wherein matplotlib itself crops most of the figure: the bbox_inches='tight' keyword argument to savefig does exactly this. The upside is that the resulting image file only contains the colorbar (as seen above in the fourth image), but the size of the resulting colorbar will be slightly different from your original. Depending on your specific needs, you'll need to experiment with the available methods to come up with a solution that's most convenient for you.
Is there a way to turn of xticks and yticks using matplotlibrc or another matplotlib config method? The only way I see currently is to set the sizes of ticks and tick labels to zero. That seems an odd way, given that I can set_xticks(())
You can do this with tick_params
plt.tick_params(axis='both', which='both')
This is affecting both axis (other options are x or y). It also affects both major and minor ticks (other options are major or minor)
This will leave ticks around the outer edge, but not in the plot. If you want the edge ticks removed, you can add:
bottom='off'
top='off'
left='off'
right='off'
If you want to remove the labels, you'll want to turn these off
labelbottom='off'
labeltop='off'
labelleft='off'
labelright='off'
Is there a way to enlarge the axis-scale label in matplotlib (circled in red in the enlarged plot below)?
I've used ax.tick_params() to successfully edit the tick labels, but I haven't been able to find anything about this specific piece of the plot.
Worse comes to worst, I could go with a manual text() insertion, but I'd like something more direct if possible.
Add a line like this
ax.xaxis.get_children()[1].set_size(15)
To change your major tick scale label (I guess we can call it so) to 15 points, if you plot the plot on ax.
If you plot using the pyplot API, add a line of ax=plt.gca() as well.
I have a matplotlib axes instance inside which I'm animating an AxesImage via blitting.
What I'd like to do is animate the ticks on the x-axis as well.
I am updating the data on the AxesImage (and subsequently) drawing its artist quite frequently, and on each update I'd like to move one extra tick placed to highlight the position of something.
This is what I'm doing right now:
axis = axes.get_xaxis
im.set_data(new_data)
axis.set_ticks([10,20,30,x,t])
axis.set_ticklabels(["p", "u", "z", "z", "i"])
axes.draw_artist(im)
axes.draw_artist(axis)
While I see the ticks correctly updating, the labels are not. I think that the axes bbox does not include the axes, is this possible? If so, how can I animate it? Should I copy and restore from somewhere else?
The axes bbox doesn't include anything outside of the "inside" of the axes (e.g. it doesn't include the tick labels, title, etc.)
One quick way around this is to just grab the entire region of the figure when you're blitting. (E.g. background = canvas.copy_from_bbox(fig.bbox))
This can cause problems if you have multiple subplots and only want to animate one of them. In that case, you can do something along the lines of background = canvas.copy_from_bbox(ax.bbox.expanded(1.1, 1.2)). You'll have to guesstimate the ratios you need, though.
If you need the exact extent of the tick labels, it's a bit trickier. The easiest way is to iterate through the ticklabel objects and get the union with ax.bbox. You can make this a one-liner: ax.bbox.union([label.get_window_extent() for label in ax.get_xticklabels()]).
At any rate, one of those three options should do what you need, I think.