Matplotlib add gridlines not working as expected [duplicate] - matplotlib

Does anyone know how to show the labels of the minor ticks on a logarithmic scale with Python/Matplotlib?

You can use plt.tick_params(axis='y', which='minor') to set the minor ticks on and format them with the matplotlib.ticker FormatStrFormatter. For example,
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import FormatStrFormatter
x = np.linspace(0,4,1000)
y = np.exp(x)
plt.plot(x, y)
ax = plt.gca()
ax.set_yscale('log')
plt.tick_params(axis='y', which='minor')
ax.yaxis.set_minor_formatter(FormatStrFormatter("%.1f"))
plt.show()

One option is to use matplotlib.ticker.LogLocator
import numpy
import pylab
import matplotlib.pyplot
import matplotlib.ticker
## setup styles
from matplotlib import rc
rc('font', **{'family': 'sans-serif', 'sans-serif': ['Times-Roman']})
rc('text', usetex = True)
matplotlib.rcParams['text.latex.preamble'] = [r"\usepackage{amsmath}"]
## make figure
figure, ax = matplotlib.pyplot.subplots(1, sharex = True, squeeze = True)
x = numpy.linspace(0.0, 20.0, 1000)
y = numpy.exp(x)
ax.plot(x, y)
ax.set_yscale('log')
## set y ticks
y_major = matplotlib.ticker.LogLocator(base = 10.0, numticks = 5)
ax.yaxis.set_major_locator(y_major)
y_minor = matplotlib.ticker.LogLocator(base = 10.0, subs = numpy.arange(1.0, 10.0) * 0.1, numticks = 10)
ax.yaxis.set_minor_locator(y_minor)
ax.yaxis.set_minor_formatter(matplotlib.ticker.NullFormatter())
## save figure
pylab.tight_layout()
pylab.savefig('./test.png', dpi = 200)
you would get
the only thing you need to manually adjust is the numticks input for both major and minor ticks, they both have to be a fraction of total possible number of major ticks.

Related

Matplotlib clearing the figure/axis for new plot

am trying to figure out how to clear the axis in readiness for new plotting, I have tried ax.clf(), fig.clf() but nothing is happening. where am I not doing well? at the moment am not getting any errors and am using Matplotlib vers. 3.4.3.
from tkinter import *
import matplotlib.pyplot as plt
import numpy as np
import time
import datetime
import mysql.connector
import matplotlib.dates as mdates
my_connect = mysql.connector.connect(host="localhost", user="Kennedy", passwd="Kennerdol05071994", database="ecg_db", auth_plugin="mysql_native_password")
mycursor = my_connect.cursor()
voltage_container = []
time_container = []
def analyze_voltage_time():
global ax, fig
pat_id = 1
query = "SELECT voltage, time FROM ecg_data_tbl where patient_id = " +str(pat_id)
mycursor.execute(query)
result = mycursor .fetchall()
voltage, time = list(zip(*result))
for volts in voltage:
voltage_container.append(volts)
for tim in time:
time_container.append(str(tim))
fig = plt.figure(1, figsize = (15, 6), dpi = 80, constrained_layout = True)
ax = fig.add_subplot()
ax.plot(time_container, voltage_container)
for label in ax.get_xticklabels():
label.set_rotation(40)
label.set_horizontalalignment('right')
ax.set_title("Electrocadiogram")
ax.set_xlabel("Time(hh:mm:ss)")
ax.set_ylabel("Voltage(mV)")
ax.grid(b=True, which='major', color='#666666', linestyle='-')
ax.minorticks_on()
ax.grid(b=True, which='minor', color='#666666', linestyle='-', alpha=0.2)
plt.show()
def clear_():
ax.cla()
fig.clf()
# =================================MAIN GUI WINDOW======================================
analysis_window = Tk()
analysis_window.configure(background='light blue')
analysis_window.iconbitmap('lardmon_icon.ico')
analysis_window.title("ECG-LArdmon - ANALYZER")
analysis_window.geometry('400x200')
analysis_window.resizable(width=False, height=False)
# ===========================BUTTONS===================================
analyse_btn = Button(analysis_window, text='analyze', width = 20, command=analyze_voltage_time)
analyse_btn.pack()
clear_btn = Button(analysis_window, text= 'clear', width = 20, command=clear_)
clear_btn.pack()
analysis_window.mainloop()

Matplotlib: strange minor ticks with log base 2 colorbar

