def update_2(attr, old, new): print(old) print(new) input_field = format_df.loc[format_df['verbage'] == new, 'field'].iloc[0] p = make_plot() p2 = make_plot_criteria(input_field) p = column(p,WidgetBox(year_select)) p2 = column(p2,WidgetBox(select)) layout = row(p,p2) curdoc().clear() curdoc().add_root(layout)
def update(attr, old, new): new_src = make_dataset(yr = int(new)) geo_src.geojson = new_src p = make_plot() p2 = make_plot_criteria(input_field) p = column(p,WidgetBox(year_select)) p2 = column(p2,WidgetBox(select)) layout = row(p,p2) curdoc().clear() curdoc().add_root(layout)
def init_solar_wx(self): sun_luminos_slider = Slider( start=0.1, end=10, step=0.1, value=self.rel_solar_lum, title='Relative Solar Luminosity (Solar Units)') earth_radius_slider = Slider(start=0.1, end=10, step=0.1, value=self.dist_from_sun_au, title='Distance from Sun (AU)') def _lum_handler(attr, old, new): self.rel_solar_lum = new self.update_solar_in() self.update_input_rays() self._update_atm_refl() def _radius_handler(attr, old, new): self.dist_from_sun_au = new self.update_solar_in() self.update_input_rays() self._update_atm_refl() sun_luminos_slider.on_change('value', _lum_handler) earth_radius_slider.on_change('value', _radius_handler) solar_sliders = WidgetBox(sun_luminos_slider, earth_radius_slider) return [solar_sliders]
def pad_plots(plots, padding=0.85): """ Accepts a grid of bokeh plots in form of a list of lists and wraps any DataTable or Tabs in a WidgetBox with appropriate padding. Required to avoid overlap in gridplot. """ widths = [] for row in plots: row_widths = [] for p in row: if isinstance(p, Tabs): width = np.max([ p.width if isinstance(p, DataTable) else t.child.plot_width for t in p.tabs ]) for p in p.tabs: p.width = int(padding * width) elif isinstance(p, DataTable): width = p.width p.width = int(padding * width) elif p: width = p.plot_width else: width = 0 row_widths.append(width) widths.append(row_widths) plots = [[ WidgetBox(p, width=w) if isinstance(p, (DataTable, Tabs)) else p for p, w in zip(row, ws) ] for row, ws in zip(plots, widths)] total_width = np.max([np.sum(row) for row in widths]) return plots, total_width
def _initialize_tab(self): """Create tab structure This internal function initializes the dataset, the widgets, the plot and the tab. The widgets for the segment and metric selections are created and initialized. The same is done with the filters and the variables to filter. Then, based on the initial selections, the data source is created and the plot is initialized. Subsequently, the layout is created and the tab is set as self.tab. """ # set widgets self.segment_select = Select(title="Segments", value=self.segments[0], options=self.segments) self.segment_select.on_change("value", self.update) self.metric_select = Select(title="Metrics", value=self.metrics[0], options=self.metrics) self.metric_select.on_change("value", self.update) # set filters self.segment_filters = {} for segment in self.segments: available_segments = list(set(self.data[segment])) self.segment_filters[segment] = CheckboxGroup(labels=available_segments, active=list( range(len(available_segments)))) self.segment_filters[segment].on_change("active", self.update) # initialize filters initial_segment = self.segment_select.value initial_metric = self.metric_select.value initial_filters = {} for segment in self.segments: initial_filters[segment] = [ self.segment_filters[segment].labels[i] for i in self.segment_filters[segment].active ] self.source = self.make_dataset(initial_segment, initial_metric, initial_filters) self.bokeh_plot = self.make_plot(self.source) self.bokeh_plot = self.style(self.bokeh_plot) self.controls = WidgetBox(self.segment_select, self.metric_select) self.filters = WidgetBox( *list(self.segment_filters[segment] for segment in self.segment_filters)) self.layout = row(self.controls, self.bokeh_plot, self.filters) return Panel(child=self.layout, title="Segment metrics")
def update(attr, old, new): new_src = make_dataset(int(new)) geo_src.geojson = new_src p = make_plot() controls = WidgetBox(year_select) layout = row(p, controls) curdoc().clear() curdoc().add_root(layout)
def init_slider_wx(self): t_eff_slider = Slider(start=1000, end=40000, step=100, value=6000, title='Star Effective Temperature (K)') luminosity_slider = Slider(start=-5, end=5, step=0.1, value=0, title='Relative Luminosity (10^x, solar units)') planet_radius_slider = Slider(start=0.1, end=4, step=0.1, value=1, title='Relative Planet Radius (earth radii)') planet_distance_slider = Slider(start=-1, end=3, step=0.1, value=0, title='Relative Planet Distance (10^x, AU)') t_eff_slider.on_change('value', self._t_eff_handler) luminosity_slider.on_change('value', self._luminosity_handler) planet_radius_slider.on_change('value', self._planet_radius_handler) planet_distance_slider.on_change('value', self._planet_dist_handler) star_wx = WidgetBox(t_eff_slider, luminosity_slider) planet_wx = WidgetBox(planet_radius_slider, planet_distance_slider) return [star_wx, planet_wx]
def init_electmap_with_controls(): print('init_electmap_with_controls()') merged_cnt_data = init_data() year_select = Slider(start=2000, end=2020, step=4, value=2000, title='Election Year') start = time.time() geo_src = GeoJSONDataSource( geojson=make_dataset(merged_cnt_data, year_select.value, True)) end = time.time() print("geo_src time={}".format(str(end - start))) start = time.time() curr_geo_src = GeoJSONDataSource( geojson=make_dataset(merged_cnt_data, 2000, False)) end = time.time() print("curr_geo_src time={}".format(str(end - start))) #slider = Slider(start=0.1, end=4, value=1, step=.1, title="power") callback = CustomJS(args=dict(source=geo_src, currsource=curr_geo_src), code=""" var c_data = source.data; var yr = cb_obj.value; for(var key in source.data){ currsource.data[key] = []; } for (var i = 0; i <= source.data['YEAR'].length; i++){ if (source.data['YEAR'][i] == yr){ for(var key in source.data){ currsource.data[key].push(source.data[key][i]); } } } currsource.change.emit(); """) year_select.js_on_change('value', callback) p = make_plot(curr_geo_src) controls = WidgetBox(year_select) layout = row(p, controls) return layout
def update(attr, old, new): new_src = make_dataset(yr = int(new)) geo_src.geojson = new_src #new_src_state = make_dataset_county(int(new),state_fips) #geo_src_county.geojson = new_src_state p = make_plot() #p2 = make_plot_county() p = column(p,WidgetBox(year_select)) layout = row(p) curdoc().clear() curdoc().add_root(layout)
def _get_layout(self): list_p = self._get_plot_list() selects = self._get_multiselects() select_ds = self._get_series_multiselect() ncols = len(self.slct_list_dict[self.ind_pltx]) if self.ind_pltx else 1 p_leg = self._get_legend() controls = WidgetBox(*selects) layout = column(select_ds, row(controls, p_leg ), gridplot(list_p, ncols=ncols)) return layout
def convert_pd_bokeh_html(df): # Put the metrics table in the html using bokeh df_data=dict(df[[i for i in df.columns]].round(4) ) df_data['Metric']=df.index # This will add the index (Note: Instead of Metric, if I use index, then the width of output index column cannot be adjustested ) source=ColumnDataSource(df_data) columns=[TableColumn(field=i,title=i) for i in df.columns] # Insert the index column to the list of columns columns.insert(0, TableColumn(field="Metric",title="Metric")) df_table=DataTable(source=source,columns=columns, height=200, width=450) table_script,table_div= components(WidgetBox(df_table)) return table_script,table_div
def create_data_preview_tab(exp_data): t = TableGenerator(exp_data) species = '白頭翁' species_select = t.species_select(species) df = t.fetch_data(species) table = t.make_table(df) btn = t.download_data_btn(df) controls = WidgetBox(species_select, btn) layout = column(row(controls, table)) tab = Panel(child=layout, title='Data Preview') return tab
def modify_doc(doc): status_selection = CheckboxGroup( labels=['viewed', 'explored', 'certified'], active=[0, 1]) status_selection.on_change('active', update) initial_status = [ status_selection.labels[i] for i in status_selection.active ] src = make_dataset(edX, initial_status) p = make_plot(src) controls = WidgetBox(status_selection) layout = row(controls, p) tab = Panel(child=layout, title='Events Histogram') tabs = Tabs(tabs=[tab]) doc.add_root(tabs)
def generic_tab(db, mode): cur = db.cursor() cur.execute("SELECT name FROM sqlite_master WHERE type='table' AND name=?", [mode]) if len(cur.fetchall()) == 0: return None cur.execute('select * from "' + mode + '"') text = "" for r in cur: l = r[0] text += l content = PreText(text=text) layout = WidgetBox(content, sizing_mode="scale_both") tab = Panel(child=layout, title=mode) return tab
def pad_plots(plots): """ Accepts a grid of bokeh plots in form of a list of lists and wraps any DataTable or Tabs in a WidgetBox with appropriate padding. Required to avoid overlap in gridplot. """ widths = [] for row in plots: row_widths = [] for p in row: width = pad_width(p) row_widths.append(width) widths.append(row_widths) plots = [[WidgetBox(p, width=w) if isinstance(p, (DataTable, Tabs)) else p for p, w in zip(row, ws)] for row, ws in zip(plots, widths)] return plots
def table_tab(doc): def make_dataset(params_list): avg = [] parms = [] values = ["Standard", "input"] colors = ["#c9d9d3", "#718dbf"] # Iterate through all the parameters for i, para_name in enumerate(params_list): subset = usrInputDf[para_name] #.mean() avg.append(subset) data = {'params' : params_list, 'Standard' : avg, } return ColumnDataSource(data=data) def make_plot(src): columns = [ TableColumn(field="params", title="Performance Parameter"), TableColumn(field="Standard", title="Average Performance") ] data_table = DataTable(source=src, columns=columns, width=500, height=380) return data_table list_of_params = list(usrInputDf.columns.unique()) list_of_params.sort() src = make_dataset(list_of_params) p = make_plot(src) # Put controls in a single element controls = WidgetBox(p) # Create a row layout layout = row(controls) doc.title = "Table view" doc.add_root(layout)
def modify_doc(self, doc): # checkboxes for groups self.group_selection_add = CheckboxGroup(labels=self.group_ids, active=[0, 1]) self.group_selection_add.on_change('active', self.update_add) initial_groups = [i + 1 for i in self.group_selection_add.active] # radio button for data type self.type_selection_add = RadioButtonGroup( labels=["Prior", "After", "Diff"], active=0) self.type_selection_add.on_change('active', self.update_add) initial_type = self.type_selection_add.active # add control and initialize display controls = WidgetBox(self.group_selection_add, self.type_selection_add) self.sources_add = self.make_dataset_add(initial_groups, initial_type) # add two panels, one for adding p = self.make_plot(self.sources_add, True) layout = row(controls, p) tab1 = Panel(child=layout, title='Add') # # checkboxes for groups # self.possible_groups = list(combinations([1,2,3], 2)) # labels = [] # for pg in self.possible_groups: # labels.append(self.group_ids[pg[0]] + ' vs ' + self.group_ids[pg[1]]) # self.group_selection_comp = RadioButtonGroup(labels=labels, active=0) # self.group_selection_comp.on_change('active', self.update_comp) # initial_groups = self.possible_groups[self.group_selection_comp.active] # # radio button for data type # self.type_selection_comp = RadioButtonGroup(labels=["Prior", "After", "Diff"], active=0) # self.type_selection_comp.on_change('active', self.update_comp) # initial_type = self.type_selection_comp.active # # add control and initialize display # controls = WidgetBox(self.group_selection_comp, self.type_selection_comp) # self.sources_comp = {} # for i, g in enumerate(self.group_ids): # # for initialization only # self.sources_comp[g] = self.make_dataset_add([i], initial_type) # # add two panels, one for adding # p = self.make_plot(self.sources_comp, False) # layout = row(controls, p) # tab2 = Panel(child=layout, title = 'Compare') # Make a tab with the layouts tabs = Tabs(tabs=[tab1]) doc.add_root(tabs)
def modify_doc(doc): def update(attr, old, new): org_option = option_selection.value print(org_option) diss(org_option) option_selection = Select(options=org_list) option_selection.on_change('value', update) initial_crimes = option_selection # Put controls in a single element controls = WidgetBox(option_selection) # Create a row layout layout = row(controls) # Make a tab with the layout doc.add_root(layout)
def update(attr, old, new): doc.clear() network = make_dataset(0) if new > 0: new_network = make_dataset(new) network.update(new_network) timeselect_slider = Slider(start=0, end=1000, value=new, value_throttled=new, step=1, title="Time", callback_policy='mouseup') timeselect_slider.on_change('value_throttled', update) p = make_plot(network) controls = WidgetBox(timeselect_slider) layout = row(controls, p) doc.add_root(layout)
def teste(): # button = Button(label='FIT', aspect_ratio=10, background='red', # align='center', button_type='primary', # width_policy='max') w1 = Button(label='FIT', aspect_ratio=10, background='red', align='center', button_type='primary', width_policy='max') # Get JavaScript/HTML resources script, div1 = components(WidgetBox(w1, width=500)) # Get JavaScript/HTML resources js_resources = INLINE.render_js() css_resources = INLINE.render_css() return render_template('index.html', js_resources=js_resources, css_resources=css_resources, script=script, div1=div1)
def histogram_tab(flights): # Function to make a dataset for histogram based on a list of carriers # a minimum delay, maximum delay, and histogram bin width def make_dataset(carrier_list, range_start=-60, range_end=120, bin_width=5): # Dataframe to hold information by_carrier = pd.DataFrame(columns=[ 'proportion', 'left', 'right', 'f_proportion', 'f_interval', 'name', 'color' ]) range_extent = range_end - range_start # Iterate through all the carriers for i, carrier_name in enumerate(carrier_list): # Subset to the carrier subset = flights[flights['name'] == carrier_name] # Create a histogram with 5 minute bins arr_hist, edges = np.histogram(subset['arr_delay'], bins=int(range_extent / bin_width), range=[range_start, range_end]) # Divide the counts by the total to get a proportion arr_df = pd.DataFrame({ 'proportion': arr_hist / np.sum(arr_hist), 'left': edges[:-1], 'right': edges[1:] }) # Format the proportion arr_df['f_proportion'] = [ '%0.5f' % proportion for proportion in arr_df['proportion'] ] # Format the interval arr_df['f_interval'] = [ '%d to %d minutes' % (left, right) for left, right in zip(arr_df['left'], arr_df['right']) ] # Assign the carrier for labels arr_df['name'] = carrier_name # Color each carrier differently arr_df['color'] = Category20_16[i] # Add to the overall dataframe by_carrier = by_carrier.append(arr_df) # Overall dataframe by_carrier = by_carrier.sort_values(['name', 'left']) return ColumnDataSource(by_carrier) def style(p): # Title p.title.align = 'center' p.title.text_font_size = '20pt' p.title.text_font = 'serif' # Axis titles p.xaxis.axis_label_text_font_size = '14pt' p.xaxis.axis_label_text_font_style = 'bold' p.yaxis.axis_label_text_font_size = '14pt' p.yaxis.axis_label_text_font_style = 'bold' # Tick labels p.xaxis.major_label_text_font_size = '12pt' p.yaxis.major_label_text_font_size = '12pt' return p def make_plot(src): # Blank plot with correct labels p = figure(plot_width=700, plot_height=700, title='Histogram of Arrival Delays by Airline', x_axis_label='Delay (min)', y_axis_label='Proportion') # Quad glyphs to create a histogram p.quad(source=src, bottom=0, top='proportion', left='left', right='right', color='color', fill_alpha=0.7, hover_fill_color='color', legend='name', hover_fill_alpha=1.0, line_color='black') # Hover tool with vline mode hover = HoverTool(tooltips=[('Carrier', '@name'), ('Delay', '@f_interval'), ('Proportion', '@f_proportion')], mode='vline') p.add_tools(hover) # Styling p = style(p) return p def update(attr, old, new): carriers_to_plot = [ carrier_selection.labels[i] for i in carrier_selection.active ] new_src = make_dataset(carriers_to_plot, range_start=range_select.value[0], range_end=range_select.value[1], bin_width=binwidth_select.value) src.data.update(new_src.data) # Carriers and colors available_carriers = list(set(flights['name'])) available_carriers.sort() airline_colors = Category20_16 airline_colors.sort() carrier_selection = CheckboxGroup(labels=available_carriers, active=[0, 1]) carrier_selection.on_change('active', update) binwidth_select = Slider(start=1, end=30, step=1, value=5, title='Bin Width (min)') binwidth_select.on_change('value', update) range_select = RangeSlider(start=-60, end=180, value=(-60, 120), step=5, title='Range of Delays (min)') range_select.on_change('value', update) # Initial carriers and data source initial_carriers = [ carrier_selection.labels[i] for i in carrier_selection.active ] src = make_dataset(initial_carriers, range_start=range_select.value[0], range_end=range_select.value[1], bin_width=binwidth_select.value) p = make_plot(src) # Put controls in a single element controls = WidgetBox(carrier_selection, binwidth_select, range_select) # Create a row layout layout = row(controls, p) # Make a tab with the layout tab = Panel(child=layout, title='Histogram') return tab
def KPI_projects_tab(panel_title, DAYS_TO_LOAD=90): timeline_source = ColumnDataSource(data=dict( Item=[], Start=[], End=[], Color=[], start=[], end=[], ID=[], ID1=[])) class Thistab(KPI): def __init__(self, table, cols=[]): KPI.__init__(self, table, name='project', cols=cols) self.table = table self.df = None self.df_pop = None self.checkboxgroup = {} self.period_to_date_cards = {} self.ptd_startdate = datetime(datetime.today().year, 1, 1, 0, 0, 0) self.timestamp_col = 'project_startdate_actual' self.pym = PythonMongo('aion') self.groupby_dict = { 'project': 'sum', 'project_duration': 'sum', 'project_start_delay': 'mean', 'project_end_delay': ' mean', 'milestone': 'sum', 'milestone_duration': 'sum', 'milestone_start_delay': 'mean', 'milestone_end_delay': ' mean', 'task': 'sum', 'task_duration': 'sum', 'task_start_delay': 'mean', 'task_end_delay': ' mean', } self.menus = { 'status': ['all', 'open', 'closed'], 'type': [ 'all', 'research', 'reconciliation', 'audit', 'innovation', 'construction', 'manufacturing', 'conference' ], 'gender': ['all', 'male', 'female'], 'variables': list(self.groupby_dict.keys()), 'history_periods': ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10'], } self.status = 'all' self.pm_gender = 'all' self.m_gender = 'all' self.t_gender = 'all' self.type = 'all' self.variables = sorted(list(self.groupby_dict.keys())) self.variable = self.variables[0] self.groupby_var = 'project' self.chord_data = { 'rename': { 'project_owner': 'source', 'milestone_owner': 'target', 'remuneration': 'value' }, 'percentile_threshold': .75, } self.percentile_threshold = 10 # ------- DIVS setup begin self.page_width = 1200 txt = """<hr/><div style="text-align:center;width:{}px;height:{}px; position:relative;background:black;margin-bottom:200px"> <h1 style="color:#fff;margin-bottom:300px">{}</h1> </div>""".format(self.page_width, 50, 'Welcome') self.notification_div = { 'top': Div(text=txt, width=self.page_width, height=20), 'bottom': Div(text=txt, width=self.page_width, height=10), } self.section_divider = '-----------------------------------' self.section_headers = { 'cards': self.section_header_div(text='Period to date:{}'.format( self.section_divider), width=1000, html_header='h2', margin_top=50, margin_bottom=5), 'pop': self.section_header_div(text='Period over period:{}'.format( self.section_divider), width=600, html_header='h2', margin_top=5, margin_bottom=-155), 'chord': self.section_header_div(text='Relationships:{}'.format( self.section_divider), width=600, html_header='h2', margin_top=5, margin_bottom=-155), 'timeline': self.section_header_div(text='Project timeline:{}'.format( self.section_divider), width=600, html_header='h2', margin_top=5, margin_bottom=-155), } self.KPI_card_div = self.initialize_cards(self.page_width, height=350) start = datetime(2014, 1, 1, 0, 0, 0) end = datetime(2019, 5, 15, 0, 0, 0) self.tools = [ BoxZoomTool(), ResetTool(), PanTool(), SaveTool(), WheelZoomTool() ] self.timeline_vars = { 'projects': '', 'project': '', 'types': ['all', 'milestone', 'task', 'project'], 'type': 'all', 'DF': None, 'G': figure(title=None, x_axis_type='datetime', width=1200, height=900, y_range=[], x_range=Range1d(start, end), toolbar_location=None), 'toolbar_box': ToolbarBox() } # ----- UPDATED DIVS END # ---------------------- DIVS ---------------------------- def section_header_div(self, text, html_header='h2', width=600, margin_top=150, margin_bottom=-150): text = """<div style="margin-top:{}px;margin-bottom:-{}px;"><{} style="color:#4221cc;">{}</{}></div>"""\ .format(margin_top,margin_bottom,html_header, text, html_header) return Div(text=text, width=width, height=15) def information_div(self, width=400, height=300): txt = """ <div {}> <h4 {}>How to interpret sentiment score</h4> <ul style='margin-top:-10px;'> <li> </li> <li> </li> <li> </li> <li> </li> </ul> </div> """.format(self.div_style, self.header_style) div = Div(text=txt, width=width, height=height) return div def initialize_cards(self, width, height=250): try: txt = '' for period in ['year', 'quarter', 'month', 'week']: design = random.choice(list(KPI_card_css.keys())) txt += self.card(title='', data='', card_design=design) text = """<div style="margin-top:100px;display:flex; flex-direction:row;"> {} </div>""".format(txt) div = Div(text=text, width=width, height=height) return div except Exception: logger.error('initialize cards', exc_info=True) def load_df(self, req_startdate, req_enddate, table, cols, timestamp_col): try: # get min and max of loaded df if self.df is not None: loaded_min = self.df[timestamp_col].min() loaded_max = self.df[timestamp_col].max() if loaded_min <= req_startdate and loaded_max >= req_enddate: df = self.df[(self.df[timestamp_col] >= req_startdate) & (self.df[timestamp_col] <= req_enddate)] return df return self.pym.load_df(req_startdate, req_enddate, table=table, cols=cols, timestamp_col=timestamp_col) except Exception: logger.error('load_df', exc_info=True) def filter_df(self, df1): if self.status != 'all': df1 = df1[df1.status == self.status] if self.pm_gender != 'all': df1 = df1[df1.project_owner_gender == self.pm_gender] if self.m_gender != 'all': df1 = df1[df1.milestone_owner_gender == self.m_gender] if self.t_gender != 'all': df1 = df1[df1.task_owner_gender == self.t_gender] if self.type != 'all': df1 = df1[df1.type == self.type] return df1 def period_to_date(self, df, timestamp=None, timestamp_filter_col=None, cols=[], period='week'): try: if timestamp is None: timestamp = datetime.now() timestamp = datetime(timestamp.year, timestamp.month, timestamp.day, timestamp.hour, 0, 0) start = self.first_date_in_period(timestamp, period) # filter df[timestamp_filter_col] = pd.to_datetime( df[timestamp_filter_col], format=self.DATEFORMAT_PTD) #logger.warning('df:%s', df[self.timestamp_col]) df = df[(df[timestamp_filter_col] >= start) & (df[timestamp_filter_col] <= timestamp)] if len(cols) > 0: df = df[cols] return df except Exception: logger.error('period to date', exc_info=True) def period_over_period(self, df, start_date, end_date, period, history_periods=2, timestamp_col='timestamp_of_first_event'): try: # filter cols if necessary string = '0 {}(s) prev(current)'.format(period) # filter out the dates greater than today df_current = df.copy() df_current = self.filter_df(df_current) logger.warning('df current:%s', df_current.head(10)) df_current['period'] = string # label the days being compared with the same label if len(df_current) > 0: df_current = self.label_dates_pop(df_current, period, timestamp_col) cols = [self.variable, 'period', 'dayset'] if 'project' in self.variable: if self.variable != 'project': df_current = df_current[[ self.variable, 'period', 'dayset', 'project' ]] elif 'milestone' in self.variable: if self.variable != 'milestone': df_current = df_current[[ self.variable, 'period', 'dayset', 'milestone', 'project' ]] elif 'task' in self.variable: if self.variable != 'task': df_current = df_current[[ self.variable, 'period', 'dayset', 'task', 'milestone', 'project' ]] # zero out time information start = datetime(start_date.year, start_date.month, start_date.day, 0, 0, 0) end = datetime(end_date.year, end_date.month, end_date.day, 0, 0, 0) cols = list(df.columns) counter = 1 if isinstance(history_periods, str): history_periods = int(history_periods) # make dataframes for request no. of periods start, end = self.shift_period_range(period, start, end) while counter < history_periods and start >= self.initial_date: # load data df_temp = self.load_df(start, end, table=self.table, cols=[], timestamp_col=timestamp_col) df_temp = self.filter_df(df_temp) if df_temp is not None: if len(df_temp) > 1: df_temp[timestamp_col] = pd.to_datetime( df_temp[timestamp_col]) string = '{} {}(s) prev'.format(counter, period) # label period df_temp['period'] = string # relabel days to get matching day of week,doy, dom, for different periods df_temp = self.label_dates_pop( df_temp, period, timestamp_col) df_temp = df_temp[cols] # logger.warning('df temp loaded for %s previous: %s',counter,len(df_temp)) df_current = pd.concat([df_current, df_temp]) del df_temp gc.collect() # shift the loading window counter += 1 start, end = self.shift_period_range(period, start, end) return df_current except Exception: logger.error('period over period', exc_info=True) # label dates for period over period (pop) def pop_include_zeros(self, df_period, plotcols, period): try: # check for no data on original dates tmp_title = '0 {}(s) prev(current)'.format(period) if tmp_title not in plotcols: df_period[tmp_title] = [0] * len(df_period) plotcols.append(tmp_title) logger.warning('line 218 cols to plot:%s', plotcols) # do other periods tmp = plotcols[0] txt = tmp[1:] if isinstance(self.pop_history_periods, str): self.pop_history_periods = int(self.pop_history_periods) for i in range(1, self.pop_history_periods): tmp_txt = str(i) + txt if tmp_txt not in plotcols: df_period[tmp_txt] = [0] * len(df_period) plotcols.append(tmp_txt) clean_plotcols = [] for idx, col in enumerate(plotcols): if 'prev' in col or 'curr' in col: clean_plotcols.append(col) logger.warning( 'LINE 340 plotcols at end of pop include zeros:%s', clean_plotcols) return df_period, sorted(clean_plotcols) except Exception: logger.error('pop include zeros', exc_info=True) def label_dates_pop(self, df, period, timestamp_col): #df[timestamp_col] = pd.to_datetime(df[timestamp_col]) def label_qtr_pop(y): try: curr_quarter = int((y.month - 1) / 3 + 1) start = datetime(y.year, 3 * curr_quarter - 2, 1) return abs((start - y).days) except Exception: logger.error('df label quarter', exc_info=True) try: logger.warning('df columns:%s', list(df.columns)) if period == 'week': df['dayset'] = df[timestamp_col].dt.dayofweek elif period == 'month': df['dayset'] = df[timestamp_col].dt.day elif period == 'year': #logger.warning('LINE 218:%s', df.head(5)) df['dayset'] = df[timestamp_col].dt.dayofyear elif period == 'quarter': df['dayset'] = df[timestamp_col].apply( lambda x: label_qtr_pop(x)) return df except Exception: logger.error('label data ', exc_info=True) def get_groupby_pop_df(self, df, variable, groupby_cols): try: if df is not None: if len(df) > 0: if 'dayset' in df.columns: if variable in ['project']: df = df.groupby(groupby_cols).agg( {variable: 'count'}) df = df.reset_index() #logger.warning('LINE 286 df:%s',df) elif variable in ['milestone']: df = df.groupby(groupby_cols).agg( {variable: 'count'}) df = df.reset_index() #logger.warning('LINE 291 df:%s', df) elif variable in ['task']: df = df.groupby(groupby_cols).agg( {variable: 'count'}) df = df.reset_index() elif variable in ['remuneration']: df = df.groupby(groupby_cols).agg( {variable: 'sum'}) df = df.reset_index() else: #logger.warning('LINE 259:df:%s',df.head()) df = df.groupby(groupby_cols).agg( {variable: 'mean'}) df = df.reset_index() # clean up if self.groupby_var in df.columns and self.variable != self.groupby_var: df = df.drop([self.groupby_var], axis=1) return df except Exception: logger.error('get groupby card data', exc_info=True) def get_groupby_card_data(self, df, variable): try: if variable in ['project']: data = len(df[variable].unique()) data = "{} {}s".format(data, variable) elif variable in ['milestone']: df = df.groupby(['project']).agg({variable: 'nunique'}) data = df[variable].sum() data = "{} {}s".format(data, variable) elif variable in ['task']: df = df.groupby(['project', 'milestone']).agg({variable: 'count'}) data = df[variable].sum() data = "{} {}s".format(data, variable) elif variable in ['project_duration'] or 'delay' in variable: df = df.groupby([self.groupby_var]).agg({variable: 'mean'}) df = df.reset_index() data = "{} days".format(round(df[variable].sum(), 2)) elif variable in ['milestone_duration']: df = df.groupby([self.groupby_var, 'project']).agg({variable: 'mean'}) df = df.reset_index() data = "{} days".format(round(df[variable].sum(), 2)) elif variable in [ 'task_duration', 'task_start_delay', 'task_start_end' ]: df = df.groupby([self.groupby_var, 'project', 'milestone']).agg({variable: 'mean'}) df = df.reset_index() data = "{} hours".format(round(df[variable].sum(), 2)) elif variable in ['remuneration']: data = df[variable].sum() data = "${:,.2f}".format(data) return data except Exception: logger.error('get groupby card data', exc_info=True) # -------------------- GRAPHS ------------------------------------------- def graph_periods_to_date(self, df2, timestamp_filter_col, variable): df1 = df2.copy() #self.section_header_updater(section='cards',label=variable,margin_top=159,html_header='h2') try: df1 = self.filter_df(df1) dct = {} for idx, period in enumerate( ['week', 'month', 'quarter', 'year']): df = self.period_to_date( df1, timestamp=dashboard_config['dates']['last_date'], timestamp_filter_col=timestamp_filter_col, period=period) df = df.drop_duplicates(keep='first') # groupby to eliminate repetition data = self.get_groupby_card_data(df, variable) del df gc.collect() dct[period] = data #title = "{} to date".format(period) #p = self.card(title=title, data=data, card_design=random.choice(list(self.KPI_card_css.keys()))) #self.period_to_date_cards[period].text = p.text self.update_cards(dct) except Exception: logger.error('graph periods to date', exc_info=True) def graph_period_over_period(self, period): try: periods = [period] start_date = self.pop_start_date end_date = self.pop_end_date if isinstance(start_date, date): start_date = datetime.combine(start_date, datetime.min.time()) if isinstance(end_date, date): end_date = datetime.combine(end_date, datetime.min.time()) today = datetime.combine(datetime.today().date(), datetime.min.time()) df = self.df_pop.copy() df = self.filter_df(df) #logger.warning('LINE 363 -df:%s',df.head()) cols = [self.variable, self.timestamp_col] if self.variable != 'project': cols.append('project') if abs(start_date - end_date).days > 7: if 'week' in periods: periods.remove('week') if abs(start_date - end_date).days > 31: if 'month' in periods: periods.remove('month') if abs(start_date - end_date).days > 90: if 'quarter' in periods: periods.remove('quarter') for idx, period in enumerate(periods): df_period = self.period_over_period( df, start_date=start_date, end_date=end_date, period=period, history_periods=self.pop_history_periods, timestamp_col=self.timestamp_col) groupby_cols = ['dayset', 'period'] if len(df_period) > 0: logger.warning('LINE 473:%s', list(df_period.columns)) df_period = self.get_groupby_pop_df( df_period, variable=self.variable, groupby_cols=groupby_cols) df_period = df_period.reset_index() else: if not 'day' in df_period.columns: df_period['dayset'] = "" else: df_period = df_period.rename( index=str, columns={'day': 'dayset'}) logger.warning('LINE 478:%s', list(df_period.columns)) prestack_cols = list(df_period.columns) df_period = self.split_period_into_columns( df_period, col_to_split='period', value_to_copy=self.variable) # short term fix: filter out the unnecessary first day added by a corrupt quarter functionality if period == 'quarter': if 'dayset' in df_period.columns: min_day = df_period['dayset'].min() df_period = df_period[ df_period['dayset'] > min_day] poststack_cols = list(df_period.columns) title = "{} over {}".format(period, period) plotcols = list(np.setdiff1d(poststack_cols, prestack_cols)) # include current period if not extant df_period, plotcols = self.pop_include_zeros( df_period, plotcols=plotcols, period=period) if self.variable in [ 'task_start_delay', 'task_end_delay', 'task_duration' ]: ylabel = 'hours' elif self.variable in [ 'project_duration', 'milestone_duration', 'project_start_delay', 'project_end_delay', 'milestone_start_delay', 'milestone_end_delay' ]: ylabel = 'days' elif self.variable in ['project', 'task', 'milestone']: ylabel = '#' elif self.variable == 'remuneration': ylabel = '$' if 'dayset' not in df_period.columns: leng = len(df_period) if leng > 0: df_period['dayset'] = 0 logger.warning('LINE 549') else: logger.warning('LINE 551') df_period['dayset'] = '' logger.warning('LINE 552: df columns:%s', list(df_period.columns)) if idx == 0: p = df_period.hvplot.bar('dayset', plotcols, rot=45, title=title, stacked=False, width=1200, height=400, value_label=ylabel) else: p += df_period.hvplot.bar('dayset', plotcols, rot=45, title=title, stacked=False, width=1200, height=400, value_label=ylabel) return p except Exception: logger.error('period over period to date', exc_info=True) def chord_diagram(self, launch): try: def normalize_value(x, total): x = int((x / total) * 1000) if x <= 0: return 1 return x df = self.df.copy() # -------------- nodes data = {} data['nodes'] = [] source_list = df['milestone_owner'].tolist() names = list(set(source_list)) person_type_dict = dict(zip(df.milestone_owner, df.type)) type_dict = {} types = list(set(df['type'].tolist())) name_dict = {} for idx, name in enumerate(names): name_dict[name] = idx for idx, name in enumerate(names): type_tmp = person_type_dict[name] index = name_dict[name] data['nodes'].append({ 'OwnerID': index, 'index': idx, 'Type': type_tmp }) nodes = hv.Dataset(pd.DataFrame(data['nodes']), 'index') # --------- make the links data['links'] = [] for idx, row in df.iterrows(): src = name_dict[row['project_owner']] tgt = name_dict[row['milestone_owner']] val = row['remuneration'] data['links'].append({ 'source': src, 'target': tgt, 'value': val }) links = pd.DataFrame(data['links']) # get the individual links links = links.groupby(['source', 'target'])['value'].sum() links = links.reset_index() total = links['value'].sum() links['value'] = links['value'].apply( lambda x: normalize_value(x, total)) # filter for top percentile quantile_val = links['value'].quantile( self.chord_data['percentile_threshold']) links = links[links['value'] >= quantile_val] #logger.warning('after quantile filter:%s',len(links)) chord_ = hv.Chord((links, nodes), ['source', 'target'], ['value']) chord_.opts( opts.Chord(cmap='Category20', edge_cmap='Category20', edge_color=dim('source').str(), labels='Type', node_color=dim('index').str(), width=1000, height=1000)) return chord_ except Exception: logger.error('chord diagram', exc_info=True) def timeline(self, project, type='milestone'): try: DF = self.df.copy() if type != project: DF = DF[DF['project'] == project] if type == 'all': rename_dct = { 'milestone_enddate_proposed': 'milestone_enddate', 'milestone_startdate_proposed': 'milestone_startdate', 'task_enddate_proposed': 'task_enddate', 'task_startdate_proposed': 'task_startdate', } DF = DF.rename(index=str, columns=rename_dct) DF = DF.groupby(['milestone', 'task']).agg({ 'milestone_startdate': 'min', 'milestone_enddate': 'max', 'task_startdate': 'min', 'task_enddate': 'max', }) DF = DF.reset_index() # melt to get milestone and task into one column df = pd.melt(DF, value_vars=['milestone', 'task'], id_vars=[ 'milestone_startdate', 'milestone_enddate', 'task_startdate', 'task_enddate' ], value_name='Item', var_name='type') df = df.groupby(['Item', 'type']).agg({ 'milestone_startdate': 'min', 'milestone_enddate': 'max', 'task_startdate': 'min', 'task_enddate': 'max' }).reset_index() df = pd.melt( df, id_vars=[ 'Item', 'type', 'milestone_startdate', 'task_startdate' ], value_vars=['milestone_enddate', 'task_enddate'], value_name='End', var_name='enddate_type') # filter out where tasks label dates and vice versa df1 = df[(df['type'] == 'task') & (df['enddate_type'] == 'task_enddate')] df = df[(df['type'] == 'milestone') & (df['enddate_type'] == 'milestone_enddate')] df = pd.concat([df1, df]) df = df.drop('enddate_type', axis=1) # do startdate df = pd.melt( df, id_vars=['Item', 'type', 'End'], value_vars=['milestone_startdate', 'task_startdate'], value_name='Start', var_name='startdate_type') # filter out where tasks label dates and vice versa df1 = df[(df['type'] == 'task') & (df['startdate_type'] == 'task_startdate')] df = df[(df['type'] == 'milestone') & (df['startdate_type'] == 'milestone_startdate')] df = pd.concat([df1, df]) df = df.drop('startdate_type', axis=1) # label colors df['Color'] = df['type'].apply( lambda x: 'black' if x == 'milestone' else 'green') # organize by milestone and tasks belonging to milestone df = df.sort_values(by=['Start']).reset_index() df = df.drop('index', axis=1) #logger.warning('LINE 605 - df:%s',df.head(50)) DF = df print( '##################################################################################' ) else: start_str = type + '_startdate_proposed' end_str = type + '_enddate_proposed' # group milestone rename_dct = { start_str: 'Start', end_str: 'End', type: 'Item' } DF = DF.rename(index=str, columns=rename_dct) DF = DF[['Item', 'Start', 'End']] DF = DF.groupby(['Item']).agg({ 'Start': 'min', 'End': 'max' }) DF = DF.reset_index() color_list = [] for item in DF.Item.tolist(): color_list.append( random.choice(dashboard_config['colors'])) DF['Color'] = np.array(color_list) DF['start'] = DF['Start'].dt.strftime('%Y-%m-%d') DF['end'] = DF['End'].dt.strftime('%Y-%m-%d') DF['ID'] = DF.index + 0.6 DF['ID1'] = DF.index + 1.4 logger.warning('LINE 648 %s', DF) self.timeline_vars['DF'] = DF # update source data = dict(Item=DF.Item.tolist(), Start=DF.Start.tolist(), End=DF.End.tolist(), Color=DF.Color.tolist(), start=DF.start.tolist(), end=DF.end.tolist(), ID=DF.ID.tolist(), ID1=DF.ID1.tolist()) # <-- This is the trick, make the x_rage empty first, before assigning new value self.timeline_vars['G'].y_range.factors = [] self.timeline_vars['G'].y_range.factors = DF.Item.tolist() #self.timeline_vars['G'].x_range.factors = [] #self.timeline_vars['G'].x_range.factors = sorted(DF.Start.tolist()) timeline_source.data = data except Exception: logger.error('timeline', exc_info=True) def timeline_plot(self, DF): try: hover = HoverTool(tooltips="Task: @Item<br>\ Start: @start<br>\ End: @end") self.timeline_vars['G'].quad(left='Start', right='End', bottom='ID', top='ID1', source=timeline_source, color="Color") self.tools = [hover] + self.tools self.timeline_vars['G'].tools = self.tools self.timeline_vars['toolbar_box'] = ToolbarBox() self.timeline_vars['toolbar_box'].toolbar = Toolbar( tools=self.tools) self.timeline_vars['toolbar_box'].toolbar_location = "above" self.timeline_vars['G'].x_range.start = DF.Start.min( ) - timedelta(days=10) self.timeline_vars['G'].x_range.start = DF.End.max( ) + timedelta(days=10) return self.timeline_vars['G'] except Exception: logger.error('timeline', exc_info=True) def update(attrname, old, new): thistab.notification_updater( "Calculations underway. Please be patient") thistab.pm_gender = pm_gender_select.value thistab.m_gender = m_gender_select.value thistab.t_gender = t_gender_select.value thistab.type = type_select.value thistab.variable = variable_select.value if 'project' in thistab.variable: thistab.groupby_var = 'project' elif 'milestone' in thistab.variable: thistab.groupby_var = 'milestone' elif 'task' in thistab.variable: thistab.groupby_var = 'task' thistab.status = status_select.value thistab.graph_periods_to_date(thistab.df, thistab.timestamp_col, variable=thistab.variable) thistab.trigger += 1 stream_launch.event(launch=thistab.trigger) thistab.notification_updater("ready") def update_pop_dates(): thistab.notification_updater( "Calculations underway. Please be patient") thistab.pop_history_periods = pop_number_select.value thistab.pop_start_date = datepicker_pop_start.value # trigger period over period thistab.pop_end_date = datepicker_pop_end.value thistab.df_pop = thistab.pym.load_df(start_date=thistab.pop_start_date, end_date=thistab.pop_end_date, cols=[], table=thistab.table, timestamp_col='startdate_actual') thistab.trigger += 1 stream_launch.event(launch=thistab.trigger) thistab.notification_updater("ready") def update_history_periods(attrname, old, new): thistab.notification_updater( "Calculations underway. Please be patient") thistab.pop_history_periods = pop_number_select.value thistab.trigger += 1 stream_launch.event(launch=thistab.trigger) thistab.notification_updater("ready") def update_timeline(attrname, old, new): thistab.notification_updater( "Calculations underway. Please be patient") thistab.timeline_vars['project'] = timeline_project_select.value thistab.timeline_vars['type'] = timeline_type_select.value thistab.timeline(thistab.timeline_vars['project'], thistab.timeline_vars['type']) thistab.notification_updater("ready") try: cols = [] thistab = Thistab(table='project_composite', cols=cols) # ------------------------------------- SETUP ---------------------------- # format dates first_date_range = thistab.initial_date last_date_range = datetime.now().date() last_date = dashboard_config['dates']['last_date'] first_date = datetime(last_date.year, 4, 1, 0, 0, 0) thistab.df = thistab.pym.load_df(start_date=first_date, end_date=last_date, table=thistab.table, cols=[], timestamp_col=thistab.timestamp_col) thistab.graph_periods_to_date( thistab.df, timestamp_filter_col=thistab.timestamp_col, variable=thistab.variable) thistab.pop_end_date = last_date thistab.pop_start_date = last_date - timedelta(days=5) thistab.df_pop = thistab.pym.load_df( start_date=thistab.pop_start_date, end_date=thistab.pop_end_date, cols=[], table=thistab.table, timestamp_col=thistab.timestamp_col) thistab.timeline_vars['projects'] = sorted( list(set(thistab.df['project'].tolist()))) thistab.timeline_vars['project'] = thistab.timeline_vars['projects'][0] # MANAGE STREAM # date comes out stream in milliseconds # --------------------------------CREATE WIDGETS --------------------------------- stream_launch = streams.Stream.define('Launch', launch=-1)() datepicker_pop_start = DatePicker(title="Period start", min_date=first_date_range, max_date=last_date_range, value=thistab.pop_start_date) datepicker_pop_end = DatePicker(title="Period end", min_date=first_date_range, max_date=last_date_range, value=thistab.pop_end_date) pop_number_select = Select(title='Select # of comparative periods', value=str(thistab.pop_history_periods), options=thistab.menus['history_periods']) pop_dates_button = Button(label="Select dates, then click me!", width=15, button_type="success") type_select = Select(title='Select project type', value=thistab.type, options=thistab.menus['type']) status_select = Select(title='Select project status', value=thistab.status, options=thistab.menus['status']) pm_gender_select = Select(title="Select project owner's gender", value=thistab.pm_gender, options=thistab.menus['gender']) m_gender_select = Select(title="Select milestone owner's gender", value=thistab.m_gender, options=thistab.menus['gender']) t_gender_select = Select(title="Select task owner's gender", value=thistab.t_gender, options=thistab.menus['gender']) variable_select = Select(title='Select variable of interest', value=thistab.variable, options=thistab.menus['variables']) timeline_project_select = Select( title='Select project', value=thistab.timeline_vars['project'], options=thistab.timeline_vars['projects']) timeline_type_select = Select(title='Select granularity', value='all', options=thistab.timeline_vars['types']) # --------------------------------- GRAPHS --------------------------- hv_pop_week = hv.DynamicMap(thistab.pop_week, streams=[stream_launch]) pop_week = renderer.get_plot(hv_pop_week) hv_pop_month = hv.DynamicMap(thistab.pop_month, streams=[stream_launch]) pop_month = renderer.get_plot(hv_pop_month) hv_pop_quarter = hv.DynamicMap(thistab.pop_quarter, streams=[stream_launch]) pop_quarter = renderer.get_plot(hv_pop_quarter) hv_pop_year = hv.DynamicMap(thistab.pop_year, streams=[stream_launch]) pop_year = renderer.get_plot(hv_pop_year) hv_chord = hv.DynamicMap(thistab.chord_diagram, streams=[stream_launch]) chord = renderer.get_plot(hv_chord) thistab.timeline(thistab.timeline_vars['project'], thistab.timeline_vars['type']) timeline = thistab.timeline_plot(DF=thistab.timeline_vars['DF']) # -------------------------------- CALLBACKS ------------------------ type_select.on_change('value', update) pop_dates_button.on_click(update_pop_dates) # lags array status_select.on_change('value', update) pm_gender_select.on_change('value', update) m_gender_select.on_change('value', update) t_gender_select.on_change('value', update) variable_select.on_change('value', update) pop_number_select.on_change('value', update_history_periods) timeline_project_select.on_change('value', update_timeline) timeline_type_select.on_change('value', update_timeline) # -----------------------------------LAYOUT ---------------------------- # put the controls in a single element controls_top = WidgetBox( variable_select, type_select, status_select, pm_gender_select, m_gender_select, t_gender_select, ) controls_pop = WidgetBox(datepicker_pop_start, datepicker_pop_end, pop_number_select) controls_timeline = WidgetBox(thistab.timeline_vars['toolbar_box'], timeline_project_select, timeline_type_select) grid = gridplot([[thistab.notification_div['top']], [Spacer(width=20, height=70)], [thistab.section_headers['cards']], [thistab.KPI_card_div, controls_top], [thistab.section_headers['pop']], [Spacer(width=20, height=25)], [pop_week.state, controls_pop], [pop_month.state], [pop_quarter.state], [pop_year.state], [thistab.section_headers['chord']], [Spacer(width=20, height=25)], [chord.state], [thistab.section_headers['timeline']], [Spacer(width=20, height=25)], [timeline, controls_timeline], [thistab.notification_div['bottom']]]) # Make a tab with the layout tab = Panel(child=grid, title=panel_title) return tab except Exception: logger.error('rendering err:', exc_info=True) return tab_error_flag(panel_title)
def timeseries_tab(dataframe): """ return a tab showing steps vs time for each person """ def make_dataset(name_list, range_start='2019-01-01', range_end='2019-12-31'): """ Filter the full dataset by name and by date range, and return it as a Bokeh ColumnDataSource """ ## why do I have to do this? What is the point of a DateRangeSlider??? if isinstance(range_start, int): range_start = datetime.fromtimestamp(range_start / 1000) if isinstance(range_end, int): range_end = datetime.fromtimestamp(range_end / 1000) # filtered_df = dataframe[name_list].loc[range_start: range_end] filtered_df = dataframe.loc[range_start:range_end] source = ColumnDataSource(filtered_df) return source def style(p): # Title p.title.align = 'center' p.title.text_font_size = '20pt' p.title.text_font = 'serif' # Axis titles p.xaxis.axis_label_text_font_size = '14pt' p.xaxis.axis_label_text_font_style = 'bold' p.yaxis.axis_label_text_font_size = '14pt' p.yaxis.axis_label_text_font_style = 'bold' # Tick labels p.xaxis.major_label_text_font_size = '12pt' p.yaxis.major_label_text_font_size = '12pt' return p def make_plot(source): """ create a Bokeh figure with the selected data """ names_to_plot = source.column_names[1:] time_series = figure(x_axis_type="datetime", plot_width=700, plot_height=550) hover = HoverTool(tooltips=[("Name", "$name"), ("Date", "@Date{%F}"), ("Steps", "$y")], formatters={'Date': 'datetime'}) time_series = style(time_series) time_series.add_tools(hover) time_series.legend.location = "top_left" for i, name in enumerate(names_to_plot): time_series.line("Date", name, source=source, line_color=Category20_16[i], line_width=2, name=name, legend_label=name) return time_series def update(attr, old, new): """ Update data source when something is changed. """ name_list = [name_selection.labels[i] for i in name_selection.active] new_src = make_dataset(name_list, date_slider.value[0], date_slider.value[1]) cds.data.update(new_src.data) def update_lines(attr, old, new): """ Hide selected lines """ names_to_plot = [ name_selection.labels[i] for i in name_selection.active ] for name in names: if name in names_to_plot: p.select_one({"name": name}).visible = True else: p.select_one({"name": name}).visible = False ### back to the timeseries_tab function names = list(dataframe.columns) names.sort() # widgets to allow user to configure the plot name_selection = CheckboxGroup(labels=names, active=list(range(len(names)))) name_selection.on_change('active', update_lines) date_slider = DateRangeSlider(title="Date range", start=date(2019, 1, 1), end=date(2019, 12, 31), value=(date(2019, 1, 1), date(2019, 12, 31)), step=1) date_slider.on_change('value', update) initial_names = [name_selection.labels[i] for i in name_selection.active] cds = make_dataset(initial_names, date_slider.value[0], date_slider.value[1]) p = make_plot(cds) controls = WidgetBox(name_selection, date_slider) layout = row(controls, p) tab = Panel(child=layout, title="Time series") return tab
def emergence_tab(company_data, founder_data, gis_data): company_data.loc[:, 'IncorporationDate'] = pd.to_datetime( company_data['IncorporationDate'], format='%d/%m/%Y') company_data.loc[:, 'year'] = company_data['IncorporationDate'].dt.to_period( 'Y').astype(str).astype(int) founder_data = founder_data.dropna() founder_data.loc[:, 'IncorporationDate'] = pd.to_datetime( founder_data['IncorporationDate'], format='%d/%m/%Y') founder_data.loc[:, 'year'] = founder_data['IncorporationDate'].dt.to_period( 'Y').astype(str).astype(int) founder_data.loc[:, 'age'] = founder_data['year'] - founder_data[ 'date_of_birth.year'] founder_data.loc[:, 'age'] = founder_data['age'].astype(int) ############################################## # def the function to prepare data for plots # ############################################## def make_dataset(plot_indicators, map_indicators, range_start=1980, range_end=2020, year_select=2020): # calculate the accumulated number of companies companies = company_data.copy() companies.loc[:, 'company_count'] = 1 companies = companies.loc[:, ['year', 'company_count']] companies = pd.DataFrame( companies.groupby(['year'])['company_count'].sum()) companies.loc[:, 'company_sum'] = companies['company_count'].cumsum() companies = companies.reset_index() data = companies.loc[:, ['year', 'company_sum']] # calculate the accumulated number of founders founders = founder_data.copy() founders.loc[:, 'founder_count'] = 1 founders = founders.loc[:, ['year', 'founder_count']] founders = pd.DataFrame( founders.groupby(['year'])['founder_count'].sum()) founders.loc[:, 'founder_sum'] = founders['founder_count'].cumsum() founders = founders.reset_index() data = pd.merge(data, founders, on='year') data = data.drop(columns=['founder_count'], axis=1) data = data[data['year'] >= range_start] data = data[data['year'] <= range_end] company_nodes = gis_data.copy() companies_1 = company_data.copy() companies_1 = companies_1.loc[:, ['RegAddress.PostCode', 'year']] companies_1 = companies_1[companies_1['year'] <= year_select] companies_1.loc[:, 'count'] = 1 companies_1 = pd.DataFrame( companies_1.groupby(['RegAddress.PostCode'])['count'].sum()) companies_1.loc[:, 'count'] = companies_1['count'].apply(np.log) companies_1.loc[:, 'count'] = companies_1['count'] * 30 companies_1 = companies_1.reset_index() companies_1.loc[:, 'RegAddress.PostCode'] = companies_1[ 'RegAddress.PostCode'].str.replace(' ', '') companies_1 = pd.merge(companies_1, company_nodes, left_on='RegAddress.PostCode', right_on='postcode') companies_1 = companies_1.loc[:, ['count', 'x', 'y']] founder_nodes = gis_data.copy() founder_1 = founder_data.copy() founder_1 = founder_1[founder_1['year'] <= year_select] founder_1.loc[:, 'count'] = 1 founder_1 = pd.DataFrame( founder_1.groupby(['RegAddress.PostCode'])['count'].sum()) founder_1.loc[:, 'count'] = founder_1['count'].apply(np.log) founder_1.loc[:, 'count'] = founder_1['count'] * 30 founder_1 = founder_1.reset_index() founder_1.loc[:, 'RegAddress.PostCode'] = founder_1[ 'RegAddress.PostCode'].str.replace(' ', '') founder_1 = pd.merge(founder_1, founder_nodes, left_on='RegAddress.PostCode', right_on='postcode') founder_1 = founder_1.loc[:, ['count', 'x', 'y']] if 'Num of Companies' not in plot_indicators: data.loc[:, 'company_sum'] = 'N/A' if 'Num of Founders' not in plot_indicators: data.loc[:, 'founder_sum'] = 'N/A' if map_indicators != 'Num of Companies': companies_1 = pd.DataFrame(columns=['count', 'x', 'y']) if map_indicators != 'Num of Founders': founder_1 = pd.DataFrame(columns=['count', 'x', 'y']) return (ColumnDataSource(data), ColumnDataSource(companies_1), ColumnDataSource(founder_1)) ############################# # plot the map of tech-city # ############################# def make_map(company_src, founder_src): # set the range of axises x_min = -12000 x_max = -8500 y_min = 6714000 y_max = 6716000 # define the map tiles to use tile_provider = get_provider(Vendors.CARTODBPOSITRON_RETINA) # plot the map p_map = figure(match_aspect=True, x_range=(x_min, x_max), y_range=(y_min, y_max), x_axis_type='mercator', y_axis_type='mercator', height=550) p_map.circle(x='x', y='y', color='darkslategray', source=company_src, size=10, fill_alpha=0.4, radius='count') p_map.circle(x='x', y='y', color='brown', source=founder_src, size=10, fill_alpha=0.4, radius='count') p_map.grid.visible = True # add map tiles map = p_map.add_tile(tile_provider) map.level = 'underlay' # formatting p_map.xaxis.visible = False p_map.yaxis.visible = False return p_map #################################### # define the function to plot data # #################################### def make_plot(src): p = figure(plot_width=1000, plot_height=550, x_axis_label='YEAR', y_axis_label='NUM') p.line(source=src, x='year', y='company_sum', color='darkslategray', legend_label='Num of Companies') p.line(source=src, x='year', y='founder_sum', color='brown', legend_label='Num of Founders') p.legend.location = 'top_left' hover = HoverTool(tooltips=[( 'Year', '@year'), ('Num of Companies', '@company_sum'), ('Num of Founders', '@founder_sum')]) p.add_tools(hover) return p ############################## # define the update function # ############################## def update(attr, old, new): plot_indicators = [ plot_indicator_selection.labels[i] for i in plot_indicator_selection.active ] map_indicators = map_indicator_selection.value new_src, new_company_src, new_founder_src = make_dataset( plot_indicators, map_indicators, range_start=range_select.value[0], range_end=range_select.value[1], year_select=year_select.value) src.data.update(new_src.data) company_src.data.update(new_company_src.data) founder_src.data.update(new_founder_src.data) # %% set controllers available_indicators = ['Num of Companies', 'Num of Founders'] plot_indicator_selection = CheckboxGroup(labels=available_indicators, active=[0, 1]) plot_indicator_selection.on_change('active', update) map_indicator_selection = Select(title="Choose Indicator", value='Num of Companies', options=available_indicators) map_indicator_selection.on_change('value', update) year_select = Slider(start=1980, end=2020, value=2020, step=1, title='Choose the year') year_select.on_change('value', update) range_select = RangeSlider(start=1980, end=2020, value=(1980, 2020), title='Time Period (year)') range_select.on_change('value', update) # %% initial indicators and data source initial_plot_indicators = [ plot_indicator_selection.labels[i] for i in plot_indicator_selection.active ] initial_map_indicator = map_indicator_selection.value src, company_src, founder_src = make_dataset( initial_plot_indicators, initial_map_indicator, range_start=range_select.value[0], range_end=range_select.value[1], year_select=year_select.value) p1 = make_plot(src) p2 = make_map(company_src, founder_src) # %% put controls in a single element plot_controls = WidgetBox(plot_indicator_selection, range_select) map_controls = WidgetBox(map_indicator_selection, year_select) # text description: title_1 = Div(text=''' <b>Emergence and Development of London Tech City</b> ''') description_1 = Div(text=''' <b>In 2008</b>, Tech City - also known as East London Tech City or Silicon Roundabout - came to prominence, with a variety of companies operating in the area, including Last.FM, Poke and Trampoline System. Being located in Inner East London, Tech City presents a large number of advantages for firms: a central location, cheap rents, accessibility to the rest of London and proximity to other like-minded tech companies. Moreover, Tech City offers many nightlife activaties, which is highly attractive to the type of workers and employees that digital and tech business want to retain - young, urban, creative and tech-savvy. ''') description_2 = Div(text=''' <b>In Nov 2010</b>, then UK Prime Minister made a speech to emphasize the importance of East London Tech firms in the UK Economy and set ambitious plans to further develop Tech City, promising a governmental support. The proposals involved building the profile of the area through government funding (£15 million in Government Funding) and support. Besides, Tech City Investment Organisation (TCIO) was created by the government aiming to make Tech City the leading digital hub in Europe. ''') description_3 = Div( text='<b>The Tech City strategy presented 3 clear objectives:</b>\n') description_4 = Div( text='1. Supporting the cluster of start-ups and small/midium-sized\ businesses(SMES);') description_5 = Div(text='2. Attracting large international investers;') description_6 = Div( text='3. Using this momentum to steer high-tech activity further east,\ including into a post-Games Olympic Park.') description_7 = Div(text=''' <b>In May 2011</b>, TweetDeck, a social media dashboard, was launched by Twitter and gave another boost to the already growing repulation of Tech City. ''') reference_1 = Div(text=''' <a href="https://www.mbymontcalm.co.uk/blog/history-behind-tech-city/ ">Reference 1</a> ''') reference_2 = Div(text=''' <a href="https://www.demos.co.uk/files/A_Tale_of_Tech_City_web.pdf ">Reference 2</a> ''') reference_3 = Div(text=''' <a href="https://www.gov.uk/government/speeches/east-end-tech-city-speech">Reference 3</a> ''') reference_4 = Div(text=''' <a href="https://olaonikoyi.medium.com/the-problems-at-east-london -tech-city-london-silicon-roundabout-d0bc2d4c7181">Reference 4</a> ''') title_2 = Div(text=''' <b>Data Visual</b> ''') description_8 = Div(text=''' The programme was a major success and resulted in an important multiplication of the number of tech companies operating in the region. In 2000, the number of companies in Tech City was 628. After Cameron's speech in 2011, the number of companies started increasing exponentially - indeed, the number of companies increased by 1204% between 2011 and 2020 (3,208 in 2011 vs. 41,841 in 2020). ''') # %% design the layout plot_layout = column(plot_controls, p1) map_layout = column(map_controls, p2) graph_layout = row(plot_layout, map_layout) layout = column(title_1, description_1, description_2, description_3, description_4, description_5, description_6, description_7, reference_1, reference_2, reference_3, reference_4, title_2, description_8, graph_layout) # %% make a tab with the layout tab = Panel(child=layout, title='Emergence of Tech-City') return tab
tss_text = Div(text=''' <b> TSS library:</b> We synthesized a library of ~18K reported TSSs and measured their promoter activity. We synthesized 150bp surrounding the TSS (-120 to +30) in LB. We classified TSSs into active and inactive based on a set of 500 negative controls (150bp genomic sequence > 200bp from TSS). We set the active threshold at 3 standard deviations greater than the median negative control. ''') # put controls in single element # controls = WidgetBox(condition_selection, position_selection) # controls_row1 = WidgetBox(general_text, norm_text, frag_text, condition_selection, # rna_text, rna_button, axis_button) # controls_row2 = WidgetBox(tss_text, tss_button, gene_button, start, end, axis_button) # create row layout # layout = gridplot([controls_row1, p, WidgetBox(tss_text, tss_button), WidgetBox(gene_button, start, end)], ncols=2) controls_group1 = WidgetBox(general_text, norm_text, frag_text, condition_selection, rna_text, rna_button, tss_button) controls_group2 = WidgetBox(gene_button, start, end, add_button, gene_search, axis_button, export_button) layout = row(controls_group1, p, controls_group2) # make tab with layout tab = Panel(child=layout, title='Genomic fragment shearing pileup') tabs = Tabs(tabs=[tab]) # add to current document (displays plot) curdoc().add_root(tabs)
def bar_update(attr, old, new): layout_bar.children[1] = create_figure_bar() def lin_update(attr, old, new): layout_lin.children[1] = create_figure_lin() y1 = Select(title='Y-Axis', value=header[1], options=header[1:]) y2 = Select(title='Y-Axis', value=header[1], options=header[1:]) y3 = Select(title='Y-Axis', value=header[1], options=header[1:]) y1.on_change('value', cir_update) y2.on_change('value', bar_update) y3.on_change('value', lin_update) controls1 = WidgetBox(y1, width=150) controls2 = WidgetBox(y2, width=150) controls3 = WidgetBox(y3, width=150) layout_cir = row(controls1, create_figure_cir()) layout_bar = row(controls2, create_figure_bar()) layout_lin = row(controls3, create_figure_lin()) # panel # tab1 = Panel(child=layout_cir, title="circle") tab2 = Panel(child=layout_bar, title='vbar') tab3 = Panel(child=layout_lin, title='line') tabs = Tabs(tabs=[ tab1, tab2, tab3 ]) curdoc().add_root(tabs)
def priceOverTimeTab(priceDf): def findProductPriceLists(df, product, country): this_product = df.query("country==\"" + country + "\"") this_product = this_product.query("_product==\"" + product + "\"") this_product = this_product.sort_values(by=['year', 'month']) month_means = [] year_months = [] for year in this_product.year.unique(): this_year = this_product.query("year==" + str(year)) for month in this_year.month.unique(): this_month = this_year.query("month==" + str(month)) month_means.append(this_month.price.mean()) year_months.append(dt.datetime(year=year, month=int(month), day=1)) return [month_means, year_months] # Function to make a dataset for histogram based on a list of carriers # a minimum delay, maximum delay, and histogram bin width def make_dataset(products_list, country, df): # Dataframe to hold information by_product = pd.DataFrame(columns=['proportion', 'f_proportion', 'product', 'date', 'color']) # Iterate through all the carriers for i, product in enumerate(products_list): # Subset to the carrier lists = findProductPriceLists(df, product, country) prices = lists[0] dates = lists[1] # Divide the counts by the total to get a proportion arr_df = pd.DataFrame({'proportion': prices / np.mean(prices)}) arr_df['date'] = dates # Format the proportion arr_df['f_proportion'] = ['%0.5f' % proportion for proportion in arr_df['proportion']] # Assign the carrier for labels arr_df['product'] = product # Color each carrier differently arr_df['color'] = Category20_16[i] # Add to the overall dataframe by_product = by_product.append(arr_df) # Overall dataframe by_product = by_product.sort_values(['product', 'date']) return ColumnDataSource(by_product) def style(p): # Title p.title.align = 'center' p.title.text_font_size = '20pt' p.title.text_font = 'serif' # Axis titles p.xaxis.axis_label_text_font_size = '14pt' p.xaxis.axis_label_text_font_style = 'bold' p.yaxis.axis_label_text_font_size = '14pt' p.yaxis.axis_label_text_font_style = 'bold' # Tick labels p.xaxis.major_label_text_font_size = '12pt' p.yaxis.major_label_text_font_size = '12pt' return p def make_plot(src): # Blank plot with correct labels p = figure(plot_width = 700, plot_height = 700, title = 'Price of products in a country over time', x_axis_label = 'Time', y_axis_label = 'Price proportional to the mean', x_axis_type="datetime") # Quad glyphs to create a histogram p.line(source = src, x = 'date', y = 'proportion', color = 'color', legend = 'product', line_color = 'black') # Hover tool with vline mode hover = HoverTool(tooltips=[('Product', '@product'), ('Proportion', '@f_proportion')], mode='vline') p.add_tools(hover) # Styling p = style(p) return p def update(attr, old, new): products_to_plot = [products_selection.labels[i] for i in products_selection.active] new_src = make_dataset(products_to_plot, 'India', df) src.data.update(new_src.data) # load dataframe priceDf = pd.read_csv("data/only_complete_years_data.csv") # available products and colors priceCountryDf = priceDf[priceDf['country'] == 'India'] available_products = list(priceCountryDf._product.unique()) available_products.sort() product_colors = Category20_16 product_colors.sort() products_selection = CheckboxGroup(labels=available_products, active = [0, 1]) products_selection.on_change('active', update) # Initial carriers and data source initial_products = [products_selection.labels[i] for i in products_selection.active] src = make_dataset(initial_products, 'India', priceDf) p = make_plot(src) # Put controls in a single element controls = WidgetBox(products_selection) # Create a row layout layout = row(controls, p) # Make a tab with the layout tab = Panel(child=layout, title = 'Product price over time') return tab
def mgstat_tab(db): def make_dataset(mgstat_list): newdf = mgstat[mgstat_list] # Convert dataframe to column data source return ColumnDataSource(newdf) def make_plot(src): # Blank plot with correct labels p = Figure( plot_width=1024, plot_height=768, x_axis_type="datetime", title="mgstat", output_backend="webgl", ) cm = plt.get_cmap("gist_rainbow") numlines = len(mgstat.columns) mypal = [cm(1.0 * i / numlines) for i in range(numlines)] mypal = list(map(lambda x: colors.rgb2hex(x), mypal)) col = 0 for key in src.data.keys(): if key == "datetime": continue l = key + " " col = col + 1 p.line( mgstat.index.values, mgstat[key], line_width=1, alpha=0.8, name=key, legend=key, color=mypal[col], ) p.legend.click_policy = "hide" return p def update(attr, old, new): print("update called") mgstats_to_plot = [ mgstat_selection.labels[i] for i in mgstat_selection.active ] new_src = make_dataset(mgstats_to_plot) src.data = new_src.data plot = make_plot(src) layout.children[1] = plot # get data from DB, setup index mgstat = pd.read_sql_query("select * from mgstat", db) mgstat.index = pd.to_datetime(mgstat["datetime"]) mgstat = mgstat.drop(["datetime"], axis=1) mgstat.index.name = "datetime" mgstat_selection = CheckboxGroup(labels=list(mgstat.columns), active=[0, 5]) mgstat_list = [mgstat_selection.labels[i] for i in mgstat_selection.active] src = make_dataset(mgstat_list) plot = make_plot(src) mgstat_selection.on_change("active", update) controls = WidgetBox(mgstat_selection) layout = row(controls, plot) tab = Panel(child=layout, title="mgstat") return tab
def get_electmap_with_controls(): #start = time.time() merged_cnt_data, merged_st_data = init_data() #end = time.time() #print("init_data time={}".format(str(end-start))) year_select = Slider(start=2000, end=2020, step=4, value=2012, title='ELECTION YEAR', bar_color="black") st_fips = -1 #start = time.time() geo_src_c = GeoJSONDataSource( geojson=make_dataset_cnt(merged_cnt_data, year_select.value, 0, True)) geo_src_s = GeoJSONDataSource( geojson=make_dataset_state(merged_st_data, year_select.value, True)) #end = time.time() #print("geo_src time={}".format(str(end-start))) #start = time.time() curr_geo_src_c = GeoJSONDataSource( geojson=make_dataset_cnt(merged_cnt_data, 2012, st_fips, False)) curr_geo_src_s = GeoJSONDataSource( geojson=make_dataset_state(merged_st_data, 2012, False)) #end = time.time() #print("curr_geo_src time={}".format(str(end-start))) #slider = Slider(start=0.1, end=4, value=1, step=.1, title="power") callbackSelector = CustomJS(args=dict(source_s=geo_src_s, currsource_s=curr_geo_src_s, source_c=geo_src_c, currsource_c=curr_geo_src_c), code=""" var yr = cb_obj.value; var has_selected_st = currsource_s.selected.indices.length > 0; var st_fip = currsource_c.data['STATE_FIPS'][0]; for(var key in source_s.data){ currsource_s.data[key] = []; } for(var key in source_c.data){ currsource_c.data[key] = []; } for (var i = 0; i <= source_s.data['YEAR'].length; i++){ if (source_s.data['YEAR'][i] == yr){ for(var key in source_s.data){ currsource_s.data[key].push(source_s.data[key][i]); } } } for (var i = 0; i <= source_c.data['YEAR'].length; i++){ if (source_c.data['YEAR'][i] == yr){ if(has_selected_st){ if(source_c.data['STATE_FIPS'][i] == st_fip){ for(var key in source_c.data){ currsource_c.data[key].push(source_c.data[key][i]); } } } else{ for(var key in source_c.data){ if(source_c.data['STATE_FIPS'][i] == 2 || source_c.data['STATE_FIPS'][i] == 15){ continue; } if(source_c.data[key][i]){ currsource_c.data[key].push(source_c.data[key][i]); } else { currsource_c.data[key].push(''); } } } } } updateDetails(null, yr); currsource_s.change.emit(); currsource_c.change.emit(); """) year_select.js_on_change('value', callbackSelector) #curr_geo_src_s.js_on_event('value', callbackStateClick) #start = time.time() p_c = make_plot_cnt(curr_geo_src_c) p_s = make_plot_st(curr_geo_src_s) callbackStateClick = CustomJS(args=dict(source=curr_geo_src_s, source_c=geo_src_c, source_curr_c=curr_geo_src_c), code=""" var st_fip = 0; var yr = source_curr_c.data['YEAR'][0]; for(var key in source.data){ if (key == 'STATE_FIPS') { st_fip = source.data['STATE_FIPS'][source.selected.indices[0]]; } } for(var key in source_c.data){ source_curr_c.data[key] = []; } for (var i = 0; i <= source_c.data['YEAR'].length; i++){ if (source_c.data['STATE_FIPS'][i] == st_fip && source_c.data['YEAR'][i] == yr){ for(var key in source_c.data){ source_curr_c.data[key].push(source_c.data[key][i]); } } } updateDetails(st_fip, null); source_curr_c.change.emit(); """) taptool = TapTool(callback=callbackStateClick) p_s.add_tools(taptool) tabOutsideCallback = CustomJS(args=dict(source=curr_geo_src_s, source_c=geo_src_c, source_curr_c=curr_geo_src_c), code=""" if(source.selected.indices.length == 0){ var yr = source_curr_c.data['YEAR'][0]; for(var key in source_c.data){ source_curr_c.data[key] = []; } for (var i = 0; i <= source_c.data['YEAR'].length; i++){ if (source_c.data['YEAR'][i] == yr){ for(var key in source_c.data){ if(source_c.data['STATE_FIPS'][i] == 2 || source_c.data['STATE_FIPS'][i] == 15){ continue; } if(source_c.data[key][i]) source_curr_c.data[key].push(source_c.data[key][i]); else { source_curr_c.data[key].push(''); } } } } updateDetails(null, null); source_curr_c.change.emit(); } """) p_s.js_on_event('tap', tabOutsideCallback) #p_s.js_on_event('value', callbackStateClick) controls = WidgetBox(year_select, width=int(950 * 0.9)) layout = column(controls, p_s, p_c) return layout
def age_hist_tab(df_selected=None): def make_dataset(age_group_list, range_start=0.076070, range_end=0.271264, bin_width=0.00001): by_age_group = pd.DataFrame(columns=[ 'proportion', 'left', 'right', 'f_proportion', 'f_interval', 'name', 'color' ]) range_extent = range_end - range_start # Iterate through all the carriers for i, age_group in enumerate(age_group_list): # Subset to the carrier subset = df_selected[df_selected['age_range'] == age_group] # Create a histogram with 5 minute bins arr_hist, edges = np.histogram(subset['meanfun'], bins=int(range_extent / bin_width), range=[range_start, range_end]) # Divide the counts by the total to get a proportion arr_df = pd.DataFrame({ 'proportion': arr_hist / np.sum(arr_hist), 'left': edges[:-1], 'right': edges[1:] }) # Format the proportion arr_df['f_proportion'] = [ '%0.5f' % proportion for proportion in arr_df['proportion'] ] # Format the interval arr_df['f_interval'] = [ '%0.5f to %0.5f KHz' % (left, right) for left, right in zip(arr_df['left'], arr_df['right']) ] # Assign the carrier for labels arr_df['name'] = age_group # Color each carrier differently arr_df['color'] = Category20_16[i] # Add to the overall dataframe by_age_group = by_age_group.append(arr_df) # Overall dataframe by_age_group = by_age_group.sort_values(['name', 'left']) return ColumnDataSource(by_age_group) def style(p): # Title p.title.align = 'center' p.title.text_font_size = '20pt' p.title.text_font = 'serif' # Axis titles p.xaxis.axis_label_text_font_size = '14pt' p.xaxis.axis_label_text_font_style = 'bold' p.yaxis.axis_label_text_font_size = '14pt' p.yaxis.axis_label_text_font_style = 'bold' # Tick labels p.xaxis.major_label_text_font_size = '12pt' p.yaxis.major_label_text_font_size = '12pt' return p def make_plot(src): # Blank plot with correct labels p = figure( plot_width=700, plot_height=700, title='Histogram of Age Range and Mean Fundamental Frequeny', x_axis_label='Mean fundamental frequency (KHz)', y_axis_label='Proportion') # Quad glyphs to create a histogram p.quad(source=src, bottom=0, top='proportion', left='left', right='right', color='color', fill_alpha=0.7, hover_fill_color='color', legend='name', hover_fill_alpha=1.0, line_color='black') # Hover tool with vline mode hover = HoverTool(tooltips=[('Age Group', '@name'), ('Meanfund frequency', '@f_interval'), ('Proportion', '@f_proportion')], mode='vline') p.add_tools(hover) # Styling p = style(p) return p def update(attr, old, new): age_group_to_plot = [ age_group_selection.labels[i] for i in age_group_selection.active ] new_src = make_dataset(age_group_to_plot, range_start=range_select.value[0], range_end=range_select.value[1], bin_width=binwidth_select.value) src.data.update(new_src.data) # This is the option on the side available_age_groups = list(df_selected['age_range'].unique()) age_group_selection = CheckboxGroup(labels=available_age_groups, active=[0, 1]) # What happens when you select it age_group_selection.on_change('active', update) # The slider on the side binwidth_select = Slider(start=0.001, end=0.01, step=0.001, value=0.001, title='Frequency Width (KHz)') #Something is updated binwidth_select.on_change('value', update) #The slider and the ranges for that one range_select = RangeSlider(start=0.076070, end=0.271264, value=(0.076070, 0.271264), step=0.01, title='Meanfun Frequency (KHz)') # Same here range_select.on_change('value', update) initial_age_grop = [ age_group_selection.labels[i] for i in age_group_selection.active ] src = make_dataset(initial_age_grop, range_start=range_select.value[0], range_end=range_select.value[1], bin_width=binwidth_select.value) p = make_plot(src) # Put controls in a single element controls = WidgetBox(age_group_selection, binwidth_select, range_select) # Create a row layout layout = row(controls, p) # Make a tab with the layout tab = Panel(child=layout, title='Age Group Histogram') return tab