Plotting Tips

Masaru Nakanotani
CSPAR, UAH, Huntsville, AL 35805, USA
Feb/01/2021 (Date created)
Oct/05/2022 (Last modified)


In this post, I show some tips to create plots using Matplotlib.
useful sites: https://pythonmatplotlibtips.blogspot.com/, https://sabopy.com/

You can toggle input cells by clicking a prompt (i.e. In [ ]: ) or an output cell.

In [1]:
%config InlineBackend.figure_format='retina'
from spacepy import pycdf
import math as mt
import matplotlib.pyplot as plt
import numpy as np
import scipy.fft as sf
import datetime
import bisect
import matplotlib.patches as patches
import matplotlib.dates as mdates
from IPython.display import display,Math
import matplotlib as mpl
import pandas as pd
from matplotlib.gridspec import GridSpec
import matplotlib.animation as animation
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes, mark_inset
from matplotlib.ticker import ScalarFormatter
from matplotlib.colors import ListedColormap, LinearSegmentedColormap

plot parameters

You need to define these different from the cell which called matplotlib.pyplot

In [2]:
color='#2c2c2c'
#color='#ffffff'
mpl.rcParams['font.family'      ]='sans serif'
mpl.rcParams['mathtext.default' ]='regular'
mpl.rcParams['font.size'        ]=12
mpl.rcParams['figure.figsize'   ]=(4,2)
mpl.rcParams['figure.dpi'       ]=180
mpl.rcParams['axes.linewidth'   ]=1.2
mpl.rcParams['xtick.major.size' ]=5
mpl.rcParams['xtick.minor.size' ]=4
mpl.rcParams['ytick.major.size' ]=5
mpl.rcParams['ytick.minor.size' ]=3
mpl.rcParams['xtick.major.width']=1
mpl.rcParams['ytick.major.width']=1
mpl.rcParams['xtick.direction'  ]='out'
mpl.rcParams['ytick.direction'  ]='out'
mpl.rcParams['axes.facecolor'   ]='None'
mpl.rcParams['figure.facecolor' ]='None'
mpl.rcParams['axes.edgecolor'   ]=color
mpl.rcParams['xtick.color'      ]=color
mpl.rcParams['ytick.color'      ]=color
mpl.rcParams['axes.labelcolor'  ]=color
mpl.rcParams['text.color'       ]=color
mpl.rcParams['patch.edgecolor'  ]=color
mpl.rcParams['savefig.bbox'     ]='tight'
mpl.rcParams['animation.html'   ]='jshtml'

###color scheme for lines: https://www.nature.com/articles/nmeth.1618 ###
from cycler import cycler
line_cycler   = (cycler(color    =[color, '#e69f00', '#56b4e9', '#009e73', '#f0e442', '#0072b2', '#d55e00', '#cc79a7']))
#line_cycler   = (cycler(color    =[color, color, color, color])+
#                 cycler(linestyle=["-"  , "--" , "-." , ":"  ]))
mpl.rcParams['axes.prop_cycle']=line_cycler
#########################################################################
In [3]:
x = np.linspace(0., 1, 200)

plt.rc("axes", prop_cycle=line_cycler)
plt.figure(figsize=(6, 2))
plt.plot(x,   np.sin(np.pi*x), label=r"$\sin(\pi x)$")
plt.plot(x,   np.cos(np.pi*x), label=r"$\cos(\pi x)$")
plt.plot(x, np.sin(2*np.pi*x), label=r"$\sin(2\pi x)$")
plt.plot(x, np.cos(2*np.pi*x), label=r"$\cos(2\pi x) \alpha a$")
plt.plot(x, np.sin(4*np.pi*x), label=r"$\cos(4\pi x) \alpha a$")
plt.plot(x, np.cos(4*np.pi*x), label=r"$\beta cos(4\pi x) \alpha a \chi$")
plt.legend(bbox_to_anchor=(1.05, 1.05))
plt.xlabel("$x$xo0O1lIi")
plt.xlim(x[0], x[-1])
plt.ylabel("Function Values")
plt.show()
In [4]:
def plot_cube_faces(arr, ax):
    x0 = np.arange(arr.shape[2])
    y0 = np.arange(arr.shape[1])
    z0 = np.arange(arr.shape[0])
    z, y, x = np.meshgrid(z0, y0, x0,indexing='ij')
    
    xmax, ymax, zmax = max(x0), max(y0), max(z0)
    xmin, ymin, zmin = min(x0), min(y0), min(z0)
    vmin, vmax = np.min(arr), np.max(arr)

    ax.contourf(x[0,:,:],y[0,:,:],arr[-1,:,:],100,zorder=-1,
                zdir='z',offset=zmax,vmin=vmin,vmax=vmax)
    ax.contourf(x[:,0,:],arr[:,0,:],z[:,0,:],100,zorder=-1,
                zdir='y',offset=0,vmin=vmin,vmax=vmax) 
    ax.contourf(arr[:,:,-1],y[:,:,0],z[:,:,0],100,zorder=-1,
                zdir='x',offset=xmax,vmin=vmin,vmax=vmax) 
    edges_kw = dict(color='r', linewidth=1, zorder=1e3)
    ax.plot([xmax, xmax], [ymin, ymax], zmax, **edges_kw)
    ax.plot([xmin, xmax], [ymin, ymin], zmax, **edges_kw)
    ax.plot([xmax, xmax], [ymin, ymin], [zmin, zmax], **edges_kw)

x0 = np.arange(128)
y0 = np.arange(64)
z0 = np.arange(32)
z, y, x = np.meshgrid(z0, y0, x0,indexing='ij')
arr = (x + y + z) // 10
fig = plt.figure(figsize=(2,2))
ax = fig.add_subplot(111, projection='3d')
ax.set_box_aspect(aspect = (4,2,1))
plot_cube_faces(arr, ax)
plt.show()

Your own colormap

In [5]:
### you need "LinearSegmentedColormap"
#from matplotlib.colors import LinearSegmentedColormap
colors = ['#1164B4', 'white', 'yellow', 'red','black']
cmap1 = LinearSegmentedColormap.from_list("mycmap", colors)

x=np.linspace(0,2*np.pi,100); y=np.linspace(0,2*np.pi,100)

X,Y=np.meshgrid(x,y)
Z=np.sin(X)*np.cos(Y)

plt.imshow(Z,cmap=cmap1)
plt.colorbar()

plt.show()
In [6]:
def linestyle(ls, i):
    X = i * 1 * np.ones(11)
    Y = np.arange(11)
    plt.plot(X, Y, ls, color=(.0, .0, 1, 1), lw=3, ms=8,
            mfc=(.75, .75, 1, 1), mec=(0, 0, 1, 1))
    plt.text(1 * i, 10.5, ls, rotation=0, fontsize=12, va='bottom', ha='center')

linestyles = ['-', '--', ':', '-.', '.', ',', 'o', '^', 'v', '<', '>', 's',
              '+', 'x', 'd', '*', '1', '2', '3', '4', 'h', 'p', '|', '_', 'D', 'H', 'P']

n_lines = len(linestyles)

size = 40 * n_lines, 300
dpi = 120
figsize= size[0] / float(dpi), size[1] / float(dpi)
fig = plt.figure(figsize=figsize, dpi=dpi)
plt.axes([0, 0.01, 1, .9], frameon=False)

for i, ls in enumerate(linestyles):
    linestyle(ls, i)

#plt.xlim(-.2, .2 + 1*n_lines)
plt.xticks([])
plt.yticks([])

plt.show()

Multiple polar plots

In [7]:
fig, ax = plt.subplots(nrows=2,ncols=1,figsize=(10,3),sharex='all')