I am plotting some contours with tricontourf. I want the colormap to be scaled in log values and tick labels and colours bounds to be in log base 2. Here's my code:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.tri as tri
import matplotlib.ticker as ticker
import matplotlib.colors as colors
section = 'T7'
data = np.loadtxt( section + '_values.dat')
x = data[:,0]
y = data[:,1]
z = data[:,2]
triang = tri.Triangulation(x,y)
fig1, ax1 = plt.subplots()
ax1.set_aspect('equal')
bounds = [2.**-1,2.**1,2**3,2**5,2**7,2**9]
norm = colors.LogNorm()
formatter = ticker.LogFormatter(2)
tcf = ax1.tricontourf(triang, z, levels = bounds, cmap='hot_r', norm = norm )
fig1.colorbar(tcf, format=formatter)
plt.show()
And here's the result:
What are thos ugly minor ticks and how do I get rid of them?
Using Matplotlib 3.3.0 an Mac OS
You could use cb.ax.minorticks_off() to turn off the minor tick and cb.ax.minorticks_on() to turn it on.
cb = fig1.colorbar(tcf, format=formatter)
cb.ax.minorticks_off()
matplotlib.pyplot.colorbar returns a Colorbar object which extends ColorbarBase.
You can find that two functions in the document of class matplotlib.colorbar.ColorbarBase.

How to annotate in 2 decimal places using Matplotlib

I am trying to create a heatmap displaying correlation coefficient values. I'm quite new at this, but the code below would annotate in multiple decimal places, whereas i'm trying to narrow down to 2 d.p.
Does anyone have experience with this?
import pandas_datareader.data as web
import pandas as pd
import datetime as dt
import csv
import matplotlib.pyplot as plt
from matplotlib import style
import numpy as np
import seaborn as sns
style.use('ggplot')
def visualize_data():
df = pd.read_csv('sti_joined.csv')
df.set_index('Date', inplace=True)
df_corr = df.pct_change().corr()
print(df_corr.head())
data = df_corr.values
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
# heatmap = ax.pcolor(data, cmap=plt.cm.get_cmap('RdYlGn'))
heatmap = ax.pcolor(data, cmap=plt.cm.RdYlGn)
fig.colorbar(heatmap)
ax.set_xticks(np.arange(data.shape[0]) + 0.5, minor=False)
ax.set_yticks(np.arange(data.shape[1]) + 0.5, minor=False)
ax.invert_yaxis()
ax.xaxis.tick_top()
for y in range(data.shape[0]):
for x in range(data.shape[1]):
plt.text(x + 0.5, y + 0.5, '%.4f' % data[y, x],
horizontalalignment='center',
verticalalignment='center',
)
column_labels = df_corr.columns
row_labels = df_corr.index
ax.set_xticklabels(column_labels)
ax.set_yticklabels(row_labels)
plt.xticks(rotation=90)
heatmap.set_clim(-1,1)
plt.tight_layout()
plt.show()
visualize_data()
Instead of '%.4f' % data[y, x], you can try using something like
'{0:.2f}'.format(data[y,x])

Colorbar scientific notation, change e^ to 10^

I am using scientific notation in a colorbar within a 2D plot. I want to write 10^{-3} instead of e-3. I tried to change that (see code below) but it does not work...
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker
x = np.random.rand(100)
y = np.random.rand(100)
z = np.random.rand(100)*0.001
x=x.reshape((10,10))
y=y.reshape((10,10))
z=z.reshape((10,10))
fig, ax = plt.subplots(figsize=(8,6))
cs = ax.contourf(x,y,z, 10)
plt.xticks(fontsize=16,rotation=0)
plt.yticks(fontsize=16,rotation=0)
cbar = plt.colorbar(cs,)
cbar.set_label("test",fontsize = 22)
cbar.formatter.set_scientific(True)
cbar.formatter.set_powerlimits((0, 0))
cbar.ax.tick_params(labelsize=16)
cbar.ax.yaxis.get_offset_text().set_fontsize(22)
cbar.ax.xaxis.major.formatter._useMathText = True
cbar.update_ticks()
plt.savefig("test.png")
It seems you want a ScalarFormatter with mathtext in use.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.ticker
x = np.tile(np.arange(10), 10).reshape((10,10))
y = np.repeat(np.arange(10),10).reshape((10,10))
z = np.sort(np.random.rand(100)*0.001).reshape((10,10))
fig, ax = plt.subplots(figsize=(8,6))
cs = ax.contourf(x,y,z, 10)
fmt = matplotlib.ticker.ScalarFormatter(useMathText=True)
fmt.set_powerlimits((0, 0))
cbar = plt.colorbar(cs,format=fmt)
plt.show()

Embedding small plots inside subplots in matplotlib

