def create_export_gui(self): self.export_path = pnw.TextInput(name="Export path", value="datasets", height=50) self.export_button = pnw.Button(name="Export", align="end", height=50) self.export_button.on_click(self.export_datasets) export_dataset_name = "" if len(self.created_datasets) == 0 else self.created_datasets[self.export_dataset_overview.selection[0]].name export_description_name = "" if len(self.created_datasets) == 0 else self.created_datasets[self.export_dataset_overview.selection[0]].description self.export_name_input = pnw.TextInput(name="Dataset name", value=export_dataset_name, height=50) self.export_name_input.param.watch(self.change_dataset_name, "value") self.export_description_input = pnw.TextAreaInput(name="Description", value=export_description_name, height=50) self.export_description_input.param.watch(self.change_dataset_description, "value") return pn.Column(pn.Row(self.export_name_input, self.export_description_input), pn.Row(self.export_path, self.export_button))
def __init__(self, defaultpath="./**/*.trk", match="", callback: CallBack = None): self.paths = pnw.TextInput(name="Path", value=defaultpath, width=600) self.match = pnw.TextInput(name="Match", value=match, width=200) self.selector = templateattribute(self, 1)(name="Track", width=850) self._cback = callback self.paths.param.watch(self._on_update, "value") self.match.param.watch(self._on_update, "value") self.selector.param.watch(self._on_newtracks, "value")
def build_gui(self): "Builds the basic gui for the gallery." self.btn_prev = pnw.Button(name="<", width=int(2 * self.width / 6)) self.btn_next = pnw.Button(name=">", width=int(2 * self.width / 6)) self.current = pnw.TextInput(value="1", width=int(self.width / 6)) self.image_count = pn.Row("/" + str(self.num_entries), width=int(self.width / 6)) self.gui_image_selection_controlls = pn.Row(self.btn_prev, self.current, self.image_count, self.btn_next, align="center", height=50) if self.sort_cols is not None: self.sorter = pnw.Select(name="Sort by", options=self.sort_cols) self.sorter.param.watch(self.update_sorting, "value") self.sort_order = pnw.CheckButtonGroup( name="Options", options=["Desc.", "Drop duplicates"]) self.sort_order.param.watch(self.update_sorting, "value") self.sort_gui = pn.Row(self.sorter, self.sort_order) if self.sort_cols is not None: self.gui_controlls = pn.Column(self.sort_gui, self.gui_image_selection_controlls) else: self.gui_controlls = self.gui_image_selection_controlls self.btn_prev.on_click(self._previous) self.btn_next.on_click(self._next) self.current.param.watch(self._number_input, "value") self._image = pn.Row( self.get_image_by_index(int(self.current.value) - 1), align="center") self.gui = pn.Column(self.gui_controlls, self.image)
def _plot(num_clusters, bins): nonlocal self predictions, cluster_centers, normalized_aspect_ratios = self._run_kmeans_clustering( num_clusters) self.aspect_ratios = cluster_centers fig, ax = plt.subplots(1, 1, figsize=(16, 9)) for pred_label, center in enumerate(cluster_centers): ax.hist(normalized_aspect_ratios[predictions == pred_label], bins=bins, range=(normalized_aspect_ratios.min(), normalized_aspect_ratios.max()), label=f"Center: {round(float(center), 2)}") ax.set_xlabel("Aspect ratios", fontsize=24) ax.tick_params(axis='both', labelsize=20) ax.legend(fontsize=25) plt.close() return pn.Column( pnw.TextInput( name="Aspect Ratios", value=f"{[round(float(i), 2) for i in cluster_centers]}", align="center", disabled=True, width=self.width, height=50), pn.pane.Matplotlib(fig, width=int((self.height - 150) * (16 / 9)), height=self.height - 150, align="center"))
def gallery( records, class_map: Optional[ClassMap] = None, display_label: bool = True, display_bbox: bool = True, display_mask: bool = True, display_keypoints: bool = True, ): """Shows a gallery for a list of records.""" # gui btn_prev = pnw.Button(name="<") btn_next = pnw.Button(name=">") current = pnw.TextInput(value="1") overall = pn.Row("/" + str(len(records))) gui = pn.Row(btn_prev, current, overall, btn_next, align="center") # plotting function @pn.depends(current.param.value) def _plot(_): nonlocal current try: index = int(current.value) - 1 except: pass img = draw_record_with_bokeh( record=records[index], class_map=class_map, display_label=display_label, display_bbox=display_bbox, display_mask=display_mask, display_keypoints=display_keypoints, return_figure=True, ) return img # add interactions def _next(_): nonlocal current nonlocal records try: index = int(current.value) if index == len(records): index = 1 else: index += 1 current.value = str(index) except: pass def _previous(_): nonlocal current nonlocal records try: index = int(current.value) if index == 1: index = len(records) else: index -= 1 current.value = str(index) except: pass btn_prev.on_click(_previous) btn_next.on_click(_next) return pn.Column(gui, pn.Row(_plot, align="center"))
class PlotManager(param.Parameterized): db_manager = DataBaseManager() endpoint = widgets.TextInput(name="Server endpoint", value="http://*****:*****@param.depends("datasource.value", "x_val.value", "y_val.value", "z_val.value", "color.value", "size.value", "endpoint.value", "extra.value") def _url(self): url = self._get_url() self.url_widget.value = url return pn.pane.Str("") @param.depends("button.clicks", watch=True) def _update_iframe(self): iframe = ( '<iframe width="800" height="600" scrolling="yes" frameBorder="0"' 'scrolling="no" src="{}"></iframe>').format(self.url_widget.value) self.display.object = iframe def _get_url(self): url = "%s?" % self.endpoint.value ds_str = "datasource=%s&" % self.datasource.value url += "" if self.datasource.value is None else ds_str url += "" if self.x_val.value is None else "x=%s" % self.x_val.value url += "" if self.y_val.value is None else "&y=%s" % self.y_val.value url += "" if self.z_val.value is None else "&z=%s" % self.z_val.value url += "" if self.color.value is None else "&color=%s" % self.color.value url += "" if self.size.value is None else "&size=%s" % self.size.value url += "" if self.extra.value is None else "&%s" % self.extra.value return url @param.depends("db_manager.connect_btn.clicks", watch=True) def populate_datasources(self): if self.db_manager.connected: datasources = [None] + list( sorted(self.db_manager.get_table_names())) self.datasource.options = datasources return pn.pane.Str() @param.depends("datasource.value", watch=True) def populate_widgets(self): if self.db_manager.connected: columns = list( sorted(self.db_manager.get_column_names( self.datasource.value))) self.x_val.options = [None] + columns self.y_val.options = [None] + columns self.z_val.options = [None] + columns self.color.options = [None] + columns self.size.options = [None] + columns return pn.pane.Str() @property def url(self): return self._get_url() def panel(self): controls = pn.Column( pn.Row(self.datasource, self.endpoint), pn.Row(self.x_val, self.y_val, self.z_val, self.db_manager.connect_btn), pn.Row(self.color, self.size, self.extra)) plot_dash = pn.Column( pn.pane.Markdown("# Plot manager"), controls, pn.Row(self.button, pn.pane.Markdown("**Target url**"), self.url_widget), self.display, self.populate_widgets, self.populate_datasources, self._url, self._update_iframe) return plot_dash return pn.Tabs(("Plot manager", plot_dash), ("DB connection", self.db_manager.panel()))
def __init__(self, plot, tabs): # pylint: disable=redefined-outer-name """Initialize form. :param plot: IsothermPlot instance for validation of results. :param tabs: Panel tabs instance for triggering tab switching. """ self.plot = plot self.tabs = tabs # isotherm metadata self.inp_doi = pw.TextInput(name='Article DOI', placeholder='10.1021/jacs.9b01891') self.inp_doi.param.watch(self.on_change_doi, 'value') self.inp_temperature = pw.TextInput(name='Temperature', placeholder='303') self.inp_adsorbent = pw.AutocompleteInput( name='Adsorbent Material', options=QUANTITIES['adsorbents']['names'], placeholder='Zeolite 5A', case_sensitive=False, **restrict_kwargs) self.inp_isotherm_type = pw.Select( name='Isotherm type', options=['Select'] + QUANTITIES['isotherm_type']['names']) self.inp_measurement_type = pw.Select( name='Measurement type', options=['Select'] + QUANTITIES['measurement_type']['names']) self.inp_pressure_scale = pw.Checkbox( name='Logarithmic pressure scale') self.inp_isotherm_data = pw.TextAreaInput( name='Isotherm Data', height=200, placeholder=config.SINGLE_COMPONENT_EXAMPLE) self.inp_figure_image = pw.FileInput(name='Figure snapshot') # units metadata self.inp_pressure_units = pw.Select( name='Pressure units', options=['Select'] + QUANTITIES['pressure_units']['names']) self.inp_pressure_units.param.watch(self.on_change_pressure_units, 'value') self.inp_saturation_pressure = pw.TextInput( name='Saturation pressure [bar]', disabled=True) self.inp_adsorption_units = pw.AutocompleteInput( name='Adsorption Units', options=QUANTITIES['adsorption_units']['names'], placeholder='mmol/g', case_sensitive=False, **restrict_kwargs) # digitizer info self.inp_source_type = pw.TextInput(name='Source description', placeholder='Figure 1a') self.inp_tabular = pw.Checkbox( name='Tabular Data (i.e., not digitized from a graphical source)') self.inp_digitizer = pw.TextInput(name='Digitized by', placeholder='Your full name') # fill form from JSON upload self.inp_json = pw.FileInput(name='Upload JSON Isotherm') # buttons self.btn_prefill = pn.widgets.Button( name='Prefill (default or from JSON)', button_type='primary') self.btn_prefill.on_click(self.on_click_prefill) self.out_info = bw.PreText( text='Press "Plot" in order to download json.') self.inp_adsorbates = Adsorbates(show_controls=False, ) self.btn_plot = pn.widgets.Button(name='Plot', button_type='primary') self.btn_plot.on_click(self.on_click_plot) for inp in self.required_inputs: inp.css_classes = ['required'] # create layout self.layout = pn.Column( pn.pane.HTML('<h2>Isotherm Digitizer</h2>'), self.inp_digitizer, self.inp_doi, pn.pane.HTML('<hr>'), self.inp_source_type, pn.Row(pn.pane.HTML("""Attach Figure Graphics"""), self.inp_figure_image), self.inp_measurement_type, self.inp_adsorbent, self.inp_adsorbates.column, self.inp_temperature, self.inp_isotherm_type, pn.Row(self.inp_pressure_units, self.inp_saturation_pressure), self.inp_pressure_scale, self.inp_adsorption_units, pn.pane.HTML("""We recommend the <b><a href='https://apps.automeris.io/wpd/' target="_blank">WebPlotDigitizer</a></b> for data extraction."""), self.inp_isotherm_data, self.inp_tabular, pn.Row(self.btn_plot, self.btn_prefill, self.inp_json), self.out_info, )
def bam_viewer(bam_file, ref_file, gff_file=None, width=1000, height=200, color='gray'): """Bam viewer widget. Args: bam_file: sorted bam file ref_file: reference sequence in fasta format gff_file: optional genomic features file """ slider = pnw.IntSlider(name='location',start=1,end=10000,value=500,step=500,width=300) main_pane = pn.pane.Bokeh(height=100) cov_pane = pn.pane.Bokeh(height=60) loc_pane = pn.pane.Str(50,width=250,style={'margin': '4pt'}) feat_pane = pn.pane.Bokeh(height=60) ref_pane = pn.pane.Bokeh(height=60) xzoom_slider = pnw.IntSlider(name='x zoom',start=50,end=8000,value=1000,step=10,width=100) yzoom_slider = pnw.IntSlider(name='y zoom',start=10,end=100,value=20,step=5,width=100)#,orientation='vertical') panleft_btn = pnw.Button(name='<',width=50,button_type='primary') panright_btn = pnw.Button(name='>',width=50,button_type='primary') chroms_select = pnw.Select(name='Chromosome', options=[], width=250) colorby = pnw.Select(name='Color by', options=['quality','pair orientation','read strand'], width=180) search_pane = pnw.TextInput(name='search',width=200) trans_option = pnw.Checkbox(name='show translation') debug_pane = pn.pane.Markdown() def pan_right(event): plot = main_pane.object plot.x_range start = slider.value loc = slider.value+100 slider.value=loc update(event) return def pan_left(event): loc = slider.value-100 if loc<1: return slider.value=loc update(event) return def update_features(): """Load features""" if gff_file is None: return ext = os.path.splitext(gff_file)[1] if ext in ['.gff','.gff3']: feats = utils.gff_to_features(gff_file) elif ext in ['.gb','.gbff']: feats = utils.genbank_to_features(gff_file) p = feat_pane.object = plotters.plot_features(feats, plot_width=width, plot_height=100) return p def search_features(event): """Find a feature""" term = search_pane.value feats = utils.gff_to_features(gff_file) df = utils.features_to_dataframe(feats) df['gene'] = df.gene.fillna('') f = df[df.gene.str.contains(term)].iloc[0] debug_pane.object = str(f.start) slider.value = int(f.start) update(event) return def update_ref(filename, start, end): """Update reference sequence""" if filename == None: return seqlen = utils.get_fasta_length(filename) slider.end = seqlen refseq = Fasta(filename) chroms = list(refseq.keys()) chroms_select.options = chroms key = chroms[0] seq = refseq[key][int(start):int(end)].seq ref_pane.object = plotters.plot_sequence(seq, plot_height=50,fontsize='9pt',xaxis=False) return def update(event): """Update viewers on widget change""" xzoom = xzoom_slider.value yzoom = yzoom_slider.value start = slider.value N = xzoom/2 end = start+N chrom = utils.get_chrom(bam_file) loc_pane.object = '%s:%s-%s' %(chrom,start,int(end)) cov = utils.get_coverage(bam_file,chrom,start,end) cov_pane.object = plotters.plot_coverage(cov,plot_width=width) main_pane.object = plotters.plot_bam_alignment(bam_file,chrom,start,end,height=yzoom,plot_width=width,plot_height=height) update_ref(ref_file, start, end) if feature_plot: feature_plot.x_range.start = start feature_plot.x_range.end = end debug_pane.object = '' return slider.param.watch(update, 'value') xzoom_slider.param.watch(update, 'value') yzoom_slider.param.watch(update, 'value') panright_btn.param.watch(pan_right, 'clicks') panleft_btn.param.watch(pan_left, 'clicks') search_pane.param.watch(search_features, 'value') feature_plot = update_features() #initialise slider slider.param.trigger('value') #menus = pn.Row(bam_input, ref_input, gff_input) top = pn.Row(slider,xzoom_slider,yzoom_slider,panleft_btn,panright_btn,loc_pane) bottom = pn.Row(chroms_select, search_pane,colorby,trans_option) app = pn.Column(top,cov_pane,main_pane,ref_pane,feat_pane,bottom,debug_pane) return app
def genome_features_viewer(gff_file, ref_file=None, plot_width=900): """Gene feature viewer app""" if gff_file is None: return features = utils.gff_to_features(gff_file) df = utils.features_to_dataframe(features) loc_pane = pnw.TextInput(name='location',value='',width=150) search_pane = pnw.TextInput(name='find_gene',value='',width=220) slider = pnw.IntSlider(name='start',start=0,end=10000,step=500,value=1,width=plot_width) xzoom_slider = pnw.IntSlider(name='zoom',start=1,end=500,value=100,step=5,width=100) chrom_select = pnw.Select(name='chrom',width=220) left_button = pnw.Button(name='<',width=40) right_button = pnw.Button(name='>',width=40) feature_pane = pn.pane.Bokeh(height=100,margin=10) seq_pane = pn.pane.Bokeh(height=50,margin=10) debug_pane = pn.pane.Str('debug',width=200,style={'background':'yellow','margin': '4pt'}) if ref_file is not None: seqlen = utils.get_fasta_length(ref_file) slider.end = seqlen else: slider.end = int(df.end.max()) def search_features(event): """Find a feature""" term = search_pane.value feats = utils.gff_to_features(gff_file) df = utils.features_to_dataframe(feats) df['gene'] = df.gene.fillna('') f = df[df.gene.str.contains(term)].iloc[0] #debug_pane.object = str(f.start) slider.value = int(f.start)-100 update(event) return def pan(event): p = feature_pane.object rng = p.x_range.end-p.x_range.start inc = int(rng/10) print (event.obj.name) if event.obj.name == '<': slider.value = int(slider.value) - inc else: slider.value = int(slider.value) + inc update(event) return def update(event): print (event.obj.name) if event.obj.name in ['start', 'zoom']: xzoom = xzoom_slider.value*200 start = int(slider.value) N = xzoom/2 end = int(start+N) loc_pane.value = str(start)+':'+str(end) elif event.obj.name == 'location': vals = loc_pane.value.split(':') start = int(vals[0]) end = int(vals[1]) slider.value = start #debug_pane.object=type(start) p = feature_pane.object p.x_range.start = start p.x_range.end = end if ref_file: sequence = utils.get_fasta_sequence(ref_file, start, end) seq_pane.object = plotters.plot_sequence(sequence, plot_width, plot_height=50,fontsize='9pt',xaxis=False) return slider.param.watch(update,'value',onlychanged=True) #slider.param.trigger('value') xzoom_slider.param.watch(update,'value') search_pane.param.watch(search_features,'value') loc_pane.param.watch(update,'value',onlychanged=True) left_button.param.watch(pan,'clicks') right_button.param.watch(pan,'clicks') #debug_pane.object = utils.get_fasta_names(ref_file)[0] if ref_file != None: chrom_select.options = utils.get_fasta_names(ref_file) #plot p = feature_pane.object = plotters.plot_features(features, 0, 10000, plot_width=plot_width, tools="", rows=4) #side = pn.Column(file_input,css_classes=['form'],width=200,margin=20) top = pn.Row(loc_pane,xzoom_slider,search_pane,chrom_select,left_button,right_button) main = pn.Column(feature_pane, seq_pane, sizing_mode='stretch_width') app = pn.Column(top,slider,main,debug_pane, sizing_mode='stretch_width',width_policy='max',margin=20) return app
def _update_widgets_panel(self): self._default_component[self.component_type] = self.component component = None controls = None if self.component is pn.pane.HoloViews: component = pn.pane.HoloViews(_create_hvplot()) if self.component is pn.pane.ECharts: # Issue https://github.com/holoviz/panel/issues/1817 component = pn.pane.ECharts(_create_echarts_plot(), min_height=400, min_width=200, sizing_mode="stretch_both") if self.component is pnw.Ace: py_code = inspect.getsource(_create_hvplot) component = pnw.Ace( value=py_code, sizing_mode="stretch_width", language="python", height=400, theme=self._ace_theme, ) elif self.component is pnw.AutocompleteInput: component = pnw.AutocompleteInput( name="Autocomplete Input", options=["Biology", "Chemistry", "Physics"], placeholder="Write something here", ) elif self.component is pnw.Button: component = pnw.Button(name="Click me", button_type="primary") elif self.component is pnw.CheckBoxGroup: component = pnw.CheckBoxGroup( name="Checkbox Group", value=["Apple", "Pear"], options=["Apple", "Banana", "Pear", "Strawberry"], inline=True, ) elif self.component is pnw.CheckButtonGroup: component = pnw.CheckButtonGroup( name="Check Button Group", value=["Apple", "Pear"], options=["Apple", "Banana", "Pear", "Strawberry"], button_type="success", ) elif self.component is pnw.Checkbox: component = pnw.Checkbox(name="Checkbox") elif self.component is pnw.ColorPicker: component = pnw.ColorPicker(name="Color Picker", value="#DF3874") elif self.component is pnw.CrossSelector: component = pnw.CrossSelector( name="Fruits", value=["Apple", "Pear"], options=["Apple", "Banana", "Pear", "Strawberry"], height=300, ) elif self.component is pnw.DataFrame: component = self.component(name="Hello") component.value = get_dataframe() component.formatters = get_default_formatters(component.value) controls = pn.Spacer() elif self.component is pnw.DatePicker: component = pnw.DatePicker(name="Date Picker") # Issue: https://github.com/holoviz/panel/issues/1810 # component.start = date(2020, 1, 20) # component.end = date(2020, 2, 20) # component.value = date(2020, 2, 18) elif self.component is pnw.DateRangeSlider: component = self.component(name="Hello") component.start = date(2020, 1, 20) component.end = date(2020, 2, 20) component.value = (date(2020, 2, 18), date(2020, 2, 20)) elif self.component is pnw.DateSlider: component = self.component(name="Hello") component.start = date(2020, 1, 20) component.end = date(2020, 2, 20) component.value = date(2020, 2, 18) elif self.component is pnw.DatetimeInput: component = self.component(name="Hello") component.value = datetime(2020, 2, 18, 1, 2, 3) elif self.component is pnw.DatetimeRangeInput: component = self.component( name="Hello", start=datetime(2020, 1, 20), end=datetime(2020, 2, 20), value=(datetime(2020, 2, 18), datetime(2020, 2, 20)), ) elif self.component is pnw.DiscretePlayer: component = pnw.DiscretePlayer( name="Discrete Player", options=[2, 4, 8, 16, 32, 64, 128], value=32, loop_policy="loop", ) elif self.component is pnw.DiscreteSlider: component = pnw.DiscreteSlider(name="Discrete Slider", options=[2, 4, 8, 16, 32, 64, 128], value=32) elif self.component is pnw.FileDownload: component = pnw.FileDownload(file="README.md", filename="README.md") elif self.component is pnw.FileInput: component = pnw.FileInput(accept=".csv,.json") elif self.component is pnw.FileSelector: component = pnw.FileSelector(name="Hello", max_height=400) elif self.component is pnw.FloatInput: component = pnw.FloatInput(name="FloatInput", value=5.0, step=1e-1, start=0, end=1000) elif self.component is pnw.FloatSlider: component = pnw.FloatSlider(name="Float Slider", start=0, end=3.141, step=0.01, value=1.57) elif self.component is pnw.IntInput: component = pnw.IntInput(name="IntInput", value=5, step=2, start=0, end=1000) elif self.component is pnw.IntRangeSlider: component = pnw.IntRangeSlider(name="Integer Range Slider", start=0, end=100, value=(8, 40), step=2) elif self.component is pnw.IntSlider: component = pnw.IntSlider(name="Integer Slider", start=0, end=20, step=2, value=4) elif self.component is pnw.LiteralInput: component = pnw.LiteralInput(name="Literal Input (dict)", value={"key": [1, 2, 3]}, type=dict) elif self.component is pnw.MenuButton: menu_items = [ ("Option A", "a"), ("Option B", "b"), ("Option C", "c"), None, ("Help", "help"), ] component = pnw.MenuButton(name="Dropdown", items=menu_items, button_type="primary") elif self.component is pnw.MultiChoice: component = pnw.MultiChoice( name="MultiSelect", value=["Apple", "Pear"], options=["Apple", "Banana", "Pear", "Strawberry"], ) elif self.component is pnw.MultiSelect: component = pnw.MultiSelect( name="MultiSelect", value=["Apple", "Pear"], options=["Apple", "Banana", "Pear", "Strawberry"], size=8, ) elif self.component is pnw.PasswordInput: component = pnw.PasswordInput(name="Password Input", placeholder="Enter a string here...") elif self.component is pnw.Player: component = pnw.Player(name="Player", start=0, end=100, value=32, loop_policy="loop") elif self.component is pnw.Progress: component = pnw.Progress(name="Progress", value=20, width=200) elif self.component is pnw.RadioBoxGroup: component = pnw.RadioBoxGroup( name="RadioBoxGroup", options=["Biology", "Chemistry", "Physics"], inline=True) elif self.component is pnw.RadioButtonGroup: component = pnw.RadioButtonGroup( name="Radio Button Group", options=["Biology", "Chemistry", "Physics"], button_type="success", ) elif self.component is pnw.RangeSlider: component = pnw.RangeSlider( name="Range Slider", start=0, end=math.pi, value=(math.pi / 4.0, math.pi / 2.0), step=0.01, ) elif self.component is pnw.Select: component = pnw.Select(name="Select", options=["Biology", "Chemistry", "Physics"]) elif self.component is pnw.StaticText: component = pnw.StaticText(name="Static Text", value="A string") elif self.component is pnw.TextAreaInput: component = pnw.input.TextAreaInput( name="Text Area Input", placeholder="Enter a string here...") elif self.component is pnw.TextInput: component = pnw.TextInput(name="Text Input", placeholder="Enter a string here...") elif self.component == pnw.Toggle: component = pnw.Toggle(name="Toggle", button_type="success") elif self.component == pnw.VideoStream: component = pnw.VideoStream(name="Video Stream", sizing_mode="stretch_width", height=300) if not component: component = self.component(name="Hello") if not controls: controls = component.controls() controls.margin = 0 self._component_panel[:] = [ pn.pane.Markdown("## " + component.__class__.name + " " + self.component_type), component, pn.layout.Divider(), pn.pane.Markdown("## Parameters"), controls, ]
class DataBaseManager(param.Parameterized): file_input = widgets.FileInput(name="Parquet file") dbtype = widgets.TextInput(name="Database type", value="postgresql", width=WIDGET_WIDTH) user = widgets.TextInput(name="Username", value="superset", width=WIDGET_WIDTH) password = widgets.TextInput(name="Password", value="superset", width=WIDGET_WIDTH) host = widgets.TextInput(name="Host", value="localhost", width=WIDGET_WIDTH) endpoint = widgets.TextInput(name="Host", value="superset", width=WIDGET_WIDTH) port = widgets.LiteralInput(name="Port", value=5432, width=WIDGET_WIDTH) data_source = widgets.TextInput(name="Table Name", width=WIDGET_WIDTH) connect_btn = widgets.Button(name="Connect to DB", width=WIDGET_WIDTH) datasource_btn = widgets.Button(name="Query table", width=WIDGET_WIDTH) def __init__(self): super().__init__() self.df = None self.datasource = None self.engine = None self._connected = False @property def connected(self) -> bool: return self._connected @param.depends("dbtype.value", "user.value", "password.value", "host.value", "port.value", "endpoint.value") def _url(self): return panel.pane.Str(self._get_url()) def _get_url(self): url = "{}://{}:{}@{}:{}/{}".format( self.dbtype.value, self.user.value, self.password.value, self.host.value, self.port.value, self.endpoint.value, ) return url def get_table_names(self): if self.engine is None: return names = pd.read_sql("SELECT tablename FROM pg_catalog.pg_tables;", self.engine) return names.values.flatten().tolist() def get_column_names(self, table): sql = "SELECT column_name FROM information_schema.COLUMNS WHERE TABLE_NAME = '%s';" % table return pd.read_sql(sql, self.engine).values.flatten().tolist() @property def url(self): return self._get_url() @param.depends("connect_btn.clicks", watch=True) def connect_to_db(self): msg = panel.Column(panel.pane.Str("Connected to"), self._url) if self.connect_btn.clicks == 0: return panel.Column(panel.pane.Str("Ready to connect to"), self._url) if self._connected: return msg try: engine = create_engine(self.url) self.engine = engine self._connected = True return msg except Exception as e: self._connected = False return panel.Column(panel.pane.Str("Error connecting to"), self._url) def panel(self): db_widgets = panel.Row( panel.Column(self.dbtype, self.host, self.port), panel.Column(self.user, self.password, self.endpoint), panel.Column(self.connect_to_db, self.connect_btn), ) return panel.Column( panel.pane.Markdown("## Connect to superset database"), db_widgets)
class WriteParquet(param.Parameterized): write_btn = widgets.Button(name="Write to DB", width=WIDGET_WIDTH) read_btn = widgets.Button(name="Read DB table", width=WIDGET_WIDTH) parquet_file = widgets.FileInput(name="Parquet file", width=WIDGET_WIDTH) table = widgets.TextInput(name="New table name", width=200) table_names = widgets.Select(name="DB tables", width=200) def __init__(self, engine, *args, **kwargs): super(WriteParquet, self).__init__(*args, **kwargs) self.engine = engine self.df = None self.db_df = None @param.depends("parquet_file.value", watch=True) def load_parquet(self): f = io.BytesIO() f.write(self.parquet_file.value) f.seek(0) self.df = pd.read_parquet(f) @param.depends("read_btn.clicks", watch=True) def get_datasource(self): if self.table.value != "": sql = "SELECT * \nFROM {}\nLIMIT 10000".format(self.table.value) self.df = self.sql(sql) table = self.table.value if self.table.value != "" else "None" return panel.pane.Str("Selected Table {}".format(table)) def sql(self, sql): df = pd.read_sql(sql, self.engine) return df def get_table_names(self): if self.engine is None: return names = pd.read_sql("SELECT tablename FROM pg_catalog.pg_tables;", self.engine) self.table_names.options = list(sorted( names.values.flatten().tolist())) @param.depends("write_btn.clicks", watch=True) def write_parquet(self): if self.write_btn.clicks > 0: try: self.load_parquet() self.df.to_sql(self.table.value, self.engine) return panel.pane.Str("Success") except Exception as e: return panel.pane.Str(str(e)) return panel.pane.Str("") @param.depends("read_btn.clicks", watch=True) def read_table(self): if self.read_btn.clicks > 0: sql = "SELECT * \nFROM {}\nLIMIT 10000".format( self.table_names.value) self.db_df = self.sql(sql) return panel.pane.HTML(self.db_df.head().to_html()) return panel.pane.Str() def panel(self): return panel.Row( panel.Column( panel.Row(self.table_names), panel.Row(panel.pane.Markdown("Parquet file"), self.parquet_file), panel.Row(self.table), panel.Row(self.read_btn, self.write_btn), ), panel.Column(self.read_table, self.write_parquet), )