nx=1600
ny=64
r =np.linspace(5,40,nx)
th=np.linspace(-10,10,ny,endpoint=True)/180*np.pi
R,Th=np.meshgrid(r,th)
X=R*np.cos(Th)
Y=R*np.sin(Th)
im1=ax[0].pcolormesh(X,Y,np.sin(R),shading='auto')
ax[0].set_aspect('auto')
ax[0].spines['right'].set_color('none')
ax[0].spines['top'  ].set_color('none')
cb1=fig.colorbar(im1, ax=ax[0])

im2=ax[1].pcolormesh(X,Y,R,shading='auto')
ax[1].set_aspect('auto')
ax[1].spines['right'].set_color('none')
ax[1].spines['top'  ].set_color('none')
ax[1].set_xlim(5,38)
cb2=fig.colorbar(im2, ax=ax[1])
plt.show()
<ipython-input-7-19cf06593bdd>:10: UserWarning: The input coordinates to pcolormesh are interpreted as cell centers, but are not monotonically increasing or decreasing. This may lead to incorrectly calculated cell edges, in which case, please supply explicit cell edges to pcolormesh.
  im1=ax[0].pcolormesh(X,Y,np.sin(R),shading='auto')
<ipython-input-7-19cf06593bdd>:16: UserWarning: The input coordinates to pcolormesh are interpreted as cell centers, but are not monotonically increasing or decreasing. This may lead to incorrectly calculated cell edges, in which case, please supply explicit cell edges to pcolormesh.
  im2=ax[1].pcolormesh(X,Y,R,shading='auto')

Change color according to values

In [8]:
from matplotlib import colors

x=np.linspace(0,6*np.pi,1000)
y=2*np.sin(x)+np.random.randn(1000)

# make a color map of fixed colors
cmap = colors.ListedColormap(['orange', 'blue'])
bounds=([-5,1,5])
norm = colors.BoundaryNorm(bounds, cmap.N)
plt.scatter(x,y,s=5,c=y,cmap=cmap,norm=norm,alpha=0.5)
#plt.colorbar()
plt.hlines(1,x.min(),x.max(),linestyles='dashed')
### another way ###
#plt.scatter(x[y< 1],y[y< 1],s=5,c='orange',alpha=0.5)
#plt.scatter(x[y>=1],y[y>=1],s=5,c='blue'  ,alpha=0.5)
###################
plt.show()

Step plot

Using the 'drawstyle' parameter of plt.plot, we can obtain the same plot.

In [9]:
x = np.arange(14)
y = np.sin(x / 2)

fig=plt.figure(figsize=(6,3))
plt.step(x, y + 2, where='pre', label='pre (default)')
plt.plot(x, y + 2, 'o--', color='grey', alpha=0.3)

plt.step(x, y + 1, where='mid', label='mid')
plt.plot(x, y + 1, 'o--', color='grey', alpha=0.3)

plt.step(x, y, where='post', label='post')
plt.plot(x, y, 'o--', color='grey', alpha=0.3)

plt.grid(axis='x', color='0.95')
plt.legend(title='Parameter where:')
plt.title('plt.step(where=...)')
plt.show()

Markevery plot

In [10]:
x = np.linspace(0, 2*np.pi, 200)
y = np.cos(x)

fig,ax=plt.subplots()
ax.plot(x, y, 'o', ls='-', ms=4, markevery=10)
plt.show()
In [11]:
import matplotlib.ticker as ticker
x=np.linspace(0,8,100)
y=np.cos(x)

fig,ax=plt.subplots(ncols=2,figsize=(8,2))
ax[0].plot(x,y)
ax[0].set_xticks([0, 2, 4,5, 6, 7,8])
ax[0].set_xticklabels([])
ax[0].xaxis.set_minor_locator(ticker.MultipleLocator(0.2))
ax[0].set_title('without tick lables')
ax[1].plot(x,y)
ax[1].set_xticks([0, 2, 4, 6, 8])
ax[1].set_xticklabels(['A', 'B', 'C', 'D', 'E'])
ax[1].xaxis.set_minor_locator(ticker.MultipleLocator(0.5))
ax[1].set_title('replaced by texts')
plt.show()
In [12]:
import matplotlib.ticker as ticker

t = np.arange(0.0, 120.0, 1)
y = np.sin(0.1 * np.pi * t) * np.exp(-t * 0.03)

fig,ax=plt.subplots(nrows=2,ncols=4,figsize=(16,5))
fig.subplots_adjust(hspace=0.4)

ax[0,0].plot(t,y)
#ax[0,0].xaxis.set_major_locator(ticker.NullLocator())
#ax[0,0].xaxis.set_minor_locator(ticker.NullLocator())
ax[0,0].xaxis.set_major_formatter(ticker.NullFormatter())
ax[0,0].set_title( "NullLocator()", fontsize=14)

ax[0,1].plot(t,y)
ax[0,1].xaxis.set_major_locator(ticker.MultipleLocator(20))
ax[0,1].xaxis.set_minor_locator(ticker.MultipleLocator(5))
ax[0,1].set_title( "MultipleLocator(20, 5)", fontsize=14)
#ax[0,1].xaxis.set_major_formatter(ticker.NullFormatter())

majors = [0, 20, 40, 80]
minors = np.linspace(0, 20, 11)[1:-1] #array([ 2.,  4.,  6.,  8., 10., 12., 14., 16., 18.])
ax[0,2].plot(t,y)
ax[0,2].xaxis.set_major_locator(ticker.FixedLocator(majors))
ax[0,2].xaxis.set_minor_locator(ticker.FixedLocator(minors))
ax[0,2].set_title( "FixedLocator(0, 20, 40, 80)", fontsize=14)

ax[0,3].plot(t,y)
ax[0,3].set_xlim(0,120)
ax[0,3].xaxis.set_major_locator(ticker.LinearLocator(6))
ax[0,3].xaxis.set_minor_locator(ticker.LinearLocator(31))
ax[0,3].set_title( "LinearLocator(6)", fontsize=14)

ax[1,0].plot(t,y)
ax[1,0].xaxis.set_major_locator(ticker.IndexLocator(base=20, offset=10))
ax[1,0].set_title( "IndexLocator(base=20, offset=10)", fontsize=14)

ax[1,1].plot(t,y)
ax[1,1].xaxis.set_major_locator(ticker.AutoLocator())
ax[1,1].xaxis.set_minor_locator(ticker.AutoMinorLocator())
ax[1,1].set_title( "AutoLocator", fontsize=14)

ax[1,2].plot(t,y)
ax[1,2].xaxis.set_major_locator(ticker.MaxNLocator(4))
ax[1,2].xaxis.set_minor_locator(ticker.MaxNLocator(8))
ax[1,2].set_title( "MaxNLocator", fontsize=14)

ax[1,3].plot(t,y)
ax[1,3].set_xlim(10**0, 10**5)
ax[1,3].set_xscale('log')
ax[1,3].xaxis.set_major_locator(ticker.LogLocator(base=10.0,subs=(1,10), numticks=7))
#ax[1,3].xaxis.set_minor_locator(ticker.LogLocator(base=10.0,subs=(1,10), numticks=7))
ax[1,3].xaxis.set_minor_locator(ticker.LogLocator(base=10.0,subs=np.arange(2, 10)*.1,numticks=7))
ax[1,3].xaxis.set_minor_formatter(ticker.NullFormatter())
ax[1,3].set_title( "LogLocator", fontsize=14)

plt.show()

Combine axes

In [13]:
fig=plt.figure()

ax1=fig.add_axes([0,0,1,1], label='cartesian', projection=None)
ax1.set_xlim(0,10)
ax1.set_ylim(0,10)
ax1.set_xticks([])
ax1.set_yticks([])
ax1.set_aspect('equal')

