How can I create figures with more Curves than there are colors in the Sets1to3 color set?
The example below creates a generic data set based on the args of the create_generic_data()
function. Below you can see args of (3, 22, 10)
will create 3 figures with 22 Curves each, with 10 points per curve. It works fine because the 22 curves don’t exceed the 22 colors available in ds.colors.Sets1to3. If you change 22 to any higher value, an error is raised.
I’ve tried using inferno
instead of Sets1to3
, but I get same error. I’ve tried using Sets1to3*10 to extend the color list, but same error still.
I imagine my options would be different if I wasn’t planning on plotting much more data, such as 100’s of Curves per plot, and using datashader
. A reasonable approximation of my big-picture task would be to create a dataset using create_generic_data(10, 300, 100000)
.
Any suggestions?
import pickle
import holoviews as hv
import panel as pn
from holoviews.operation.datashader import datashade, rasterize, dynspread
import datashader as ds
import ipdb
hv.extension('bokeh')
class MultiPlot:
"""tbd description
Inputs?
- data: can be dictionary with two levels of keys. One plot is created for each first-level key, then subseq.
keys are plotted within each plot.
"""
def __init__(self, data, max_plots=6, plot_width=800, plot_height=150, cnorm="eq_hist", line_width=2,
pixel_ratio=2):
# Create a dictionary of all Curves. Top-level keys define number of subplots. Secondary-level keys point to
# each parameter to be plotted in each subplot. Time indices are aligned to start time.
curves_dict = {top_key: {sec_key: hv.Curve((sec_value.index.map(lambda x: (x-x[0]).total_seconds()),
sec_value.values), kdims=['Time'], vdims=['Value'])
for sec_key, sec_value in top_value.items()
}
for top_key, top_value in data.items()}
# Create color key for all second-level keys in data dictionary, and color_points as invisible element to drive
# legend
sec_keys = sorted(set([sec_key for primary_key, primary_value in data.items()
for sec_key in primary_value.keys()]))
color_key = zip(sec_keys, ds.colors.Sets1to3)
color_points = hv.NdOverlay({k: hv.Points([(0,0)], label=str(k)).opts(color=v, size=0) for k, v in color_key})
# Create list of overlay objects; one per top-level key, with each containing one Curve per secondary-key
self.overlay = [(datashade(hv.NdOverlay(curves, kdims='k'), line_width=line_width, pixel_ratio=pixel_ratio,
cnorm=cnorm, aggregator=ds.by('k', ds.count())
)*color_points).opts(width=plot_width, tools=['hover']).relabel(top_key)
for top_key, curves in curves_dict.items()]
# Create Layout to plot each Overlay figure in a single column
self.layout = hv.Layout(self.overlay).cols(1)
def show(self):
pn.serve(self.layout)
def create_generic_data(level1_parm_count, level2_parm_count, parm_sample_count):
"""Generates generic data dictionary"""
import pandas as pd
l1_parms = [f'L1P_{str(i)}' for i in range(level1_parm_count)]
l2_parms = [f'L2P_{str(i)}' for i in range(level2_parm_count)]
return {l1p: {l2p: pd.Series([j**int(l2p[-1]) for j in range(parm_sample_count)],
index = pd.to_timedelta(range(parm_sample_count), unit='s'))
for l2p in l2_parms} for l1p in l1_parms}
if __name__ == '__main__':
# # Pull data from file
# with open('data_cache.pkl', 'rb') as data_cache:
# data = pickle.load(data_cache)
# Optional creation of generic data set for troubleshooting. Args are (# of top keys, # of sec. keys, and # of
# points per Curve
data = create_generic_data(3, 22, 10)
myplot = MultiPlot(data)
myplot.show()