Same ticks in log-plot - python

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)))

Related

Puzzling behavior for matplotlib.pyplot yticks([])

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.

Matplotlib dual x-axis logarithmic ticks

I've set the upper x-axis manually (the conversion is 1.218x the values on the lower x-axis) and I'd like the upper minor logarithmic ticks to move up the scale by 1.218x too. Any suggestions?
fig = plt.figure()
ax1 = fig.add_subplot(111)
ax2 = ax1.twiny()
X = np.linspace(0,10000000, 1000000)
ax1.semilogx(X, zero, label='$\mathbb{P} (X=0)$')
ax1.semilogx(X, one, label='$\mathbb{P} (X=1)$')
ax1.semilogx(X, two+more, label='$\mathbb{P} (X\geq2)$')
ax1.set_xlabel(r"Particle Concentration m$^{-3}$")
ax1.set_ylabel(r"Probability of occurrence")
ax1.legend(loc=6)
ax1.grid()
ax2.semilogx(X, one, label='one', alpha = 0)
ax2.set_xlim(ax1.get_xlim())
ax2.set_xticks([12.18323586744639, 121.8323586744639, 1218.323586744639, 12183.23586744639, 121832.3586744639, 1218323.586744639])
ax2.set_xticklabels(['10$^1$','10$^2$','10$^3$','10$^4$','10$^5$','10$^6$'])
ax2.set_xlabel(r"Disdrometer Particle Count (min$^{-1}$)")
plt.show()
EDIT: Rewriting after your comment below.
There will be a way to move the minor ticks but actually I think your approach here is misguided. Looking close you aren't using ax2 to plot anything: you just want it as an alternative scale. You are messing with the ticks and ticklabels when as a way of faking changing the limits. It would be much easier to just change that limits (so that matplotlib can handle the ticks etc automatically).
Replace your code above with
ax2.set_xscale("log", nonposx='clip')
ax2.set_xlim(np.array(ax1.get_xlim())/1.218)

Python Matplotlib: Dual y-axis with same tick spacing and different scale [duplicate]

I created a matplotlib plot that has 2 y-axes. The y-axes have different scales, but I want the ticks and grid to be aligned. I am pulling the data from excel files, so there is no way to know the max limits beforehand. I have tried the following code.
# creates double-y axis
ax2 = ax1.twinx()
locs = ax1.yaxis.get_ticklocs()
ax2.set_yticks(locs)
The problem now is that the ticks on ax2 do not have labels anymore. Can anyone give me a good way to align ticks with different scales?
Aligning the tick locations of two different scales would mean to give up on the nice automatic tick locator and set the ticks to the same positions on the secondary axes as on the original one.
The idea is to establish a relation between the two axes scales using a function and set the ticks of the second axes at the positions of those of the first.
import matplotlib.pyplot as plt
import matplotlib.ticker
fig, ax = plt.subplots()
# creates double-y axis
ax2 = ax.twinx()
ax.plot(range(5), [1,2,3,4,5])
ax2.plot(range(6), [13,17,14,13,16,12])
ax.grid()
l = ax.get_ylim()
l2 = ax2.get_ylim()
f = lambda x : l2[0]+(x-l[0])/(l[1]-l[0])*(l2[1]-l2[0])
ticks = f(ax.get_yticks())
ax2.yaxis.set_major_locator(matplotlib.ticker.FixedLocator(ticks))
plt.show()
Note that this is a solution for the general case and it might result in totally unreadable labels depeding on the use case. If you happen to have more a priori information on the axes range, better solutions may be possible.
Also see this question for a case where automatic tick locations of the first axes is sacrificed for an easier setting of the secondary axes tick locations.
To anyone who's wondering (and for my future reference), the lambda function f in ImportanceofBeingErnest's answer maps the input left tick to a corresponding right tick through:
RHS tick = Bottom RHS tick + (% of LHS range traversed * RHS range)
Refer to this question on tick formatting to truncate decimal places:
from matplotlib.ticker import FormatStrFormatter
ax2.yaxis.set_major_formatter(FormatStrFormatter('%.2f')) # ax2 is the RHS y-axis

customize ticks label when sharex is on in matplotlib

I have two stacked subplots which share the x axis, for both subplots visibility of ticks is set to false because I don't want to see tick labels. after having plotted both subplots, I would like to put some extra ticks on x-asis, only for second subplot, but they don't have to became the main ticks.
I mean, doing this:
#xticks = list of x points
#xlabs = list of labels
#secondplot.set_xticks(xticks)
#secondplot.set_xticklabels(xlabs)
will change the first sublplot grid according to these new ticks as if they became the new major ticks. is there a way to label just some x-axis point in second subplot without affecting the whole plots area? thank you
I know im late to the party but I faced a similar problem and want to share my solution, in case anyone else needs help.
You can use matplotlib.axes.Axes.tick_params to control the style of both major and minor ticks of the axes. Setting the tick lengths of the first subplot to 0 should do the trick:
ax.tick_params(axis="x", which="both", length=0.)
axis ("x", "y" or "both") selects the axes, on which the setting has an effect, which ("major", "minor" or "both") chooses the tick type.
Of course you can then also set major and minor ticks with ax.set_xticks(ticks, minor=False). A full example:
import matplotlib.pyplot as plt
fig, axarr = plt.subplots(2, 1, sharex="col")
axarr[0].plot(range(11))
axarr[1].plot(range(11)[::-1])
axarr[0].tick_params(axis="x", which="both", length=0.)
axarr[1].set_xticks(range(0, 11, 3))
axarr[1].set_xticks(range(0, 11), minor=True)
plt.show()
which yields: https://i.stack.imgur.com/oc7y0.png
This works for removing the tick labels from a single axis when using sharex, but I don't see a solution to also remove the ticks..
import matplotlib.pylab as pl
pl.figure()
ax1=pl.subplot(211)
ax1.plot([0,10],[0,10])
ax2=pl.subplot(212, sharex=ax1)
ax2.plot([0,10],[10,0])
pl.setp(ax1.get_xticklabels(), visible=False)

Matplotlib minor ticks

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))

Categories