ax2=fig.add_axes([0,0,1,1], label='polar'    , projection='polar')
ax2.set_ylim(2,10)
ax2.set_thetamin(0)
ax2.set_thetamax(90)
ax2.set_rorigin(-2)
ax2.set_xticklabels([])
ax2.set_yticklabels([])
#ax2.set_rlabel_position(22.5)  # Move radial labels away from plotted line
ax2.grid(True)

Annotate

In [14]:
fig,ax = plt.subplots(figsize=(6,2))

x = np.linspace(0,7,100)
y = np.random.randn(100)
ax.plot(x,y)
ax.scatter(3,0.1)

ax.annotate('test', xy=(3,0.1), xytext=(4,2),color='r',
            arrowprops=dict(arrowstyle='->',connectionstyle='arc3, rad=-0.1',color='r'),
            bbox=dict(boxstyle='round,pad=-0.07', fc='none', ec='none'),)

plt.show()
In [15]:
x = ["a","b","c","d"]
y1 = np.array([3,8,6,4])
y2 = np.array([10,2,4,3])

plt.figure(figsize=(4,3))

plt.bar(x, y1, label='y1')
plt.bar(x, y2 ,bottom=y1,label='y2')

# add text annotation corresponding to the values of each bar.
for xpos, ypos, yval in zip(x, y1/2, y1):
    plt.text(xpos, ypos, yval, ha="center", va="center",color='w')
for xpos, ypos, yval in zip(x, y1+y2/2, y2):
    plt.text(xpos, ypos, yval, ha="center", va="center")
    
# add text annotation corresponding to the "total" value of each bar
for xpos, ypos, yval in zip(x, y1+y2, y1+y2):
    plt.text(xpos, ypos, "N=%d"%yval, ha="center", va="bottom")

plt.ylim(0,15)

plt.legend()
plt.show()
In [16]:
fig = plt.figure(figsize=(6,2))
ax1 = fig.add_subplot(2,1,1)
ax2 = fig.add_subplot(2,1,2,sharex=ax1)
ax1.set_ylabel("y Axis 1")
ax2.set_ylabel("y Axis 2")
ax2.set_xlabel("x Axis")
plt.setp(ax1.get_xticklabels(),visible=False)
fig.align_ylabels([ax1,ax2])
plt.show()

fig = plt.figure(figsize=(6,2))
ax1 = plt.subplot(2,1,1)
ax2 = plt.subplot(2,1,2,sharex=ax1)
ax1.set_ylabel("y Axis 1")
ax2.set_ylabel("y Axis 2")
ax2.set_xlabel("x Axis")
ax1.yaxis.set_label_coords(-0.1,0.5)
ax2.yaxis.set_label_coords(-0.1,0.5)
plt.setp(ax1.get_xticklabels(),visible=False)
plt.show()

Streamplot

In [17]:
x,y = np.linspace(-3,3,100),np.linspace(-3,3,100)
X,Y = np.meshgrid(x,y)
U = -Y
V = X
Z=np.sqrt(X**2+Y**2)

stream_points = np.array((3*(1-2*np.random.rand(100)), 3*(1-2*np.random.rand(100)))).reshape(-1,2)
stream_points = np.array((np.linspace(-3,3,100), np.linspace(-3,3,100))).reshape(-1,2)
fig=plt.figure(figsize=(4,2))
plt.streamplot(X,Y,U,V,color=Z,start_points=stream_points,density=30,linewidth=0.5,arrowstyle='-')
plt.colorbar()
#plt.streamplot(X,Y,U,V,density=2)
plt.plot(stream_points[:,0],stream_points[:,1],'o',ms=2)
plt.grid()
plt.show()

Scientific notation

In [18]:
fig, ax = plt.subplots()
ax.plot(range(2003,2012,1),range(200300,201200,100))
ax.ticklabel_format(useOffset=False)
plt.show()
In [19]:
fig,ax=plt.subplots(figsize=(8,2))
ax.plot(np.random.randn(1000)*1e4)
ax.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax.ticklabel_format(axis='y', style='sci', scilimits=(2,2))
ax.yaxis.offsetText.set_fontsize(12)
plt.show()

fig,ax=plt.subplots(figsize=(2,2))
im1=ax.imshow(np.random.randn(100,100)*1e5)
fmt=ScalarFormatter(useMathText=True)
fmt.set_powerlimits((0,0))
cb=fig.colorbar(im1,ax=ax,format=fmt)
cb.ax.yaxis.set_offset_position('left')
cb.update_ticks()
plt.show()

Sky map

You can also use cartopy for more flexible maps.

In [20]:
fig = plt.figure(figsize=(6,2))
ax = fig.add_subplot(111, projection='mollweide')
lon = np.linspace(-np.pi, np.pi,36)
lat = np.linspace(-np.pi/2., np.pi/2.,18)
arr = np.random.randn(18, 36)
im = ax.pcolormesh(lon,lat,arr,shading='nearest',cmap='RdBu')
fig.colorbar(im,ax=ax)
plt.show()

Ticks for both sides

In [21]:
fig, ax = plt.subplots(nrows=1,ncols=1,figsize=(6,3),sharex='all',dpi=80)

ax.xaxis.set_tick_params(which='major',  top='on')
ax.yaxis.set_tick_params(which='both' ,right='on')

ax.set_ylim(0.1,10)
ax.set_yscale('log')
ax.set_xlabel(r'x$\alpha a$a')
plt.show()
In [22]:
fig, ax = plt.subplots(nrows=3,ncols=1,figsize=(6,3),sharex='all',dpi=80)
plt.subplots_adjust(hspace=0.)
for ic in range(3):
    ax[ic].xaxis.set_tick_params(which='major',  top='on', direction='in', length=5, width=1)
plt.show()

Heat map with log-scaled bins

It is better to use 'pcolormesh' rather than 'imshow'

In [23]:
x=np.linspace(0,2*np.pi,200)
y=np.logspace(-1,1,200)
X,Y=np.meshgrid(x,y)
Z=np.cos(X)*np.sin(Y)

fig,ax=plt.subplots(figsize=(8,2))
im1=ax.pcolormesh(X,Y,Z,cmap='jet',shading='auto')
ax.set_yscale('log')
fig.colorbar(im1,ax=ax,label='test',pad=0.02)
plt.show()

Shaded region over several panels

In [24]:
#### for observational data ###
#data = cdas.get_data(
#    'sp_phys',
#    'STA_L1_MAG_RTN',
#    datetime.datetime(2010, 1, 1, 0,  0,  0),
#    datetime.datetime(2010, 1, 1, 1,  0,  1),
#    ['BFIELD'],
#    cdf=True # download data in CDF format
#)
#
#### convert to the dataframe of pandas ###
#d = {'BR': data['BFIELD'][:,0], 'BT': data['BFIELD'][:,1], 'BN':data['BFIELD'][:,2]}
#df0 = pd.DataFrame(data=d,index=data['Epoch'][:])
#df0.index.name='time'
###########################################

dates = pd.date_range(start='2010-01-01', periods=3601,  freq='S')
d={'R':np.linspace(0,100,3601),'BR': np.random.randn(3601), 'BT': np.random.randn(3601), 'BN': np.random.randn(3601)}
df0=pd.DataFrame(data=d, index=dates)
df0.index.name='time'
#print(df0)

fig, ax = plt.subplots(nrows=3, sharex=True, figsize=(8, 2))

ax[2].set_xlim(0,10)

### add a rectangle patch ###
rect = patches.Rectangle((2, 0), 3, 3+2*fig.subplotpars.hspace, color='grey',alpha=.25, clip_on=False,transform=ax[2].get_xaxis_transform())
ax[2].add_patch(rect)
#############################
plt.show()


### date time format ###
fig, ax = plt.subplots(nrows=3, sharex=True, figsize=(8, 2))
ax[2].plot(df0.index[:], df0['BR'][:])

