Skip to content

Commit

Permalink
Added hvPlotters.curvePlot()
Browse files Browse the repository at this point in the history
and updated env handling.
  • Loading branch information
phockett committed Jan 13, 2022
1 parent 25c714d commit 6030520
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 6 deletions.
4 changes: 3 additions & 1 deletion epsproc/basicPlotters.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@
raise
print('* Seaborn not found, clustermap plots not available. ')


# Env check
from epsproc.util.env import isnotebook
__notebook__ = isnotebook()

# Arrow3D class from https://stackoverflow.com/questions/22867620/putting-arrowheads-on-vectors-in-matplotlibs-3d-plot
# Code: https://stackoverflow.com/a/22867877
Expand Down
72 changes: 69 additions & 3 deletions epsproc/plot/hvPlotters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
Aim: simple plotters for different datatypes, interactive in Jupyter Notebook + HTML formats.
13/01/21 Added
- env check
- setPlotDefaults() (from tmo-dev/PEMtk codes)
- curvePlot() for general multi-dim Holomap curve plots.
15/07/20 Debugged, still pretty basic but running.
05/07/20 v1 in development.
Expand Down Expand Up @@ -55,8 +59,15 @@
except:
print('* Hvplot not found, some hvPlotters may not be available. See https://hvplot.holoviz.org/user_guide/Gridded_Data.html for package details.')

# Env check
from epsproc.util.env import isnotebook
__notebook__ = isnotebook()

from .util import showPlot


# Set plotters & options.
def setPlotters(hvBackend = 'bokeh', width = 500, snsStyle = "darkgrid"):
def setPlotters(hvBackend = 'bokeh', width = 500, height = None, snsStyle = "darkgrid"):
"""
Set some plot options - Seaborn style + HV defaults.
Expand Down Expand Up @@ -112,6 +123,7 @@ def setPlotters(hvBackend = 'bokeh', width = 500, snsStyle = "darkgrid"):
# Set HV extension
try:
hv.extension(hvBackend)
print(f"* Set Holoviews with {hvBackend}.")

except ImportError as e:
if e.msg != "None of the backends could be imported":
Expand All @@ -121,15 +133,30 @@ def setPlotters(hvBackend = 'bokeh', width = 500, snsStyle = "darkgrid"):
print("Possible bokeh version issue, see https://github.com/holoviz/holoviews/issues/2012. (For Holoviews 1.12.5, Bokeh 1.4.0 works, Bokeh 2.0.0 doesn't.)")



# Set global HV options
# Setting frame_width here results in offset plots in layout - try setting later?
# opts.defaults(opts.Curve(frame_width=500, tools=['hover'], show_grid=True, padding=0.01))
opts.defaults(opts.Curve(width=width, tools=['hover'], show_grid=True, padding=0.01))
# opts.defaults(opts.Curve(width=width, tools=['hover'], show_grid=True, padding=0.01))
if height is None:
height = width

setPlotDefaults(fSize = [width, height], imgSize = height)

# return hv.output.info()


# Set some default plot options
def setPlotDefaults(fSize = [800,400], imgSize = 500):
"""Basic plot defaults"""

if hvFlag:
opts.defaults(opts.Scatter(width=fSize[0], height=fSize[1], tools=['hover'], show_grid=True),
opts.Curve(width=fSize[0], height=fSize[1], tools=['hover'], show_grid=True),
opts.Image(width=imgSize, frame_width=imgSize, aspect='square', tools=['hover'], colorbar=True), # Force square format for images (suitable for VMI)
opts.HeatMap(width=imgSize, frame_width=imgSize, aspect='square', tools=['hover'], colorbar=True),
opts.HexTiles(width=fSize[0], height=fSize[1], tools=['hover'], colorbar=True))


# Convert "standard" XS dataarray to dataset format.
def hvdsConv(dataXS):
"""
Expand All @@ -145,6 +172,45 @@ def hvdsConv(dataXS):
return hv_ds, ds


def curvePlot(dataXR, kdims = None, returnPlot = True, renderPlot = True, **kwargs):
"""
Basic routine for curve/Holomap plot from Xarray dataset.
Currently assumes all plot type selection & cleaning done in calling function.
11/01/22: basic version from recent OCS work plus TMO-dev & PEMtk codes.
"""

# Convert to HV dataset
hvds = hv.Dataset(dataXR)

# TODO: set default kdims if not passed? & dim checks.

# Curves
hvPlot = hvds.to(hv.Curve, kdims = kdims)

# TODO: wrap this
# # Code from showPlot()
# if self.__notebook__ and (not returnMap):
# if overlay is None:
# display(hmap) # If notebook, use display to push plot.
# else:
# display(hmap.overlay(overlay))
#
# # Is this necessary as an option?
# if returnMap:
# return hmap # Otherwise return hv object.

# Use showPlot() to control render & return, or just return object - might be overkill?
if renderPlot:
return showPlot(hvPlot, returnPlot = returnPlot, __notebook__ = __notebook__) # Currently need to pass __notebook__?

else:
return hvPlot



# HV plotting routine for XS data
def XCplot(dataXS, lineDashList = {'L': 'dashed', 'M': 'solid', 'V': 'dashed'}, kdims = "Eke", tString = None):
"""
Expand Down
33 changes: 33 additions & 0 deletions epsproc/plot/util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""
ePSproc additional plotting utility functions
13/01/22
"""

# Show plot from tmo-dev - assumes dict based data structure
# def showPlot(self, dim, run, pType='curve'):
# """Render (show) specified plot from pre-set plot dictionaries (very basic!)."""
#
# try:
# if self.__notebook__:
# display(self.data[run][pType][dim]) # If notebook, use display to push plot.
# else:
# return self.data[run][pType][dim] # Otherwise return hv object.
#
# except:
# print(f'Plot [{run}][{pType}][{dim}] not set.')

# Basic show plot routine
def showPlot(plotObj, returnPlot = False, __notebook__ = False):
"""Render (show) specified plot if notebook (very basic!)."""

# try:
if __notebook__:
display(plotObj) # If notebook, use display to push plot.

if returnPlot or not __notebook__:
return plotObj # Return hv object.

# except:
# print(f'Plot [{run}][{pType}][{dim}] not set.')
11 changes: 9 additions & 2 deletions epsproc/util/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@

# THIS works, IPython v7.1.3, Jupyter notebook 6.0.3
# COULD also use Scooby here, see https://pypi.org/project/scooby/
def isnotebook(warn = 'once'):
def isnotebook(): # (warn = 'once'):
"""
Check if code is running in Jupyter Notebook.
Expand All @@ -39,7 +39,7 @@ def isnotebook(warn = 'once'):
shell = get_ipython().__class__.__name__

if shell == 'ZMQInteractiveShell':
warnings.filterwarnings(warn)
# warnings.filterwarnings(warn) # Better to use a separate function here to avoid confusion
return True # Jupyter notebook or qtconsole

elif shell == 'TerminalInteractiveShell':
Expand All @@ -50,3 +50,10 @@ def isnotebook(warn = 'once'):

except NameError:
return False # Probably standard Python interpreter


def setWarnings(warn = 'once'):
"""Control warnings output."""

warnings.filterwarnings(warn) # set 'once' or 'ignore'
warnings.simplefilter(warn)

0 comments on commit 6030520

Please sign in to comment.