I want to suppress pyplot's automatically generated tick labels in favor of my own labels. When I suppress the y-tick labels using pyplot.yticks([]) in the following Python script,
from matplotlib import pyplot as plt
num_points = 10
data = [i for i in range(num_points)]
fig = plt.figure()
ax = plt.subplot(1,1,1)
ax.plot(data)
ax.set_yscale('log')
plt.yticks([])
plt.text(1, 7, '10 data points')
plt.show()
pyplot suppresses y-tick labels, as desired:
But when the num_points is less than ten, pyplot ignores pyplot.yticks([]), inserts its automatically generated tick labels, and produces
When I supply my own tick labels by supplying a list of value and a list of labels, via plt.yticks(values_list, labels_list), pyplot.yticks() accepts my labels, but it still draws its automatically generated tick labels, overwriting my labels.
If I change the nine-point log plot to a linear plot by omitting the ax.set_yscale('log') statement, pyplot does not draw automatically generate tick labels:
The problem appears to be related to log plots with fewer than ten points. How do I suppress the automatically generated tick labels in log plots having fewer than ten points?
When working with a log axis, not only the major ticks but also the minor ticks are shown by default. You can turn them off separately. Note that when there are only very few major ticks, the minor ticks also can get a label.
Also note it usually isn't a good idea to have zero values on a log scale. As log(0) is minus infinity, matplotlib has to do some fragile guesswork about the desired tick distances.
from matplotlib import pyplot as plt
from matplotlib import ticker
num_points = 10
data = [i+2 for i in range(num_points)]
fig = plt.figure()
ax = plt.subplot(1,1,1)
ax.plot(data)
ax.set_yscale('log')
ax.text(1, 7, '10 data points')
ax.yaxis.set_major_locator(ticker.NullLocator())
ax.yaxis.set_minor_locator(ticker.NullLocator())
plt.show()
The image shows the major ticks in blue and the minor ticks in red. As in this example there is only one major tick, some of the minor ticks also got a label.
Related
I'm generating a logplot using the following lines:
# Set log-los scale and axes
ax.set_xscale('log')
ax.set_yscale('log')
ax.set_xlabel(r'$x$')
ax.set_ylabel(r'$y$')
ax.set_aspect('equal')
ax.set_xlim([1e-7, 1e0])
ax.set_ylim([1e-7, 1e0])
but the result is not what I expected:
How can I make the x-axis look like the y-axis in terms of ticks? Thanks
While it's technically true that ax.set_adjustable('datalim') brings back the minor ticks, that's only because it negates the equal axes set in this line:
...
ax.set_aspect('equal')
...
The root cause: set_aspect('equal') shrinks the x axis to the point that matplotlib decides to auto-remove the minor ticks.
To have both an equal aspect ratio and minor x ticks, use the LogLocator from the ticker module:
from matplotlib.ticker import LogLocator
ax.xaxis.set_major_locator(LogLocator(numticks=10))
ax.xaxis.set_minor_locator(LogLocator(numticks=10, subs=np.arange(0.1, 1, 0.1)))
When I'm plotting my data, I want to be able to control the major and minor ticks of my subplots. However, whatever I try I seem to be unable modify the ticks of my second subplot. I've tried applying the advice from other stackoverflow questions, unfortunately to no avail. I think I'm doing something fundamentally wrong when constructing my boxplots.
As none of my colleagues have much experience with matplotlib, I'm turning to you stackoverflow! Any help would be greatly appreciated!
Currently, my figures look like this:
On the second boxplot, I also want to force a major tick on every 10^xth and show the default log minor ticks.
Currently, I generate my boxplots as follows:
def generateLogBoxPlot(title, plot_id, xlabels, data, initializion_time, fig):
# Create an axes instance
ax = fig.add_subplot(plot_id)
# Set Log Scale
ax.set_yscale('log')
# Create the boxplot
bp = ax.boxplot(data_of_plot)
# Show Initialization Time (as a Line)
line = plt.plot(...)
# Custom rotated x-axis labels
ax.set_xticklabels(xlabels)
plt.xticks(rotation=15)
#Set Labels
plt.ylabel('Time (ms)')
ax.set_title(title)
#Show Grid
ax.get_yaxis().grid()
And I call this function like this:
# Create a figure instance
fig = plt.figure(1, figsize=(9, 3))
# Generate first subplot
generateLogBoxPlot("No Context-Dependent A.C.\nBusiness Case", #title
121, #plot_id
["Add User", "Add Role", "Add Demarcation", "Add Permission"], #labels
results["AddEntities"], #data
40000, #initializion_time
fig) #figure
line = generateLogBoxPlot("Context-Dependent A.C.\nBusiness Case",
122, #plot_id
["Add User", "Add Role", "Add Demarcation", "Add Permission"], #labels
results["AddEntities2"], #data
153000, #initialization_time
fig) #figure
#Show Legend
plt.legend(plt.plot([], [],linestyle="--", color="#A9A9A9", label="Initialization
Time"),["Initialization Time"], loc='center left', bbox_to_anchor=(1, 0.5))
#Show
plt.tight_layout()
plt.show()
Whatever I try, I only seem to be able to modify the ticks of the fist subplot. How could I force/edit them on the second subbplot?
Matplotlib automatically shows or hides minor ticks of log scales depending on the range of values and to some extent the figure size as well. With regards to a y-axis base 10 log scale, here is what I have noticed from testing variations of the example shown further below (using matplotlib 3.3.2 with default settings):
For a figure height of 4 inches (default) or more: when the range of the y-axis covers 9 integer powers or more, the log scale switches from showing major ticks with labels at every power integer as well as all minor tick marks to showing major ticks every two (or more) power integers with no minor ticks (like in your plot on the right).
For a figure height of less than 4 inches (which seems to be your case): there is a more flexible adjustment of the ticks based on the range of the y-axis and the space available.
For your particular example, I would in any case start off by sharing the y-axis to make the plots more comparable. That then leaves two options: either leave the default tick formatting as it is and make do with no minor ticks or else force minor ticks for both plots.
Examples of matplotlib default log tick behavior and how to change it
First, here is an illustration of the matplotlib default behavior with log ticks:
import numpy as np # v 1.19.2
import matplotlib.pyplot as plt # v 3.3.2
import matplotlib.ticker as ticker
# Create sample data with exponentially increasing values for x and
# the y functions and where the y functions are nearly identical
x = 10**np.linspace(0, 3, 30)
y1 = x**2
y2 = x**2.5
# Create figure and subplots containing semilogy plots
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3))
fig.suptitle('Matplotlib defaults with figure height of 3 inches', y=1.25)
ax1.set_title('Minor ticks are shown\n\n', pad=10)
ax1.semilogy(x, y1, label='y1')
ax1.legend(loc='lower right')
ax2.set_title(f'Minor ticks are not shown:\nthe y range covers less than 9 \
integer\npowers, but the figure height is <4 inches', pad=10)
ax2.semilogy(x, y2, label='y2')
ax2.legend(loc='lower right')
plt.show()
Now, what if the figure height is increased to make more space for the ticks?
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4))
fig.suptitle('Figure height of 4 inches', y=1.15)
ax1.set_title('Minor ticks are not shown:\nthe custom y-axis limits causes the\
\ny range to cover 9 integer powers', pad=10)
ax1.semilogy(x, y1, label='y1')
ax1.legend(loc='lower right')
ax1.set_ylim(1, 10**8) # the minor ticks disappear by changing the axis limits
ax2.set_title('Minor ticks are shown by default:\nthe y range covers less \
than 9 integer\npowers and the figure height is 4 inches', pad=10)
ax2.semilogy(x, y2, label='y2')
ax2.legend(loc='lower right')
plt.show()
This particular example shows that increasing the figure size can solve the problem of minor ticks not showing, but this may often not be the case.
Here is how to force minor ticks to be shown whatever the range of y and the figure size, by using the LogLocator from the matplotlib.ticker module (this example also includes a shared y-axis):
# Add sharey=True
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3), sharey=True)
fig.suptitle('Figure height of 3 inches with\ncustomized tick locator and shared \
y-axis', y=1.25)
ax1.set_title('Ticks shared by ax2\n', pad=10)
ax1.semilogy(x, y1, label='y1')
ax1.legend(loc='lower right')
ax2.set_title('Customized LogLocator:\nminor ticks are forced to be shown', pad=10)
ax2.semilogy(x, y2, label='y2')
ax2.legend(loc='lower right')
# Set ax2 major and minor tick locators with custom parameters to show
# all major and minor ticks despite the small figure height and the large
# range of y: the numticks argument must be an arbitrary number at least
# one unit above the number of integer powers covering the range of y
nticks = 9
maj_loc = ticker.LogLocator(numticks=nticks)
min_loc = ticker.LogLocator(subs='all', numticks=nticks)
ax2.yaxis.set_major_locator(maj_loc)
ax2.yaxis.set_minor_locator(min_loc)
# The tick labels are formatted as one would expect, so no need to use
# log tick formatters for this example.
plt.show()
If you want to create a plotting function that always shows minor ticks for any range of values, you need to set numticks at a high value.
References: answer by ImportanceOfBeingErnest, matplotlib Log Demo, matplotlib Tick Locators
I encounter a plotting issue I don't understand. Below code shall draw a straight line, fill the area above the line with a colour and plot several scattered dots in it. That all works but if I combine scatter and any of line or fill_between I cannot set the plot limits. The plot area is much larger than it had to be.
So how do I set the plot limits?
from matplotlib import pyplot as plt
import numpy as np
x = np.linspace(0,160,100)
MCSample = np.random.normal(112,10,1000)
YSample = np.random.normal(100,2.41,1000)
y_limit = max(160, np.max(YSample))
fig, ax = plt.subplots(1, 1)
ax.plot(x,x, label="Limit State function")
ax.scatter(MCSample,YSample, marker='.', color='b', alpha=0.5)
ax.fill_between(x,y_limit,x, alpha=0.1, color='r')
ax.set_xlim=(0,160)
ax.set_ylim=(0,y_limit)
plt.show()
I'm using Python 3.5.1 and Matplotlib 1.5.1.
In your code you are setting ax.set_xlim to equal (0,160).
All you have to do to make your code work is to get rid of the equal signs as shown below:
ax.set_xlim(0,160)
ax.set_ylim(0,y_limit) # no equals sign on these 2 lines
Now you are applying those limits to the graph rather than defining them to equal the limits.
I am trying to customize the minor ticks in a matplotlib plot. Consider the following code:
import pylab as pl
from matplotlib.ticker import AutoMinorLocator
fig, ax = pl.subplots(figsize=(11., 7.4))
x = [1,2,3, 4]
y = [10, 45, 77, 55]
errorb = [20,66,58,11]
pl.xscale("log")
ax.xaxis.set_minor_locator(AutoMinorLocator(2))
ax.yaxis.set_minor_locator(AutoMinorLocator(2))
pl.tick_params(which='both', width=1)
pl.tick_params(which='minor', length=4, color='g')
pl.tick_params(axis ='both', which='major', length=8, labelsize =20, color='r' )
pl.errorbar(x, y, yerr=errorb)
#pl.plot(x, y)
pl.show()
As far as I understood, AutoMinorLocator(n) is supposed to insert n minor ticks between each major tick, and this is what happens on a linear scale but simply cannot figure out the logic behind the placement of the minor ticks on a logscale. On the top of that, there are much more minor ticks when using errorbar() then when using the simple plot().
AutoMinorLocator is only designed to work for linear scales:
From the ticker documentation:
AutoMinorLocator
locator for minor ticks when the axis is linear and the major ticks are uniformly spaced. It subdivides the major tick interval into a specified number of minor intervals, defaulting to 4 or 5 depending on the major interval.
And the AutoMinorLocator documentation:
Dynamically find minor tick positions based on the positions of major ticks. Assumes the scale is linear and major ticks are evenly spaced.
You probably want to use the LogLocator for your purposes.
For example, to put major ticks in base 10, and minor ticks at 2 and 5 on your plot (or every base*i*[2,5]), you could:
ax.xaxis.set_major_locator(LogLocator(base=10))
ax.xaxis.set_minor_locator(LogLocator(base=10,subs=[2.0,5.0]))
ax.yaxis.set_minor_locator(AutoMinorLocator(2))
I'm having some trouble setting up a pcolormesh plot with a colorbar that includes logarithmically spaced minor tick marks on the colorbar.
The closest I've come is something like this:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
xbins = np.linspace(0, 1, 50)
ybins = np.linspace(0, 1, 50)
data = np.random.random((49,49))
fig, ax = plt.subplots()
im = ax.pcolormesh(xbins, ybins, data, norm=matplotlib.colors.LogNorm())
cb = fig.colorbar(im)
cb.ax.minorticks_on()
plt.savefig('test.png')
The trouble with this solution is that the minor ticks are spaced evenly in log space:
I'd like to set up the plot so I have evenly spaced minor ticks in linear space, which should show up unevenly spaced on this plot.
I know that I can manually set the minor tick labels using a FixedFormatter, but I'd prefer not to do that if possible since I will be making a large number of plots automatically.
I think the best way to custom colorbars' ticks is to use the "ticks" argument of the fig.colorbar method and not trying to modify the attributes of the axe that contains the colorbar.
from matplotlib.ticker import LogLocator
"..."
cb = fig.colorbar(im, ticks = LogLocator(subs=range(10)))
Added for posterity:
From this answer: #JoeKington https://stackoverflow.com/a/20079644/230468:
minorticks = p.norm(np.arange(1, 10, 2))
cb.ax.xaxis.set_ticks(minorticks, minor=True)
This is annoying that you have to create the tick locations manually, but it seems to work.