Matplotlib increase the number of minor ticks - matplotlib

When I turn on minor ticks in a plot with something like plt.minorticks_on(), I often want to have a larger number of minor ticks.
Is there a simple method to achieve that?

I found a good answer to my question, so in order to be able to find it more quickly next time, I'm including it here:
To have minor ticks every 10 and major ticks every 100 on the x-axis:
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator
plt.plot(my_data)
plt.minorticks_on()
ax = plt.gca()
ax.xaxis.set_major_locator(MultipleLocator(100)) # major ticks every 100 (optional)
ax.xaxis.set_minor_locator(MultipleLocator(10)) # minor ticks every 10
In my original plot, ticks defaulted to 100 for major ticks and 20 for minor (5 minor for every major). With this code I get 10 minor ticks for every major.
This is not quite what I was after, but makes it easy enough to get the desired effect.

Related

How to show min and max values at the end of the axes

I generate plots like below:
from pylab import *
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker
import matplotlib.ticker as ticker
rcParams['axes.linewidth'] = 2 # set the value globally
rcParams['font.size'] = 16# set the value globally
rcParams['font.family'] = ['DejaVu Sans']
rcParams['mathtext.fontset'] = 'stix'
rcParams['legend.fontsize'] = 24
rcParams['axes.prop_cycle'] = cycler(color=['grey','b','g','r','orange'])
rc('lines', linewidth=2, linestyle='-',marker='o')
rcParams['axes.xmargin'] = 0
rcParams['axes.ymargin'] = 0
t = arange(0,21,1)
v = 2.0
s = v*t
plt.figure(figsize=(12, 4))
plt.plot(t,s,label='$s=%1.1f\cdot t$'%v)
plt.title('Wykres drogi w czasie $s=v\cdot t$')
plt.xlabel('Czas $t$, s')
plt.ylabel('Droga $s$, m')
plt.autoscale(enable=True, axis='both', tight=None)
legend(loc='best')
plt.xlim(min(t),max(t))
plt.ylim(min(s),max(s))
plt.grid()
plt.show()
When I am changing the value t = arange(0,21,1) for example to t = arange(0,20,1) which gives me for example on the x axis max value= 19.0 my max value dispirs from the x axis. The same situation is of course with y axis.
My question is how to force matplotlib to produce always plots where on the axes are max values just at the end of the axes like should be always for my purposes or should be possible to chose like an option?
Imiage from my program in Fortan I did some years ago
Matplotlib is more efficiens that I use it but there should be an opition like that (the picture above).
In this way I can always observe max min in text windows or do take addiional steps to make sure about max min values. I would like to read them from axes and the question is ...Are there such possibilites in mathplotlib ??? If not I will close the post.
Axes I am thinking about more or less
I see two ways to solve the problem.
Set the axes automatic limit mode to round numbers
In the rcParams you can do this with
rcParams['axes.autolimit_mode'] = 'round_numbers'
And turn off the manual axes limits with min and max
plt.xlim(min(t),max(t))
plt.ylim(min(s),max(s))
This will produce the image below. Still, the extreme values of the axes are shown at the nearest "round numbers", but the user can approximately catch the data range limits. If you need the exact value to be displayed, you can see the second solution which cannot be directly used from the rcParams.
or – Manually generate axes ticks
This solution implies explicitly asking for a given number of ticks. I guess there is a way to automatize it depending on the axes size etc. But if you are dealing with more or less every time the same graph size, you can decide a fixed number of ticks manually. This can be done with
plt.xlim(min(t),max(t))
plt.ylim(min(s),max(s))
plt.xticks(np.linspace(t.min(), t.max(), 7)) # arbitrary chosen
plt.yticks(np.linspace(s.min(), s.max(), 5)) # arbitrary chosen
generated the image below, quite similar to your image example.

Add more deciamals to matplotlib chart?

Simple question and I tried a quick search before posting but could not find. I am trying to do a chart and axis Y consists of price.
However Y is scaled like attached image and has only 1 decimal. How do I make y axis more precise with 2 decimals and more entries with increment of 0.01?
::Update with code::
# Make the plot
fig, ax = plt.subplots(figsize=(48,32))
ax.scatter(x=times, y=tidy['Price'], c=colors, s=tidy['Volume'] / 4000, alpha=0.4)
ax.ticklabel_format(axis='y', style='plain')
ax.set(
xlabel='Time',
xlim=(xmin, xmax),
ylabel='Price'
)
ax.xaxis.set_major_formatter(DateFormatter('%H:%M'))
One method to increase the number of decimals is to use a formatter for your axis:
from matplotlib.ticker import FormatStrFormatter
ax.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))
However, this method will not increase the number of ticks on your axis. You can set the yticks with .01 increments using the following but you might end up over-saturating the axis might want to increase the increment size.
ax.set_yticks(np.arange(108.30,108.71,.01))

Better ticks and tick labels with log scale

