"""
plot.py - Plotting module for DAS4Whales
This module provides functions for plotting das data and data products in various formats.
Authors: Léa Bouffaut, Quentin Goestchel
Date: 2023-2024
"""
from __future__ import annotations
from datetime import datetime
from typing import Dict, List, Tuple, Union, Optional, Any
import matplotlib.pyplot as plt
import matplotlib.ticker as tkr
import numpy as np
import scipy.signal as sp
import das4whales as dw
from das4whales.dsp import get_fx, instant_freq
[docs]
def plot_rawdata(trace: np.ndarray, time: np.ndarray, dist: np.ndarray, fig_size: Tuple[int, int] = (12, 10)) -> None:
"""
Plot the raw DAS data.
Parameters
----------
trace : ndarray
The DAS trace data.
time : ndarray
The time values corresponding to the trace data.
dist : ndarray
The distance values corresponding to the trace data.
fig_size : tuple, optional
The size of the figure in inches, by default (12, 10).
"""
fig = plt.figure(figsize=fig_size)
wv = plt.imshow(trace * 1e9, aspect='auto', cmap='RdBu', extent=[min(time),max(time),min(dist)*1e-3,max(dist)*1e-3], origin='lower', vmin=-500, vmax=500, interpolation_stage='data')
plt.title('Raw DAS data')
plt.ylabel('Distance [km]')
plt.xlabel('Time [s]')
bar = fig.colorbar(wv, aspect=30, pad=0.015)
bar.set_label(label='Strain [-] x$10^{-9}$)')
plt.show()
[docs]
def plot_tx(trace: np.ndarray, time: np.ndarray, dist: np.ndarray, title_time_info: float = 0, fig_size: Tuple[int, int] = (12, 10), v_min: Optional[float] = None, v_max: Optional[float] = None, cbar_label: str = 'Strain Envelope (x$10^{-9}$)') -> None:
"""
Spatio-temporal representation (t-x plot) of the strain data
Parameters:
----------
trace : np.ndarray
A [channel x time sample] nparray containing the strain data in the spatio-temporal domain
time : np.ndarray
The corresponding time vector
dist : np.ndarray
The corresponding distance along the FO cable vector
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
fig_size : tuple, optional
Tuple of the figure dimensions (default is (12, 10))
v_min : float, optional
Sets the min nano strain amplitudes of the colorbar (default is None)
v_max : float, optional
Sets the max nano strain amplitudes of the colorbar (default is None)
Returns:
-------
None
Notes:
------
This function plots a spatio-temporal representation (t-x plot) of the strain data. It uses the given strain data,
time vector, and distance vector to create the plot. The plot shows the strain envelope as a color map, with time
on the x-axis and distance on the y-axis. The color of each point in the plot represents the strain amplitude at
that point. The function also supports customizing the figure size, colorbar limits, and title.
"""
fig = plt.figure(figsize=fig_size)
#TODO determine if the envelope should be implemented here rather than just abs
# Replace abs(trace) per abs(sp.hilbert(trace, axis=1)) ?
shw = plt.imshow(abs(trace) * 1e9, extent=[time[0], time[-1], dist[0] * 1e-3, dist[-1] * 1e-3, ], aspect='auto',
origin='lower', cmap='turbo', vmin=v_min, vmax=v_max, interpolation_stage='data')
plt.ylabel('Distance (km)')
plt.xlabel('Time [s]')
bar = fig.colorbar(shw, aspect=30, pad=0.015)
bar.set_label(cbar_label)
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def plot_tx_env(trace, time, dist, title_time_info=0, fig_size=(12, 10), v_min=None, v_max=None, cbar_label='Strain Envelope (x$10^{-9}$)'):
"""
Spatio-temporal representation (t-x plot) of the strain data envelope
Parameters:
----------
trace : np.ndarray
A [channel x time sample] nparray containing the strain data in the spatio-temporal domain
time : np.ndarray
The corresponding time vector
dist : np.ndarray
The corresponding distance along the FO cable vector
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
fig_size : tuple, optional
Tuple of the figure dimensions (default is (12, 10))
v_min : float, optional
Sets the min nano strain amplitudes of the colorbar (default is None)
v_max : float, optional
Sets the max nano strain amplitudes of the colorbar (default is None)
Returns:
-------
None
Notes:
------
This function plots a spatio-temporal representation (t-x plot) of the strain data. It uses the given strain data,
time vector, and distance vector to create the plot. The plot shows the strain envelope as a color map, with time
on the x-axis and distance on the y-axis. The color of each point in the plot represents the strain amplitude at
that point. The function also supports customizing the figure size, colorbar limits, and title.
"""
fig = plt.figure(figsize=fig_size)
#TODO determine if the envelope should be implemented here rather than just abs
# Replace abs(trace) per abs(sp.hilbert(trace, axis=1)) ?
shw = plt.imshow(abs(trace), extent=[time[0], time[-1], dist[0] * 1e-3, dist[-1] * 1e-3, ], aspect='auto',
origin='lower', cmap='turbo', vmin=v_min, vmax=v_max, interpolation_stage='data')
plt.ylabel('Distance (km)')
plt.xlabel('Time [s]')
bar = fig.colorbar(shw, aspect=30, pad=0.015)
bar.set_label(cbar_label)
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def plot_tx_lined(trace, ln_idx, time, dist, title_time_info=0, fig_size=(12, 10), v_min=None, v_max=None):
"""
Spatio-temporal representation (t-x plot) of the strain data
Parameters:
----------
trace : np.ndarray
A [channel x time sample] nparray containing the strain data in the spatio-temporal domain
ln_idx : int
The index of the line to be plotted
time : np.ndarray
The corresponding time vector
dist : np.ndarray
The corresponding distance along the FO cable vector
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
fig_size : tuple, optional
Tuple of the figure dimensions (default is (12, 10))
v_min : float, optional
Sets the min nano strain amplitudes of the colorbar (default is None)
v_max : float, optional
Sets the max nano strain amplitudes of the colorbar (default is None)
Returns:
-------
None
Notes:
------
This function plots a spatio-temporal representation (t-x plot) of the strain data with a line highlighted for a given channel index.
It uses the given strain data, time vector, and distance vector to create the plot. The plot shows the strain envelope as a color map, with time
on the x-axis and distance on the y-axis. The color of each point in the plot represents the strain amplitude at
that point. The function also supports customizing the figure size, colorbar limits, and title.
"""
fig = plt.figure(figsize=fig_size)
#TODO determine if the envelope should be implemented here rather than just abs
# Replace abs(trace) per abs(sp.hilbert(trace, axis=1)) ?
shw = plt.imshow(abs(trace) * 10 ** 9, extent=[time[0], time[-1], dist[0] * 1e-3, dist[-1] * 1e-3, ], aspect='auto',
origin='lower', cmap='turbo', vmin=v_min, vmax=v_max, interpolation_stage='data')
plt.plot([time[0], time[-1]], [dist[ln_idx] * 1e-3, dist[ln_idx] * 1e-3], 'w--', linewidth=3)
plt.ylabel('Distance (km)')
plt.xlabel('Time [s]')
bar = fig.colorbar(shw, aspect=30, pad=0.015)
bar.set_label('Strain Envelope (x$10^{-9}$)')
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def plot_fx(trace, dist, fs, title_time_info=0, win_s=2, nfft=4096, fig_size=(12, 10), f_min=0,
f_max=100, v_min=None, v_max=None):
"""
Spatio-spectral (f-k plot) of the strain data
Parameters
----------
trace : np.ndarray
A [channel x time sample] nparray containing the strain data in the spatio-temporal domain
dist : np.ndarray
The corresponding distance along the FO cable vector
fs : float
The sampling frequency (Hz)
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
win_s : int, optional
The duration of each f-k plot (s), by default 2
nfft : int, optional
Number of time samples used for the FFT, by default 4096
fig_size : tuple, optional
Tuple of the figure dimensions, by default (12, 10)
f_min : int, optional
Displayed minimum frequency interval (Hz), by default 0
f_max : int, optional
Displayed maximum frequency interval (Hz), by default 100
v_min : float, optional
Set the min nano strain amplitudes of the colorbar, by default None
v_max : float, optional
Set the max nano strain amplitudes of the colorbar, by default None
Returns
-------
None
Notes
-----
This function plots the spatio-spectral (f-k plot) of the strain data.
- The number of subplots is evaluated based on the duration of each f-k plot.
- The frequency axis is created using the FFT.
- The strain data is processed and plotted for each subplot.
Examples
--------
>>> plot_fx(trace, dist, fs, title_time_info=0, win_s=2, nfft=4096, fig_size=(12, 10), f_min=0,
f_max=100, v_min=None, v_max=None)
"""
# Evaluate the number of subplots
nb_subplots = int(np.ceil(trace.shape[1] / (win_s * fs)))
# Create the frequency axis
freq = np.fft.fftshift(np.fft.fftfreq(nfft, d=1 / fs))
# Prepare the plot
rows = 3
cols = int(np.ceil(nb_subplots/rows))
fig, axes = plt.subplots(rows, cols, figsize=fig_size)
# Run through the data
for ind in range(nb_subplots):
fx = get_fx(trace[:, int(ind * win_s * fs):int((ind + 1) * win_s * fs):1], nfft)
# fx = np.transpose(fx) - np.mean(fx, axis=1)
# fx = np.transpose(fx)
# Plot
r = ind // cols
c = ind % cols
ax = axes[r][c]
shw = ax.imshow(fx, extent=[freq[0], freq[-1], dist[0] * 1e-3, dist[-1] * 1e-3], aspect='auto',
origin='lower', cmap='jet', vmin=v_min, vmax=v_max, interpolation_stage='data')
ax.set_xlim([f_min, f_max])
if r == rows-1:
ax.set_xlabel('Frequency [Hz]')
else:
ax.set_xticks([])
ax.xaxis.set_tick_params(labelbottom=False)
if c == 0:
ax.set_ylabel('Distance (km)')
else:
ax.set_yticks([])
ax.yaxis.set_tick_params(labelleft=False)
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
# Colorbar
bar = fig.colorbar(shw, ax=axes.ravel().tolist())
bar.set_label('Strain (x$10^{-9}$)')
plt.show()
[docs]
def plot_spectrogram(p, tt, ff, fig_size=(20, 6), v_min=None, v_max=None, f_min=None, f_max=None):
"""
Plot a spectrogram.
Parameters
----------
p : ndarray
Spectrogram values in dB.
tt : ndarray
Associated time vector (s).
ff : ndarray
Associated frequency vector (Hz).
fig_size : tuple, optional
Tuple of the figure dimensions. Default is (17, 5).
v_min : float, optional
Minimum dB strain amplitudes of the colorbar.
v_max : float, optional
Maximum dB strain amplitudes of the colorbar.
f_min : float, optional
Minimum frequency for the spectrogram display.
f_max : float, optional
Maximum frequency for the spectrogram display.
Returns
-------
None
"""
roseus = import_roseus()
fig, ax = plt.subplots(figsize=fig_size)
shw = ax.pcolormesh(tt, ff, p, shading='auto', cmap=roseus, vmin=v_min, vmax=v_max, rasterized=True)
ax.set_ylim(f_min, f_max)
ax.set_xlabel('Time [s]')
ax.set_ylabel('Frequency [Hz]')
# Colorbar
bar = fig.colorbar(shw, aspect=30, pad=0.015)
bar.set_label('dB (strain x$10^{-9}$)')
plt.tight_layout()
# plt.show()
return fig
[docs]
def plot_3calls(channel, time, t1, t2, t3):
"""
Plot the strain channel with 3 calls highlighted.
Parameters
----------
channel : np.ndarray
The strain channel.
time : np.ndarray
The time values.
t1 : float
The time of the first call.
t2 : float
The time of the second call.
t3 : float
The time of the third call.
Returns
-------
None
"""
plt.figure(figsize=(17,6))
plt.subplot(211)
plt.plot(time, channel, ls='-')
plt.xlim([time[0], time[-1]])
plt.ylabel('Strain [-]')
plt.grid()
plt.tight_layout()
plt.subplot(234)
plt.plot(time, channel)
plt.ylabel('Strain [-]')
plt.xlabel('Time [s]')
plt.xlim([t1, t1+2.])
plt.grid()
plt.tight_layout()
plt.subplot(235)
plt.plot(time, channel)
plt.xlim([t2, t2+2.])
plt.xlabel('Time [s]')
plt.grid()
plt.tight_layout()
plt.subplot(236)
plt.plot(time, channel)
plt.xlim([t3, t3+2.])
plt.xlabel('Time [s]')
plt.grid()
plt.tight_layout()
# plt.savefig('3calls.pdf', format='pdf')
plt.show()
return
[docs]
def design_mf(trace, hnote, lnote, th, tl, time, fs):
"""Plot to design the matched filter
Parameters
----------
trace : numpy.ndarray
1D time series channel trace
hnote : numpy.ndarray
1D time series high frequency note template
lnote : numpy.ndarray
1D time series low frequency note template
th : float
start time of the high frequency note
tl : float
start time of the low frequency note
time : numpy.ndarray
1D vector of time values
fs : float
sampling frequency
"""
nf = int(th * fs)
nl = int(tl * fs)
# Create a dummy channel made of two notes at given times (not robust)
dummy_chan = np.zeros_like(hnote)
dummy_chan[nf:] = hnote[:-nf]
dummy_chan[nl:] = lnote[:-nl]
# Matched filter instantaneous freq
fi = instant_freq(trace, fs)
fi_mf = instant_freq(dummy_chan, fs)
# Plot the generated linear chirp signal
plt.figure(figsize=(18, 8))
plt.subplot(121)
plt.plot(time, (trace) / (np.max(abs(trace))), label='Normalized measured fin call', lw=3)
plt.plot(time, (dummy_chan) / (np.max(abs(dummy_chan))), label='Synthetic template', lw=3)
plt.title('Fin whale call template design - HF note')
plt.xlabel('Time (seconds)')
plt.ylabel('Amplitude')
plt.xlim(th-0.5, th+1.5)
plt.grid()
plt.legend()
plt.subplot(122)
plt.plot(time[1:], fi, label='Measured fin call', lw=3)
plt.plot(time[1:], fi_mf, label='Synthetic template', lw=3)
plt.xlim([th-0.5, th+1.5])
plt.ylim([15., 35])
plt.xlabel('Time (seconds)')
plt.ylabel('Instantaneous frequency [Hz]')
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
plt.figure(figsize=(18, 4))
plt.subplot(121)
plt.plot(time, (trace - np.mean(trace)) / (np.max(abs(trace))), label='normalized measured fin call')
plt.plot(time, (dummy_chan - np.mean(dummy_chan)) / (np.max(abs(dummy_chan))), label='template')
plt.title('fin whale call template - LF note')
plt.xlabel('Time (seconds)')
plt.ylabel('Amplitude')
plt.xlim([tl-0.5, tl+1.5])
plt.grid()
plt.legend()
plt.subplot(122)
plt.plot(time[1:], fi, label='measured fin call')
plt.plot(time[1:], fi_mf, label='template')
plt.xlim([tl-0.5, tl+1.5])
plt.ylim([12., 28.])
plt.xlabel('Time (seconds)')
plt.ylabel('Instantaneous frequency [Hz]')
plt.legend()
plt.grid()
plt.tight_layout()
plt.show()
return
[docs]
def detection_mf(trace, peaks_idx_HF, peaks_idx_LF, time, dist, fs, dx, selected_channels, title_time_info=None):
"""Plot the strain trace matrix [dist x time] with call detection above it
Parameters
----------
trace : numpy.ndarray
[channel x time sample] array containing the strain data in the spatio-temporal domain
peaks_idx_HF : tuple
tuple of lists containing the detected call indexes coordinates (first list: channel idx, second list: time idx) for the high frequency call
peaks_idx_LF : tuple
tuple of lists containing the detected call indexes coordinates (first list: channel idx, second list: time idx) for the low frequency call
time : numpy.ndarray
time vector
dist : numpy.ndarray
distance vector along the cable
fs : float
sampling frequency
dx : float
spatial step
selected_channels : list
list of selected channels indexes [start, stop, step]
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
"""
fig = plt.figure(figsize=(12,10))
cplot = plt.imshow(abs(sp.hilbert(trace, axis=1)) * 1e9, extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='jet', origin='lower', aspect='auto', vmin=0, vmax=0.4, alpha=0.35)
plt.scatter(peaks_idx_HF[1] / fs, (peaks_idx_HF[0] * selected_channels[2] + selected_channels[0]) * dx /1e3, color='red', marker='.', label='HF_note')
plt.scatter(peaks_idx_LF[1] / fs, (peaks_idx_LF[0] * selected_channels[2] + selected_channels[0]) * dx /1e3, color='green', marker='.', label='LF_note')
bar = fig.colorbar(cplot, aspect=30, pad=0.015)
bar.set_label('Strain Envelope [-] (x$10^{-9}$)')
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
plt.legend(loc="upper right")
# plt.savefig('test.pdf', format='pdf')
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def detection_spectcorr(trace, peaks_idx_HF, peaks_idx_LF, time, dist, spectro_fs, dx, selected_channels, title_time_info=None):
"""Plot the strain trace matrix [dist x time] with call detection above it
Parameters
----------
trace : numpy.ndarray
[channel x time sample] array containing the strain data in the spatio-temporal domain
peaks_idx_HF : tuple
tuple of lists containing the detected call indexes coordinates (first list: channel idx, second list: time idx) for the high frequency call
peaks_idx_LF : tuple
tuple of lists containing the detected call indexes coordinates (first list: channel idx, second list: time idx) for the low frequency call
time : numpy.ndarray
time vector
dist : numpy.ndarray
distance vector along the cable
spectro_fs : float
sampling frequency of the spectrograms
dx : float
spatial step
selected_channels : list
list of selected channels indexes [start, stop, step]
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
"""
fig = plt.figure(figsize=(12,10))
cplot = plt.imshow(abs(sp.hilbert(trace, axis=1)) * 1e9, extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='jet', origin='lower', aspect='auto', vmin=0, vmax=0.4, alpha=0.35, interpolation_stage='data')
plt.scatter(peaks_idx_HF[1] / spectro_fs, (peaks_idx_HF[0] * selected_channels[2] + selected_channels[0]) * dx /1e3, color='red', marker='x', label='HF call')
plt.scatter(peaks_idx_LF[1] / spectro_fs, (peaks_idx_LF[0] * selected_channels[2] + selected_channels[0]) * dx /1e3, color='green', marker='.', label='LF_note')
bar = fig.colorbar(cplot, aspect=30, pad=0.015)
bar.set_label('Strain Envelope [-] (x$10^{-9}$)')
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
plt.legend(loc="upper right")
# plt.savefig('test.pdf', format='pdf')
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def detection_grad(trace, peaks_idx, time, dist, fs, dx, selected_channels, title_time_info=None):
"""Plot the strain trace matrix [dist x time] with call detection above it
Parameters
----------
trace : numpy.ndarray
[channel x time sample] array containing the strain data in the spatio-temporal domain
peaks_idx_HF : tuple
tuple of lists containing the detected call indexes coordinates (first list: channel idx, second list: time idx) for the high frequency call
peaks_idx_LF : tuple
tuple of lists containing the detected call indexes coordinates (first list: channel idx, second list: time idx) for the low frequency call
time : numpy.ndarray
time vector
dist : numpy.ndarray
distance vector along the cable
fs : float
sampling frequency
dx : float
spatial step
selected_channels : list
list of selected channels indexes [start, stop, step]
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
"""
fig = plt.figure(figsize=(12,10))
cplot = plt.imshow(abs(sp.hilbert(trace, axis=1)) * 1e9, extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='jet', origin='lower', aspect='auto', vmin=0, vmax=0.4, alpha=0.35, interpolation_stage='data')
plt.scatter(peaks_idx[1] / fs, (peaks_idx[0] * selected_channels[2] + selected_channels[0]) * dx /1e3, color='red', marker='x', label='Fin call')
bar = fig.colorbar(cplot, aspect=30, pad=0.015)
bar.set_label('Strain Envelope [-] (x$10^{-9}$)')
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
plt.legend(loc="upper right")
# plt.savefig('test.pdf', format='pdf')
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def snr_matrix(snr_m, time, dist, vmax, title_time_info=None):
"""Matrix plot of the local signal to noise ratio (SNR)
Parameters
----------
snr_m : numpy.ndarray
[channel x time sample] array containing the SNR in the spatio-temporal domain
time : nummpy.ndarray
time vector
dist : numpy.ndarray
distance vector along the cable
vmax : float
maximun value of the plot (dB)
"""
fig = plt.figure(figsize=(12, 10))
snrp = plt.imshow(snr_m, extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='turbo', origin='lower', aspect='auto', vmin=0, vmax=vmax, interpolation_stage='data')
bar = fig.colorbar(snrp, aspect=30, pad=0.015)
bar.set_label('SNR [dB]')
bar.ax.yaxis.set_major_formatter(tkr.FormatStrFormatter('%.0f'))
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
plt.tight_layout()
plt.show()
return
[docs]
def plot_cross_correlogramHL(corr_m_HF, corr_m_LF, time, dist, maxv, minv=0, title_time_info=None):
"""
Plot the cross-correlogram between HF and LF notes.
Parameters
----------
corr_m_HF : numpy.ndarray
The cross-correlation matrix of the HF notes.
corr_m_LF : numpy.ndarray
The cross-correlation matrix of the LF notes.
time : numpy.ndarray
The time values.
dist : numpy.ndarray
The distance values.
maxv : float
The maximum value for the colorbar.
minv : int, optional
The minimum value for the colorbar. Default is 0.
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
Returns
-------
None
"""
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8), constrained_layout=True)
im1 = ax1.imshow(abs(sp.hilbert(corr_m_HF, axis=1)), extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='turbo', origin='lower', aspect='auto', vmin=minv, vmax=maxv, interpolation_stage='data')
ax1.set_xlabel('Time [s]')
ax1.set_ylabel('Distance [km]')
ax1.set_title('HF note', loc='right')
im2 = ax2.imshow(abs(sp.hilbert(corr_m_LF, axis=1)), extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='turbo',origin='lower', aspect='auto', vmin=minv, vmax=maxv, interpolation_stage='data')
ax2.set_xlabel('Time [s]')
ax2.set_title('LF note', loc='right')
cbar = fig.colorbar(im1, ax=[ax1, ax2], orientation='horizontal', aspect=50, pad=0.02)
cbar.set_label('Cross-correlation envelope []')
plt.show()
return
[docs]
def plot_cross_correlogram(corr_m, time, dist, maxv, minv=0, title_time_info=None):
"""
Plot the cross-correlogram between HF and LF notes.
Parameters
----------
corr_m : numpy.ndarray
The cross-correlation matrix
time : numpy.ndarray
The time values.
dist : numpy.ndarray
The distance values.
maxv : float
The maximum value for the colorbar.
minv : int, optional
The minimum value for the colorbar. Default is 0.
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
Returns
-------
None
"""
fig, ax = plt.subplots(figsize=(12, 10), constrained_layout=True)
im = ax.imshow(abs(sp.hilbert(corr_m, axis=1)), extent=[time[0], time[-1], dist[0] / 1e3, dist[-1] / 1e3], cmap='turbo', origin='lower', aspect='auto', vmin=minv, vmax=maxv, interpolation_stage='data')
ax.set_xlabel('Time [s]')
ax.set_ylabel('Distance [km]')
ax.set_title('Cross-correlogram', loc='right')
cbar = fig.colorbar(im, ax=ax, orientation='horizontal', aspect=50, pad=0.02)
cbar.set_label('Cross-correlation envelope []')
plt.show()
return
[docs]
def plot_fk_domain(trace, fs, dx, selected_channels, title_time_info=0, fig_size=(12, 10), v_min=None, v_max=None, fk_params=None, ax_lims=None):
"""
Spatio-spectral representation (f-k plot) of the strain data
Parameters
----------
trace : np.ndarray
A [channel x time sample] nparray containing the strain data in the spatio-temporal domain
fs : float
The sampling frequency (Hz)
dx : float
The spatial step (m)
selected_channels : list
List of selected channels indexes [start, stop, step]
title_time_info : int, str, or datetime.datetime, optional
A time reference to display or the plot title. Can be a UTC timestamp (int),
a formatted string, or a `datetime.datetime` object (default is 0).
fig_size : tuple, optional
Tuple of the figure dimensions, by default (12, 10)
v_min : float, optional
Sets the min nano strain amplitudes of the colorbar, by default None
v_max : float, optional
Sets the max nano strain amplitudes of the colorbar, by default None
fk_params : dict, optional
Dictionary containing the fmin, fmax, c_min, and c_max parameters, by default None
ax_lims : list, optional
List of the form [f_min, f_max, k_min, k_max] for zoomed plots, by default None
Returns
-------
None
Notes
-----
This function plots the spatio-spectral representation (f-k plot) of the strain data.
- The frequency axis is created using the FFT.
- The strain data is processed and plotted.
Examples
--------
>>> plot_fk_domain(trace, time, dist, title_time_info=0, fig_size=(12, 10), v_min=None, v_max=None)
"""
f = np.fft.fftshift(np.fft.fftfreq(trace.shape[1], d=1 / fs))
k = np.fft.fftshift(np.fft.fftfreq(trace.shape[0], d=dx * selected_channels[2]))
# Taper the data
# win_x = sp.windows.tukey(trace.shape[1], alpha=0.1)
# win_y = sp.windows.tukey(trace.shape[0], alpha=0.1)
# win_2d = np.sqrt(np.outer(win_y, win_x))
fk = np.fft.fftshift(np.fft.fft2(trace))
fig = plt.figure(figsize=fig_size)
shw = plt.imshow(abs(fk), extent=[f[0], f[-1], k[0], k[-1]], aspect='auto', origin='lower', cmap='turbo', vmin=v_min, vmax=v_max, interpolation_stage='data')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Wavenumber [m$^{-1}$]')
bar = fig.colorbar(shw, aspect=30, pad=0.015)
bar.set_label('Amplitude [arbitrary units]')
if fk_params is not None:
plt.vlines(fk_params['fmin'], k[0], k[-1], color='tab:orange', linestyle='--', label='fmin', lw=2)
plt.vlines(fk_params['fmax'], k[0], k[-1], color='tab:red', linestyle='--', label='fmax', lw=2)
plt.plot(f, f / fk_params['c_min'], color='tab:pink', linestyle='--', label=f'c = {fk_params["c_min"]:.2f} m/s', lw=2)
plt.plot(f, f / fk_params['c_max'], color='white', linestyle='--', label=f'c = {fk_params["c_max"]:.2f} m/s', lw=2)
if title_time_info:
if isinstance(title_time_info, datetime):
title_text = title_time_info.strftime("%Y-%m-%d %H:%M:%S")
elif isinstance(title_time_info, str):
title_text = title_time_info
elif isinstance(title_time_info, int):
title_text = datetime.utcfromtimestamp(title_time_info).strftime("%Y-%m-%d %H:%M:%S")
else:
raise ValueError("title_time_info must be an int, str, or datetime.datetime.")
plt.title(title_text, loc='right')
if ax_lims is not None:
plt.xlim(ax_lims[0], ax_lims[1])
plt.ylim(ax_lims[2], ax_lims[3])
# plt.xlim([12, 30])
# plt.ylim([0, 0.025])
# Display legend if needed
if fk_params is not None:
plt.legend()
plt.tight_layout()
# plt.show()
return
[docs]
def plot_associated(peaks, longi_offset, associated_list, localizations, cable_pos, dist, dx, c0, fs):
plt.figure(figsize=(20,8))
# Plot the time picks with colored associated ones
plt.subplot(1, 2, 1)
plt.scatter(peaks[1][:] / fs, (longi_offset + peaks[0][:]) * dx * 1e-3, label='LF', s=0.5, alpha=0.2, color='tab:grey')
for i, select in enumerate(associated_list):
plt.scatter(select[1][:] / fs, (longi_offset + select[0][:]) * dx * 1e-3, label='LF', s=0.5)
plt.xlim(0, 60)
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
# Plot the time picks with the the predicted hyperbola
plt.subplot(1, 2, 2)
for i, select in enumerate(associated_list):
plt.scatter(select[1][:] / fs, (longi_offset + select[0][:]) * dx * 1e-3, label='LF', s=0.5)
plt.plot(dw.loc.calc_arrival_times(localizations[i][-1], cable_pos, localizations[i][:3], c0), dist/1e3, color='tab:grey', ls='-', lw=2, alpha=0.7)
# plt.plot(select[1][:] / fs, dw.loc.calc_arrival_times(0, cable_pos, alt_localizations[i][:3], c0), color='tab:orange', ls='-', lw=1)
plt.grid(linestyle='--', alpha=0.6)
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
plt.show()
[docs]
def plot_reject_pick(peaks, longi_offset, dist, dx, associated_list, rejected_list, rejected_hyperbolas, fs):
# Plot the selected picks alongside the original picks
plt.figure(figsize=(20,8))
plt.subplot(2, 2, 1)
plt.scatter(peaks[1][:] / fs, (longi_offset + peaks[0][:]) * dx * 1e-3, label='HF', s=0.5)
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
plt.subplot(2, 2, 2)
for select in associated_list:
plt.scatter(select[1][:] / fs, (longi_offset + select[0][:]) * dx * 1e-3, label='LF', s=0.5)
plt.xlabel('Time [s]')
# Plot the deleted hyperbolas
plt.subplot(2, 2, 3)
for hyp in rejected_hyperbolas:
plt.plot(hyp, dist/1e3, label='Rejected hyperbola')
plt.xlabel('Time [s]')
plt.ylabel('Distance [km]')
# plot the rejected picks
plt.subplot(2, 2, 4)
for select in rejected_list:
plt.scatter(select[1][:] / fs, (longi_offset + select[0][:]) * dx * 1e-3, label='LF', s=0.5)
plt.xlabel('Time [s]')
plt.show()
[docs]
def plot_pick_analysis(associated_list, fs, dx, longi_offset, cable_pos, dist, window_size=5, mu_ref=None, sigma_ref=None):
"""
Create detailed plots of seismic picks with continuity analysis and a normalized curvature score.
Parameters:
-----------
associated_list : list
List of tuples containing pick coordinates and times
fs : float
Sampling frequency
dx : float
Spatial sampling interval
longi_offset : float
Longitudinal offset value
window_size : float, optional
Size of analysis window in seconds (default: 5)
mu_ref : float, optional
Reference mean curvature for normalization (default: computed from data)
sigma_ref : float, optional
Reference standard deviation of curvature for normalization (default: computed from data)
Returns:
--------
fig : matplotlib.figure.Figure
The created figure object
"""
fig = plt.figure(figsize=(24, 8))
curvature_means = []
curvature_stds = []
for i, select in enumerate(associated_list):
times = select[1][:] / fs
distances = (longi_offset + select[0][:]) * dx * 1e-3
ax = plt.subplot(1, 2*len(associated_list), (i + 1) * 2 - 1)
if i == 0:
ax.set_ylabel('Distance [km]')
ax.scatter(times, distances, label='All Picks', s=0.5, color='gray', alpha=0.5)
window_mask = (times > np.min(times)) & (times < np.min(times) + window_size)
window_times = times[window_mask]
window_distances = distances[window_mask]
ax.plot(window_times, window_distances,
label='Windowed Picks',
lw=2,
color='tab:red',
alpha=0.6)
# Calulate least squares fit
idxmin_t = np.argmin(select[1][:])
apex_loc = cable_pos[:, 0][select[0][idxmin_t]]
Ti = select[1][:] / fs
Nbiter = 20
# Initial guess (apex_loc, mean_y, -30m, min(Ti))
n_init = [apex_loc, np.mean(cable_pos[:,1]), -40, np.min(Ti)]
# Solve the least squares problem
n, residuals = dw.loc.solve_lq(Ti, cable_pos[select[0][:]], c0, Nbiter, fix_z=True, ninit=n_init, residuals=True)
loc_hyerbola = dw.loc.calc_arrival_times(n[-1], cable_pos, n[:3], c0)
test = np.cumsum(abs(residuals))
# rms residual
rms = np.sqrt(np.mean(residuals[window_mask]**2))
# rms *= 1e4
left_cs = np.cumsum(abs(residuals[idxmin_t::-1]))
right_cs = np.cumsum(abs(residuals[idxmin_t:]))
mod_cs = np.concatenate((left_cs[::-1], right_cs[1:]))
mask_resi = mod_cs < 1500
# plot indexes for which only the cumulative sum is less than 1000
ax.scatter(select[1][mask_resi] / fs, (longi_offset + select[0][mask_resi]) * dx * 1e-3, label='HF', s=1, color='tab:blue')
ax.plot(loc_hyerbola, dist/1e3, label='Hyperbola', color='tab:green', alpha=0.5)
# Plot residuals
# ax.plot(abs(residuals), distances, label='Residuals', color='tab:orange', alpha=0.5)
# ax.plot(abs(residuals[window_mask]), window_distances, label='Windowed Residuals', color='tab:blue', alpha=0.5)
# ax.plot(np.cumsum(residuals), distances, label='Cumulative Residuals', color='tab:green', alpha=0.5)
# Calculate curvature
ddx = np.diff(window_times)
ddy = np.diff(window_distances)
ddx2 = np.diff(ddx)
ddy2 = np.diff(ddy)
curvature = np.abs(ddx2 * ddy[1:] - ddx[1:] * ddy2) / (ddx[1:]**2 + ddy[1:]**2)**(3/2)
# curvature = curvature[curvature > 10e-10]
curvature_mean = np.mean(curvature)
ax.set_title(f"Pick Analysis\n"
f"$\\mu_k$ = {compute_curvature(window_times, window_distances):.2f}\n"
f"$\\mu_r$ = {np.mean(abs(residuals[window_mask])):.2f}\n"
f"$RMS$ = {rms:.2f}\n",
fontsize=10)
ax.set_xlabel('Time [s]')
ax = plt.subplot(1, 2*len(associated_list), (i + 2) * 2 - 2)
ax.plot(mod_cs, distances, label='Modified Cumulative Residuals', color='tab:purple', alpha=0.5)
ax.set_xlabel('Cumulative Residuals')
plt.tight_layout()
return fig
[docs]
def import_roseus():
"""
Import the colormap from the colormap/roseus_matplotlib.py file
Returns
-------
ListedColormap
colormap
"""
from matplotlib.colors import ListedColormap
# Roseus colormap data
# https://github.com/dofuuz/roseus
roseus_data = [
[0.004528, 0.004341, 0.004307],
[0.005625, 0.006156, 0.006010],
[0.006628, 0.008293, 0.008161],
[0.007551, 0.010738, 0.010790],
[0.008382, 0.013482, 0.013941],
[0.009111, 0.016520, 0.017662],
[0.009727, 0.019846, 0.022009],
[0.010223, 0.023452, 0.027035],
[0.010593, 0.027331, 0.032799],
[0.010833, 0.031475, 0.039361],
[0.010941, 0.035875, 0.046415],
[0.010918, 0.040520, 0.053597],
[0.010768, 0.045158, 0.060914],
[0.010492, 0.049708, 0.068367],
[0.010098, 0.054171, 0.075954],
[0.009594, 0.058549, 0.083672],
[0.008989, 0.062840, 0.091521],
[0.008297, 0.067046, 0.099499],
[0.007530, 0.071165, 0.107603],
[0.006704, 0.075196, 0.115830],
[0.005838, 0.079140, 0.124178],
[0.004949, 0.082994, 0.132643],
[0.004062, 0.086758, 0.141223],
[0.003198, 0.090430, 0.149913],
[0.002382, 0.094010, 0.158711],
[0.001643, 0.097494, 0.167612],
[0.001009, 0.100883, 0.176612],
[0.000514, 0.104174, 0.185704],
[0.000187, 0.107366, 0.194886],
[0.000066, 0.110457, 0.204151],
[0.000186, 0.113445, 0.213496],
[0.000587, 0.116329, 0.222914],
[0.001309, 0.119106, 0.232397],
[0.002394, 0.121776, 0.241942],
[0.003886, 0.124336, 0.251542],
[0.005831, 0.126784, 0.261189],
[0.008276, 0.129120, 0.270876],
[0.011268, 0.131342, 0.280598],
[0.014859, 0.133447, 0.290345],
[0.019100, 0.135435, 0.300111],
[0.024043, 0.137305, 0.309888],
[0.029742, 0.139054, 0.319669],
[0.036252, 0.140683, 0.329441],
[0.043507, 0.142189, 0.339203],
[0.050922, 0.143571, 0.348942],
[0.058432, 0.144831, 0.358649],
[0.066041, 0.145965, 0.368319],
[0.073744, 0.146974, 0.377938],
[0.081541, 0.147858, 0.387501],
[0.089431, 0.148616, 0.396998],
[0.097411, 0.149248, 0.406419],
[0.105479, 0.149754, 0.415755],
[0.113634, 0.150134, 0.424998],
[0.121873, 0.150389, 0.434139],
[0.130192, 0.150521, 0.443167],
[0.138591, 0.150528, 0.452075],
[0.147065, 0.150413, 0.460852],
[0.155614, 0.150175, 0.469493],
[0.164232, 0.149818, 0.477985],
[0.172917, 0.149343, 0.486322],
[0.181666, 0.148751, 0.494494],
[0.190476, 0.148046, 0.502493],
[0.199344, 0.147229, 0.510313],
[0.208267, 0.146302, 0.517944],
[0.217242, 0.145267, 0.525380],
[0.226264, 0.144131, 0.532613],
[0.235331, 0.142894, 0.539635],
[0.244440, 0.141559, 0.546442],
[0.253587, 0.140131, 0.553026],
[0.262769, 0.138615, 0.559381],
[0.271981, 0.137016, 0.565500],
[0.281222, 0.135335, 0.571381],
[0.290487, 0.133581, 0.577017],
[0.299774, 0.131757, 0.582404],
[0.309080, 0.129867, 0.587538],
[0.318399, 0.127920, 0.592415],
[0.327730, 0.125921, 0.597032],
[0.337069, 0.123877, 0.601385],
[0.346413, 0.121793, 0.605474],
[0.355758, 0.119678, 0.609295],
[0.365102, 0.117540, 0.612846],
[0.374443, 0.115386, 0.616127],
[0.383774, 0.113226, 0.619138],
[0.393096, 0.111066, 0.621876],
[0.402404, 0.108918, 0.624343],
[0.411694, 0.106794, 0.626540],
[0.420967, 0.104698, 0.628466],
[0.430217, 0.102645, 0.630123],
[0.439442, 0.100647, 0.631513],
[0.448637, 0.098717, 0.632638],
[0.457805, 0.096861, 0.633499],
[0.466940, 0.095095, 0.634100],
[0.476040, 0.093433, 0.634443],
[0.485102, 0.091885, 0.634532],
[0.494125, 0.090466, 0.634370],
[0.503104, 0.089190, 0.633962],
[0.512041, 0.088067, 0.633311],
[0.520931, 0.087108, 0.632420],
[0.529773, 0.086329, 0.631297],
[0.538564, 0.085738, 0.629944],
[0.547302, 0.085346, 0.628367],
[0.555986, 0.085162, 0.626572],
[0.564615, 0.085190, 0.624563],
[0.573187, 0.085439, 0.622345],
[0.581698, 0.085913, 0.619926],
[0.590149, 0.086615, 0.617311],
[0.598538, 0.087543, 0.614503],
[0.606862, 0.088700, 0.611511],
[0.615120, 0.090084, 0.608343],
[0.623312, 0.091690, 0.605001],
[0.631438, 0.093511, 0.601489],
[0.639492, 0.095546, 0.597821],
[0.647476, 0.097787, 0.593999],
[0.655389, 0.100226, 0.590028],
[0.663230, 0.102856, 0.585914],
[0.670995, 0.105669, 0.581667],
[0.678686, 0.108658, 0.577291],
[0.686302, 0.111813, 0.572790],
[0.693840, 0.115129, 0.568175],
[0.701300, 0.118597, 0.563449],
[0.708682, 0.122209, 0.558616],
[0.715984, 0.125959, 0.553687],
[0.723206, 0.129840, 0.548666],
[0.730346, 0.133846, 0.543558],
[0.737406, 0.137970, 0.538366],
[0.744382, 0.142209, 0.533101],
[0.751274, 0.146556, 0.527767],
[0.758082, 0.151008, 0.522369],
[0.764805, 0.155559, 0.516912],
[0.771443, 0.160206, 0.511402],
[0.777995, 0.164946, 0.505845],
[0.784459, 0.169774, 0.500246],
[0.790836, 0.174689, 0.494607],
[0.797125, 0.179688, 0.488935],
[0.803325, 0.184767, 0.483238],
[0.809435, 0.189925, 0.477518],
[0.815455, 0.195160, 0.471781],
[0.821384, 0.200471, 0.466028],
[0.827222, 0.205854, 0.460267],
[0.832968, 0.211308, 0.454505],
[0.838621, 0.216834, 0.448738],
[0.844181, 0.222428, 0.442979],
[0.849647, 0.228090, 0.437230],
[0.855019, 0.233819, 0.431491],
[0.860295, 0.239613, 0.425771],
[0.865475, 0.245471, 0.420074],
[0.870558, 0.251393, 0.414403],
[0.875545, 0.257380, 0.408759],
[0.880433, 0.263427, 0.403152],
[0.885223, 0.269535, 0.397585],
[0.889913, 0.275705, 0.392058],
[0.894503, 0.281934, 0.386578],
[0.898993, 0.288222, 0.381152],
[0.903381, 0.294569, 0.375781],
[0.907667, 0.300974, 0.370469],
[0.911849, 0.307435, 0.365223],
[0.915928, 0.313953, 0.360048],
[0.919902, 0.320527, 0.354948],
[0.923771, 0.327155, 0.349928],
[0.927533, 0.333838, 0.344994],
[0.931188, 0.340576, 0.340149],
[0.934736, 0.347366, 0.335403],
[0.938175, 0.354207, 0.330762],
[0.941504, 0.361101, 0.326229],
[0.944723, 0.368045, 0.321814],
[0.947831, 0.375039, 0.317523],
[0.950826, 0.382083, 0.313364],
[0.953709, 0.389175, 0.309345],
[0.956478, 0.396314, 0.305477],
[0.959133, 0.403499, 0.301766],
[0.961671, 0.410731, 0.298221],
[0.964093, 0.418008, 0.294853],
[0.966399, 0.425327, 0.291676],
[0.968586, 0.432690, 0.288696],
[0.970654, 0.440095, 0.285926],
[0.972603, 0.447540, 0.283380],
[0.974431, 0.455025, 0.281067],
[0.976139, 0.462547, 0.279003],
[0.977725, 0.470107, 0.277198],
[0.979188, 0.477703, 0.275666],
[0.980529, 0.485332, 0.274422],
[0.981747, 0.492995, 0.273476],
[0.982840, 0.500690, 0.272842],
[0.983808, 0.508415, 0.272532],
[0.984653, 0.516168, 0.272560],
[0.985373, 0.523948, 0.272937],
[0.985966, 0.531754, 0.273673],
[0.986436, 0.539582, 0.274779],
[0.986780, 0.547434, 0.276264],
[0.986998, 0.555305, 0.278135],
[0.987091, 0.563195, 0.280401],
[0.987061, 0.571100, 0.283066],
[0.986907, 0.579019, 0.286137],
[0.986629, 0.586950, 0.289615],
[0.986229, 0.594891, 0.293503],
[0.985709, 0.602839, 0.297802],
[0.985069, 0.610792, 0.302512],
[0.984310, 0.618748, 0.307632],
[0.983435, 0.626704, 0.313159],
[0.982445, 0.634657, 0.319089],
[0.981341, 0.642606, 0.325420],
[0.980130, 0.650546, 0.332144],
[0.978812, 0.658475, 0.339257],
[0.977392, 0.666391, 0.346753],
[0.975870, 0.674290, 0.354625],
[0.974252, 0.682170, 0.362865],
[0.972545, 0.690026, 0.371466],
[0.970750, 0.697856, 0.380419],
[0.968873, 0.705658, 0.389718],
[0.966921, 0.713426, 0.399353],
[0.964901, 0.721157, 0.409313],
[0.962815, 0.728851, 0.419594],
[0.960677, 0.736500, 0.430181],
[0.958490, 0.744103, 0.441070],
[0.956263, 0.751656, 0.452248],
[0.954009, 0.759153, 0.463702],
[0.951732, 0.766595, 0.475429],
[0.949445, 0.773974, 0.487414],
[0.947158, 0.781289, 0.499647],
[0.944885, 0.788535, 0.512116],
[0.942634, 0.795709, 0.524811],
[0.940423, 0.802807, 0.537717],
[0.938261, 0.809825, 0.550825],
[0.936163, 0.816760, 0.564121],
[0.934146, 0.823608, 0.577591],
[0.932224, 0.830366, 0.591220],
[0.930412, 0.837031, 0.604997],
[0.928727, 0.843599, 0.618904],
[0.927187, 0.850066, 0.632926],
[0.925809, 0.856432, 0.647047],
[0.924610, 0.862691, 0.661249],
[0.923607, 0.868843, 0.675517],
[0.922820, 0.874884, 0.689832],
[0.922265, 0.880812, 0.704174],
[0.921962, 0.886626, 0.718523],
[0.921930, 0.892323, 0.732859],
[0.922183, 0.897903, 0.747163],
[0.922741, 0.903364, 0.761410],
[0.923620, 0.908706, 0.775580],
[0.924837, 0.913928, 0.789648],
[0.926405, 0.919031, 0.803590],
[0.928340, 0.924015, 0.817381],
[0.930655, 0.928881, 0.830995],
[0.933360, 0.933631, 0.844405],
[0.936466, 0.938267, 0.857583],
[0.939982, 0.942791, 0.870499],
[0.943914, 0.947207, 0.883122],
[0.948267, 0.951519, 0.895421],
[0.953044, 0.955732, 0.907359],
[0.958246, 0.959852, 0.918901],
[0.963869, 0.963887, 0.930004],
[0.969909, 0.967845, 0.940623],
[0.976355, 0.971737, 0.950704],
[0.983195, 0.975580, 0.960181],
[0.990402, 0.979395, 0.968966],
[0.997930, 0.983217, 0.976920],]
return ListedColormap(roseus_data, name='Roseus')
[docs]
def import_parula():
"""
Import the colormap parula from matlab
Returns
-------
ListedColormap
colormap
"""
from matplotlib.colors import ListedColormap
# Parula colormap data
parula_data = cm_data = [
[0.2422, 0.1504, 0.6603],
[0.2444, 0.1534, 0.6728],
[0.2464, 0.1569, 0.6847],
[0.2484, 0.1607, 0.6961],
[0.2503, 0.1648, 0.7071],
[0.2522, 0.1689, 0.7179],
[0.254, 0.1732, 0.7286],
[0.2558, 0.1773, 0.7393],
[0.2576, 0.1814, 0.7501],
[0.2594, 0.1854, 0.761],
[0.2611, 0.1893, 0.7719],
[0.2628, 0.1932, 0.7828],
[0.2645, 0.1972, 0.7937],
[0.2661, 0.2011, 0.8043],
[0.2676, 0.2052, 0.8148],
[0.2691, 0.2094, 0.8249],
[0.2704, 0.2138, 0.8346],
[0.2717, 0.2184, 0.8439],
[0.2729, 0.2231, 0.8528],
[0.274, 0.228, 0.8612],
[0.2749, 0.233, 0.8692],
[0.2758, 0.2382, 0.8767],
[0.2766, 0.2435, 0.884],
[0.2774, 0.2489, 0.8908],
[0.2781, 0.2543, 0.8973],
[0.2788, 0.2598, 0.9035],
[0.2794, 0.2653, 0.9094],
[0.2798, 0.2708, 0.915],
[0.2802, 0.2764, 0.9204],
[0.2806, 0.2819, 0.9255],
[0.2809, 0.2875, 0.9305],
[0.2811, 0.293, 0.9352],
[0.2813, 0.2985, 0.9397],
[0.2814, 0.304, 0.9441],
[0.2814, 0.3095, 0.9483],
[0.2813, 0.315, 0.9524],
[0.2811, 0.3204, 0.9563],
[0.2809, 0.3259, 0.96],
[0.2807, 0.3313, 0.9636],
[0.2803, 0.3367, 0.967],
[0.2798, 0.3421, 0.9702],
[0.2791, 0.3475, 0.9733],
[0.2784, 0.3529, 0.9763],
[0.2776, 0.3583, 0.9791],
[0.2766, 0.3638, 0.9817],
[0.2754, 0.3693, 0.984],
[0.2741, 0.3748, 0.9862],
[0.2726, 0.3804, 0.9881],
[0.271, 0.386, 0.9898],
[0.2691, 0.3916, 0.9912],
[0.267, 0.3973, 0.9924],
[0.2647, 0.403, 0.9935],
[0.2621, 0.4088, 0.9946],
[0.2591, 0.4145, 0.9955],
[0.2556, 0.4203, 0.9965],
[0.2517, 0.4261, 0.9974],
[0.2473, 0.4319, 0.9983],
[0.2424, 0.4378, 0.9991],
[0.2369, 0.4437, 0.9996],
[0.2311, 0.4497, 0.9995],
[0.225, 0.4559, 0.9985],
[0.2189, 0.462, 0.9968],
[0.2128, 0.4682, 0.9948],
[0.2066, 0.4743, 0.9926],
[0.2006, 0.4803, 0.9906],
[0.195, 0.4861, 0.9887],
[0.1903, 0.4919, 0.9867],
[0.1869, 0.4975, 0.9844],
[0.1847, 0.503, 0.9819],
[0.1831, 0.5084, 0.9793],
[0.1818, 0.5138, 0.9766],
[0.1806, 0.5191, 0.9738],
[0.1795, 0.5244, 0.9709],
[0.1785, 0.5296, 0.9677],
[0.1778, 0.5349, 0.9641],
[0.1773, 0.5401, 0.9602],
[0.1768, 0.5452, 0.956],
[0.1764, 0.5504, 0.9516],
[0.1755, 0.5554, 0.9473],
[0.174, 0.5605, 0.9432],
[0.1716, 0.5655, 0.9393],
[0.1686, 0.5705, 0.9357],
[0.1649, 0.5755, 0.9323],
[0.161, 0.5805, 0.9289],
[0.1573, 0.5854, 0.9254],
[0.154, 0.5902, 0.9218],
[0.1513, 0.595, 0.9182],
[0.1492, 0.5997, 0.9147],
[0.1475, 0.6043, 0.9113],
[0.1461, 0.6089, 0.908],
[0.1446, 0.6135, 0.905],
[0.1429, 0.618, 0.9022],
[0.1408, 0.6226, 0.8998],
[0.1383, 0.6272, 0.8975],
[0.1354, 0.6317, 0.8953],
[0.1321, 0.6363, 0.8932],
[0.1288, 0.6408, 0.891],
[0.1253, 0.6453, 0.8887],
[0.1219, 0.6497, 0.8862],
[0.1185, 0.6541, 0.8834],
[0.1152, 0.6584, 0.8804],
[0.1119, 0.6627, 0.877],
[0.1085, 0.6669, 0.8734],
[0.1048, 0.671, 0.8695],
[0.1009, 0.675, 0.8653],
[0.0964, 0.6789, 0.8609],
[0.0914, 0.6828, 0.8562],
[0.0855, 0.6865, 0.8513],
[0.0789, 0.6902, 0.8462],
[0.0713, 0.6938, 0.8409],
[0.0628, 0.6972, 0.8355],
[0.0535, 0.7006, 0.8299],
[0.0433, 0.7039, 0.8242],
[0.0328, 0.7071, 0.8183],
[0.0234, 0.7103, 0.8124],
[0.0155, 0.7133, 0.8064],
[0.0091, 0.7163, 0.8003],
[0.0046, 0.7192, 0.7941],
[0.0019, 0.722, 0.7878],
[0.0009, 0.7248, 0.7815],
[0.0018, 0.7275, 0.7752],
[0.0046, 0.7301, 0.7688],
[0.0094, 0.7327, 0.7623],
[0.0162, 0.7352, 0.7558],
[0.0253, 0.7376, 0.7492],
[0.0369, 0.74, 0.7426],
[0.0504, 0.7423, 0.7359],
[0.0638, 0.7446, 0.7292],
[0.077, 0.7468, 0.7224],
[0.0899, 0.7489, 0.7156],
[0.1023, 0.751, 0.7088],
[0.1141, 0.7531, 0.7019],
[0.1252, 0.7552, 0.695],
[0.1354, 0.7572, 0.6881],
[0.1448, 0.7593, 0.6812],
[0.1532, 0.7614, 0.6741],
[0.1609, 0.7635, 0.6671],
[0.1678, 0.7656, 0.6599],
[0.1741, 0.7678, 0.6527],
[0.1799, 0.7699, 0.6454],
[0.1853, 0.7721, 0.6379],
[0.1905, 0.7743, 0.6303],
[0.1954, 0.7765, 0.6225],
[0.2003, 0.7787, 0.6146],
[0.2061, 0.7808, 0.6065],
[0.2118, 0.7828, 0.5983],
[0.2178, 0.7849, 0.5899],
[0.2244, 0.7869, 0.5813],
[0.2318, 0.7887, 0.5725],
[0.2401, 0.7905, 0.5636],
[0.2491, 0.7922, 0.5546],
[0.2589, 0.7937, 0.5454],
[0.2695, 0.7951, 0.536],
[0.2809, 0.7964, 0.5266],
[0.2929, 0.7975, 0.517],
[0.3052, 0.7985, 0.5074],
[0.3176, 0.7994, 0.4975],
[0.3301, 0.8002, 0.4876],
[0.3424, 0.8009, 0.4774],
[0.3548, 0.8016, 0.4669],
[0.3671, 0.8021, 0.4563],
[0.3795, 0.8026, 0.4454],
[0.3921, 0.8029, 0.4344],
[0.405, 0.8031, 0.4233],
[0.4184, 0.803, 0.4122],
[0.4322, 0.8028, 0.4013],
[0.4463, 0.8024, 0.3904],
[0.4608, 0.8018, 0.3797],
[0.4753, 0.8011, 0.3691],
[0.4899, 0.8002, 0.3586],
[0.5044, 0.7993, 0.348],
[0.5187, 0.7982, 0.3374],
[0.5329, 0.797, 0.3267],
[0.547, 0.7957, 0.3159],
[0.5609, 0.7943, 0.305],
[0.5748, 0.7929, 0.2941],
[0.5886, 0.7913, 0.2833],
[0.6024, 0.7896, 0.2726],
[0.6161, 0.7878, 0.2622],
[0.6297, 0.7859, 0.2521],
[0.6433, 0.7839, 0.2423],
[0.6567, 0.7818, 0.2329],
[0.6701, 0.7796, 0.2239],
[0.6833, 0.7773, 0.2155],
[0.6963, 0.775, 0.2075],
[0.7091, 0.7727, 0.1998],
[0.7218, 0.7703, 0.1924],
[0.7344, 0.7679, 0.1852],
[0.7468, 0.7654, 0.1782],
[0.759, 0.7629, 0.1717],
[0.771, 0.7604, 0.1658],
[0.7829, 0.7579, 0.1608],
[0.7945, 0.7554, 0.157],
[0.806, 0.7529, 0.1546],
[0.8172, 0.7505, 0.1535],
[0.8281, 0.7481, 0.1536],
[0.8389, 0.7457, 0.1546],
[0.8495, 0.7435, 0.1564],
[0.86, 0.7413, 0.1587],
[0.8703, 0.7392, 0.1615],
[0.8804, 0.7372, 0.165],
[0.8903, 0.7353, 0.1695],
[0.9, 0.7336, 0.1749],
[0.9093, 0.7321, 0.1815],
[0.9184, 0.7308, 0.189],
[0.9272, 0.7298, 0.1973],
[0.9357, 0.729, 0.2061],
[0.944, 0.7285, 0.2151],
[0.9523, 0.7284, 0.2237],
[0.9606, 0.7285, 0.2312],
[0.9689, 0.7292, 0.2373],
[0.977, 0.7304, 0.2418],
[0.9842, 0.733, 0.2446],
[0.99, 0.7365, 0.2429],
[0.9946, 0.7407, 0.2394],
[0.9966, 0.7458, 0.2351],
[0.9971, 0.7513, 0.2309],
[0.9972, 0.7569, 0.2267],
[0.9971, 0.7626, 0.2224],
[0.9969, 0.7683, 0.2181],
[0.9966, 0.774, 0.2138],
[0.9962, 0.7798, 0.2095],
[0.9957, 0.7856, 0.2053],
[0.9949, 0.7915, 0.2012],
[0.9938, 0.7974, 0.1974],
[0.9923, 0.8034, 0.1939],
[0.9906, 0.8095, 0.1906],
[0.9885, 0.8156, 0.1875],
[0.9861, 0.8218, 0.1846],
[0.9835, 0.828, 0.1817],
[0.9807, 0.8342, 0.1787],
[0.9778, 0.8404, 0.1757],
[0.9748, 0.8467, 0.1726],
[0.972, 0.8529, 0.1695],
[0.9694, 0.8591, 0.1665],
[0.9671, 0.8654, 0.1636],
[0.9651, 0.8716, 0.1608],
[0.9634, 0.8778, 0.1582],
[0.9619, 0.884, 0.1557],
[0.9608, 0.8902, 0.1532],
[0.9601, 0.8963, 0.1507],
[0.9596, 0.9023, 0.148],
[0.9595, 0.9084, 0.145],
[0.9597, 0.9143, 0.1418],
[0.9601, 0.9203, 0.1382],
[0.9608, 0.9262, 0.1344],
[0.9618, 0.932, 0.1304],
[0.9629, 0.9379, 0.1261],
[0.9642, 0.9437, 0.1216],
[0.9657, 0.9494, 0.1168],
[0.9674, 0.9552, 0.1116],
[0.9692, 0.9609, 0.1061],
[0.9711, 0.9667, 0.1001],
[0.973, 0.9724, 0.0938],
[0.9749, 0.9782, 0.0872],
[0.9769, 0.9839, 0.0805]]
return ListedColormap(parula_data, name='Parula')