import io import param import panel as pn import pandas as pd import random from datetime import datetime, timedelta import plotly.express as px pn.extension('plotly', 'tabulator', sizing_mode="stretch_width") class SampleDataApp(param.Parameterized): samples = param.Integer(default=40, bounds=(0,100), doc=""" Number of data samples to generate.""") voltage_bounds=param.Range(default=(0,100), bounds=(0,1000), doc=""" The bounds of the voltage values to generate.""") time_bounds=param.CalendarDateRange( default=(datetime(2020, 2, 1), datetime(2020, 2, 26)), bounds=(datetime(2020, 1, 1), datetime(2020, 3, 26)), doc="The bounds of the time values to generate.") fub_ids = param.ListSelector( default=["a1", "b1", "b2"], objects=["a1", "b1", "b2"], doc=""" The IDS to generate.""") sample_df = param.DataFrame(doc=""" The current dataframe of samples.""") generate_sample_df = param.Action(lambda self: self.update_sample_df(), label="Generate Data", doc=""" An action callback which will update the sample_df.""") file_name = param.String(default="data.csv", doc=""" The filename to save to.""") def __init__(self, **params): super().__init__(**params) self.update_sample_df() self.download = pn.widgets.FileDownload( name="Download Data", filename=self.file_name, callback=self._download_callback, button_type="primary" ) self.table = pn.widgets.Tabulator( self.sample_df.head(10), layout='fit_data_stretch', theme='site', height=360 ) @pn.depends('file_name', watch=True) def _update_filename(self): self.download.filename = self.file_name def _download_callback(self): """ A FileDownload callback will return a file-like object which can be serialized and sent to the client. """ self.download.filename = self.file_name sio = io.StringIO() self.sample_df.to_csv(sio, index=False) sio.seek(0) return sio def update_sample_df(self, event=None): start = self.time_bounds[0] end = self.time_bounds[1] days = (end-start).days sample_data = { "Time": [start+timedelta(days=random.uniform(0,days)) for _ in range(0,self.samples)], "Voltage": [random.uniform(*self.voltage_bounds) for _ in range(0,self.samples)], "FubId": [random.choice(self.fub_ids) for _ in range(0,self.samples)], } self.sample_df = pd.DataFrame(sample_data) @pn.depends("sample_df", watch=True) def _update_table(self): if hasattr(self, "table"): self.table.value = self.sample_df.head(10) def save_sample_data(self, event=None): if not self.sample_df is None: self.sample_df def view(self): return pn.Column( "## Generate and Download Data", pn.Row( pn.Param(self, parameters=['samples', 'voltage_bounds', 'time_bounds', 'generate_sample_df'], show_name=False, widgets={"generate_sample_df": {"button_type": "primary"}}), pn.Column(self.param.file_name, self.download, align='end', margin=(10,5,5,5)), ), "**Sample data (10 Rows)**", self.table, ) sample_data_app = SampleDataApp() sample_data_app_view = sample_data_app.view() sample_data_app_view class VoltageApp(param.Parameterized): data = param.DataFrame() file_input = param.Parameter() def __init__(self, **params): super().__init__(file_input=pn.widgets.FileInput(), **params) self.plotly_pane = pn.pane.Plotly(height=400, sizing_mode="stretch_width") @pn.depends("file_input.value", watch=True) def _parse_file_input(self): value = self.file_input.value if value: string_io = io.StringIO(value.decode("utf8")) self.data = pd.read_csv(string_io, parse_dates=["Time"]) else: print("error") @pn.depends('data', watch=True) def get_plot(self): df = self.data if df is None: return assert ("Voltage" in df.columns) and ("Time" in df.columns), "no columns voltage and time" df = (df.loc[df['Voltage'] != 'Invalid/Calib']).copy(deep=True) df['Voltage'] = df['Voltage'].astype(float) if "FubId" in df.columns: p = px.scatter(df, x="Time", y="Voltage", color="FubId") else: p = px.scatter(df, x="Time", y="Voltage") self.plotly_pane.object = p def view(self): return pn.Column( "## Upload and Plot Data", self.file_input, self.plotly_pane, ) voltage_app = VoltageApp() voltage_app_view = voltage_app.view() voltage_app_view description = """ This application demonstrates the ability to **download** a file using the `FileDownload` widget and **upload** a file using the `FileInput` widget.

Try filtering the data, download the file by clicking on the Download button and then plot it on the right by uploading that same file. """ component = pn.Column( description, sample_data_app_view, voltage_app_view, sizing_mode='stretch_both' ) component pn.template.FastListTemplate(site="Panel", title="Download and Upload CSV File", main=[ description, sample_data_app_view, voltage_app_view,]).servable();