Oceanographic plotting in Python - python

I am plotting graphs. And I would like to have the range of values on the colorbars for graphs "U_velocity" and "U_shear_velocity" from -0.3 to 0.3. Moreover, I am trying to make the range of x ax in hours from 0 to 12.5 for U and V shear velocity plots but nothing works and instead of that I have meanings of the speed. How can I do that, please help me.
from netCDF4 import *
import matplotlib as mp
import numpy as np
#import matplotlib.pyplot as plt
import pylab as plt
#%%
file = "/home/vlad/Desktop/task/Untitled Folder/result.nc"
ncdata = Dataset(file, 'r')
u = np.squeeze(ncdata.variables['u'][:])
v = np.squeeze(ncdata.variables['v'][:])
z = np.squeeze(ncdata.variables['z'][:])
time = ncdata.variables['time'][:]/3600
ncdata.close()
u_mean = np.mean(u[0:100,:],0)
z_mean = np.mean(z[0:100,:],0)
v_mean = np.mean(v[0:100,:],0)
u_mean_10 = u[900:1000,:]
v_mean_10 = v[900:1000,:]
z_10 = np.mean(z[900:1000,:],0)
time_10 = time[900:1000] - time[900]
T = len(time_10)
L = len(z_10)
fig = plt.figure(6)
plt.pcolormesh(time_10,z_10,u_mean_10.T)
plt.xlim([0, time_10[-1]])
fig.suptitle('U_velocity', fontsize=25)
plt.xlabel('time', fontsize=20)
plt.ylabel('depth(m)', fontsize=20)
plt.colorbar()
plt.show()
shear_u_mean_10 = np.zeros([T,L])
for t in range(T):
for i in range(L-1):
tmp=(u_mean_10[t, i+1]-u_mean_10[t, i])/(z_10[i+1]-z_10[i])
tmp_depth = 0.5 * (z_10[i+1]+z_10[i])
shear_u_mean_10[t,i] = tmp
fig = plt.figure(10)
plt.pcolormesh(time_10/3600,z_10, shear_u_mean_10.T)
plt.xlim([0, time_10[-1]/3600])
plt.colorbar()
#plt.ylim([-30, -25])
fig.suptitle('U_shear velocity', fontsize=25)
plt.xlabel('time', fontsize=20)
plt.ylabel('depth(m)', fontsize=20)
plt.show()
shear_v_mean_10 = np.zeros([T,L])
for t in range(T):
for i in range(L-1):
tmp=(v_mean_10[t, i+1]-v_mean_10[t, i])/(z_10[i+1]-z_10[i])
tmp_depth = 0.5 * (z_10[i+1]+z_10[i])
shear_v_mean_10[t,i] = tmp
fig = plt.figure(11)
plt.pcolormesh(time_10/3600,z_10, shear_v_mean_10.T)
plt.xlim([0, time_10[-1]/3600])
plt.colorbar()
#plt.ylim([-30, -25])
fig.suptitle('V_shear velocity', fontsize=25)
plt.xlabel('time', fontsize=20)
plt.ylabel('depth(m)', fontsize=20)
plt.show()
fig = plt.figure(7)
plt.pcolormesh(time_10,z_10,v_mean_10.T)
plt.xlim([0, time_10[-1]])
fig.suptitle('V_velocity', fontsize=25)
plt.xlabel('time', fontsize=20)
plt.ylabel('depth(m)', fontsize=20)
plt.colorbar()
plt.show()

