Commit 0f857872 authored by Christian Schneider's avatar Christian Schneider
Browse files

Implementing holoviews datashader for datamodule

parent 4e9057a1
......@@ -2,7 +2,7 @@ from .version import __version__
from . import plot_style
from .base import data_module_base
from .data_complex import data_complex, data_cplx
from .data_line import data_line, data_2d
from .data_xy import data_xy, data_2d
from .data_surface import data_surface, data_3d
from .data_IQ import data_IQ
from .functions import *
......
......@@ -145,6 +145,3 @@ class data_module_base(object):
idx = np.where((self.x >= xrng[0]) & (self.x <= xrng[1]))[0]
self.idx_min = idx[0]
self.idx_max = idx[-1]
self.lensel = self.idx_max-self.idx_min
......@@ -6,7 +6,7 @@ import numpy as np
from CircleFit.plotting import plot_rawdata
import CircleFit.plotting as cp
from CircleFit.circuit import Notch, Reflection
from .data_line import data_line
from .data_xy import data_xy
from CircleFit.fit_toolbox import get_delay
......@@ -47,9 +47,9 @@ class data_complex(data_module_base):
"""
self.x = np.array(x)
self.value = np.array(re + 1j*im)
self.dB = data_line(self.x, 20*np.log10(np.abs(self.value)))
self.phase = data_line(self.x,
np.unwrap(np.angle(self.value))*180/np.pi)
self.dB = data_xy(self.x, 20 * np.log10(np.abs(self.value)))
self.phase = data_xy(self.x,
np.unwrap(np.angle(self.value)) * 180 / np.pi)
self.select() # check this needs some work
def load_cplx_var(self, x, y):
......@@ -64,9 +64,9 @@ class data_complex(data_module_base):
"""
self.x = np.array(x)
self.value = np.array(y)
self.dB = data_line(self.x, 20*np.log10(np.abs(self.value)))
self.phase = data_line(self.x,
np.unwrap(np.angle(self.value))*180/np.pi)
self.dB = data_xy(self.x, 20 * np.log10(np.abs(self.value)))
self.phase = data_xy(self.x,
np.unwrap(np.angle(self.value)) * 180 / np.pi)
self.select()
def select(self, xrng=None):
......
# -*- coding: utf-8 -*-
"""
Author: Christian Schneider <c.schneider@uibk.ac.at>
Date: 17.03.2018
"""
from .base import data_module_base
import holoviews as hv
hv.extension('bokeh')
import holoviews.operation.datashader as hd
class data_grid(data_module_base):
"""Class for grid like data with one or two independent variables and
one or more dependent variables
Parameters
-----------
data_arrays :
Data to save. Format should be
[array_xaxis, array_yaxis, matrix(yaxis, xaxis)]
"""
def __init__(self, data_arrays, data_names=None):
super().__init__()
# Create default names
df_names = ['x{}'.format(i) for i in range(len(data_arrays))]
# Replace default names by the names given
if data_names:
for idx in range(len(data_names)):
if data_names[idx]:
df_names[idx] = data_names[idx]
# Create holoviews object TODO: Adapt to xarray
# Assume the last element of the given arrays is the grid data
self.ds = hv.Dataset(tuple(i for i in data_arrays),
[i for i in df_names[:-1]], df_names[-1])
self.df = self.ds.dframe()
@property
def x(self):
return self.df
def import_data(self, data_arrays, data_names=None):
"""Import data from new arrays. Naming highly recommencd!
Assumes first given array is the array of the independant variable.
Parameters
-----------
data_arrays : list, array, np.array
List of data arrays. Structure
[[x, x, x, x, ....], [y, y, y,....], ... ]
name_list : list, array, np.array, None
List of names for arrays:
['x1', 'y', 'Resistances', ... ]
"""
if data_names:
order_names = data_names
else:
order_names = df.columns
for d, idx in zip(data_arrays[0],
list(self.df[order_names[0]]
.index.reindex(data_arrays[0])[1])):
if idx != -1:
for i in range(1, len(data_arrays)):
# Use mean
self.df[order_names[i]][idx] += data_arrays[i]
self.df[order_names[i]][idx] /= 2
else:
self.df = self.df.append({key: value[idx]} for key, value
in zip(order_names, data_arrays))
def plot_hv(self, name_x=None, name_y=None, height=400, width=800,
cmap='magma'):
"""Plot table with Holoviews
Parameters
-----------
name_x : None, str, list
Column name(s) used for x axis
name_y : None, str, list
Column name(s) used for y axis
height : int
Height of plot in pixels
width : int
Width of plot in pixels
"""
if name_x is None:
x_vals = [self.df.keys()[0]]
elif isinstance(name_x, (list, np.array)):
# len(y) == len(x)
x_vals = []
for x_i in name_x:
x_vals.append(x_i)
else:
x_vals = [name_x]
if name_y is None:
y_vals = [self.df.keys()[1]]
elif isinstance(name_x, (list, np.array)):
# len(y) == len(x)
y_vals = []
for y_i in name_y:
y_vals.append(y_i)
else:
y_vals = [name_y]
if len(y_vals) != len(x_vals):
for i in range(len(y_vals) - len(x_vals)):
x_vals.append(self.df.keys()[0])
hd.regrid(self.ds.to(hv.Image).opts(
plot=dict(width=800, height=400), Image=dict(cmap=cmap))
#n -*- coding: utf-8 -*-
# n -*- coding: utf-8 -*-
"""
Class for simple data y=f(x)
!!!DEPRECIATED!!!
ONLY HERE FOR COMPATIBLITY TO OLD DATAMODULES. DO NOT USE OR MODIFY IT
Author: Iman, Oscar Gargiulo, Christian Schneider
"""
from .data_table import data_table
from .base import data_module_base
from .plot_style import cc
import numpy as np
import matplotlib.pyplot as plt
......@@ -18,24 +23,33 @@ from collections import OrderedDict
from .plot_style import plot_xy
class data_line(data_table):
class data_line(data_module_base):
"""Class for real y=f(x) data."""
def __init__(self, x, y, name_x='x', name_y='y'):
super().__init__([x, y], [name_x, name_y])
def __init__(self, x=None, y=None):
super().__init__()
self._fit_executed = False
self._fit_labels = None
def return_x(self):
return np.array(self.df[self.df.columns[0]])[self.idx_min:self.idx_max]
if x is None:
self.x = np.array([])
self.y = np.array([])
else:
if y is None:
print('Error: no y-axis inserted')
raise Exception('EMPTYARRAY')
else:
self.load_var(x, y)
def return_y(self):
return np.array(self.df[self.df.columns[1]])[self.idx_min:self.idx_max]
self.__errtype_list = ['ABS', 'REL', 'RELPC']
x = property(return_x)
y = property(return_y)
print('Data_line depreciated. Please use data_xy')
# TODO Redesign
self.xerr = (0, 0, True)
self.yerr = (0, 0, True)
def load_var(self, x, y, name_x='x', name_y='y'):
def load_var(self, x, y):
"""Import data from two tuples/lists/array.
Parameters
......@@ -45,13 +59,15 @@ class data_line(data_table):
y : list
Y-Array. Typically magnitude or phase values
"""
x = np.array(x)
y = np.array(y)
if x.size/len(x) != 1.:
if x.size / len(x) != 1.:
print('Error in the x-axis, check it!')
raise Exception('NOTANARRAY')
if y.size/len(y) != 1.:
if y.size / len(y) != 1.:
print('Error in the y-axis, check it!')
raise Exception('NOTANARRAY')
......@@ -66,11 +82,13 @@ class data_line(data_table):
if len(x) != len(y):
print('WARNING: x and y length mismatch')
self.import_data([x, y], ['x', 'y'])
self.x = x
self.y = y
self.select()
def return_ysel(self):
"""Return currently selected y values"""
return self.y
return self.y[self.idx_min:self.idx_max]
# Plotting ################################################################
def plot(self, style='b-o', color=None, xscale=1, yscale=1,
......@@ -132,8 +150,8 @@ class data_line(data_table):
you want to add for example another points, lines, labels, etc
afterwards.
"""
x = self.x
y = self.y
xsel = self.return_xsel()
ysel = self.return_ysel()
# Don't show plot if figure is given (normally one does not need this)
if fig:
......@@ -156,12 +174,12 @@ class data_line(data_table):
fig = bp.figure(plot_width=800, plot_height=400, tools=tools,
toolbar_location='above', title=title)
# Data
plot_xy(x*xscale, y*yscale, style, color, linewidth,
plot_xy(xsel * xscale, ysel * yscale, style, color, linewidth,
markersize, legend, legend_pos, engine, title, show, fig,
**kwargs)
# Fit
if plot_fit and self._fit_executed:
plot_xy(x*xscale, (fitfunc(x, *self._fit_parameters)) *
plot_xy(xsel * xscale, (fitfunc(xsel, *self._fit_parameters)) *
yscale, '-', fitcolor, fit_linewidth, markersize,
legend, legend_pos, engine, title, show, fig)
......@@ -176,7 +194,7 @@ class data_line(data_table):
elif engine in ['pyplot', 'p']:
# Data
plt.title(title)
plot_xy(x*xscale, y*yscale, style, color, linewidth,
plot_xy(xsel * xscale, ysel * yscale, style, color, linewidth,
markersize, legend, legend_pos, engine, title, show=False,
fig=fig, **kwargs)
# Fit
......@@ -186,18 +204,16 @@ class data_line(data_table):
except:
fig = plt.figure()
if plot_fit and self._fit_executed:
if not fit_on_top:
fit_zorder=0
fit_zorder = 0
else:
fit_zorder=99
plt.plot(x*xscale, fitfunc(x,
*self._fit_parameters)*yscale,
fit_zorder = 99
plt.plot(xsel * xscale, fitfunc(xsel,
*self._fit_parameters) * yscale,
'-', color=fitcolor, linewidth=fit_linewidth,
zorder=fit_zorder)
# ToDO: Error Bars
# if plot_error_bars is True:
# plt.errorbar(xsel*xscale,ysel*yscale,self.return_yerr()*yscale,
......@@ -278,8 +294,9 @@ class data_line(data_table):
self._fit_parameters = fit_p_fit
self._fit_par_errors = np.sqrt(np.diag(err))
# Chi squared
self._fit_data_error = (np.sum((fitfunc(xsel, *fit_p_fit)-ysel)**2) /
(len(xsel) - 2))
self._fit_data_error = (
np.sum((fitfunc(xsel, *fit_p_fit) - ysel) ** 2) /
(len(xsel) - 2))
self._fit_labels = labels
if plot_params:
......@@ -478,120 +495,120 @@ class data_line(data_table):
if type(errtype) is str:
try:
num= self.__errtype_list.index(errtype.upper() )
num = self.__errtype_list.index(errtype.upper())
except:
print('Wrong Type inserted')
return 'Err'
else:
num=int(errtype)
if num<0 or num>len(self.__errtype_list):
num = int(errtype)
if num < 0 or num > len(self.__errtype_list):
print('Wrong Type number inserted')
return 'Err'
return num
return num
def set_xerror(self,xerr,errtype='abs'):
def set_xerror(self, xerr, errtype='abs'):
"""This function writes in the datamodule the error of the x-axis points
The error can be a number (same error for all the axis) or an array.
The type can be:
"abs" (def) or 0 - for absolute error
"rel" or 1 - for a relative error, given as a number
"relpc" or 2 - for a relative error, given in %
"""
errtype = self.__error_type_check(errtype)
#checking the length of xerr, only 1 or a N-array (where N is the length of the x-axis) are allowed
# checking the length of xerr, only 1 or a N-array (where N is the length of the x-axis) are allowed
try:
len(xerr)
singlepoint = False
if len(xerr) != len(self.x):
print('ERROR: The array length is smaller than the x-axis length')
if len(xerr) != len(self.x):
print(
'ERROR: The array length is smaller than the x-axis length')
raise Exception('ARRLENGTH')
except TypeError: #if it is a single element we get this exception, I don't have a better solution at the moment
except TypeError: # if it is a single element we get this exception, I don't have a better solution at the moment
singlepoint = True
self.xerr = (xerr,errtype,singlepoint)
def set_yerror(self,yerr,errtype='abs'):
self.xerr = (xerr, errtype, singlepoint)
def set_yerror(self, yerr, errtype='abs'):
"""This function writes in the datamodule the error of the y-axis points
The error can be a number (same error for all the axis) or an array.
The type can be:
"abs" (def) or 0 - for absolute error
"rel" or 1 - for a relative error, given as a number
"relpc" or 2 - for a relative error, given in %
"""
errtype = self.__error_type_check(errtype)
#checking the length of xerr, only 1 or a N-array (where N is the length of the x-axis) are allowed
# checking the length of xerr, only 1 or a N-array (where N is the length of the x-axis) are allowed
try:
len(yerr)
singlepoint = False
if len(yerr) != len(self.y):
print('ERROR: The array length is smaller than the y-axis length')
print(
'ERROR: The array length is smaller than the y-axis length')
raise Exception('ARRLENGTH')
except TypeError: #if it is a single element we get this exception, I don't have a better solution at the moment
except TypeError: # if it is a single element we get this exception, I don't have a better solution at the moment
singlepoint = True
self.yerr = (yerr,errtype,singlepoint)
self.yerr = (yerr, errtype, singlepoint)
def return_xerr(self):
"""
This function returns the error array evaluated on the selected x-axis
"""
#First let's check if the error is a number (same error for all the points)
# First let's check if the error is a number (same error for all the points)
if self.xerr[2] is True:
if self.xerr[1] is 0: #abs
return np.ones(self.sellen)*self.xerr[0]
elif self.xerr[1] is 1: #rel
return self.return_xsel()*self.xerr[0]
elif self.xerr[1] is 2: #relpc
return self.return_xsel()*self.xerr[0]/100
if self.xerr[1] is 0: # abs
return np.ones(self.sellen) * self.xerr[0]
elif self.xerr[1] is 1: # rel
return self.return_xsel() * self.xerr[0]
elif self.xerr[1] is 2: # relpc
return self.return_xsel() * self.xerr[0] / 100
else:
print('Wrong type in error')
raise Exception('ERRTYPE')
else:
if self.xerr[1] is 0: #abs
if self.xerr[1] is 0: # abs
return self.xerr[0][self.idx_min:self.idx_max]
elif self.xerr[1] is 1: #rel
return self.return_xsel()*self.xerr[0][self.idx_min:self.idx_max]
elif self.xerr[1] is 2: #relpc
return self.return_xsel()*self.xerr[0][self.idx_min:self.idx_max]/100
elif self.xerr[1] is 1: # rel
return self.return_xsel() * self.xerr[0][
self.idx_min:self.idx_max]
elif self.xerr[1] is 2: # relpc
return self.return_xsel() * self.xerr[0][
self.idx_min:self.idx_max] / 100
else:
print('Wrong type in error')
raise Exception('ERRTYPE')
def return_yerr(self):
"""
This function returns the error array evaluated on the selected x-axis
"""
#First let's check if the error is a number (same error for all the points)
# First let's check if the error is a number (same error for all the points)
if self.yerr[2] is True:
if self.yerr[1] is 0: #abs
return np.ones(self.sellen)*self.yerr[0]
elif self.yerr[1] is 1: #rel
return self.return_ysel()*self.yerr[0]
elif self.yerr[1] is 2: #relpc
return self.return_ysel()*self.yerr[0]/100
if self.yerr[1] is 0: # abs
return np.ones(self.sellen) * self.yerr[0]
elif self.yerr[1] is 1: # rel
return self.return_ysel() * self.yerr[0]
elif self.yerr[1] is 2: # relpc
return self.return_ysel() * self.yerr[0] / 100
else:
print('Wrong type in error')
raise Exception('ERRTYPE')
else:
if self.yerr[1] is 0: #abs
if self.yerr[1] is 0: # abs
return self.yerr[0][self.idx_min:self.idx_max]
elif self.yerr[1] is 1: #rel
return self.return_ysel()*self.yerr[0][self.idx_min:self.idx_max]
elif self.yerr[1] is 2: #relpc
return self.return_ysel()*self.yerr[0][self.idx_min:self.idx_max]/100
elif self.yerr[1] is 1: # rel
return self.return_ysel() * self.yerr[0][
self.idx_min:self.idx_max]
elif self.yerr[1] is 2: # relpc
return self.return_ysel() * self.yerr[0][
self.idx_min:self.idx_max] / 100
else:
print('Wrong type in error')
raise Exception('ERRTYPE')
......@@ -602,6 +619,8 @@ class data_line(data_table):
Same as fit_func for compatibility to previous versions
"""
return self.fit_func(x)
###############################################################################
# Aliases (for compatibility to previous datamdoule versions) #################
data_2d = data_line
......@@ -5,7 +5,7 @@
Author: Iman, Oscar Gargiulo, Christian Schneider
"""
from .base import data_module_base
from .data_line import data_line
from .data_xy import data_xy
import numpy as np
import matplotlib.pyplot as plt
import scipy.signal as sp_sig
......@@ -122,10 +122,12 @@ class data_surface(data_module_base):
Maximum z value for color scale
"""
# Just plot selection
xsel = self.return_xsel()
ysel = self.return_ysel()
zsel = self.return_zsel()
#xsel = self.return_xsel()
#ysel = self.return_ysel()
#zsel = self.return_zsel()
xsel = self.x
ysel = self.y
zsel = self.z
# Create color mapper
if z_min is None:
z_min = np.min(zsel)
......@@ -311,7 +313,7 @@ class data_surface(data_module_base):
zsel = self.return_zsel()
idx = np.argmax(self.y >= y0)
data = data_line()
data = data_xy()
data.par = self.par
data.comments = self.comments
......@@ -353,7 +355,7 @@ class data_surface(data_module_base):
idx = np.argmax(self.x >= x0)
data = data_line()
data = data_xy()
data.par = self.par
data.comments = self.comments
data.temp_start = self.temp_start
......@@ -416,7 +418,7 @@ class data_surface(data_module_base):
for i in range(len(tmp)):
tmp[i] = np.min(zsel[i, :])
data = data_line()
data = data_xy()
data.par = self.par
data.temp_start = self.temp_start
data.temp_stop = self.temp_stop
......@@ -465,7 +467,7 @@ class data_surface(data_module_base):
if argument:
# Return x values
for i in range(len(tmp)):
tmp_dm = data_line(xsel, zsel[i, :])
tmp_dm = data_xy(xsel, zsel[i, :])
fpars, fpars_err, _ = tmp_dm.fit(lorentzian_fit, p0, plot=plot,
plot_init=False,
plot_params=False,
......@@ -477,7 +479,7 @@ class data_surface(data_module_base):
else:
# Return z values
for i in range(len(tmp)):
tmp_dm = data_line(xsel, zsel[i, :])
tmp_dm = data_xy(xsel, zsel[i, :])
fpars, fpars_err, _ = tmp_dm.fit(lorentzian_fit, p0, plot=plot,
plot_init=False,
plot_params=False,
......@@ -489,7 +491,7 @@ class data_surface(data_module_base):
if adapt_p0:
p0 = fpars
data = data_line()
data = data_xy()
data.par = self.par
data.temp_start = self.temp_start
data.temp_stop = self.temp_stop
......@@ -532,7 +534,7 @@ class data_surface(data_module_base):
if argument:
# Return x values
for i in range(len(tmp)):
tmp_dm = data_line(xsel, zsel[i, :])
tmp_dm = data_xy(xsel, zsel[i, :])
fpars, fpars_err, _ = tmp_dm.fit(mode_fit, p0, plot=plot,
plot_init=False,
plot_params=False,
......@@ -542,13 +544,13 @@ class data_surface(data_module_base):
else:
# Return z values
for i in range(len(tmp)):