[plotly] starting

This commit is contained in:
mzwiessele 2015-10-07 11:37:05 +01:00
parent e0d48a0558
commit 6fba6acc2b
3 changed files with 393 additions and 0 deletions

View file

View file

@ -0,0 +1,75 @@
#===============================================================================
# Copyright (c) 2015, Max Zwiessele
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of GPy nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#===============================================================================
from matplotlib import cm
from .. import Tango
'''
This file is for defaults for the gpy plot, specific to the plotting library.
Create a kwargs dictionary with the right name for the plotting function
you are implementing. If you do not provide defaults, the default behaviour of
the plotting library will be used.
In the code, always ise plotting.gpy_plots.defaults to get the defaults, as
it gives back an empty default, when defaults are not defined.
'''
# Data plots:
data_1d = dict(lw=1.5, marker='x', edgecolor='k')
data_2d = dict(s=35, edgecolors='none', linewidth=0., cmap=cm.get_cmap('hot'), alpha=.5)
inducing_1d = dict(lw=0, s=500, facecolors=Tango.colorsHex['darkRed'])
inducing_2d = dict(s=14, edgecolors='k', linewidth=.4, facecolors='white', alpha=.5)
inducing_3d = dict(lw=.3, s=500, facecolors='white', edgecolors='k')
xerrorbar = dict(color='k', fmt='none', elinewidth=.5, alpha=.5)
yerrorbar = dict(color=Tango.colorsHex['darkRed'], fmt='none', elinewidth=.5, alpha=.5)
# GP plots:
meanplot_1d = dict(color=Tango.colorsHex['mediumBlue'], linewidth=2)
meanplot_2d = dict(cmap='hot', linewidth=.5)
meanplot_3d = dict(linewidth=0, antialiased=True, cstride=1, rstride=1, cmap='hot', alpha=.3)
samples_1d = dict(color=Tango.colorsHex['mediumBlue'], linewidth=.3)
samples_3d = dict(cmap='hot', alpha=.1, antialiased=True, cstride=1, rstride=1, linewidth=0)
confidence_interval = dict(edgecolor=Tango.colorsHex['darkBlue'], linewidth=.5, color=Tango.colorsHex['lightBlue'],alpha=.2)
density = dict(alpha=.5, color=Tango.colorsHex['lightBlue'])
# GPLVM plots:
data_y_1d = dict(linewidth=0, cmap='RdBu', s=40)
data_y_1d_plot = dict(color='k', linewidth=1.5)
# Kernel plots:
ard = dict(edgecolor='k', linewidth=1.2)
# Input plots:
latent = dict(aspect='auto', cmap='Greys', interpolation='bicubic')
gradient = dict(aspect='auto', cmap='RdBu', interpolation='nearest', alpha=.7)
magnification = dict(aspect='auto', cmap='Greys', interpolation='bicubic')
latent_scatter = dict(s=40, linewidth=.2, edgecolor='k', alpha=.9)
annotation = dict(fontdict=dict(family='sans-serif', weight='light', fontsize=9), zorder=.3, alpha=.7)

View file

