an original idea by Luna Bai
import numpy as np
import matplotlib as matplotlib
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.patches as patches
# some 1D random data and associated grid points
x = np.linspace(0,10,100)
h_1D = np.cos(x)
#some 2D random data and associated grid points
xx,yy = np.meshgrid(x,x)
h_2D = np.cos(xx)*np.cos(yy)
#some 3D random data and associated grid points
z=np.linspace(-10,0,100)
xxx=np.tile(xx,(len(z),1,1))
yyy=np.tile(yy,(len(z),1,1))
zzz=np.tile(z,(xxx.shape[2],yyy.shape[1],1)).T
h_3D = np.cos(xxx)*np.cos(yyy)*np.exp(zzz/2)
plt.plot(x,h_1D)
plt.show()
fontsize = 16 #define the primary fontsize for plot # always choose > 14 otherwise we cannot read well in a paper...
fig = plt.figure(figsize = (8,12)) # set the size of the figure in figsize
for iplot in range(3):
ax = plt.subplot(3,1,iplot+1) # nb of lines, nb of columns, index of the plot
# global settings of axes
ax.set_xlim(np.min(x),np.max(x)) #the limits of the plot
ax.set_ylim(-1.5,1.5)
if iplot == 0 :
#remove every ticks and make a bold frame
for axis in ['top','bottom','left','right']:
ax.spines[axis].set_linewidth(3)
ax.tick_params(direction='inout',width=0,length=0,bottom='off',top='off',left='off',right='off')
ax.yaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_major_formatter(plt.NullFormatter())
plt.title('Plot a simple line with error interval', fontsize=fontsize,loc='center',x=0.5,y=1.) #you can move the title to put it on the side
#simple line plotting
plt.plot(x,h_1D,
color='k',
linestyle='-', #'-', '--', ':', '.-'
linewidth=3,
alpha=1)
#if we want to set the color of a plot on a matplotlib colorbar:
#cmap = plt.get_cmap('nipy_spectral')
#colors = [cmap(i) for i in np.linspace(0, 1,N)]
#then call with c=colors[imod]
#plot an envelope around the data line for e.g. an error interval
plt.fill_between(x,h_1D*0.8,h_1D*1.2,
facecolor='grey', #'None' for a transparent one
edgecolor='k', #'None' for no line
linewidth=1,
alpha=0.8)
if iplot == 1 :
plt.title('Plot a nice colorful scatter plot', fontsize=fontsize,loc='right',x=1.,y=1.) #you can move the title to put it on the side
#we don't plot the entire dataset for clarity
nplot=3
tmpx=x[::nplot]
tmph=h_1D[::nplot]
#plot the data as a scatter plot
plt.scatter(tmpx,tmph,
c=tmph, #the color encoding
vmin=-1,vmax=1,
cmap='RdBu_r', #_r to invert the colorbar
s=100, #the size of the marker
marker='o',
ec='k', #the color of the edge
lw=1, #the width of the edge
zorder=2) # this plot will be on top of every other plotting with zorder<2
#add some errorbars
plt.errorbar(tmpx,tmph,
#xerr=1, to add an x error
yerr=0.2*tmph,
linestyle='None', #to remove the line between markers
marker='.', #we just want the bars here
ecolor='k',
elinewidth=2, #the width of the errorbar
capsize=4, #the size of the cap
capthick=2, #the width of the cap (basically put the same than elinewidth)
zorder=1)
# put the y ticks label ont the right # the same can be done to put the xlabel at the top
ax.yaxis.set_label_position("right")
ax.yaxis.tick_right()
plt.ylabel(r'Data [${\rm m^2\,s^{-1}}$]',fontsize=fontsize,
rotation=-90,labelpad=20) #shift the label and rotate it for reading sake
plt.xticks(fontsize=fontsize-2) #the x-ticks
plt.yticks(fontsize=fontsize-2) #the y-ticks
#frame for the plot (do this after the right label position otherwise missing ticks)
ax.spines['left'].set_linewidth(2) #set the width of axis lines -> version without loop
ax.spines['right'].set_linewidth(2)
ax.spines['top'].set_linewidth(2)
ax.spines['bottom'].set_linewidth(2)
ax.tick_params(direction='inout',width=2,length=5,bottom=1,top=1,left=1,right=1) #set the tick parameters
plt.grid(ls=':')
#annotate the axes when multiple subplots
plt.annotate('(b)', xy=(0, 1.05),
xycoords='axes fraction',ha='right', va='bottom',
size=20)
if iplot == 2 :
plt.title('Plot stats', fontsize=fontsize,loc='left',x=0.01,y=0.02) #you can move the title to put it on the side
tmpx=x[::nplot]
tmph=h_1D[::nplot]
dx=np.gradient(tmpx) #find the spacing between gridpoints to set the bar width
plt.bar(tmpx,tmph,
width=dx, #imperative to set the width of the bars
align='center', #the alignment of the bar,
facecolor='grey',
edgecolor='k',
linewidth=2,
alpha=0.7,
label='bars' #the label
)
#add some envelope # or just plot this instead of bars
plt.step(tmpx,tmph,
where='mid', #need to set this otherwise x-shift
color='k',
linewidth=4,
label='steps'
)
#frame for the plot
ax.spines['left'].set_linewidth(2) #set the width of axis lines -> version without loop
ax.spines['right'].set_linewidth(0)
ax.spines['top'].set_linewidth(0)
ax.spines['bottom'].set_linewidth(2)
ax.tick_params(direction='in',width=2,length=10,bottom=1,top=0,left=1,right=0) #set the tick parameters
plt.xlabel('Time [s]',fontsize=fontsize) #<-- no need to be fancy here
plt.xticks(fontsize=fontsize-2) #the x-ticks
plt.yticks([-1,0,1], #which tick we show
[r'$\hat \psi^2$','nada','a lot'],
fontsize=fontsize-2)
# What a beautiful legend
legend = ax.legend(fontsize=fontsize-2,
bbox_to_anchor=[1, 0.9], #set the location of the legend
loc='center')
frame = legend.get_frame()
frame.set_linewidth(2) #the width of the legend edge
frame.set_edgecolor('k') #the color of the edge
frame.set_alpha(0.7) #make it transparent
frame.set_facecolor('gainsboro') #this is fancy
#anotation for the letter
plt.subplots_adjust(hspace=0.3, #the vertical spacing
wspace=0.1, #the horizontal spacing
)
#plt.savefig('1D.png',dpi=200,bbox_inches='tight') #don't forget the tight thing for correct positionning of annotations !!!
plt.show()
plt.loglog(x,h_1D)
[<matplotlib.lines.Line2D at 0x7fe121beefd0>]
in process
plt.subplot(121)
plt.pcolor(h_2D)
plt.colorbar()
plt.subplot(122)
plt.plot(h_2D[10,:])
[<matplotlib.lines.Line2D at 0x7fe120743520>]
# we plot the particular value of the 2D array at a given x position
ix=90
tmph=h_2D[:,ix]
tmpy=yy[:,ix]
# create your own colorbar by combining to exsting one
import matplotlib as mpl
from matplotlib import cm
from matplotlib.colors import ListedColormap, LinearSegmentedColormap
from collections import OrderedDict
ncol=500
nsample=int(ncol/4) #divide in two at 1/4 of the range
Blues = cm.get_cmap('hot_r', ncol)
Colors_Blues = Blues(np.linspace(0, 1, ncol))
mycolors=np.zeros(Colors_Blues.shape)
Reds = cm.get_cmap('Blues', ncol)
Colors_Reds = Reds(np.linspace(0, 1, nsample+1))
mycolors[nsample:]=Colors_Blues[:-nsample,:]
mycolors[:nsample+1]=Colors_Reds[::-1]
MYCMP = ListedColormap(mycolors)
fontsize = 16 #define the primary fontsize for plot # always choose > 14 otherwise we cannot read well in a paper...
fig = plt.figure(figsize = (15,10))
gs = gridspec.GridSpec(10,30)
# define the number of division #first vertical second horizontal
#its convenient to put a large number of division to perform smart tuning of the subplot position
ax=plt.subplot(gs[:,:20], #choose the position of the subplot #first vertical second horizontal
aspect='equal') #this is mandatory to do a correct plot if we plot spatial data ! same aspect ratio for x and y
#remove every ticks and make a bold frame
for axis in ['top','bottom','left','right']:
ax.spines[axis].set_linewidth(2)
ax.tick_params(direction='inout',width=0,length=0,bottom='off',top='off',left='off',right='off')
ax.yaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_major_formatter(plt.NullFormatter())
#plot the color background
pc=plt.pcolormesh(xx,yy,h_2D, #/!\ always use pcolormesh instead of pcolor !!!
cmap=MYCMP,
vmin=-1,
vmax=1,
shading='auto', #if small number of grid point rather use shading='nearest' so the position of pixels is ok
rasterized=True #this one allows to save storage if big plotting (but does not allow vectorizing...)
)
#show contours
CS=plt.contour(xx,yy,h_2D,
np.linspace(-1,1,10), #the contours we want : if symmetric vmin and vmax, choose an even number of contours to avoid the zero contour
linewidths=1, #don't forget the s
linestyles='--',
colors='k'
)
#the value of the contours
#plt.clabel(CS, fontsize=fontsize-4, inline=1,
# fmt='%2.2f') #set the format of numbers
#hatch the values inferior to trigger value
trigger=0.5
plt.contour(xx,yy,h_2D,[trigger,1000],colors='k')
plt.contourf(xx,yy,h_2D,[trigger,1000], hatches=['//'],colors='none')#,alpha=0.5)
# Do a homemade sizebar
dy_bar=1 #the size of the bar
dx_bar=1
x0=1.5 #the position of the sizebar
y0=1.5
ax.annotate('', xy=(x0,y0+dy_bar), xytext=(x0,y0),
arrowprops=dict(facecolor='black', shrink=0,width=1,headwidth=10,headlength=5),)
ax.annotate('', xy=(x0+dx_bar,y0), xytext=(x0,y0),
arrowprops=dict(facecolor='black', shrink=0,width=1,headwidth=10,headlength=5),)
t=ax.annotate('{} km'.format(int(dx_bar)), xy=(x0+dx_bar/2.,y0),
xycoords='data',ha='center', va='top',
size=15,zorder=1000)
t=ax.annotate('{} km'.format(int(dy_bar)), xy=(x0,y0+dy_bar/2.),
xycoords='data',ha='right', va='center',rotation=90,
size=15,zorder=1000)
t=ax.annotate('x'.format(dx_bar), xy=(x0+dx_bar,y0),
xycoords='data',ha='left', va='center',
size=15,zorder=1000)
t=ax.annotate('y'.format(dx_bar), xy=(x0,y0+dy_bar),
xycoords='data',ha='center', va='bottom',
size=15,zorder=1000)
#the position where we show the 1D data
plt.plot(xx[:,ix],yy[:,ix],'--k',lw=4,zorder=10)
ax0tr = ax.transData #save this axes for linking
#add a random rectangle and an annotation
dxrect=1#the size of the rectangle
dyrect=2
x0rect=6#the position of the rectangle
y0rect=2#0.5*(yll+yur)
rect = patches.Rectangle((x0rect,y0rect), dxrect, dyrect,
linewidth=2,
linestyle='--',
edgecolor='k',
facecolor='none', #if we want it to be transparent
zorder=2000) #just to put it on top of everything
ax.add_patch(rect)
t=ax.annotate('a',
xytext=(5,5),
xy=(x0rect,y0rect+dyrect),
textcoords='data', #to set the position using the data we plot
va="center",
ha="center",
fontsize=25,
zorder=1000,
color='k',
bbox=dict(boxstyle="round4", fc="w",alpha=0.8), #the style of the bow around the text
arrowprops=dict(arrowstyle="-|>",color='k') #the properties of the arrow
)
#do an insert
from mpl_toolkits.axes_grid1.inset_locator import zoomed_inset_axes
axins = zoomed_inset_axes(ax, 3, loc=2) #choose the location (what corner?) of the insert
for axis in ['top','bottom','left','right']: #frame of the insert
axins.spines[axis].set_linewidth(2)
x1, x2, y1, y2 = 6,7,8,9 # specify the limits in the data we want to zoom in
axins.set_xlim(x1, x2) # apply the x-limits
axins.set_ylim(y1, y2) # apply the y-limits
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
mark_inset(ax, axins, #choose the correct axes
loc1=1, loc2=4, #the location of links
fc="none", ec="k",lw=2)
axins.xaxis.set_visible(False)
axins.yaxis.set_visible(False)
#plot in the insert #here the same
plt.pcolormesh(xx,yy,h_2D, #/!\ always use pcolormesh instead of pcolor !!!
cmap=MYCMP,vmin=-1,vmax=1,shading='auto')
#define the colorbar
cbar_ax = fig.add_axes([0.17, 0.93, 0.4, 0.02]) #position of the colorbar (this is tricky just do tests)
cbar=fig.colorbar(pc, cax=cbar_ax,extend='both',orientation='horizontal',ticks=np.arange(-1,2,0.5))
cbar_ax.set_title(r'[$\times 10^{-5} \,{\rm kg\,s^{-5}}$]', fontsize=fontsize-2, x=1.0,y=1.02)
cbar.ax.yaxis.set_offset_position('right')
#cbar.formatter.set_powerlimits((0, 0)) #if we want scientific notation
cbar.update_ticks()
cbar.outline.set_linewidth(2)
cbar_ax.tick_params(direction='inout',width=2,length=10,labelsize=16)
ax=plt.subplot(gs[:,23:],
facecolor='w')
#remove every ticks and make a bold frame
ax.spines['top'].set_linewidth(2)
ax.spines['bottom'].set_linewidth(0)
ax.spines['right'].set_linewidth(0)
ax.spines['left'].set_linewidth(0)
ax.tick_params(direction='in',width=2,length=10,bottom=True,top=True,left=False,right=False) #sometimes this one works instead better than 'on' and 'off'
ax.yaxis.set_major_formatter(plt.NullFormatter())
ax.xaxis.set_label_position("top")
ax.xaxis.tick_top()
plt.xlabel(r'Data at x= {:.2f}'.format(xx[0,ix]),fontsize=fontsize,labelpad=15)
plt.xticks(fontsize=fontsize-2) #the x-ticks
plt.plot(tmph,tmpy,'-k',lw=2)
ax.set_xlim(-1.05,1.05)
ax.set_ylim(np.min(tmpy),np.max(tmpy))
#link the two plots
ax1tr = ax.transData
figtr = fig.transFigure.inverted()
ptB = figtr.transform(ax0tr.transform((xx[0,ix],5))) #the point in the 2D plot
ptE = figtr.transform(ax1tr.transform((tmph[70],tmpy[70]))) #the point in the 1D plot
arrow = matplotlib.patches.FancyArrowPatch(
ptE, ptB, transform=fig.transFigure,
fc = 'k',
arrowstyle='simple, head_width=10, head_length=10, tail_width=0.0',alpha = 0.7,lw= 2.,ec='k', #the parameters of the arrow
connectionstyle="arc3,rad=0.1") #the bending of the arrow
fig.patches.append(arrow)
plt.show()
#the lib for 3D plotting
from mpl_toolkits.mplot3d import Axes3D
import mpl_toolkits.mplot3d.art3d as art3d
from matplotlib.patches import Circle, PathPatch
from matplotlib.text import TextPath
from matplotlib import cm
from matplotlib.ticker import LinearLocator, FormatStrFormatter
from matplotlib.transforms import Affine2D
#this function allows some 3D text annoting
def text3d(ax, xyz, s, zdir="z", size=None, angle=0, usetex=False, **kwargs):
x, y, z = xyz
if zdir == "y":
xy1, z1 = (x, z), y
elif zdir == "y":
xy1, z1 = (y, z), x
else:
xy1, z1 = (x, y), z
text_path = TextPath((0, 0), s, size=size, usetex=usetex)
trans = Affine2D().rotate(angle).translate(xy1[0], xy1[1])
p1 = PathPatch(trans.transform_path(text_path), **kwargs)
ax.add_patch(p1)
art3d.pathpatch_2d_to_3d(p1, z=z1, zdir=zdir)
# the trick is to do 3D scatter plots
#define the two sections we want to plot
iy=33
iz=-1
#define the vertical section
xcut_vert=xxx[:iz,iy,:].ravel()
ycut_vert=yyy[:iz,iy,:].ravel()
zcut_vert=zzz[:iz,iy,:].ravel()
h_vert=h_3D[:iz,iy,:].ravel()
#define the horizontal section
xcut_horiz=xxx[iz,iy:,:].ravel()
ycut_horiz=yyy[iz,iy:,:].ravel()
zcut_horiz=zzz[iz,iy:,:].ravel()
h_horiz=h_3D[iz,iy:,:].ravel()
fig = plt.figure(figsize=(10,10))
ax = fig.add_subplot(111, projection='3d',fc='w')
#### define the view
ax.view_init(20,-75)
#remove every lines of the frame
ax.w_zaxis.line.set_lw(0.)
ax.set_zticks([])
ax.w_xaxis.line.set_lw(0.)
ax.set_xticks([])
ax.w_yaxis.line.set_lw(0.)
ax.set_yticks([])
# make the panes transparent
ax.xaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.yaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
ax.zaxis.set_pane_color((1.0, 1.0, 1.0, 0.0))
# make the grid lines transparent
ax.xaxis._axinfo["grid"]['color'] = (1,1,1,0)
ax.yaxis._axinfo["grid"]['color'] = (1,1,1,0)
ax.zaxis._axinfo["grid"]['color'] = (1,1,1,0)
#plot the vertical section
nplot=1
ax.scatter(xcut_vert[::nplot], ycut_vert[::nplot], zcut_vert[::nplot],c=h_vert[::nplot],\
s=20, #this one needs to be adapted depending on the resolution
cmap=MYCMP,
vmin=-1,vmax=1,
marker='s',
edgecolor='None')
#plot the horizontal section
ax.scatter(xcut_horiz[::nplot], ycut_horiz[::nplot], zcut_horiz[::nplot],c=h_horiz[::nplot],\
s=20,
cmap=MYCMP,
vmin=-1,vmax=1,
marker='s',
edgecolor='None')
#plot some lines to delimitate the plot
lw=5
plt.plot(xxx[iz,iy,:],yyy[iz,iy,:],zzz[iz,iy,:],'-k',lw=lw,zorder=10)
plt.plot(xxx[iz,-1,:],yyy[iz,-1,:],zzz[iz,-1,:],'-k',lw=lw,zorder=10)
plt.plot(xxx[0,iy,:],yyy[0,iy,:],zzz[0,iy,:],'-k',lw=lw,zorder=10)
plt.plot(xxx[:,iy,0],yyy[:,iy,0],zzz[:,iy,0],'-k',lw=lw,zorder=10)
plt.plot(xxx[:,iy,-1],yyy[:,iy,-1],zzz[:,iy,-1],'-k',lw=lw,zorder=10)
plt.plot(xxx[iz,iy:,0],yyy[iz,iy:,0],zzz[iz,iy:,0],'-k',lw=lw,zorder=10)
plt.plot(xxx[iz,iy:,-1],yyy[iz,iy:,-1],zzz[iz,iy:,-1],'-k',lw=lw,zorder=10)
#the colorbar
cbar_ax = fig.add_axes( [0.72,0.3,0.012,0.15 ] )
cbar = fig.colorbar( pc , cax=cbar_ax,extend='both',orientation='vertical',ticks=np.arange(-1,2,0.5))
plt.title( r'$[{\rm .10^{-9}\,s^{-3}}]$',fontsize=14,x=2 )
cbar.ax.tick_params(labelsize=14,direction='in',width=1,size=5)
cbar.ax.xaxis.set_label_position('top')
cbar.ax.xaxis.set_ticks_position('both')
cbar.outline.set_linewidth(2)
#annotate in 3D
date=("ce qu'on veut")
text3d(ax, (0, 11, 0), date, zdir="z", size=0.8, usetex=False,
ec="none", fc="k",angle=0)
plt.show()