### add a rectangle patch ###
#start='2010-01-01 00:20:00'
#end  ='2010-01-01 00:30:00'
#startplt = mdates.date2num(start)
#endplt   = mdates.date2num(end)
#rect = patches.Rectangle((startplt, 0), endplt-startplt, 3+2*fig.subplotpars.hspace, color='grey',alpha=.25, clip_on=False, transform=ax[2].get_xaxis_transform())

start = datetime.datetime(2010, 1, 1, 0,20,0)
end   = datetime.datetime(2010, 1, 1, 0,30,0)
rect = patches.Rectangle((start, 0), end-start, 3+2*fig.subplotpars.hspace, color='grey',alpha=.25, clip_on=False, transform=ax[2].get_xaxis_transform())
ax[2].add_patch(rect)
#############################

#ax[2].set_xlim(start,end)

plt.show()

Vertical line over several panels

In [25]:
fig, ax = plt.subplots(nrows=3, sharex=True, figsize=(8, 2))
ax[2].set_xlim(0,10)
ax[2].axvline(4, 0, 3+2*fig.subplotpars.hspace, ls='dashed', color='k', clip_on=False)
plt.show()

### for observation ###
fig, ax = plt.subplots(nrows=3, sharex=True, figsize=(8, 2))
start = datetime.datetime(2010, 1, 1, 0,20,0)
ax[2].plot(df0.index[:], df0['BR'][:])
ax[2].axvline(start, 0, 3+2*fig.subplotpars.hspace, ls='dashed', color='k', clip_on=False)
plt.show()

Crossed axes and equal aspect

In [26]:
fig,ax=plt.subplots(nrows=1,ncols=1,figsize=(4,2))

# Move left y-axis and bottim x-axis to centre, passing through (0,0)
ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('center')

# Eliminate upper and right axes
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

# Show ticks in the left and lower axes only
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')

ax.set_xlim(-5,20)
ax.set_ylim(-5,5)

ax.set_aspect('equal') 

plt.show()

Log scale color map

In [27]:
fig,ax=plt.subplots(figsize=(4,2))
im1=ax.imshow(10**np.random.randn(100,100),cmap='jet',aspect='auto',origin='lower', norm=mpl.colors.LogNorm())
fig.colorbar(im1,ax=ax,label='test',pad=0.02)
plt.show()

Colorbar scale of date

In [28]:
#### plot figure ###
fig, ax = plt.subplots(ncols=1, figsize=(3,3))

N_TICKS = 12
cmap = plt.cm.get_cmap('jet', N_TICKS)    # 11 discrete colors

smap = ax.scatter(df0['BR'][:],df0['BT'][:],c=df0.index,cmap=cmap,marker='o',s=10,alpha=0.8)

smap.set_facecolor("none")

indexes = [df0['2010-01-01 00:00'].index[0], df0['2010-01-01 00:15'].index[0], df0['2010-01-01 00:30'].index[0], df0['2010-01-01 00:45'].index[0], df0['2010-01-01 01:00'].index[0]]

cb = fig.colorbar(smap, ax=ax, orientation='vertical', ticks= df0.loc[indexes].index.astype(int), label='hh:mm')

cb.ax.set_yticklabels([index.strftime('%H:%M') for index in indexes])

ax.set_xlabel(r'$B_R$ [nT]')
ax.set_ylabel(r'$B_T$ [nT]')

plt.show()

X label time format

In [29]:
### plot figure ###
fig, ax = plt.subplots(figsize=(8,2))

ax.plot(df0.index, df0['BR'][:],'k')

myfmt=mdates.DateFormatter('%H:%M:%S\n%d %b %Y')
ax.xaxis.set_major_formatter(myfmt)

plt.show()
In [30]:
nt=len(df0)
### date time format ###
fig, ax = plt.subplots(nrows=1, sharex=True, figsize=(8, 2))
ax.plot(df0.index[:], df0['BR'][:])