This is not an easy question to answer with a wall of code, reference to unknown file result.nc and several unrelated and fairly specific problems. The following may help:
The colorbar range can be set by passing vmin=-0.3 and vmax=0.3 to pcolormesh.
To limiting the range of time, you can use array slicing (e.g. time[time<12.5], u[time<12.5]).
For your data, surely the speed is just speed = np.sqrt(np.power(u,2) + np.power(v,2)
Please provide a Minimal, Complete, and Verifiable example if you want further help.

Related

Modifying saved plot with matplotlib

I am having a problem right now. I have run an extremely heavy simulation and, thus, generated a plot with matplotlib containing the results and saved it (as .jpg). However, there are some elemnts of the plot I would like to change, such as labels size and one vertical line. Is there a straighforward way to do this using matplotlib? I know I could have stored the data and now just replot changing the parameters (and, actually, I have done this), but I was wondering whether there is an easier way. Maybe something like:
fig, ax = plt.figure(path_to_figure)
ax.set_ylabel("Y_label")
...
You can refer to below example, which gives you more idea on how you can do this while plotting everything.
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
%matplotlib inline
plt.rc('text', usetex=True)
def f(t):
return t ** 2
t1 = np.arange(0.0, 2.0, 0.1)
noise = np.random.randn(len(t1)) * 0.04
# x coordinates for the lines
xcoords = [0.1, 0.3, 0.5]
# colors for the lines
colors = ['r','k','b']
fig = plt.figure(figsize=(4, 3), dpi=200)
ax = fig.add_subplot(1, 1, 1)
plt.scatter(t1, f(t1 + noise), color = 'hotpink', label='Values obtained by experiment', edgecolors='k')
plt.plot(t1, f(t1), ls='solid', label='Theoretical expectation', color='b')
plt.title(r'This is latex title example $\mathbf{E = m \times c^2}$', fontsize='small')
for xc,c in zip(xcoords,colors):
plt.axvline(x=xc, label='line at x = {}'.format(xc), c=c)
plt.grid()
plt.legend(loc=0)
If you want to make all the fonts bold, you can also use below code to make everything bold:
font = {'weight' : 'bold',
'size' : 14 }
plt.rc('font', **font)
def f(t):
return t ** 2
t1 = np.arange(0.0, 2.0, 0.1)
noise = np.random.randn(len(t1)) * 0.04
# x coordinates for the lines
xcoords = [0.1, 0.3, 0.5]
# colors for the lines
colors = ['r','k','b']
fig = plt.figure(figsize=(4, 3), dpi=200)
ax = fig.add_subplot(1, 1, 1)
plt.scatter(t1, f(t1 + noise), color = 'hotpink', label='Values obtained by experiment', edgecolors='k')
plt.plot(t1, f(t1), ls='solid', label='Theoretical expectation', color='b')
plt.title(r'This is latex title example $\mathbf{E = m \times c^2}$', fontsize='small')
plt.xlabel("This is X-label.", fontsize=12)
plt.ylabel("This is Y-label.", fontsize=16)
for xc,c in zip(xcoords,colors):
plt.axvline(x=xc, label='line at x = {}'.format(xc), c=c)
plt.grid()
plt.legend(loc=(1.15,0.2))

python: sns distplot area overlap

How can I get the overlapping area of 2 sns.distplots?
Apart from the difference in mean (as below) I would like to add a number that descripes how different the (normalised) distributions are (for example 2 distributions could have the same mean but still look very different if they are not normal).
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
x1 = np.random.normal(size=2000)
x2 = np.random.normal(size=1000)+1
sns.distplot(x1, hist=False, kde=True, color="r", norm_hist=True)
sns.distplot(x2, hist=False, kde=True, color="b", norm_hist=True)
m1 = x1.mean()
m2 = x2.mean()
plt.title("m1={:2.2f}, m2={:2.2f} (diffInMean={:2.2f})".format(m1, m2, m1-m2))
plt.show(block=True)
If somebody is interested: I have approximated it now with an integral of the distributions (unfortunately not quite the 1-liner I was searching for):
data1 = np.random.normal(size=9000)
data2 = np.random.normal(size=5000, loc=0.5, scale=1.5)
num_bins = 100
xmin = min(data1.min(), data2.min())
xmax = max(data1.max(), data2.max())
bins = np.linspace(xmin, xmax, num_bins)
weights1 = np.ones_like(data1) / float(len(data1))
weights2 = np.ones_like(data2) / float(len(data2))
hist_1 = np.histogram(data1, bins, weights=weights1)[0]
hist_2 = np.histogram(data2, bins, weights=weights2)[0]
tvd = 0.5*sum(abs(hist_1 - hist_2))
print("overlap: {:2.2f} percent".format((1-tvd)*100))
plt.figure()
ax = plt.gca()
ax.hist(data1, bins, weights=weights1, color='red', edgecolor='white', alpha=0.5)[0]
ax.hist(data2, bins, weights=weights2, color='blue', edgecolor='white', alpha=0.5)[0]
plt.show()

Connector patch between subplots with animation not visible (matplotlib)

I am using an artist animation method with 5 subplots. There is one static plot on the left, with 3 smaller animated imshow plots to the right (the colorbar is the 5th). I have successfully used ConnectionPatch to connect subplots to show where the data is coming from, but only on static plots. No matter what I try, I can't seem to get the patches to show up on the animation. I've tried to include the patch in the image artist list, tried to update the figure with the artist instead of the axis (which I guess doesn't make much sense), among other things. It will be very difficult to extract a working example due to the complexity of the plot, but maybe someone has a tip.
Could setting the facecolor to 'white' with the animation savefig_kwargs be covering up the connector lines? If so, how do I change the z order of the patch/facecolor?
Without a minimal working example, I can only tell you that it is possible to use a ConnectionPatch in an animation. However, as seen below, one has to recreate it for every frame.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(0)
import matplotlib.gridspec as gridspec
from matplotlib.patches import ConnectionPatch
import matplotlib.animation
plt.rcParams["figure.figsize"] = np.array([6,3.6])*0.7
x = np.linspace(-3,3)
X,Y = np.meshgrid(x,x)
f = lambda x,y: (1 - x / 2. + x ** 5 + y ** 3) * np.exp(-x ** 2 - y ** 2)+1.5
Z = f(X,Y)
bins=np.linspace(Z.min(), Z.max(), 16)
cols = plt.cm.PuOr((bins[:-1]-Z.min())/(Z.max()-Z.min()))
gs = gridspec.GridSpec(2, 2, height_ratios=[34,53], width_ratios=[102,53])
fig = plt.figure()
ax=fig.add_subplot(gs[:,0])
ax2=fig.add_subplot(gs[0,1])
ax3=fig.add_subplot(gs[1,1])
ax.imshow(Z, cmap="PuOr")
rec = plt.Rectangle([-.5,-.5], width=9, height=9, edgecolor="crimson", fill=False, lw=2)
conp = ConnectionPatch(xyA=[-0.5,0.5], xyB=[9.5,4], coordsA="data", coordsB="data",
axesA=ax3, axesB=ax, arrowstyle="-|>", zorder=25, shrinkA=0, shrinkB=1,
mutation_scale=20, fc="w", ec="crimson", lw=2)
ax3.add_artist(conp)
ax.add_artist(rec)
im = ax3.imshow(Z[:9,:9], cmap="PuOr", vmin=Z.min(), vmax=Z.max())
ticks = np.array([0,4,8])
ax3.set_yticks(ticks); ax3.set_xticks(ticks)
ax2.hist(Z[:9,:9].flatten(), bins=bins)
def ins(px,py):
global rec, conp, histpatches
ll = [px-.5,py-.5]
rec.set_xy(ll)
conp.remove()
conp = ConnectionPatch(xyA=[-0.5,0.5], xyB=[px+9.5,py+4], coordsA="data", coordsB="data",
axesA=ax3, axesB=ax, arrowstyle="-|>", zorder=25, shrinkA=0, shrinkB=1,
mutation_scale=20, fc="w", ec="crimson", lw=2)
ax3.add_patch(conp)
data = Z[px:px+9,py:py+9]
im.set_data(data)
ax3.set_xticklabels(ticks+px)
ax3.set_yticklabels(ticks+py)
ax2.clear()
ax2.set_ylim(0,60)
h, b_, patches = ax2.hist(data.flatten(), bins=bins, ec="k", fc="#f1a142")
[pat.set_color(cols[i]) for i, pat in enumerate(patches)]
def func(p):
px,py = p
ins(px, py)
phi = np.linspace(0.,2*np.pi)
r = np.sin(2*phi)*20+np.pi/2
xr = (r*np.cos(phi)).astype(np.int8)
yr = (r*np.sin(phi)).astype(np.int8)
plt.subplots_adjust(top=0.93,bottom=0.11,left=0.04,right=0.96,hspace=0.26,wspace=0.15)
frames = np.c_[xr+20, yr+20]
ani = matplotlib.animation.FuncAnimation(fig, func, frames=frames, interval=300, repeat=True)
plt.show()

How to create equal number of primary and secondary y-axes ticks with matplotlib?

I have been working for a while to create a plot with secondary axis so that both the primary and secondary axes have equal number of major ticks so that the grid lines coincide. In the figure below I have shown grid lines on the secondary axis to illustrate the problem.
By manually setting the secondary axis limits I got this plot, which is my desired output:
I have included the reproducible code:
import numpy as np
import matplotlib.pyplot as plt
data = np.loadtxt('data.dat', skiprows=2, delimiter=',', unpack=True).transpose()
time = data[:,0]
pressure = data[:,1]
lift = data[:,2]
figure_pressure_trace = plt.figure(figsize=(5.15, 5.15))
figure_pressure_trace.clf()
P_vs_t = plt.subplot(111)
P_vs_t.plot(time, pressure, linewidth=1.0)
P_vs_t.set_ylabel(r'\textit{Pressure (bar)}', labelpad=6)
P_vs_t.set_xlabel(r'\textit{Time (ms)}', labelpad=6)
lift_vs_t = P_vs_t.twinx()
lift_vs_t.plot(time, lift, color='#4DAF4A')
lift_vs_t.set_ylabel(r'\textit{Lift(mm)}', labelpad=6)
plt.show()
plt.close()
The data is available here.
UPDATE:
I created a function to create equal number of ticks, the entire code is:
import numpy as np
import matplotlib.pyplot as plt
def equal_y_ticks(primary, secondary):
y_min_primary, y_max_primary = primary.get_ybound()
y_min_secondary, y_max_secondary = secondary.get_ybound()
primary_ticks = len(primary.yaxis.get_major_ticks())
secondary_ticks = len(secondary.yaxis.get_major_ticks())
primary_spacing = (y_max_primary - y_min_primary) / (primary_ticks - 1)
secondary_spacing = (y_max_secondary - y_min_secondary) / (secondary_ticks - 1)
ticks = max(primary_ticks, secondary_ticks)
if secondary_ticks < primary_ticks:
y_max_secondary = y_min_secondary + (primary_ticks * secondary_spacing)
secondary.yaxis.set_ticks(np.arange(y_min_secondary, y_max_secondary, secondary_spacing))
else:
y_max_primary = y_min_primary + (secondary_ticks * primary_spacing)
primary.yaxis.set_ticks(np.arange(y_min_primary, y_max_primary, primary_spacing))
data = np.loadtxt('data.dat', skiprows=2, delimiter=',', unpack=True).transpose()
time = data[:,0]
pressure = data[:,1]
lift = data[:,2]
figure_pressure_trace = plt.figure(figsize=(5.15, 5.15))
figure_pressure_trace.clf()
P_vs_t = plt.subplot(111)
P_vs_t.plot(time, pressure, linewidth=1.0)
P_vs_t.set_ylabel(r'\textit{Pressure (bar)}', labelpad=6)
P_vs_t.set_xlabel(r'\textit{Time (ms)}', labelpad=6)
lift_vs_t = P_vs_t.twinx()
lift_vs_t.plot(time, lift, color='#4DAF4A')
equal_y_ticks(P_vs_t, lift_vs_t)
lift_vs_t.set_ylabel(r'\textit{Lift(mm)}', labelpad=6)
plt.show()
plt.close()
But this function gives me plots like these (for some data):
I think you are looking for LinearLocator (docs)
import matplotlib.pyplot as plt
from matplotlib import ticker as mtick
fig, ax = plt.subplots()
ax2 = ax.twinx()
ax.yaxis.set_major_locator(mtick.LinearLocator(5))
ax2.yaxis.set_major_locator(mtick.LinearLocator(5))
ax.set_ylim(0, 15)
ax2.set_ylim(0, 1500)
ax.yaxis.grid(True, lw=7, color='g', ls='--')
ax2.yaxis.grid(True, color='k', ls='-', lw=3)
Which will put N evenly spaced ticks between the min and max.

Animation with matplotlib where points are dynamically added to a graph

I've written a simple code which generates random points (x0, y0) between certain values using a while loop. After the coordinates of each point are set, that point is drawn in an empty graph which is showed at the end of the while loop.
However, I would like to set up an animation with matplotlib which would allow me to see the initial graph and the points progressively added to it as the code is calculating them. I've looked for some examples but the ones I found are mainly concerned with waves and so on and I guess I need a slightly different approach.
This is the basic code:
from numpy import *
from pylab import *
import random
figure(figsize=(8,6), dpi=150)
x = np.linspace(-1, 4.5, 250)
h=5
a=0.5
b=4
ylim(-0.5,5.5)
xlim(-1,5.0)
i= 0
while i< 500:
R1 = random.random()
R2 = random.random()
x0 = (b - a)*R1 + a
y0 = h*R2
scatter(x0, y0, 10, color="red")
i = i + 1
show()
Thanks for your help!
EDIT: ANIMATION CODE
import numpy as np
import matplotlib.pyplot as plt
from pylab import *
import matplotlib.animation as animation
import random
fig = plt.figure(figsize=(8,6), dpi=150)
x = np.linspace(-2, 4.5, 250)
h=4
a=1
b=3
hlines(y=h, xmin=1, xmax=3, linewidth=1.5)
vlines(x=a, ymin=0, ymax=4, linewidth=1.5)
vlines(x=b, ymin=0, ymax=4, linewidth=1.5)
ylim(-2.5,10.5)
xlim(-2.5,4.5)
grid()
def data_gen():
i = 0
while i< 1:
R1 = random.random()
R2 = random.random()
x0 = (b - a)*R1 + a
y0 = h*R2
i = i + 1
yield x0, y0
line, = plot([], [], linestyle='none', marker='o', color='r')
ax = gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
xdata, ydata = [], []
def run(data):
x0,y0 = data
xdata.append(x0)
ydata.append(y0)
line.set_data(xdata, ydata)
return line,
ani = animation.FuncAnimation(fig, run, data_gen, blit=True, interval=0.5,
repeat=False)
plt.show()
I do not know if this is exactly what you are looking for; in any case, you can generate random points inside the run function and there plot them. You do not need neither blit = True nor clear the axis from one frame to another.
Here is my code:
from pylab import *
from matplotlib.animation import FuncAnimation
import random
fig = plt.figure(figsize=(8,6), dpi=150)
x = np.linspace(-2, 4.5, 250)
h=4
a=1
b=3
hlines(y=h, xmin=a, xmax=b, linewidth=1.5)
vlines(x=a, ymin=0, ymax=h, linewidth=1.5)
vlines(x=b, ymin=0, ymax=h, linewidth=1.5)
ylim(-2.5,10.5)
xlim(-2.5,4.5)
grid()
ax = gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
def run(i):
R1 = random.random()
R2 = random.random()
x0 = (b - a)*R1 + a
y0 = h*R2
ax.scatter(x0, y0, 10, color='red')
ani = FuncAnimation(fig = fig, func = run, frames = 500, interval = 10, repeat = False)
plt.show()
which produces this animation:
(I cut this animation to 100 points in order to get a lighter file, less than 2 MB; the code above produces an animation wiht 500 points)

Categories