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]
Related
I'm trying to set up an inverted axis bar chart such that smaller numbers have bigger bars, and those bars start from the top of the bar chart. Ideally, my y-axis would vary from 10e-10 on the bottom to 10e-2 on the top, and would look similar to this excel plot:
In presenting this data, getting to a lower number is better, so I was hoping to represent this with bigger bars, rather than the absence of bars.
Inverting the y-axis limits makes the bars start from the top, but it does not solve my problem, since the smaller bars are still associated with the smaller numbers. Is there some way to move the origin, and specify that bars should be drawn from the origin to the appropriate tick on the axis?
The data and code are really not so important here, but here is an excerpt:
plt.rcParams['xtick.bottom'] = plt.rcParams['xtick.labelbottom'] = False
plt.rcParams['xtick.top'] = plt.rcParams['xtick.labeltop'] = True
barVals = [ 10**(-x) for x in range(10) ]
ticks = [x for x in range(10)]
plt.bar(ticks, barVals)
plt.yscale('log')
plt.ylim([1e-2, 1e-10])
#plt.axes().spines['bottom'].set_position(('data', 0))
plt.show()
The resultant plot has bigger bars for bigger numbers and smaller bars for smaller numbers. I could instead plot the difference between each value and the maximum, but I was hoping there was some built-in way to do this in matplotlib/pyplot.
Using matlab, the functionality I am looking for is setting the axis base value:
b = bar(ticks, barValues);
b(1).BaseValue = 1e0;
Given the way a normal log-scaling of the axis works, I think your best bet is to scale the data manually, and adjust the labels to match. The following is a simple example to get you started, using the OO API:
data = 10.0**np.arange(-2, -7, -1)
plot_data = np.log10(data)
fig, ax = plt.subplots()
ax.bar(np.arange(data.size) + 1, plot_data)
You can set the ticks manually, but I would recommend using a Formatter:
from matplotlib.ticker import StrMethodFormatter
...
ax.yaxis.set_major_formatter(StrMethodFormatter('$10^{{{x}}}$'))
This particular Formatter accepts a template string suitable for str.format and interpolates it with the tick value bound to the name x. If you only wanted to display the integer portion of the exponent, you could initialize it as
StrMethodFormatter('$10^{{{x:.0f}}}$')
The symbols $...$ tell matplotlib that the string is LaTeX, and {{...}} are escaped curly braces to tell LaTeX to group the entire exponent as a superscript.
To adjust the limits of your chart:
ax.set_ylim([plot_data.min() - 0.5, -1])
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.
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 using Matplotlib to plot data on Ubuntu 15.10. My y-axis has numeric values and my x-axis timestamps.
I'm having the problem that the date labels intersect with each other making it look bad. How do I increase the distance between the x-axis ticks/labels to be evenly spaced still? Since the automatic selection of ticks was bad I'm okay with manually setting the amount of date ticks. Any other solution is appreciated, too.
Besides, I'm using the following DateFormatter:
formatter = DateFormatter('%m/%d/%y')
axis = plt.gca()
axis.xaxis.set_major_formatter(formatter)
You could add the following to your code:
plt.gcf().autofmt_xdate()
Which automatically formats the x axis for you (rotates the labels to something like 30 degrees etc).
You can also manually set the amount of x ticks that show on your x-axis to avoid it getting crowded, by using the following:
max_xticks = 10
xloc = plt.MaxNLocator(max_xticks)
ax.xaxis.set_major_locator(xloc)
I personally use both together as it makes the graph look much nicer when using dates.
You can simply set the locations you want to be labeled:
axis.set_xticks(x[[0, int(len(x)/2), -1]])
where x would be your array of timestamps
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)