I have made a plot with symlog on x-axis, and intend to make the linear region short enough (linscalex = 0.2). Please see my graph. However, the first tick label (1e-2) of the log region overlaps with the origin (0). Is there anyway to remove the tick label 1e-2?
Here is my code
plt.xscale('symlog', linthreshx = 0.05,
subsx = range(2,10), linscalex = 0.2)
As #ImportanceOfBeingErnest noted in the comments, you can simply set the ticks explicitly with
plt.gca().set_xticks([0, .1, 1, 10])
But since you ask for a more general solution, I thought to provide one - you can get the existing xticks and simply remove the second one indiscriminately with the following (probably a way to collapse this into a one-liner)
ticks = plt.xticks()[0]
ticks[1] = ticks[0]
plt.xticks(ticks[1:])
Obviously this is a bit of a blunt approach as it will always remove the second label, even if it isn't interfering.
Related
I have a plot of values w/ errorbars with a categorical variable on the X-axis, made using the errorbar method. I have followed the instructions here to create a discontinuity in the X-axis (I'm only showing points with values > or < some absolute threshold).
So far so good, with one slight issue - the axis break ends up being exactly on a data point on each side, which makes it harder to read on the axis, and also, the datapoints themselves end up split in two, which is kind of awkward.
I would like the axis break to instead be between datapoints, something like:
----(last value before break)--/ /--(first value after break)----
Is there a way to do this?
The breakpoints are determined with set_xlim, and I'm not sure if there's a way to do move them off the datapoints with a categorical x-axis...
sort_res_h = sort_res_a[sort_res_a > threshold]
sort_res_l = sort_res_a[sort_res_a < -threshold]
ax0.errorbar(sort_res_a.index, sort_res_a, yerr=chg_dpm_err, fmt='o')
ax1.errorbar(sort_res_a.index, sort_res_a, yerr=chg_dpm_err, fmt='o')
ax0.set_xlim(xmax=sort_res_h.index[-1])
ax1.set_xlim(xmin=sort_res_l.index[0])
I am going to share what I have been able to complete so far, although it is not a flawless solution. But maybe this will help you in any case. I would propose that you set your xaxis limits using the ticks positions, instead of the data. The problem is that if you take ticks as provided by default by matplotlib, sometimes there are more ticks than those that you see (for example there could be ticks before the minimum value in the xaxis or after the maximum). As in your case you seem to be setting the ticks, I think this should work (Replace the way you set your axes limits by this. I only provide the code for the ax0):
# First we get current ticks positions
ax0_xticks_positions = ax0.get_xticks()
# then we get the distance between two ticks
ax0_ticks_distance = ax0_xticks_positions[1] - ax0_xticks_positions[0]
# percentage of tick separation that we want the axis to extend beyond/before the last/first tick
percentage_add = 0.5
# set the xlim to the last tick position plus a percentage of tick distance
ax0.set_xlim(xmax = ax0_xticks_positions[-1] + percentage_add*ax0_ticks_distance)
You can play around with percentage_add until you find a value that suits you. For ax1 you would have to use the first tick:
ax1.set_xlim(xmin = ax1_xticks_positions[0] - percentage_add*ax0_ticks_distance)
The problem of this solution, is if the tick you use to fix the limit is outside the current axis limits. That would make the breakpoint go further than you would expect. To solve that, you can compare the tick position (for example ax0_xticks_positions[-1]) to the applicable axis limit (following the example ax0.get_xlim()[-1]). If the tick position is larger than the limit, you would have to use the second to last tick ax0_xticks_positions[-2]
Is there a way to anchor the ticks and tick labels of the x-axis so that they cross the y-axis at a different location than where the actual x-axis crosses the y-axis? This can basically be accomplished with:
ax = plt.gca()
ax.get_xaxis().set_tick_params(pad=5)
or
ax.xaxis.set_tick_params(pad=500)
For example:
Except that I am working with audio file inputs and the y-axis is variable (based on the highest/lowest amplitude of the waveform). Therefore, the maximum and minimum y-axis values change depending on the audio file. I am concerned that pad=NUM will be moving around relative to the y-axis.
Therefore, I am looking for a way to accomplish what pad does, but have the ticks and tick labels be anchored at the minimum y-axis value.
As a bonus, flipping this around so that the y-axis is anchored somewhere differently than the y-axis tick labels would surely benefit someone also.
In my particular case, I have the x-axis crossing the y-axis at y=0. The x-axis ticks and tick labels will sometimes be at -1.0, sometimes at -0.5, sometimes at -0.25, etc. I always know what the minimum value of the y-axis is, and therefore want it to be the anchor point for x-axis ticks and tick labels. (In fact, I am happy to do it with only the x-axis tick labels, if it is possible to treat ticks and tick labels separately). An example of this is shown in this image above (which I accomplished with pad=500).
I looked around other threads and in the documentation, but I'm either missing it or don't know the correct terms to find it.
UPDATE: I added gridlines and was getting very unexpected behavior (e.g. linestyle and linewidth didn't work as expected) due to the top x-axis being shifted. I realized yet a better way - keep the axes (turn off the splines) and simply plot a second line at (0, 0) to (max_time, 0).
ax.plot([0,times[-1]], [0,0], color='k') # Creates a 'false' x-axis at y=0
ax.spines['top'].set_color('none') # Position unchanged
ax.spines['bottom'].set_color('none') # Position unchanged
Figured it out! I was thinking about this the wrong way...
Problem: Moving the bottom x-axis to the center and padding the tick labels
Solution: Keep the bottom x-axis where it is (turn off the bottom spine) and move the top x-axis to the center (keep top spine, but turn off ticks and tick labels).
ax.spines['top'].set_position('center')
ax.spines['bottom'].set_color('none') # Position unchanged
ax.xaxis.set_tick_params(top='off')
plt.setp() as in https://matplotlib.org/stable/gallery/images_contours_and_fields/image_annotated_heatmap.html#sphx-glr-gallery-images-contours-and-fields-image-annotated-heatmap-py solved the problem for me.
I'm creating a subplot figure with 2 columns and a number of rows. I'm using the following code to move my tick labels and axis label to the right side for the right column (but still keeping the tick marks on both sides):
fig, ax = plt.subplots(4, 2, sharex=False, sharey=False)
fig.subplots_adjust(wspace=0, hspace=0)
for a in ax[:,1]:
a.yaxis.tick_right()
a.yaxis.set_ticks_position('both')
a.yaxis.set_label_position('right')
Then, because the subplots are close together (which is what I want, I don't want any padding in between the plots), the top and bottom y-tick labels overlap between plots. I have attempted to fix this using the method described here (this selects only those ticks that are inside the view interval - check the link for more info):
import matplotlib.transforms as mtransforms
def get_major_ticks_within_view_interval(axis):
interval = axis.get_view_interval()
ticks_in_view_interval = []
for tick, loc in zip(axis.get_major_ticks(), axis.get_major_locator()()):
if mtransforms.interval_contains(interval, loc):
ticks_in_view_interval.append(tick)
return ticks_in_view_interval
for i,a in enumerate(ax.ravel()):
nplots = len(ax.ravel())
yticks = get_major_ticks_within_view_interval(a.yaxis)
if i != 0 and i != 1:
yticks[-1].label.set_visible(False)
if i != nplots-2 and i != nplots-1:
yticks[0].label.set_visible(False)
This seems to work fine for the left column, but in the right column the overlapping ticks are still visible. Does anyone know why this happens, and how to fix it? I just can't seem to figure it out.
I have finally found the solution, so I figured I'd put it here as well in case someone ever has the same problem (or if I forget what I did, haha). I found out when I happened upon the following page: http://matplotlib.org/1.3.1/users/artists.html
What I didn't realize is that the labels on the left and the right of the y-axis can be modified independently of each other. When using yticks[0].label.set_visible(False), the label refers only to the left side labels, so the right side labels stay unchanged. To fix it, I replaced
yticks[0].label.set_visible(False)
by
yticks[0].label1.set_visible(False)
yticks[0].label2.set_visible(False)
(and the same for yticks[-1]). Now it works like a charm!
Generally I've found that problems with overlap in matplotlib can be solved by using
plt.tight_layout()
have you tried that?
I have a figure with a log axis
and I would like to relabel the axis ticks with logs of the values, rather than the values themselves
The way I've accomplished this is with
plt.axes().set_xticklabels([math.log10(x) for x in plt.axes().get_xticks()])
but I wonder if there isn't a less convoluted way to do this.
What is the correct idiom for systematically relabeling ticks on matplotlib plots with values computed from the original tick values?
Look into the Formatter classes. Unless you are putting text on your ticks you should almost never directly use set_xticklabels or set_yticklabels. This completely de-couples your tick labels from you data. If you adjust the view limits, the tick labels will remain the same.
In your case, a formatter already exists for this:
fig, ax = plt.subplots()
ax.loglog(np.logspace(0, 5), np.logspace(0, 5)**2)
ax.xaxis.set_major_formatter(matplotlib.ticker.LogFormatterExponent())
matplotlib.ticker.LogFormatterExponent doc
In general you can use FuncFormatter. For an example of how to use FuncFomatter see matplotlib: change yaxis tick labels which one of many examples floating around SO.
A concise example for what you want, lifting exactly from JoeKington in the comments,:
ax.xaxis.set_major_formatter(
FuncFormatter(lambda x, pos: '{:0.1f}'.format(log10(x))))
I tried hard, but I'm stuck with matplotlib here. Please overlook, that the mpl docs are a bit confusing to me . My question concerns the following:
I draw a symmetrical n*n matrix D with matshow function. That works.
I want to do the same thing, just with different order of (the n) items in D
D = [:,neworder]
D = [neworder,:]
Now, how do I make the ticks reproduce this neworder, preferably using additionally MaxNLocator?
As far as I understand...
set_xticklabels assigns labels to the ticks by order, independently of where the ticks are set?!
set_xticks (mpl docs: 'Set the x ticks with list of ticks') here I'm really not sure what it does. Can somebody explain it precisely? I don't know, whether these functions are helpful in my case at all. Maybe even things are different between using a common xy plot and matshow.
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca()
D = np.arange(100).reshape(10,10)
neworder = np.arange(10)
np.random.shuffle(neworder)
D = D[:,neworder]
D = D[neworder, :]
# modify ticks somehow...
ax.matshow(D)
plt.show()
Referring to Paul's answer, think I tried smth like this. Using the neworder to define positions and using it for the labels, I added plt.xticks(neworder, neworder) as tick-modifier. For example with neworder = [9 8 4 7 2 6 3 0 1 5] I get is this
The order of the labels is correct, but the ticks are not. The labels should be independently show the correct element independently of where the ticks are set. So where is the mistake?
I think what you want to do is set the labels on the new plot to show the rearranged order of the values. Is that right? If so, you want to keep the tick locations the same, but change the labels:
plt.xticks(np.arange(0,10), neworder)
plt.yticks(np.arange(0,10), neworder)
Edit: Note that these commands must be issued after matshow. This seems to be a quirk of matshow (plot does not show this behaviour, for example). Perhaps it's related to this line from the plt.matshow documentation:
Because of how :func:matshow tries to set the figure aspect ratio to be the
one of the array, if you provide the number of an already
existing figure, strange things may happen.
Perhaps the safest way to go is to issue plt.matshow(D) without first creating a figure, then use plt.xticks and plt.yticks to make adjustments.
Your question also asks about the set_ticks and related axis methods. The same thing can be accomplished using those tools, again after issuing matshow:
ax = plt.gca()
ax.xaxis.set_ticks(np.arange(0,10)) # turn on all tick locations
ax.xaxis.set_ticklabels(neworder) # use neworder for labels
Edit2: The next part of your question is related to setting a max number of ticks. 20 would require a new example. For our example I'll set the max no. of ticks at 2:
ax = plt.gca()
ax.xaxis.set_major_locator(plt.MaxNLocator(nbins=3)) # one less tick than 'bin'
tl = ax.xaxis.get_ticklocs() # get current tick locations
tl[1:-1] = [neworder[idx] for idx in tl[1:-1]] # find what the labels should be at those locs
ax.xaxis.set_ticklabels(tl) # set the labels
plt.draw()
You are on the right track. The plt.xticks command is what you need.
You can specify the xtick locations and the label at each position with the following command.
labelPositions = arange(len(D))
newLabels = ['z','y','x','w','v','u','t','s','q','r']
plt.xticks(labelPositions,newLabels)
You could also specify an arbitrary order for labelPositions, as they will be assigned based on the values in the vector.
labelPositions = [0,9,1,8,2,7,3,6,4,5]
newLabels = ['z','y','x','w','v','u','t','s','q','r']
plt.xticks(labelPositions,newLabels)