ax.set_xticks([df0.index[nt//4*i] for i in range(5)])
ax.set_xticklabels(['%s\n%d' %(df0.index[nt//4*i].strftime('%M:%S'),df0['R'][nt//4*i]) for i in range(5)])

plt.show()

Different size panels

In [31]:
fig7, f7_axs = plt.subplots(ncols=3, nrows=3,figsize=(6,3))
gs = f7_axs[1, 2].get_gridspec()
# remove the underlying axes
for ax in f7_axs[1:, -1]:
    ax.remove()
axbig = fig7.add_subplot(gs[1:, -1])

fig7.tight_layout()
In [32]:
widths = [2, 3, 1]
heights = [1, 3, 2]
#gs_kw = dict(width_ratios=widths, height_ratios=heights)
fig6, f6_axes = plt.subplots(ncols=3, nrows=3, figsize=(6,3), constrained_layout=True,gridspec_kw={'width_ratios':widths, 'height_ratios':heights}) #or gridspec_kw=gs_kw

Mixed cartesian and Polar plots

In [33]:
### read the H number distribution ###
r =np.linspace(0, 70,100)
th=np.linspace(0,360,200,endpoint=True)/180*np.pi
R,Th=np.meshgrid(r,th)

### plot figure ###
#fig,ax=plt.subplots(nrows=2,figsize=(10,12))
fig=plt.figure(figsize=(12,3),dpi=120)

#plt.rcParams['font.size'] = 10

gs=GridSpec(1,3) # 2 rows, 3 columns
gs.update(wspace=0.1) # set the spacing between axes. 

ax0=fig.add_subplot(gs[0,0:2]) # First row, first column
ax1=fig.add_subplot(gs[0,2], polar=True) # First row, second column


#fig.add_subplot(121)
#ax0.plot(mu,label='monthly')
#ax0.plot(mu.rolling("8760D").mean(),label='24 year')
#ax0.legend()
ax0.grid()
ax0.set_xlabel('time [year]')
ax0.set_ylabel(r'$\mu$')
#ax0.set_xlim(mu.index[154],mu.index[634])

#ax=fig.add_subplot(122, polar=True,facecolor='grey')
#CS=ax.pcolormesh(Th,R,data,cmap=plt.cm.get_cmap('coolwarm', 10))
#fig.colorbar(CS, ax=ax,shrink=0.8,ticks=np.linspace(0,0.1,11),label='$n_H$ [cm$^{-3}$]')
#CS=ax1.pcolormesh(Th,R,data2,cmap='coolwarm')
#fig.colorbar(CS, ax=ax1,shrink=1,label='$n_H$ [cm$^{-3}$]')
#ax1.plot(P10rphi[::2000]['phi']-np.pi, P10rphi[::2000]['R'],'k-')
#ax1.plot(V1rphi[::1000]['phi']-np.pi, V1rphi[::1000]['R'],'k-.')
#ax1.plot(V2rphi[::100]['phi']-np.pi, V2rphi[::100]['R'],'k--')
#ax1.grid(False)
#ax.clabel(CS, inline=1, fontsize=10)
#ax.set_yticklabels([])
#ax1.thetagrids([theta * 15 for theta in range(360//15)])
#ax1.set_rmax(70)
#ax1.set_rlabel_position(135/2)
#import matplotlib.text as txt
#ax1.text(177*np.pi/180,60,'P10')
#ax1.text(-10*np.pi/180,60,'V1')
#ax1.text( 30*np.pi/180,60,'V2')
#ax1.text(135/2*np.pi/180,82,'[au]')
#plt.colorbar()
#ax.grid(True)
#cmap = cm.get_cmap('PiYG', 11)    # 11 discrete colors
#ax.set_thetamin(0)
#ax.set_thetamax(180)
#fig.tight_layout()
plt.show()

Scatter points over a line

In [34]:
x=np.arange(100)
y=np.random.randn(100)
plt.plot(np.zeros(100), 'red', lw=5)
plt.scatter(x,y, zorder=5)
plt.show()

Subplots including a heatmap and a line plot.

Also setting gridspec_kw and width_ratios, you can adjust the size of figures.

In [35]:
xx=np.linspace(0,100*np.pi,1000)
yy=np.linspace(0,  2*np.pi,1000)
yy=np.cos(xx/4)*np.exp(-xx/100)
XX,YY=np.meshgrid(xx,yy)
ZZ=np.cos(XX/4)*np.exp(-XX/100)

fig, ax = plt.subplots(nrows=3, sharex=True, figsize=(16, 4))
plt.subplots_adjust(hspace=0.)

im0=ax[0].imshow(np.random.randn(200,1000),aspect='auto',origin='lower')
im1=ax[1].plot(np.random.randn(1000))
im2=ax[2].imshow(np.random.randn(200,1000)*1e5,aspect='auto',origin='lower',cmap='jet')

fig.colorbar(im0,ax=ax[0],label='test'            ,aspect=5, pad=0.01)
fig.colorbar(im2,ax=ax[2],label='test\ntest\ntest',aspect=5, pad=0.01)

cb = fig.colorbar(im0,ax=ax[1],aspect=5, pad=0.01)
cb.ax.set_visible(False)

plt.show()
In [36]:
widths = [2, 2, 2]
heights = [1, 1]
gs_kw = dict(width_ratios=widths, height_ratios=heights)
fig, ax = plt.subplots(ncols=3, nrows=2, constrained_layout=True,gridspec_kw=gs_kw)
Z=np.random.randn(20,20)
im1=ax[1,2].imshow(Z, aspect='auto')
fig.colorbar(im1, ax=ax[1,2])
plt.show()

Multiple axes

In [37]:
fig,ax=plt.subplots(figsize=(8,2))
ax.plot(np.random.rand(100))
ax.set_ylim(0,3)
ax.set_ylabel('Y values for exp(-x)')
ax.set_xlabel('Same X for both exp(-x) and ln(x)')

ax2=ax.twinx()
ax2.plot(np.random.rand(100)+1,'r')
ax2.set_ylim([0,3])
ax2.set_ylabel('Y values for ln(x)', color='r')
ax2.tick_params(axis='y', colors='r')
ax2.spines["right"].set_edgecolor('r')

ax3=ax.twinx()
ax3.spines["right"].set_position(("axes", 1.12))# move the spine of the second axes outwards
ax3.plot(np.random.rand(100)+2,'g')
ax3.set_ylim(0,3)
ax3.set_ylabel('Y values for ln(x)', color='g')
ax3.tick_params(axis='y', colors='g')
ax3.spines["right"].set_edgecolor('g')

plt.show()
In [38]:
fig,ax=plt.subplots(nrows=1,ncols=2,figsize=(6,1))
plt.subplots_adjust(wspace=0.4,hspace=0.4)
xx=np.linspace(0,2*np.pi,100)

ax[0].plot(xx,np.sin(xx))
ax[1].plot(xx,np.sin(xx))

ax2=np.copy(ax)
for i in range(2):
    ax2[i]=ax[i].twinx()
    
ax2[0].plot(xx,np.cos(xx),'r--')
ax2[1].plot(xx,np.cos(xx),'r--')

plt.show()

Animation of heatmaps

In [39]:
def update_anim(it):
    
    fig.clf() #clear the figure
    
    ax=fig.subplots(2, 2) #add subplots

    fig.tight_layout() #reduce spacing around the figure

    #for i in range(2):
    #    for j in range(2):
    #        ax[i,j].cla()  
                    
    Z1=np.random.randn(N,N) #random numbers in 2D
    Z2=np.random.randn(N,N) #random numbers in 2D
    Z3=np.random.randn(N,N) #random numbers in 2D
    Z4=np.random.randn(N,N) #random numbers in 2D
    
    im1=ax[0,0].imshow(Z1 ,aspect='equal', origin='lower', cmap='Greys')
    im2=ax[1,0].imshow(Z2 ,aspect='equal', origin='lower', cmap='Blues')
    im3=ax[0,1].imshow(Z3 ,aspect='equal', origin='lower', cmap='Reds')
    im4=ax[1,1].imshow(Z4 ,aspect='equal', origin='lower', cmap='Greens')
    #im4=ax[1,1].plot(x,np.sin(it*x))
    
    cb1=fig.colorbar(im1, ax=ax[0,0])
    cb2=fig.colorbar(im2, ax=ax[1,0])
    cb3=fig.colorbar(im3, ax=ax[0,1])
    cb4=fig.colorbar(im4, ax=ax[1,1])

N=10
nt=10

fig=plt.figure(figsize=(6,6))
anim=animation.FuncAnimation(fig,update_anim,frames=nt)
#plt.subplots_adjust(wspace=0.1,hspace=0.01, bottom=0,top=1)

plt.close()
anim
#anim.save('sample.gif', writer='imagemagick') #save the animation as a gif file
Out[39]:

Hatched region

In [40]:
x=np.linspace(0,10,1000)
y1=np.zeros(1000)
y2=x**2/(1+x**2)
y3=x**(1/4)

fig, ax = plt.subplots()
ax.plot(x, y1, "k")
ax.plot(x, y2, "k")
ax.plot(x, y3, "k")

ax.fill_between(x, y1, y2, fc='w', hatch= "x") #{'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'}
ax.fill_between(x, y2, y3, fc='w', hatch="//")
ax.set_ylim(0,2)

plt.show()

Figure in a figure

In [41]:
Z = np.random.randn(100,100)

fig = plt.figure()
ax = plt.axes()
plt.imshow(Z, extent=[0, 5, 0, 5], origin='lower',  cmap='jet')
plt.colorbar()

axins = ax.inset_axes([0.25, 0.3, 0.4, 0.4])
axins.imshow(Z, extent=[0, 5, 0, 5], origin="lower",cmap='jet')

# sub region of the original image
x1, x2, y1, y2 = 2, 3, 0.4, 1.4
axins.set_xlim(x1, x2)
axins.set_ylim(y1, y2)
axins.set_xticklabels('')
axins.set_yticklabels('')

#ax.indicate_inset_zoom(axins,ec='red',alpha=1)
mark_inset(ax, axins, loc1=3, loc2=4, fc="none", ec="k",alpha=1)

plt.show()
In [42]:
x = np.arange(-10, 10, 0.1)
plt.plot(x, x**2) 

ax=plt.axes([0.5, 0.6, 0.2, 0.2]) 
ax.plot(x, x)
ax.set_xlim(-5,5)

plt.show()

Connect paths over panels

In [43]:
from matplotlib.patches import ConnectionPatch

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(4, 2))

# Draw a simple arrow between two points in axes coordinates
# within a single axes.
xyA = (0.2, 0.2)
xyB = (0.8, 0.8)
coordsA = "data"
coordsB = "data"
con = ConnectionPatch(xyA, xyB, coordsA, coordsB,
                      arrowstyle="->", shrinkA=5, shrinkB=5,
                      mutation_scale=20, fc="w")
ax1.plot([xyA[0], xyB[0]], [xyA[1], xyB[1]], "o")
ax1.add_artist(con)

# Draw an arrow between the same point in data coordinates,
# but in different axes.
xy = (0.0, 0.0)
coordsA = "data"
coordsB = "data"
con = ConnectionPatch(xyA=(0.3, 0.2), xyB=(0,0), coordsA=coordsA, coordsB=coordsB,
                      axesA=ax2, axesB=ax1,
                      arrowstyle="-", shrinkB=0)
ax2.add_artist(con)

# Draw a line between the different points, defined in different coordinate
# systems.
xyA = (0.6, 1.0)  # in axes coordinates
xyB = (0.0, 0.2)  # x in axes coordinates, y in data coordinates
coordsA = "axes fraction"
coordsB = ax2.get_yaxis_transform()
con = ConnectionPatch(xyA=xyA, xyB=xyB, coordsA=coordsA, coordsB=coordsB,
                      arrowstyle="-")
ax2.add_artist(con)

ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
ax2.set_xlim(0, .5)
ax2.set_ylim(0, .5)

plt.show()

Contour plot and colorbar controll

In [44]:
x=np.linspace(-5,5,200)
y=np.linspace(-5,5,200)

X, Y = np.meshgrid(x,y)

nr=2000
cx=-10+20*np.random.rand(nr)
cy=-10 +20*np.random.rand(nr)
k=np.zeros(nr)
for i in range(nr):
    if cx[i]<0: k[i]=1
    if cx[i]>0: k[i]=1

Jz=np.zeros((200,200))
for i in range(nr):
    R=np.sqrt((X-cx[i])**2+(Y-cy[i])**2)
    Jz=Jz+2*k[i]/(1+(k[i]*R)**2)**2

fig,ax = plt.subplots(nrows=1, ncols=1, sharex=True, figsize=(2,2))
im0=ax.contour( X, Y, Jz, levels=20, colors='black',alpha=0.9)
In [45]:
x=np.linspace(-5,5,200)
y=np.linspace(-4,4,200)

X, Y = np.meshgrid(x,y)

nr=1000
cx=-10+20*np.random.rand(nr)
cy=-5 +10*np.random.rand(nr)
k=np.zeros(nr)
for i in range(nr):
    if cx[i]<0: k[i]=1
    if cx[i]>0: k[i]=2

Jz=np.zeros((200,200))
for i in range(nr):
    R=np.sqrt((X-cx[i])**2+(Y-cy[i])**2)
    Jz=Jz+2*k[i]/(1+(k[i]*R)**2)**2

fig,ax = plt.subplots(nrows=1, ncols=3, sharex=True, figsize=(12,4))
im0=ax[0].contour( X, Y, Jz, levels=40, colors='grey',alpha=0.4)
im1=ax[1].contour( X, Y, Jz, levels=40, cmap='jet')
im2=ax[2].contourf(X, Y, Jz, levels=20, cmap='jet')


from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable

divider = make_axes_locatable(ax[2])
cax = divider.append_axes("top", size="5%", pad=0.1)
cb2=fig.colorbar(im2, cax=cax, ax=ax[2], orientation='horizontal')
cax.xaxis.set_ticks_position('top')

divider1 = make_axes_locatable(ax[1])
cax1 = divider1.append_axes("top", size="5%", pad=0.1)
cb1=fig.colorbar(im1, cax=cax1, ax=ax[1], orientation='horizontal', pad=0.05)
cax1.xaxis.set_ticks_position('top')
#cb1.ax.set_visible(False)

divider0 = make_axes_locatable(ax[0])
cax0 = divider0.append_axes("top", size="5%", pad=0.1)
cb2=fig.colorbar(im0, cax=cax0, ax=ax[0], orientation='horizontal', pad=0.05)
cax0.xaxis.set_ticks_position('top')
cb2.ax.set_visible(False)

#fig.colorbar(im2, cax=cax, ax=ax[1], orientation='horizontal', pad=0.05, anchor=(0.5, 1.0))

for i in range(3):
    ax[i].set_aspect('equal')

plt.show()

Multicolored lines

Actually, there is no easy to plot it. Alternatively, you can use scatter (but points). If you really need multicolored lines, you can check here; [https://matplotlib.org/3.3.3/gallery/lines_bars_and_markers/multicolored_line.html]

In [46]:
x = np.linspace(0, 2*np.pi, 1000)
y = np.sin(10*x)*np.exp(-x)
z = np.arange(1000)
fig, ax = plt.subplots(figsize=(3,2 ))
im1=ax.scatter(x,y, s=10, c=z, edgecolor='none', cmap='jet')
fig.colorbar(im1, ax=ax)
plt.show()
In [47]:
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap, BoundaryNorm

x = np.linspace(0, 3 * np.pi, 100)
y = np.sin(x)
dydx = np.cos(0.5 * (x[:-1] + x[1:]))  # first derivative

# Create a set of line segments so that we can color them individually
# This creates the points as a N x 1 x 2 array so that we can stack points
# together easily to get the segments. The segments array for line collection
# needs to be (numlines) x (points per line) x 2 (for x and y)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)

fig, axs = plt.subplots(2, 1, sharex=True, sharey=True)

# Create a continuous norm to map from data points to colors
norm = plt.Normalize(dydx.min(), dydx.max())
lc = LineCollection(segments, cmap='viridis', norm=norm)
# Set the values used for colormapping
lc.set_array(dydx)
lc.set_linewidth(2)
line = axs[0].add_collection(lc)
fig.colorbar(line, ax=axs[0])

# Use a boundary norm instead
cmap = ListedColormap(['r', 'g', 'b'])
norm = BoundaryNorm([-1, -0.5, 0.5, 1], cmap.N)
lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(dydx)
lc.set_linewidth(2)
line = axs[1].add_collection(lc)
fig.colorbar(line, ax=axs[1])

axs[0].set_xlim(x.min(), x.max())
axs[0].set_ylim(-1.1, 1.1)
plt.show()
In [48]:
### discrete ###
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)

#cmap = mpl.cm.get_cmap('jet', n_lines)
#fig, ax = plt.subplots(dpi=100)
## Make dummie mappable
#dummie_cax = ax.scatter(c, c, c=c, cmap=cmap)
## Clear axis
#ax.cla()
#for i, yi in enumerate(y.T):
#    ax.plot(x, yi, c=cmap(i))
#fig.colorbar(dummie_cax, ticks=c)
#plt.show();

cmap = plt.get_cmap("jet", len(c))
norm = mpl.colors.BoundaryNorm(np.arange(len(c)+1)+0.5,len(c))
sm = plt.cm.ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])  # this line may be ommitted for matplotlib >= 3.1

fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
    ax.plot(x, yi, c=cmap(i))
fig.colorbar(sm, ticks=c)
plt.show()


### continuous ###
n_lines = 5
x = np.linspace(0, 10, 100)
y = np.sin(x[:, None] + np.pi * np.linspace(0, 1, n_lines))
c = np.arange(1, n_lines + 1)

norm = mpl.colors.Normalize(vmin=c.min(), vmax=c.max())
cmap = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.jet)
cmap.set_array([])

fig, ax = plt.subplots(dpi=100)
for i, yi in enumerate(y.T):
    ax.plot(x, yi, c=cmap.to_rgba(i + 1))
fig.colorbar(cmap, ticks=c)
plt.show();

Axis setting

In [49]:
color='#545454'

fig = plt.figure(figsize=(4,2))
ax = fig.add_subplot(111)
ax.plot(np.random.rand(10), 'k', lw=1.5, alpha=0.8)
ax.plot(np.random.rand(10), 'o', color='none', markersize=10, markeredgewidth=3, markeredgecolor=color, alpha=0.8)

ax.spines['top'   ].set_linewidth(0)
ax.spines['right' ].set_linewidth(0)
ax.spines['left'  ].set_linewidth(2)
ax.spines['bottom'].set_linewidth(2)

ax.spines['left'  ].set_color(color)
ax.spines['bottom'].set_color(color)

#ax.spines['right'].set_visible(False)
#ax.spines['left'].set_visible(False)
#ax.spines['top'].set_visible(False)
 
ax.tick_params(direction='out', length=6, width=2, colors=color, labelsize=14)

#ax.set_xlim(0,370)
#ax.set_ylim(0,105)

#ax.set_xticks([60*i for i in np.arange(7)])
#ax.set_yticks([0, 25, 50, 75, 100])

#ax.set_xticklabels([x for x in np.arange(7)], fontsize=14, color=color)
#ax.set_yticklabels([0,25,50,75, 100]        , fontsize=14, color=color)

#ax.xaxis.label.set_color('red')
#ax.tick_params(axis='x', colors='red')`1

ax.set_xlabel('X', color=color)
ax.set_ylabel('Y', color=color)
#plt.savefig('test.pdf')
plt.show()

Error bar

In [50]:
x=np.linspace(0,45,20)
y=x*np.exp(-(x/10.0)**2)*np.sin(x/4)
yerror=np.random.rand(20)

plt.figure(1, figsize = (3,2) )
plt.plot(x, y, 'r-', label="theory")
plt.errorbar(x, y,yerr=yerror,fmt='o', ecolor='green', markeredgecolor = "black", color='w',capsize=4,label="data")
plt.xlabel('x')
plt.ylabel('transverse displacement')
plt.legend(frameon=False,numpoints=1)
#plt.legend(loc='upper right')

plt.show()
In [51]:
fig,ax = plt.subplots(nrows=2,ncols=1,sharex=True, sharey=True)

ax[0].loglog(10**np.random.randn(100))
ax[1].loglog(10**np.random.randn(100))
ax[1].set_ylim(1e-2,1e2)

# Set common labels
fig.text(0.50,-0.05, 'common xlabel', ha='center', va='center')
fig.text(0.00, 0.50, 'common ylabel', ha='center', va='center', rotation='vertical')

plt.show()

Panel label

In [52]:
label=[['A', 'B'], ['C', 'D']]

### put panel labels outside ###
fig,ax = plt.subplots(nrows=2, ncols=2)
for i in range(2):
    for j in range(2):
        ax[j,i].text(-0.1, 1.15, label[i][j], transform=ax[j,i].transAxes, fontsize=16, fontweight='bold', va='top', ha='right')
plt.show()
################################

### put panel labels inside with a frame ###
props = dict(boxstyle='square', facecolor='w', alpha=0.8)
fig,ax = plt.subplots(nrows=2, ncols=2)
for i in range(2):
    for j in range(2):
        ax[j,i].text(0.1, 0.95, label[i][j], transform=ax[j,i].transAxes, fontsize=14, fontweight='bold', va='top', ha='right', bbox=props)

ax[0,0].imshow(np.random.randn(100,100), aspect='auto')
plt.show()

Colorbar over several plots

In [53]:
fig, ax = plt.subplots(nrows=4, sharex=True, figsize=(6, 2),dpi=120)
plt.subplots_adjust(hspace=0.4)
im0=ax[0].imshow(np.random.randn(20,200),cmap='jet',origin='lower',aspect='auto')
im1=ax[1].imshow(np.random.randn(20,200),cmap='jet',origin='lower',aspect='auto')
im2=ax[2].imshow(np.random.randn(20,200),cmap='jet',origin='lower',aspect='auto')
im3=ax[3].imshow(np.random.randn(20,200),cmap='jet',origin='lower',aspect='auto')
    
fig.colorbar(im0,ax=ax[:],pad=0.02)
plt.show()
In [54]:
fig,ax=plt.subplots(figsize=(4,2), nrows=3, ncols=2)
#fig.subplots_adjust(wspace=0.1)

im0=ax[0,0].imshow(np.random.randn(20,100), origin='lower', aspect='equal')
im1=ax[1,0].imshow(np.random.randn(20,100), origin='lower', aspect='equal')
im2=ax[2,0].imshow(np.random.randn(20,100), origin='lower', aspect='equal')
im3=ax[0,1].imshow(np.random.randn(20,100), origin='lower', aspect='equal')
im4=ax[1,1].imshow(np.random.randn(20,100), origin='lower', aspect='equal')
im5=ax[2,1].imshow(np.random.randn(20,100), origin='lower', aspect='equal')

cbar=fig.colorbar(im0, ax=ax[:,:], orientation='horizontal', shrink=0.8)
#cbar=fig.colorbar(im0, ax=ax[:,1], orientation='horizontal', shrink=0.6)

plt.show()
In [55]:
#Fixing random state for reproducibility
np.random.seed(19680801)

# the random data
x = np.random.randn(1000)
y = np.random.randn(1000)

# definitions for the axes
left, width = 0.1, 0.65
bottom, height = 0.1, 0.65
spacing = 0.01

rect_scatter = [left, bottom, width, height]
rect_histx = [left, bottom + height + spacing, width, 0.2]
rect_histy = [left + width + spacing, bottom, 0.2, height]

# start with a rectangular Figure
plt.figure(figsize=(4, 4))

ax_scatr= plt.axes(rect_scatter)
ax_histx= plt.axes(rect_histx)
ax_histy= plt.axes(rect_histy)

ax_scatr.tick_params(direction='in', top=True, right=True)
ax_histy.tick_params(direction='in', labelleft=False)
ax_histx.tick_params(direction='in', labelbottom=False)

# the scatter plot:
ax_scatr.scatter(x, y)
#ax_scatr.hist2d(x,y)

# now determine nice limits by hand:
binwidth = 0.25
lim = np.ceil(np.abs([x, y]).max() / binwidth) * binwidth
ax_scatr.set_xlim((-lim, lim))
ax_scatr.set_ylim((-lim, lim))

bins = np.arange(-lim, lim + binwidth, binwidth)
ax_histx.hist(x, bins=bins)
ax_histy.hist(y, bins=bins, orientation='horizontal')

ax_histx.set_xlim(ax_scatr.get_xlim())
ax_histy.set_ylim(ax_scatr.get_ylim())

plt.show()

Uneven subplots and ticks

In [56]:
fig, ax = plt.subplots(3,2,sharex=True)
ax[2,1].axis('off') #or fig.delaxes(ax[2,1])
ax[1,1].xaxis.set_tick_params(labelbottom=True)
ax[1,1].set_xlabel('X')
plt.show()

Uneven spacing subplots

In [57]:
from matplotlib import gridspec

fig = plt.figure(figsize=(12,3))

gs0 = gridspec.GridSpec(2,2, hspace=0.5, wspace=0.4)
gsList = [gridspec.GridSpecFromSubplotSpec(nrows=1,ncols=2, subplot_spec=gs0[i,j], hspace=0, wspace=0) for i in range(2) for j in range(2)]

ax000=fig.add_subplot(gsList[0][0,0])
ax001=fig.add_subplot(gsList[0][0,1])
ax100=fig.add_subplot(gsList[1][0,0])
ax101=fig.add_subplot(gsList[1][0,1])
ax200=fig.add_subplot(gsList[2][0,0])
ax201=fig.add_subplot(gsList[2][0,1])
ax300=fig.add_subplot(gsList[3][0,0])
ax301=fig.add_subplot(gsList[3][0,1])

plt.show()

Bar plot along a trajectory

I'm not sure there is an official way to do this using plt.bar. Here, I use rectangle patches. If the trajectory is just a circle, you may wanna use plt.bar in polar coordinates.

In [58]:
nt=100
tt=np.linspace(0,2*np.pi,nt)
x=6*np.cos(tt)
y=2*np.sin(tt)

fig, ax = plt.subplots(nrows=1,ncols=1)
ax.set_xlim(-10,10)
ax.set_ylim( -5, 5)

ax.plot(x,y)

ax.set_aspect('equal')

### calculate vectors vertical to the orbit ###
angle=np.zeros(nt)
for i in range(1,nt-1):
    a=[x[i-1],y[i-1]]
    b=[x[i+1],y[i+1]]
    angle[i]=np.arccos((b[1]-a[1])/np.sqrt((b[0]-a[0])**2+(b[1]-a[1])**2))
    if (b[0]-a[0])>0: angle[i]=2*np.pi-angle[i]
    angle[i]=angle[i]/np.pi*180-90

### add a rectangle patch ###
height=np.ones(100)
for i in range(1,nt-1):
    rect = patches.Rectangle(xy=(x[i], y[i]), width=0.2, height=height[i], angle=angle[i], color='r', alpha=.25, transform=ax.transData)
    ax.add_patch(rect)

plt.show()

Line plot with space between markers and a line

https://sabopy.com/py/matplotlib-35/

In [59]:
x = np.arange(11)
y = np.arange(11)**(3/4)

# plot
fig=plt.figure(facecolor='w')
plt.plot(x, y, "m")
plt.plot(x, y, 'wo',ms=12)
plt.plot(x, y, 'go',ms=8)
plt.show()
In [60]:
fig, ax = plt.subplots()
ax.plot(np.random.rand(20), '-o', ms=8, lw=2, alpha=0.7, mfc='orange')
ax.grid()

ax.text(0.5, 0.5, 'created with matplotlib', transform=ax.transAxes,
        fontsize=30, color='grey', alpha=0.5,
        ha='center', va='center', rotation='-20',zorder=-5)
plt.show()

xkcd-like plot

It's better to wrap plt.xkcd() with a 'with' sentence since xkcd modifies the setting of rcParams.

In [61]:
x = np.linspace(0, 2*np.pi, 100)
y1 = np.sin(x)
y2 = np.cos(x)

fig = plt.figure(figsize=(8, 2))
with plt.xkcd():
    ax=fig.add_subplot(1,2,1,title='xkcd plot')
    ax.plot(x, y1, label="$y=sin(x)$")
    ax.plot(x, y2, label="$y=cos(x)$")
    ax.set_xlabel(r'abcd $abcd$')
    ax.legend(frameon=False)

ax=fig.add_subplot(1,2,2,title='usual plot')
ax.plot(x, y1, label="$y=sin(x)$")
ax.plot(x, y2, label="$y=cos(x)$")
ax.legend()

plt.show()

Old-Style Chart

This section is inspired by this post, https://scipython.com/blog/old-style-matplotlib-charts/. Mine is not as authentic as this post... I was looking for a possibility to put noises into 'fig' directory, but I couldn't find a way.

In [62]:
fig=plt.figure(figsize=(4,2),facecolor='w')

ax1=fig.add_axes([0.,0.,1,1], label='cartesian', projection=None)
x=np.linspace(1,9,50)
y=10-x
y_err=10-x+2*np.random.randn(50)
ax1.set_xlim(0,10)
ax1.set_ylim(0,10)
ax1.plot(x,y)
ax1.scatter(x,y_err,ec='k',fc='none')
#ax1.set_xticks([])
#ax1.set_yticks([])
ax1.set_title('THIS IS AN OLD-STYLE PLOT')
ax1.set_aspect('equal')

ax2=fig.add_axes([-0.2,-0.2,1.4,1.4])
x = np.random.rand(3000)
y = np.random.rand(3000)
z = np.random.rand(3000)

for i in np.arange(.1,1.01,.1):
    ax2.scatter(x, y, s=(2*i*(z+.1))**2, ec='none',fc='w', alpha=0.5,zorder=10)

ax2.set_xticks([])
ax2.set_yticks([])
ax2.spines['right' ].set_visible(False)
ax2.spines['left'  ].set_visible(False)
ax2.spines['top'   ].set_visible(False)
ax2.spines['bottom'].set_visible(False)
ax2.set_aspect('equal') 
plt.show()

Output this notebook as html file

I use a template answered in this post; https://stackoverflow.com/questions/24062013/how-to-convert-an-ipython-notebook-to-html-with-collapsed-output-and-or-input and tweak as follows. nbconvert=6.0.6 does not work for this template. So you need to downgrade nbconvert.

In [2]:
%%writefile tmp.tpl
{%- extends 'full.tpl' -%}

{% block output_group %}
<div class="output_hidden">
{{ super() }}
</div>
{% endblock output_group %}

{% block input_group -%}
<div class="input_hidden">
{{ super() }}
</div>
{% endblock input_group %}

{%- block input -%}
<div class="in_container">
<div class="in_hidden">
{{ super() }}
<div class="gradient">
</div>
</div>
</div>
{%- endblock input -%}


{%- block header -%}
{{ super() }}

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<style type="text/css">
div.output_wrapper {
margin-top: 0px;
}
.output_hidden {
display: block;
margin-top: 5px;
}
.in_hidden {
 width: 100%;
 overflow: hidden;
 position: relative;
}
.container{
 width: 95% !important;
}

.in_container {
  width: 100%;
  margin-left:  0px;
  margin-right:  0px;
  overflow: auto;
}
.gradient {
  width:100%;
  height:3px;  
  background:#eeeeee;
  position:absolute;
  bottom:0px;
  left:0;
  display: none;
  opacity: 0.4;
  border-bottom: 2px dashed #000;
}
div.input_prompt {
  color: #178CE3;
  font-weight: bold;
}
div.output_prompt {
  color: rgba(249, 33, 33, 1);
  font-weight: bold;
}


.rendered_html img {
  display: block;
 /* float: left;*/
 margin-left:unset;
  max-height:initial;
text-align:center;
}


</style>

<script>
$(document).ready(function(){
//   $(".output_hidden").click(function(){
//       $(this).prev('.input_hidden').slideToggle();
//   });
//   $(".input_hidden").click(function(){
//       $(this).next('.output_hidden').slideToggle();
//   });
var slideHeight = 25;
$(".in_container").each(function () {
  var $this = $(this);
  var $in_hidden = $this.children(".in_hidden");
  var defHeight  = $in_hidden.height();
  if (defHeight >= 61) {
      var $prompt = $this.prev(".input_prompt");
      var $input_hidden =$this.parents(".input_hidden");
      var $output_hidden = $input_hidden.next(".output_hidden");
      var $gradient = $in_hidden.children(".gradient");
      var $anim_control=$output_hidden.find(".anim-controls")
      $in_hidden.css("height", slideHeight + "px");
      $gradient.css("display", "block");
      $prompt.click(function () {
          var curHeight = $in_hidden.height();
          if (curHeight == slideHeight) {
              $in_hidden.animate({
                  height: defHeight
              }, "normal");
              $gradient.fadeOut();
          } 
          else {
              $in_hidden.animate({
                  height: slideHeight
              }, "normal");
              $gradient.fadeIn();
          }
          return false;
      });
      
      $anim_control.click(function (){
        return false;
       });
      
      $output_hidden.click(function () {
          var curHeight = $in_hidden.height();
          if (curHeight == slideHeight) {
              $in_hidden.animate({
                  height: defHeight
              }, "normal");
              $gradient.fadeOut();
          } 
          else {
              $in_hidden.animate({
                  height: slideHeight
              }, "normal");
              $gradient.fadeIn();
          }
      return false;
      });
  }
});
});

</script>
{%- endblock header -%}
Overwriting tmp.tpl
In [3]:
%%javascript //save the notebook before output
$("#save-notbook button").trigger('click')
In [4]:
!jupyter nbconvert --to html --template tmp.tpl plotting_tips.ipynb
[NbConvertApp] Converting notebook plotting_tips.ipynb to html
[NbConvertApp] Writing 16580832 bytes to plotting_tips.html
In [14]:
!rm tmp.tpl ### erase the temporary template (tmp.tpl)

note: 2022/Oct/05 may need to change the version of jinja2

In [6]:
!pip install jinja2==3.0.3
Requirement already satisfied: jinja2==3.0.3 in /Users/mnakanot/opt/anaconda3/lib/python3.9/site-packages (3.0.3)
Requirement already satisfied: MarkupSafe>=2.0 in /Users/mnakanot/opt/anaconda3/lib/python3.9/site-packages (from jinja2==3.0.3) (2.0.1)