Hi,
I’m trying to use Holoviews / hvplot / panel for a 1-off project I’m having to build for work. I’m finding myself so overwhelmed by the number of permutations between hvplot, Holoviews and panel in what I thought would be a fairly straight forward use case. I was hoping I could post a workable example here in the hopes of someone getting me started in the right direction…
Here’s what I’m trying to do…
-
My (very, very, small) user base primarily uses the ipython console in Spyder or VSCode when working with my python pacakge. We want to avoid jupyter notebooks. The ideal output would be, when the plotting function is called, is some kind of new popup window [like matplotlib does], otherwise a new microsoft edge [company specific thing] tab.
-
I’m looking to display time series data that can all be represented by pandas dataframes like the one I’ve created below. All x-axis are the same for all series.
-
I’d like the user to be able to select what time-series to view dynamically. Specifically, if you look at my multiindex columns:
* Level 1 : User selects ONE of these
* Level 2: User selects MANY (1+) of these, for a given Field 1
* Fields: User selects MANY (1+) of these.
- Lastly, I was hoping to create a toggle to first-difference the dataframe [ie,
df.diff(1)
]. I could also pre-populate this data in the dataframe [another index layer] if that simplified things. I was looking at the Operators documentation for this, but I couldn’t make heads or tails out of it…
I really appreciate any help! I think this is my 3rd or 4th time trying to integrate the holoviz library into packages I’ve built for work, but everytime I try I never seem to make much headway
import pandas as pd
import numpy as np
import holoviews as hv
import panel as pn
class DataViewer:
def __init__(self):
# Parameters
start_date = '2023-01-01'
end_date = '2023-04-10'
freq = 'D' # Daily frequency
# Create a date range
dates = pd.date_range(start=start_date, end=end_date, freq=freq)
num_dates = len(dates)
# Define the levels for the MultiIndex
level_1_and_2 = [
('total', 'total'),
('by_sensor_type', 'sensor_type1'),
('by_sensor_type', 'sensor_type2'),
('by_sensor_type', 'sensor_type3'),
('by_sensor', 'sensor_1'),
('by_sensor', 'sensor_2'),
('by_sensor', 'sensor_3')
]
fields = ['field_a', 'field_b', 'field_c']
# Create the MultiIndex
cols = pd.MultiIndex.from_tuples([(lvl1, lvl2, field) for lvl1, lvl2 in level_1_and_2 for field in fields],
names=['Level 1', 'Level 2', 'Fields'])
# Initialize a DataFrame
df = pd.DataFrame(index=dates, columns=cols)
# Generating random walks and random walks with drift
np.random.seed(0) # for reproducibility
for column in df.columns:
drift = 0.1 if 'sensor_type1' in column or 'sensor_1' in column else 0
random_walk = np.random.normal(loc=drift, scale=1, size=num_dates)
df[column] = random_walk.cumsum()
self.df = df
def to_awesome_plot(self) -> Union[a popout window that launches the chart, the chart object itself to stack ontop of another]
# see below, output the same
pass
def __add__(self, other):
return DataViewerContainer(self, other)
class DataViewerContainer:
def __init__(self, *args):
self.data_viewers = args
def to_awesome_plot(self):
plots = [x.to_awesome_plot() for x in self.data_viewers]
plotme = pn.Column(plots)
# Ideally plotme pops out in some standalone window! Not jupyter inline.
# If there is a way to do this without a running server thats preferred,
# but if not, thats ok.
#