@ -0,0 +1,318 @@
#===============================================================================
# Copyright (c) 2015, Max Zwiessele
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of GPy.plotting.matplot_dep.plot_definitions nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#===============================================================================
import numpy as np
from ..abstract_plotting_library import AbstractPlottingLibrary
from .. import Tango
from . import defaults
import itertools
from plotly import tools
from plotly import plotly as py
from plotly.graph_objs import Scatter, Line, Data
class PlotlyPlots(AbstractPlottingLibrary):
def __init__(self):
super(PlotlyPlots, self).__init__()
self._defaults = defaults.__dict__
self.current_states = dict()
def figure(self, rows=1, cols=1, **kwargs):
if 'filename' not in kwargs:
print('PlotlyWarning: filename was not given, this may clutter your plotly workspace')
filename = None
else: filename = kwargs.pop('filename')
figure = tools.make_subplots(rows, cols, **kwargs)
self.current_states[hex(id(figure))] = dict(filename=filename)
index = 1
for i in rows:
for j in cols:
self.current_states[hex(id(figure))][(i,j)] = ('xaxis{}'.format(index), 'yaxis{}'.format(index))
index += 1
return figure
def new_canvas(self, figure=None, row=1, col=1, projection='2d', xlabel=None, ylabel=None, zlabel=None, title=None, xlim=None, ylim=None, zlim=None, **kwargs):
if figure is None:
figure = self.figure(**kwargs)
return (figure, self.current_states[hex(id(figure))][(row,col)]), kwargs
def show_canvas(self, canvas, traces, legend=False, **kwargs):
fig = canvas[0]
axis = fig['layout'][canvas[1]]
axis.update(title=title, label)
figure.add_traces(traces, row, col, **kwargs)
# If shared_axes is False (default) use list_of_domains
# This is used for insets and irregular layouts
if not shared_xaxes and not shared_yaxes:
x_dom = list_of_domains[::2]
y_dom = list_of_domains[1::2]
subtitle_pos_x = []
subtitle_pos_y = []
for x_domains in x_dom:
subtitle_pos_x.append(sum(x_domains) / 2)
for y_domains in y_dom:
subtitle_pos_y.append(y_domains[1])
# If shared_axes is True the domin of each subplot is not returned so the
# title position must be calculated for each subplot
else:
subtitle_pos_x = [None] * cols
subtitle_pos_y = [None] * rows
delt_x = (x_e - x_s)
for index in range(cols):
subtitle_pos_x[index] = ((delt_x / 2) +
((delt_x + horizontal_spacing) * index))
subtitle_pos_x *= rows
for index in range(rows):
subtitle_pos_y[index] = (1 - ((y_e + vertical_spacing) * index))
subtitle_pos_y *= cols
subtitle_pos_y = sorted(subtitle_pos_y, reverse=True)
plot_titles = []
for index in range(len(subplot_titles)):
if not subplot_titles[index]:
pass
else:
plot_titles.append({'y': subtitle_pos_y[index],
'xref': 'paper',
'x': subtitle_pos_x[index],
'yref': 'paper',
'text': subplot_titles[index],
'showarrow': False,
'font': graph_objs.Font(size=16),
'xanchor': 'center',
'yanchor': 'bottom'
})
layout['annotations'] = plot_titles
try:
url = py.iplot(figure, self.current_filename)
except:
url = py.plot(figure, self.current_filename)
return url
def scatter(self, ax, X, Y, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, marker='o', **kwargs):
def plot(self, ax, X, Y, Z=None, color=None, label=None, **kwargs):
if Z is not None:
return ax.plot(X, Y, color=color, zs=Z, label=label, **kwargs)
return ax.plot(X, Y, color=color, label=label, **kwargs)
def plot_axis_lines(self, ax, X, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs):
from matplotlib import transforms
from matplotlib.path import Path
if 'marker' not in kwargs:
kwargs['marker'] = Path([[-.2,0.], [-.2,.5], [0.,1.], [.2,.5], [.2,0.], [-.2,0.]],
[Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY])
if 'transform' not in kwargs:
if X.shape[1] == 1:
kwargs['transform'] = transforms.blended_transform_factory(ax.transData, ax.transAxes)
if X.shape[1] == 2:
return ax.scatter(X[:,0], X[:,1], ax.get_zlim()[0], c=color, label=label, **kwargs)
return ax.scatter(X, np.zeros_like(X), c=color, label=label, **kwargs)
def barplot(self, ax, x, height, width=0.8, bottom=0, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs):
if 'align' not in kwargs:
kwargs['align'] = 'center'
return ax.bar(left=x, height=height, width=width,
bottom=bottom, label=label, color=color,
**kwargs)
def xerrorbar(self, ax, X, Y, error, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs):
if not('linestyle' in kwargs or 'ls' in kwargs):
kwargs['ls'] = 'none'
if Z is not None:
return ax.errorbar(X, Y, Z, xerr=error, ecolor=color, label=label, **kwargs)
return ax.errorbar(X, Y, xerr=error, ecolor=color, label=label, **kwargs)
def yerrorbar(self, ax, X, Y, error, Z=None, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs):
if not('linestyle' in kwargs or 'ls' in kwargs):
kwargs['ls'] = 'none'
if Z is not None:
return ax.errorbar(X, Y, Z, yerr=error, ecolor=color, label=label, **kwargs)
return ax.errorbar(X, Y, yerr=error, ecolor=color, label=label, **kwargs)
def imshow(self, ax, X, extent=None, label=None, vmin=None, vmax=None, **imshow_kwargs):
if 'origin' not in imshow_kwargs:
imshow_kwargs['origin'] = 'lower'
#xmin, xmax, ymin, ymax = extent
#xoffset, yoffset = (xmax - xmin) / (2. * X.shape[0]), (ymax - ymin) / (2. * X.shape[1])
#xmin, xmax, ymin, ymax = extent = xmin-xoffset, xmax+xoffset, ymin-yoffset, ymax+yoffset
return ax.imshow(X, label=label, extent=extent, vmin=vmin, vmax=vmax, **imshow_kwargs)
def imshow_interact(self, ax, plot_function, extent=None, label=None, resolution=None, vmin=None, vmax=None, **imshow_kwargs):
if 'origin' not in imshow_kwargs:
imshow_kwargs['origin'] = 'lower'
return ImshowController(ax, plot_function, extent, resolution=resolution, vmin=vmin, vmax=vmax, **imshow_kwargs)
def annotation_heatmap(self, ax, X, annotation, extent=None, label=None, imshow_kwargs=None, **annotation_kwargs):
imshow_kwargs = imshow_kwargs or {}
if 'origin' not in imshow_kwargs:
imshow_kwargs['origin'] = 'lower'
if ('ha' not in annotation_kwargs) and ('horizontalalignment' not in annotation_kwargs):
annotation_kwargs['ha'] = 'center'
if ('va' not in annotation_kwargs) and ('verticalalignment' not in annotation_kwargs):
annotation_kwargs['va'] = 'center'
imshow = self.imshow(ax, X, extent, label, **imshow_kwargs)
if extent is None:
extent = (0, X.shape[0], 0, X.shape[1])
xmin, xmax, ymin, ymax = extent
xoffset, yoffset = (xmax - xmin) / (2. * X.shape[0]), (ymax - ymin) / (2. * X.shape[1])
xmin, xmax, ymin, ymax = extent = xmin+xoffset, xmax-xoffset, ymin+yoffset, ymax-yoffset
xlin = np.linspace(xmin, xmax, X.shape[0], endpoint=False)
ylin = np.linspace(ymin, ymax, X.shape[1], endpoint=False)
annotations = []
for [i, x], [j, y] in itertools.product(enumerate(xlin), enumerate(ylin)):
annotations.append(ax.text(x, y, "{}".format(annotation[j, i]), **annotation_kwargs))
return imshow, annotations
def annotation_heatmap_interact(self, ax, plot_function, extent, label=None, resolution=15, imshow_kwargs=None, **annotation_kwargs):
if 'origin' not in imshow_kwargs:
imshow_kwargs['origin'] = 'lower'
return ImAnnotateController(ax, plot_function, extent, resolution=resolution, imshow_kwargs=imshow_kwargs or {}, **annotation_kwargs)
def contour(self, ax, X, Y, C, levels=20, label=None, **kwargs):
return ax.contour(X, Y, C, levels=np.linspace(C.min(), C.max(), levels), label=label, **kwargs)
def surface(self, ax, X, Y, Z, color=None, label=None, **kwargs):
return ax.plot_surface(X, Y, Z, label=label, **kwargs)
def fill_between(self, ax, X, lower, upper, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs):
return ax.fill_between(X, lower, upper, facecolor=color, label=label, **kwargs)
def fill_gradient(self, canvas, X, percentiles, color=Tango.colorsHex['mediumBlue'], label=None, **kwargs):
ax = canvas
plots = []
if 'edgecolors' not in kwargs:
kwargs['edgecolors'] = 'none'
if 'facecolors' in kwargs:
color = kwargs.pop('facecolors')
if 'array' in kwargs:
array = kwargs.pop('array')
else:
array = 1.-np.abs(np.linspace(-.97, .97, len(percentiles)-1))
if 'alpha' in kwargs:
alpha = kwargs.pop('alpha')
else:
alpha = .8
if 'cmap' in kwargs:
cmap = kwargs.pop('cmap')
else:
cmap = LinearSegmentedColormap.from_list('WhToColor', (color, color), N=array.size)
cmap._init()
cmap._lut[:-3, -1] = alpha*array
kwargs['facecolors'] = [cmap(i) for i in np.linspace(0,1,cmap.N)]
# pop where from kwargs
where = kwargs.pop('where') if 'where' in kwargs else None
# pop interpolate, which we actually do not do here!
if 'interpolate' in kwargs: kwargs.pop('interpolate')
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
from itertools import tee
#try:
# from itertools import izip as zip
#except ImportError:
# pass
a, b = tee(iterable)
next(b, None)
return zip(a, b)
polycol = []
for y1, y2 in pairwise(percentiles):
import matplotlib.mlab as mlab
# Handle united data, such as dates
ax._process_unit_info(xdata=X, ydata=y1)
ax._process_unit_info(ydata=y2)
# Convert the arrays so we can work with them
from numpy import ma
x = ma.masked_invalid(ax.convert_xunits(X))
y1 = ma.masked_invalid(ax.convert_yunits(y1))
y2 = ma.masked_invalid(ax.convert_yunits(y2))
if y1.ndim == 0:
y1 = np.ones_like(x) * y1
if y2.ndim == 0:
y2 = np.ones_like(x) * y2
if where is None:
where = np.ones(len(x), np.bool)
else:
where = np.asarray(where, np.bool)
if not (x.shape == y1.shape == y2.shape == where.shape):
raise ValueError("Argument dimensions are incompatible")
from functools import reduce
mask = reduce(ma.mask_or, [ma.getmask(a) for a in (x, y1, y2)])
if mask is not ma.nomask:
where &= ~mask
polys = []
for ind0, ind1 in mlab.contiguous_regions(where):
xslice = x[ind0:ind1]
y1slice = y1[ind0:ind1]
y2slice = y2[ind0:ind1]
if not len(xslice):
continue
N = len(xslice)
p = np.zeros((2 * N + 2, 2), np.float)
# the purpose of the next two lines is for when y2 is a
# scalar like 0 and we want the fill to go all the way
# down to 0 even if none of the y1 sample points do
start = xslice[0], y2slice[0]
end = xslice[-1], y2slice[-1]
p[0] = start
p[N + 1] = end
p[1:N + 1, 0] = xslice
p[1:N + 1, 1] = y1slice
p[N + 2:, 0] = xslice[::-1]
p[N + 2:, 1] = y2slice[::-1]
polys.append(p)
polycol.extend(polys)
from matplotlib.collections import PolyCollection
if 'zorder' not in kwargs:
kwargs['zorder'] = 0
plots.append(PolyCollection(polycol, **kwargs))
ax.add_collection(plots[-1], autolim=True)
ax.autoscale_view()
return plots