AJMR-Python-Baird/Mustique/adcptool/quickviz.py

468 lines
16 KiB
Python

# -*- coding: iso-8859-15 -*-
'''
Created on 14.09.2012
@author: Jakob
'''
from __future__ import print_function
#
#import matplotlib.cm as cm
def plot_matrix(m):
import matplotlib.pyplot as plt
plt.imshow(m, interpolation='none', cmap = plt.cm.Spectral) # @UndefinedVariable
plt.show()
def subplot_matrix(m):
import matplotlib.pyplot as plt
for i in range(m.shape[2]):
plt.subplot(m.shape[2]*100 + 11 + i)
plt.imshow(m[:,:,i], interpolation='none', cmap = plt.cm.Spectral) # @UndefinedVariable
plt.show()
def plot_logfit_ensemble(e, cfg):
import numpy as np
import matplotlib.pyplot as plt
# prepare data in lists
depth = e.depth
z_max = depth * cfg['logheight']
z = []
v = []
for c in e.cells:
z.append(depth + c.z_position)
v.append(c.velocity.magn2d() if cfg['component'] == 3 else c.velocity[cfg['component']] )
# fitted velocity profile with more points to look nicer
z_dense = np.linspace(0, depth)
v_dense = (2.5 * np.log(30 * z_dense / e.ks)) * e.v_shear
# actual "raw" data
plt.plot(v,z)
plt.plot(v_dense, z_dense)
plt.grid(True)
plt.show()
def plot_logfit_ensembles(p, cfg, initial_ensemble=100):
'''
like plot_logfit_ensemble() but with interactiveness
based on: http://matplotlib.org/mpl_examples/widgets/slider_demo.py
'''
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.widgets import Slider
from pylab import axes
# prepare data in lists
depth = p.ensembles[initial_ensemble].depth
z_max = depth * cfg['logheight']
z,v = [],[]
for c in p.ensembles[initial_ensemble].cells:
z.append(depth + c.z_position)
v.append(c.velocity.magn2d()() if cfg['component'] == 3 else c.velocity[cfg['component']] )
# fitted velocity profile with more points to look nicer
z_dense = np.linspace(0, depth)
v_dense = (2.5 * np.log(30 * z_dense / p.ensembles[initial_ensemble].ks)) * p.ensembles[initial_ensemble].v_shear
# actual "raw" data
p1, = plt.plot(v,z)
p2, = plt.plot(v_dense, z_dense)
plt.grid(True)
# update function.
def update(en):
en = int(en)
if not p.ensembles[en].void:
z = []
v = []
for c in p.ensembles[en].cells:
z.append(depth + c.z_position)
v.append(c.velocity.magn2d() if cfg['component'] == 3 else c.velocity[cfg['component']] )
z_dense = np.linspace(0, depth)
v_dense = (2.5 * np.log(30 * z_dense / p.ensembles[en].ks)) * p.ensembles[en].v_shear
p1.set_data(v,z)
p2.set_data(v_dense, z_dense)
ens_slider = Slider(axes([0.25, 0.1, 0.65, 0.03]), label='Ensemble', valmin=0, valmax=len(p.ensembles)-1, valinit=initial_ensemble, valfmt='%1.0f')
ens_slider.on_changed(update)
plt.show()
def plot_logfit_profile(p, cfg):
'''
plot some data regarding the estimated roughness
kwargs:
p ... the profile in question
cfg ... config that was used for logfit_profile()
'''
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
data = np.zeros(shape=(len(p.ensembles), 8))
data_mask = np.zeros(shape=(len(p.ensembles), 8))
'''
array indices:
0 ks
1 tau_shear
2 v_shear
3 a a from ln(z) = a*v + b
4 b b from ln(z) = a*v + b
5 r pearson correlation coefficient
6 n numer of cells taken for fitting
7 depth
'''
for i in range(len(p.ensembles)):
if hasattr(p.ensembles[i], 'ks'):
data[i,0] = p.ensembles[i].ks
data[i,1] = p.ensembles[i].tau_shear
data[i,2] = p.ensembles[i].v_shear
data[i,3] = p.ensembles[i].logfit_debug[0]
data[i,4] = p.ensembles[i].logfit_debug[1]
data[i,5] = p.ensembles[i].logfit_debug[2]
data[i,6] = p.ensembles[i].logfit_debug[4]
else:
data_mask[i,:] = 1
data[i,7] = p.ensembles[i].depth if p.ensembles[i].depth > 0 else 0
data_masked = np.ma.masked_array(data, data_mask)
x = list(range(len(p.ensembles)))
plt.figure(1)
plt.subplot(311)
cell_hi = []
cell_lo = []
cell_lg = [] # depth of last cell used for logfit
for e in p.ensembles:
if not e.void:
temp = [-i.z_position for i in e.cells]
cell_hi.append(min(temp)) # topmost cells
cell_lo.append(max(temp)) # lowest cells
z_max = e.depth * (1 - cfg['logheight'] )
cell_lg.append(max([z if z<z_max else 0 for z in temp]))
# cell_lg.append((e.cells[0] - e.cells[1]) * data[] )
else:
# if no void value
cell_hi.append(0)
cell_lo.append(0)
cell_lg.append(0)
cell_hi = np.array(cell_hi)
cell_lo = np.array(cell_lo)
cell_lg = np.array(cell_lg)
plt.plot(x, data[:,7], color='0', linewidth=2, label='depth')
plt.plot(x, data_masked[:,6], label='# of cells used')
plt.gca().invert_yaxis()
plt.bar(np.array(x)-0.5, height=cell_lo-cell_hi, width=[1]*len(x), bottom=cell_hi, color='0.95', linewidth=0, label='existing cell')
plt.bar(np.array(x)-0.5, height=-data_masked[:,6]*p.cell_height, bottom=cell_lo, width=[1]*len(x), color='0.8', linewidth=0, label='cell used for logfit')
#plt.fill_between(x, cell_lo, cell_hi, color='0.95', label='existing cell')
#plt.fill_between(x, cell_lo, cell_lg, color='0.8', label='cell used for logfit')
plt.xlim(0,max(x))
plt.ylabel('depth [m], # of used cells')
plt.grid(True)
# small legend font
fontP = FontProperties()
fontP.set_size('small')
plt.legend(loc=2, bbox_to_anchor=(1,1), prop=fontP)
# plot #2: log things
plt.subplot(312)
p1 = plt.scatter(x, abs(data_masked[:,0]), marker='x', color='0', label='ks')
plt.ylim(0,100)
plt.xlim(0,max(x))
plt.ylabel('ks [m]')
# plt.yscale('log')
plt.grid(True)
plt.twinx()
p2 = plt.scatter(x, data_masked[:,1], marker='x', color='.5', label='tau_shear')
plt.ylabel('tau_shear [N/m^2]')
plt.legend([p1, p2], ['ks', 'tau_shear'], loc=2, bbox_to_anchor=(1.03,1), prop=fontP)
plt.xlim(0,max(x))
# plot #3: linear data
plt.subplot(313)
plt.scatter(x, abs(data_masked[:,5]), marker='x', color='0')
plt.ylabel('correlation coefficient')
plt.xlim(0,max(x))
plt.grid(True)
# i = 0
# print(('median: {}, min: {}, max: {}'.format(np.ma.median(data_masked[:,i]), data_masked[:,i].min(), data_masked[:,i].max())))
plt.show()
def plot_profile_3d(p, cfg={}, vmin=None, vmax=None, axes=None, ymin=None, ymax=None):
'''
general profile plotting function
cfg vars:
datatype string determines what to plot. available types:
- "velocity" requires variable $component
- "custom" requires variable $cellattr
- "backscatter" (not implemented yet)
components list a list of of velocity components, that will be used. valid components: "x", "y", "z"
cellattr string the attribute of cell the cells that will be plotted.
style string visualization method. implemented methods: "contour", "gradient", "vector"
saveas string path to output file, optional
title string title of plot, optional
'''
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import rc
from outliers import get_cell_matrix, get_valuematrix_from_cellmatrix
if 'style' in cfg and cfg['style'] not in ["contour", "gradient", "vector", "stream"]:
raise NotImplementedError('plot_profile(): "{}" is not a valid plot style!'.format(cfg['style']))
#
# default values
cfg_datatype = cfg['datatype'] if 'datatype' in cfg else 'velocity'
cfg_components = cfg['components'] if 'components' in cfg else ['x', 'y']
cfg_style = cfg['style'] if 'style' in cfg else 'gradient'
#
# produce profile coordinates
# max number of cells, for the matrix size..
# ymax = max([len(e.cells) for e in p.ensembles])
# x
e_positions = [e.position for e in p.ensembles]
x = [0]
for i in range(1, len(e_positions)):
x.append(x[i-1] + (e_positions[i] - e_positions[i-1]).magn())
# z
# z with possible irregular values (when extrapolated)
# ensemble with most cells, to steal the z positions of the cells
ncells = [len(e.cells) if hasattr(e, 'cells') else 0 for e in p.ensembles]
longestensemble = ncells.index(max(ncells))
z = [c.z_position for c in p.ensembles[longestensemble].cells]
# profile depth
z_depth = np.ma.masked_array([-e.depth for e in p.ensembles], [e.void for e in p.ensembles])
z_depths = -np.ma.masked_array([e.four_depths for e in p.ensembles],[[e.void, e.void, e.void, e.void] for e in p.ensembles])
# matrix with ProcesscedCell objects
cm = get_cell_matrix(p)
#
# fetch data to be displayed
data = []
if cfg_datatype == 'velocity':
for c in cfg_components:
if c in ['x', 'y', 'z']:
eval = '.velocity.'+c
data.append(get_valuematrix_from_cellmatrix(cm, eval, outputs=1, nvalues=1))
else:
raise NotImplementedError('plot_profile(): "{}" is not a valid component!'.format(c))
elif cfg_datatype == 'custom':
for ca in cfg['cellattr']:
data.append(get_valuematrix_from_cellmatrix(cm, ca, outputs=1, nvalues=1))
else:
raise NotImplementedError('plot_profile(): "{}" is not a valid datatype!'.format(cfg['datatype']))
# matrix to mask the profile
goodmat = get_valuematrix_from_cellmatrix(cm, eval, outputs=2, nvalues=1)
#
# prepare data depending on plot style
plot_data = np.zeros(shape=(data[0].shape[0], data[0].shape[1], 2))
for i in range(data[0].shape[0]):
for j in range(data[0].shape[1]):
if cfg_style != 'vector':
# merge data into a scalar by computing its magnitude
plot_data[i,j] = np.sqrt((np.array([d[i,j,0] for d in data]) ** 2).sum())
else:
# re-order data for vector plotting
temp = np.array([d[i,j,0] for d in data])
plot_data[i,j] = temp
# mask unusable matrix data (eg. parts not inside the river)
plot_data = np.ma.masked_array(plot_data, np.dstack((~goodmat, ~goodmat)))
#
# actually plot
# rc('text', usetex=True) # enable this to use TeX type setting
# rc('font', family='serif') # font closer to LaTeX documents
# river depth
# FIXME see [] on how to customize line plots
if axes is None:
fig, ax = plt.figure(figsize=(20, 5))
else:
ax = axes
ax.plot(x, z_depths, '0.5')
ax.plot(x, z_depth, 'k', linewidth=2)
if ymin is not None:
ax.set_ylim(ymin, ymax)
else:
ax.set_ylim(ymax=0)
ax.set_xlim(0, max(x))
# plt.tight_layout()
# ax.set_xlabel('Profile station [m]')
ax.set_ylabel('Profile depth [m]')
ax.set_title(cfg['title'] if 'title' in cfg else 'section view')
# default "jet" color map is bad: http://www.jwave.vt.edu/~rkriz/Projects/create_color_table/color_07.pdf
cmap = plt.cm.turbo # @UndefinedVariable
# cmap = plt.cm.Spectral # @UndefinedVariable
if cfg_style == 'gradient':
# re align grid and append one value, because pcolor() puts values in between the x/z grid
# see http://matplotlib.org/api/pyplot_api.html?highlight=pcolor#matplotlib.pyplot.pcolor
x_pcolor = np.append(np.array(x), x[-1] + p.cell_height) - p.cell_height / 2.0
z_pcolor = np.append(np.array(z), z[-1] - p.cell_height) + p.cell_height / 2.0
colorPlot = ax.pcolor(x_pcolor, z_pcolor, plot_data[:,:,0], cmap=cmap)
# plt.colorbar(pad=0.01)
elif cfg_style == 'contour':
number_of_contours = 10
colorPlot = ax.contourf(x, z, plot_data[:,:,0], 256, interpolation='none', cmap=cmap) # @UndefinedVariable, dunno why eclipse doent find this cm..
ax.contour(x, z, plot_data[:,:,0], number_of_contours, interpolation='none') # @UndefinedVariable
#plt.colorbar()
elif cfg_style == 'vector':
ax.quiver(x, z, plot_data[:,:,0], plot_data[:,:,1], width=0.001)
# elif cfg_style == 'stream':
# plt.streamplot(np.array(x), np.array(z), plot_data[:,:,0], plot_data[:,:,1])
#fig.subplots_adjust(bottom=0.10, left=0.04, right=0.98, top=0.92)
# color bar if needed
# if cfg_style in ['gradient', 'contour']:
# # fixes to remove unneeded whitespace
# plt.colorbar(colorPlot, fraction=.05, pad=0.01, ax=axes)
ax.grid(True)
if vmin is not None:
colorPlot.set_clim(vmin=vmin)
if vmax is not None:
colorPlot.set_clim(vmax=vmax)
# optionally save the produced image. otherwise it will be displayed
# if not 'saveas' in cfg or cfg['saveas'] == False:
# plt.show()
# else:
# fig.savefig(cfg['saveas'])
# clear figure and axis.
#plt.clf()
#plt.cla()
def plot_profile_2d(p, cfg=[]):
''' plot the ground view
cfg vars:
vscale float scale the the displayed velocity vectors
saveas string path to output file, optional
title string title of plot, optional
'''
import matplotlib.pyplot as plt
import numpy as np
# position of ensembles
x = [e.position.x for e in p.ensembles]
y = [e.position.y for e in p.ensembles]
# velocity components. expects uv_rot to be False!!
vx = [e.velocity.x if not e.void else 0 for e in p.ensembles]
vy = [e.velocity.y if not e.void else 0 for e in p.ensembles]
# average length for the quiverkey
avglen = np.sqrt(np.array(vx) ** 2 + np.array(vy) ** 2).mean()
displen = np.around(avglen, np.int(np.ceil(np.abs(np.log10(avglen)))))
# scale the vectors
vscale = cfg['vscale'] if 'vscale' in cfg else 1
#print(vscale)
# FIXME: scale doesnt have any effect!
plt.plot(x, y, marker='x', color='black')
plt.scatter(x[0], y[0], marker='o')
plt.axis('equal')
plt.grid()
q = plt.quiver(x, y, vx * vscale, vy * vscale, width=0.003, color='grey')
plt.quiverkey(q, 0.2, 0.05, displen * vscale, 'velocity: {} [m/s]'.format(displen))
plt.title(cfg['title'] if 'title' in cfg else 'plan view')
plt.ylabel('y coordinate [m]')
plt.xlabel('x coordinate [m]')
if not 'saveas' in cfg or cfg['saveas'] == False:
plt.show()
else:
plt.savefig(cfg['saveas'])
pass
# clear figure and axis.
plt.clf()
plt.cla()
if __name__ == '__main__':
print('importing')
import pickle
print('unpickle')
p, p4, p5 = pickle.load(open('../testfiles/debug.pickle','rb'))
print('plot_profile')
# cfg_plot = dict(datatype='velocity', components=['y', 'z'], style='contour', saveas='../testfiles/testplot.pdf')
cfg_plot = dict(datatype='velocity', components=['x', 'y'], style='vector', saveas=False)
#plot_profile_3d(p, cfg_plot)
from averaging import thin_out
p1 = thin_out(p, dict(keep_ensemble=5, keep_cell=1))
#plot_profile_2d(p, cfg_plot)
plot_profile_3d(p1, dict(Xsaveas='../testfiles/aspecttest.pdf', style='vector', components=['y','z']))