I am trying to get better looking log-log plots and I almost got what I want except for a minor problem.
The reason my example throws off the standard settings is that the x values are confined within less than one decade and I want to use decimal, not scientific notation.
Allow me to illustrate with an example:
import matplotlib.pyplot as plt
%matplotlib inline
import matplotlib as mpl
import numpy as np
x = np.array([0.6,0.83,1.1,1.8,2])
y = np.array([1e-5,1e-4,1e-3,1e-2,0.1])
fig1,ax = plt.subplots()
ax.plot(x,y)
ax.set_xscale('log')
ax.set_yscale('log')
which produces:
There are two problems with the x axis:
The use of scientific notation, which in this case is counterproductive
The horrible "offset" at the lower right corner
After much reading, I added three lines of code:
ax.xaxis.set_major_formatter(mpl.ticker.ScalarFormatter())
ax.xaxis.set_minor_formatter(mpl.ticker.ScalarFormatter())
ax.ticklabel_format(style='plain',axis='x',useOffset=False)
This produces:
My understanding of this is that there are 5 minor ticks and 1 major one. It is much better, but still not perfect:
I would like some additional ticks between 1 and 2
Formatting of label at 1 is wrong. It should be "1.0"
So I inserted the following line before the formatter statement:
ax.xaxis.set_major_locator(mpl.ticker.MultipleLocator(0.2))
I finally get the ticks I want:
I now have 8 major and 2 minor ticks. Now, this almost looks right except for the fact that the tick labels at 0.6, 0.8 and 2.0 appear bolder than the others. What is the reason for this and how can I correct it?
The reason, some of the labels appear bold is that they are part of the major and minor ticklabels. If two texts perfectly overlap, they appear bolder due to the antialiasing.
You may decide to only use minor ticklabels and set the major ones with a NullLocator.
Since the locations of the ticklabels you wish to have is really specific there is no automatic locator that would provide them out of the box. For this special case it may be easiest to use a FixedLocator and specify the labels you wish to have as a list.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np
x = np.array([0.6,0.83,1.1,1.8,2])
y = np.array([1e-5,1e-4,1e-3,1e-2,0.1])
fig1,ax = plt.subplots(dpi=72, figsize=(6,4))
ax.plot(x,y)
ax.set_xscale('log')
ax.set_yscale('log')
locs = np.append( np.arange(0.1,1,0.1),np.arange(1,10,0.2))
ax.xaxis.set_minor_locator(ticker.FixedLocator(locs))
ax.xaxis.set_major_locator(ticker.NullLocator())
ax.xaxis.set_minor_formatter(ticker.ScalarFormatter())
plt.show()
For a more generic labeling, one could of course subclass a locator, but we would then need to know the logic to use to determine the ticklabels. (As I do not see a well defined logic for the desired ticks from the question, I feel it would be wasted effort to provide such a solution for now.)

Python matplotlib: fractional logscale

I would like to plot some data with a fractional logscale, such that the y axis has the ticks at 10^(-0.1), 10^(-0.2), 10^(-0.3), etc.
The problem is that when I plot my data, there are only ticks at 10^0 and 10^-1, which leaves the slope of the line too slight to see.
Is is possible to set a fractional logscale this way?
Thanks
It sounds like you want tick labels, not the tick marks in particular. In most figures, the minor tick marks are already there where you want them.
The following may then work, though I would think there's an easier way. Note that I'm applying labels to the minor tick marks only: the (two) major tick marks already have a label. Unfortunately, the fonts of the two types of tick marks are not the same; I think that's a result of the LaTeX equation usage.
import numpy as np
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
X = np.logspace(0, 3)
Y = X**-0.2
plt.plot(X,Y)
plt.yscale('log')
yticks = np.linspace(-0.1, -0.9, 9)
ax.set_yticks(10**yticks, minor=True)
ax.set_ylim(0.1, 1)
ax.set_yticklabels(['$10^{{{:.1f}}}$'.format(ytick) for ytick in yticks], minor=True)
plt.show()
which results in:
For the issue of the different label fonts, you can manually change the major tick labels:
ax.set_yticks([1, 0.1])
ax.set_yticklabels(['$10^0$', '$10^{-1}$'])
(and probably the same for the x-axis).

matplotlib ticks thickness

Is there a way to increase the thickness and size of ticks in matplotlib without having to write a long piece of code like this:
for line in ax1.yaxis.get_ticklines():
line.set_markersize(25)
line.set_markeredgewidth(3)
The problem with this piece of code is that it uses a loop which costs usually a lot of CPU usage.
A simpler way is to use the set_tick_params function of axis objects:
ax.xaxis.set_tick_params(width=5)
ax.yaxis.set_tick_params(width=5)
Doing it this way means you can change this on a per-axis basis with out worrying about global state and with out making any assumptions about the internal structure of mpl objects.
If you want to set this for all the ticks in your axes,
ax = plt.gca()
ax.tick_params(width=5,...)
Take a look at set_tick_params doc and tick_params valid keywords
You can change all matplotlib defaults using rcParams like in
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
# set tick width
mpl.rcParams['xtick.major.size'] = 20
mpl.rcParams['xtick.major.width'] = 4
mpl.rcParams['xtick.minor.size'] = 10
mpl.rcParams['xtick.minor.width'] = 2
x = np.linspace(0., 10.)
plt.plot(x, np.sin(x))
plt.show()
You can use matplotlib.pyplot.setp
plt.setp(ax.yaxis.get_ticklines(), 'markersize', 25)
plt.setp(ax.yaxis.get_ticklines(), 'markeredgewidth', 3)
You can also use list comprehension, although not having a return value probably does not make much sense, besides reducing the number of lines in the code see e.g. here
[line.set_markersize(25) for line in ax1.yaxis.get_ticklines()]
[line.set_markeredgewidth(3) for line in ax1.yaxis.get_ticklines()]