If you want to insert a small plot inside a bigger one you can use Axes, like here.
The problem is that I don't know how to do the same inside a subplot.
I have several subplots and I would like to plot a small plot inside each subplot.
The example code would be something like this:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
for i in range(4):
ax = fig.add_subplot(2,2,i)
ax.plot(np.arange(11),np.arange(11),'b')
#b = ax.axes([0.7,0.7,0.2,0.2])
#it gives an error, AxesSubplot is not callable
#b = plt.axes([0.7,0.7,0.2,0.2])
#plt.plot(np.arange(3),np.arange(3)+11,'g')
#it plots the small plot in the selected position of the whole figure, not inside the subplot
Any ideas?
I wrote a function very similar to plt.axes. You could use it for plotting yours sub-subplots. There is an example...
import matplotlib.pyplot as plt
import numpy as np
#def add_subplot_axes(ax,rect,facecolor='w'): # matplotlib 2.0+
def add_subplot_axes(ax,rect,axisbg='w'):
fig = plt.gcf()
box = ax.get_position()
width = box.width
height = box.height
inax_position = ax.transAxes.transform(rect[0:2])
transFigure = fig.transFigure.inverted()
infig_position = transFigure.transform(inax_position)
x = infig_position[0]
y = infig_position[1]
width *= rect[2]
height *= rect[3] # <= Typo was here
#subax = fig.add_axes([x,y,width,height],facecolor=facecolor) # matplotlib 2.0+
subax = fig.add_axes([x,y,width,height],axisbg=axisbg)
x_labelsize = subax.get_xticklabels()[0].get_size()
y_labelsize = subax.get_yticklabels()[0].get_size()
x_labelsize *= rect[2]**0.5
y_labelsize *= rect[3]**0.5
subax.xaxis.set_tick_params(labelsize=x_labelsize)
subax.yaxis.set_tick_params(labelsize=y_labelsize)
return subax
def example1():
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111)
rect = [0.2,0.2,0.7,0.7]
ax1 = add_subplot_axes(ax,rect)
ax2 = add_subplot_axes(ax1,rect)
ax3 = add_subplot_axes(ax2,rect)
plt.show()
def example2():
fig = plt.figure(figsize=(10,10))
axes = []
subpos = [0.2,0.6,0.3,0.3]
x = np.linspace(-np.pi,np.pi)
for i in range(4):
axes.append(fig.add_subplot(2,2,i))
for axis in axes:
axis.set_xlim(-np.pi,np.pi)
axis.set_ylim(-1,3)
axis.plot(x,np.sin(x))
subax1 = add_subplot_axes(axis,subpos)
subax2 = add_subplot_axes(subax1,subpos)
subax1.plot(x,np.sin(x))
subax2.plot(x,np.sin(x))
if __name__ == '__main__':
example2()
plt.show()
You can now do this with matplotlibs inset_axes method (see docs):
from mpl_toolkits.axes_grid.inset_locator import inset_axes
inset_axes = inset_axes(parent_axes,
width="30%", # width = 30% of parent_bbox
height=1., # height : 1 inch
loc=3)
Update: As Kuti pointed out, for matplotlib version 2.1 or above, you should change the import statement to:
from mpl_toolkits.axes_grid1.inset_locator import inset_axes
There is now also a full example showing all different options available.
From matplotlib 3.0 on, you can use matplotlib.axes.Axes.inset_axes:
import numpy as np
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2,2)
for ax in axes.flat:
ax.plot(np.arange(11),np.arange(11))
ins = ax.inset_axes([0.7,0.7,0.2,0.2])
plt.show()
The difference to mpl_toolkits.axes_grid.inset_locator.inset_axes mentionned in #jrieke's answer is that this is a lot easier to use (no extra imports etc.), but has the drawback of being slightly less flexible (no argument for padding or corner locations).
source: https://matplotlib.org/examples/pylab_examples/axes_demo.html
from mpl_toolkits.axes_grid.inset_locator import inset_axes
import matplotlib.pyplot as plt
import numpy as np
# create some data to use for the plot
dt = 0.001
t = np.arange(0.0, 10.0, dt)
r = np.exp(-t[:1000]/0.05) # impulse response
x = np.random.randn(len(t))
s = np.convolve(x, r)[:len(x)]*dt # colored noise
fig = plt.figure(figsize=(9, 4),facecolor='white')
ax = fig.add_subplot(121)
# the main axes is subplot(111) by default
plt.plot(t, s)
plt.axis([0, 1, 1.1*np.amin(s), 2*np.amax(s)])
plt.xlabel('time (s)')
plt.ylabel('current (nA)')
plt.title('Subplot 1: \n Gaussian colored noise')
# this is an inset axes over the main axes
inset_axes = inset_axes(ax,
width="50%", # width = 30% of parent_bbox
height=1.0, # height : 1 inch
loc=1)
n, bins, patches = plt.hist(s, 400, normed=1)
#plt.title('Probability')
plt.xticks([])
plt.yticks([])
ax = fig.add_subplot(122)
# the main axes is subplot(111) by default
plt.plot(t, s)
plt.axis([0, 1, 1.1*np.amin(s), 2*np.amax(s)])
plt.xlabel('time (s)')
plt.ylabel('current (nA)')
plt.title('Subplot 2: \n Gaussian colored noise')
plt.tight_layout()
plt.show()