Commit 7967f2d5 authored by Theo Steininger's avatar Theo Steininger
Browse files

Merge branch 'plotting' into 'master'

Plotting

See merge request !70
parents 54885033 a1f0b918
Pipeline #11743 passed with stages
in 16 minutes and 14 seconds
......@@ -8,7 +8,8 @@ RUN \
libopenmpi-dev libatlas-base-dev libfftw3-bin libfftw3-dev \
libfftw3-double3 libfftw3-long3 libfftw3-mpi-dev libfftw3-mpi3 \
libfftw3-quad3 libfftw3-single3 libhdf5-10 libhdf5-dev \
libhdf5-openmpi-10 libhdf5-openmpi-dev hdf5-tools
libhdf5-openmpi-10 libhdf5-openmpi-dev hdf5-tools \
python-tk
# python dependencies
ADD ci/requirements.txt /tmp/requirements.txt
......
......@@ -2,6 +2,7 @@ numpy
cython
mpi4py
matplotlib
plotly
ipython==5.3.0
nose
parameterized
......
......@@ -50,6 +50,8 @@ from spaces import *
from operators import *
from plotting import *
from probing import *
from sugar import *
# -*- coding: utf-8 -*-
import os
__all__ = []
try:
import matplotlib
except ImportError:
pass
else:
try:
display = os.environ['DISPLAY']
except KeyError:
matplotlib.use('Agg')
else:
if display == '':
matplotlib.use('Agg')
......@@ -16,15 +16,22 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import matplotlib_init
import os
import numpy as np
import keepers
__all__ = ['dependency_injector', 'nifty_configuration']
# Setup the dependency injector
dependency_injector = keepers.DependencyInjector(
[('mpi4py.MPI', 'MPI'),
'pyHealpix'])
'pyHealpix',
'plotly',
'pylab',
'healpy'])
dependency_injector.register('pyfftw', lambda z: hasattr(z, 'FFTW_MPI'))
......@@ -36,7 +43,7 @@ variable_fft_module = keepers.Variable(
if z == 'fftw' else True))
def _dtype_validator(dtype):
def dtype_validator(dtype):
try:
np.dtype(dtype)
except(TypeError):
......@@ -47,7 +54,7 @@ def _dtype_validator(dtype):
variable_default_field_dtype = keepers.Variable(
'default_field_dtype',
['float'],
_dtype_validator,
dtype_validator,
genus='str')
variable_default_distribution_strategy = keepers.Variable(
......@@ -72,4 +79,4 @@ nifty_configuration = keepers.get_Configuration(
try:
nifty_configuration.load()
except:
pass
\ No newline at end of file
pass
import descriptors
import plots
import figures
from plotting import plot, plot_image
from plottable import Plottable
__all__ = ['descriptors', 'plots', 'figures', 'plot', 'plot_image', 'Plottable']
from descriptors import *
from plots import *
from figures import *
from axis import Axis
from line import Line
from marker import Marker
from plotly_wrapper import _PlotlyWrapper
# -*- coding: utf-8 -*-
class Marker(_PlotlyWrapper):
# find symbols at: https://plot.ly/python/reference/#scatter-marker-symbol
def __init__(self, color=None, size=None, symbol=None, opacity=None):
self.color = color
self.size = size
self.symbol = symbol
self.opacity = opacity
def _to_plotly(self):
return dict(color=self.color, size=self.size, symbol=self.symbol, opacity=self.opacity)
class Line(_PlotlyWrapper):
def __init__(self, color=None, width=None):
self.color = color
self.width = width
def _to_plotly(self):
return dict(color=self.color, width=self.width)
from nifty.plotting.plotly_wrapper import PlotlyWrapper
class Axis(_PlotlyWrapper):
def __init__(self, text=None, font='', color='', log=False, show_grid=True):
class Axis(PlotlyWrapper):
def __init__(self, text=None, font='', color='', log=False,
show_grid=True):
self.text = text
self.font = font
self.color = color
self.log = log
self.show_grid = show_grid
def _to_plotly(self):
def to_plotly(self):
ply_object = dict()
if self.text:
ply_object.update(dict(
......
# -*- coding: utf-8 -*-
from nifty.plotting.plotly_wrapper import PlotlyWrapper
class Line(PlotlyWrapper):
def __init__(self, color=None, width=None):
self.color = color
self.width = width
def to_plotly(self):
return dict(color=self.color,
width=self.width)
# -*- coding: utf-8 -*-
from nifty.plotting.plotly_wrapper import PlotlyWrapper
class Marker(PlotlyWrapper):
# find symbols at: https://plot.ly/python/reference/#scatter-marker-symbol
def __init__(self, color=None, size=None, symbol=None, opacity=None):
self.color = color
self.size = size
self.symbol = symbol
self.opacity = opacity
def to_plotly(self):
return dict(color=self.color,
size=self.size,
symbol=self.symbol,
opacity=self.opacity)
from figure import Figure, MultiFigure
__all__ = ['Figure', 'MultiFigure']
\ No newline at end of file
from figure_2D import Figure2D
from figure_3D import Figure3D
from multi_figure import MultiFigure
from nifty.plotting.plots.private import _Plot2D, _Plot3D
from figure_internal import _2dFigure, _3dFigure, _MapFigure, _BaseFigure
from nifty.plotting.plots import HeatMap, MollweideHeatmap
from nifty.plotting.figures.util import validate_plots
from plotly.tools import make_subplots
class Figure(_BaseFigure):
def __init__(self, data, title=None, xaxis=None, yaxis=None, zaxis=None, width=None, height=None):
_BaseFigure.__init__(self, data, title, width, height)
kind, self.data = validate_plots(data)
if kind == _Plot2D:
if isinstance(self.data[0], HeatMap) and not width and not height:
x = len(self.data[0].data)
y = len(self.data[0].data[0])
if x > y:
width = 500
height = int(500*y/x)
else:
height = 500
width = int(500 * y / x)
if isinstance(self.data[0], MollweideHeatmap):
if not xaxis:
xaxis = False
if not yaxis:
yaxis = False
self.internal = _2dFigure(self.data, title, width, height, xaxis, yaxis)
elif kind == _Plot3D:
self.internal = _3dFigure(self.data, title, width, height, xaxis, yaxis, zaxis)
elif kind:
self.internal = _MapFigure(self.data, title)
def _to_plotly(self):
return self.internal._to_plotly()
class MultiFigure(_BaseFigure):
def __init__(self, rows, cols, title=None, width=None, height=None):
_BaseFigure.__init__(self, None, title, width, height)
self.cols = cols
self.rows = rows
self.subfigures = []
def get_subfigure(self, row, col):
for fig, r, c, _, _ in self.subfigures:
if r == row and c == col:
return fig
else:
return None
def add_subfigure(self, figure, row, col, row_span=1, col_span=1):
self.subfigures.append((figure, row, col, row_span, col_span))
def _to_plotly(self):
sub_titles = tuple([a[0].title for a in self.subfigures])
sub_specs = [[None]*self.cols for _ in range(self.rows)]
for fig, r, c, rs, cs in self.subfigures:
sub_specs[r][c] = dict(colspan=cs, rowspan=rs)
if isinstance(fig.internal, _3dFigure):
sub_specs[r][c]['is_3d'] = True
multi_figure_ply = make_subplots(self.rows,self.cols, subplot_titles=sub_titles, specs=sub_specs)
for fig, r, c, _, _ in self.subfigures:
for plot in fig.data:
multi_figure_ply.append_trace(plot._to_plotly(), r+1, c+1)
multi_figure_ply['layout'].update(height=self.height, width=self.width, title=self.title)
return multi_figure_ply
@staticmethod
def from_figures_2cols(figures, title=None, width=None, height=None):
multi_figure = MultiFigure((len(figures)+1)/2, 2, title, width, height)
for i in range(0, len(figures), 2):
multi_figure.add_subfigure(figures[i], i/2, 0)
for i in range(1, len(figures), 2):
multi_figure.add_subfigure(figures[i], i/2, 1)
return multi_figure
# -*- coding: utf-8 -*-
from figure_from_plot import FigureFromPlot
from nifty.plotting.plots import Heatmap, Mollweide
class Figure2D(FigureFromPlot):
def __init__(self, plots, title=None, width=None, height=None,
xaxis=None, yaxis=None):
# TODO: add sanitization of plots input
if isinstance(plots[0], Heatmap) and not width and not height:
(x, y) = self.plots[0].data.shape
if x > y:
width = 500
height = int(500*y/x)
else:
height = 500
width = int(500 * y / x)
if isinstance(self.plots[0], Mollweide):
if not xaxis:
xaxis = False
if not yaxis:
yaxis = False
super(Figure2D, self).__init__(plots, title, width, height)
self.xaxis = xaxis
self.yaxis = yaxis
def to_plotly(self):
plotly_object = super(Figure2D, self).to_plotly()
if self.xaxis or self.yaxis:
plotly_object['layout']['scene']['aspectratio'] = {}
if self.xaxis:
plotly_object['layout']['xaxis'] = self.xaxis.to_plotly()
elif not self.xaxis:
plotly_object['layout']['xaxis'] = dict(
autorange=True,
showgrid=False,
zeroline=False,
showline=False,
autotick=True,
ticks='',
showticklabels=False
)
if self.yaxis:
plotly_object['layout']['yaxis'] = self.yaxis._to_plotly()
elif not self.yaxis:
plotly_object['layout']['yaxis'] = dict(showline=False)
return plotly_object
# -*- coding: utf-8 -*-
from figure_from_plot import FigureFromPlot
class Figure3D(FigureFromPlot):
def __init__(self, plots, title=None, width=None, height=None,
xaxis=None, yaxis=None, zaxis=None):
super(Figure3D, self).__init__(plots, title, width, height)
self.xaxis = xaxis
self.yaxis = yaxis
self.zaxis = zaxis
def to_plotly(self):
plotly_object = super(Figure3D, self).to_plotly()
if self.xaxis or self.yaxis or self.zaxis:
plotly_object['layout']['scene']['aspectratio'] = dict()
if self.xaxis:
plotly_object['layout']['scene']['xaxis'] = self.xaxis.to_plotly()
elif not self.xaxis:
plotly_object['layout']['scene']['xaxis'] = dict(showline=False)
if self.yaxis:
plotly_object['layout']['scene']['yaxis'] = self.yaxis.to_plotly()
elif not self.yaxis:
plotly_object['layout']['scene']['yaxis'] = dict(showline=False)
if self.zaxis:
plotly_object['layout']['scene']['zaxis'] = self.zaxis.to_plotly()
elif not self.zaxis:
plotly_object['layout']['scene']['zaxis'] = dict(showline=False)
return plotly_object
# -*- coding: utf-8 -*-
from nifty.plotting.plotly_wrapper import PlotlyWrapper
class FigureBase(PlotlyWrapper):
def __init__(self, title, width, height):
self.title = title
self.width = width
self.height = height
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
from abc import abstractmethod
from figure_base import FigureBase
class FigureFromPlot(FigureBase):
def __init__(self, plots, title, width, height):
super(FigureFromPlot, self).__init__(title, width, height)
self.plots = plots
@abstractmethod
def to_plotly(self):
data = [plt.to_plotly() for plt in self.plots]
layout = {'title': self.title,
'scene': {'aspectmode': 'cube'},
'autosize': False,
'width': self.width,
'height': self.height,
}
plotly_object = {'data': data,
'layout': layout}
return plotly_object
from abc import ABCMeta, abstractmethod
from nifty.plotting.plotly_wrapper import _PlotlyWrapper
class _BaseFigure(_PlotlyWrapper):
__metaclass__ = ABCMeta
def __init__(self, data, title, width, height):
self.data = data
self.title = title
self.width = width
self.height = height
@abstractmethod
def _to_plotly(self):
ply_object = dict(
data=[plt._to_plotly() for plt in self.data],
layout=dict(
title=self.title,
scene = dict(
aspectmode='cube'
),
autosize=False,
width=self.width,
height=self.height,
)
)
return ply_object
class _2dFigure(_BaseFigure):
def __init__(self, data, title=None, width=None, height=None, xaxis=None, yaxis=None):
_BaseFigure.__init__(self, data, title, width, height)
self.xaxis = xaxis
self.yaxis = yaxis
def _to_plotly(self):
ply_object = _BaseFigure._to_plotly(self)
if self.xaxis or self.yaxis:
ply_object['layout']['scene']['aspectratio'] = dict()
if self.xaxis:
ply_object['layout']['xaxis'] = self.xaxis._to_plotly()
elif self.xaxis == False:
ply_object['layout']['xaxis'] = dict(
autorange=True,
showgrid=False,
zeroline=False,
showline=False,
autotick=True,
ticks='',
showticklabels=False
)
if self.yaxis:
ply_object['layout']['yaxis'] = self.yaxis._to_plotly()
elif self.yaxis == False:
ply_object['layout']['yaxis'] = dict(showline=False)
return ply_object
class _3dFigure(_2dFigure):
def __init__(self, data, title=None, width=None, height=None, xaxis=None, yaxis=None, zaxis=None):
_2dFigure.__init__(self, data, title, width, height, xaxis, yaxis)
self.zaxis = zaxis
def _to_plotly(self):
ply_object = _BaseFigure._to_plotly(self)
if self.xaxis or self.yaxis or self.zaxis:
ply_object['layout']['scene']['aspectratio'] = dict()
if self.xaxis:
ply_object['layout']['scene']['xaxis'] = self.xaxis._to_plotly()
elif self.xaxis == False:
ply_object['layout']['scene']['xaxis'] = dict(showline=False)
if self.yaxis:
ply_object['layout']['scene']['yaxis'] = self.yaxis._to_plotly()
elif self.yaxis == False:
ply_object['layout']['scene']['yaxis'] = dict(showline=False)
if self.zaxis:
ply_object['layout']['scene']['zaxis'] = self.zaxis._to_plotly()
elif self.zaxis == False:
ply_object['layout']['scene']['zaxis'] = dict(showline=False)
return ply_object
class _MapFigure(_BaseFigure):
def __init__(self, data, title, width=None, height=None):
_BaseFigure.__init__(self, data, title, width, height)
def _to_plotly(self):
ply_object = _BaseFigure._to_plotly(self)
# print(ply_object, ply_object['layout'])
# ply_object['layout']['geo'] = dict(
# projection=dict(type=self.data.projection),
# showcoastlines=False
# )
return ply_object
# -*- coding: utf-8 -*-
import numpy as np
from nifty import dependency_injector as gdi
from figure_base import FigureBase
from figure_3D import Figure3D
plotly = gdi.get('plotly')
class MultiFigure(FigureBase):
def __init__(self, rows, columns, subfigures=None,
title=None, width=None, height=None):
if 'plotly' not in gdi:
raise ImportError("The module plotly is needed but not available.")
super(MultiFigure, self).__init__(title, width, height)
self.subfigures = np.empty((rows, columns), dtype=np.object)
self.subfigures[:] = subfigures
@property
def rows(self):
return self.subfigures.shape[0]
@property
def columns(self):
return self.subfigures.shape[1]
def add_subfigure(self, figure, row, column):
self.subfigures[row, column] = figure
def to_plotly(self):
sub_titles = self.subfigures.copy()
sub_titles = sub_titles.flatten
title_extractor = lambda z: z.title
sub_titles = np.vectorize(title_extractor)(sub_titles)
sub_specs = self.subfigures.copy_empty()
specs_setter = \
lambda z: {'is_3d': True} if isinstance(z, Figure3D) else {}
sub_specs = np.vectorize(specs_setter)(sub_specs)
multi_figure_plotly_object = plotly.tools.make_subplots(
self.rows,
self.columns,
subplot_titles=sub_titles,
specs=sub_specs)
for index, fig in np.ndenumerate(self.subfigures):
for plot in fig.plots:
multi_figure_plotly_object.append_trace(plot.to_plotly(),
index[0]+1,
index[1]+1)
multi_figure_plotly_object['layout'].update(height=self.height,
width=self.width,
title=self.title)
return multi_figure_plotly_object
@staticmethod
def from_figures_2cols(figures, title=None, width=None, height=None):
multi_figure = MultiFigure((len(figures)+1)/2, 2, title, width, height)
for i in range(0, len(figures), 2):
multi_figure.add_subfigure(figures[i], i/2, 0)
for i in range(1, len(figures), 2):
multi_figure.add_subfigure(figures[i], i/2, 1)
return multi_figure
from nifty.plotting.plots.private import _Plot2D, _Plot3D
from nifty.plotting.plots import ScatterGeoMap
def validate_plots(data, except_empty=True):
if not data:
if except_empty:
raise Exception('Error: no plots given')
else:
return True
if type(data) != list:
data = [data]
if isinstance(data[0], _Plot2D):