layout3 = row(p3, p2) p4, p5, p6, p7, p8 = get_plot() tab1 = Panel(child=layout1, title="Country Comparison") tab2 = Panel(child=layout2, title="Top Climbers/Top Fallers") tab3 = Panel(child=layout3, title="GDP Incoming Rank vs. Rank Relation") tab4 = Panel(child=p4, title="Score Comparison") tab5 = Panel(child=p5, title="GDP Per Capita with Score") tab6 = Panel(child=p6, title="Incoming vs Outgoing Rates") tab7 = Panel(child=p7, title="Where Can I travel to?") tab8 = Panel(child=p8, title="Highlighting Differences") tabs = Tabs(tabs=[tab1, tab2, tab4, tab5, tab6, tab7, tab8, tab3]) call_back_obj = False def panelActive(attr, old, new): global call_back_obj if tabs.active == 7: call_back_obj = curdoc().add_periodic_callback(update_gdp, 2000) elif tabs.active != 7 and call_back_obj: curdoc().remove_periodic_callback(call_back_obj) call_back_obj = False #curdoc().add_root(tabs) save(tabs) output_file("output.html", title='runner_code.py example') tabs.on_change('active', panelActive)
def re_analyze_callback(): re_analyze() # set callbacks top_n_dropdown.on_change('value', top_n_phrases_changed_callback) top_n_clusters_dropdown.on_change('value', top_n_clusters_changed_callback) radio_group_area.on_change('active', selected_graph_changed_callback) # pylint: disable=no-member filter_topics_table_source.selected.on_change('indices', filter_topic_selected_callback) filter_custom_table_source.selected.on_change('indices', filter_custom_selected_callback) search_button.on_click(search_topic_callback) clear_button.on_click(clear_search_callback) filter_tabs.on_change('active', tab_changed_callback) analyse_button.on_click(re_analyze_callback) # start app draw_ui(top_n_dropdown.value, top_n_clusters_dropdown.value, radio_group_area.active) doc = curdoc() main_title = "Trend Analysis" doc.title = main_title doc.add_root(grid)
def make_start_end_figure(doc): """ Creates a Bokeh app for visualizations of start and end of hurricanes """ df_spawn_end = pd.read_csv('files/df_start_end_bokeh.csv', index_col=0) year_min, year_max, lon_boundaries, lat_boundaries = get_boundaries(df_spawn_end) gulf_stream_lon1, gulf_stream_lon2, gulf_stream_lat1, gulf_stream_lat2 = get_gulf_stream() # credits of the map url = 'http://a.basemaps.cartocdn.com/rastertiles/voyager/{Z}/{X}/{Y}.png' attribution = "Tiles by Carto, under CC BY 3.0. Data by OSM, under ODbL" add_paragraph = additional_legend(loc='tracks') # ----------------------------------------------------- # WIDGETS # ----------------------------------------------------- # definition and configuration of the number selection options_number = ['-1'] + [str(x) for x in list(np.arange(1, 21))] select_number = Select(title='Number of hurricanes:', value='5', options=options_number) # definition and configuration of the zone selection options_zone = ['All', 'Mexico_Caribbean', 'Atlantic'] select_zone = Select(title='Spawning Zone:', value='All', options=options_zone) # Definition of buttons for end points and distances toggle_month = Toggle(label="Show end points", button_type="success") toggle_dist_month = Toggle(label="Show distance traveled", button_type="success") # definition and configuration of the year and month sliders slider_year = RangeSlider(start=year_min, end=year_max, value=(year_min, year_max), step=1, title="Years") slider_month = RangeSlider(start=1, end=12, value=(1, 12), step=1, title="Months") # End points toggle_season = Toggle(label="Show end points", button_type="success") toggle_dist_season = Toggle(label="Show distance traveled", button_type="success") # definition and configuration of the number selection select_number_season = Select(title='Number of hurricanes:', value='5', options=options_number) # definition and configuration of the zone selection select_zone_season = Select(title='Spawning Zone:', value='All', options=options_zone) # definition and configuration of the year and sliders slider_year_season = RangeSlider(start=year_min, end=year_max, value=(year_min, year_max), step=1, title="Years") # definition and configuration of the season selection options_season = ['All', 'Winter', 'Spring', 'Summer', 'Autumn'] select_season = Select(title='Season:', value='All', options=options_season) # ------------------------------------------------------- # DATA SOURCE AND RANDOMIZATION # ------------------------------------------------------- np.random.seed(42) n = 5 select_list = list(np.random.choice(df_spawn_end.index, size=n, replace=False)) filtr = df_spawn_end.index.map(lambda x: x in select_list) source = ColumnDataSource(data=df_spawn_end[filtr]) # -------------------------------------------------------- # FIRST TAB # -------------------------------------------------------- # Initialization of the map p = figure(tools='pan, wheel_zoom', x_range=(lon_boundaries[0], lon_boundaries[1]), y_range=(lat_boundaries[0], lat_boundaries[1]), x_axis_type="mercator", y_axis_type="mercator") p.add_tile(WMTSTileSource(url=url, attribution=attribution)) # Add data points # - Start # - End # - Start with size adjusted to the traveled distance c1 = p.circle(x='x_start', y='y_start', fill_color='green', size=8, source=source, legend_label='Start points') c2 = p.circle(x='x_end', y='y_end', fill_color='orange', size=8, source=source, legend_label='End points') d1 = p.circle(x='x_start', y='y_start', fill_color='green', radius='Distance_draw', source=source) # Line between start and end points s1 = p.segment(x0='x_start', y0='y_start', x1='x_end', y1='y_end', line_dash='dashed', source=source) # Initial configuration of WIDGETS for FIRST TAB # - Don't show end points # - Don't show segments between start and end points # - Uniform size for starting points c2.visible, s1.visible, d1.visible = False, False, False # Configuration of the hovertool hover = HoverTool(tooltips=[("ID", "@ID"), ("Duration", "@Duration"), ("Distance", "@Distance")], renderers=[c1, c2, d1], formatters={'Duration': 'printf'}) p.tools.append(hover) # Draw the Gulf Stream p.segment(x0=gulf_stream_lon1[:-1], y0=gulf_stream_lat1[:-1], x1=gulf_stream_lon1[1:], y1=gulf_stream_lat1[1:], legend_label='Gulf Stream', color='red', line_alpha=0.5, line_width=2) p.segment(x0=gulf_stream_lon2[:-1], y0=gulf_stream_lat2[:-1], x1=gulf_stream_lon2[1:], y1=gulf_stream_lat2[1:], color='red', line_alpha=0.5, line_width=2) p.legend.location = "top_left" # DataFrame display no_cols = ['x_start', 'x_end', 'y_start', 'y_end', 'Distance_draw'] cols = [TableColumn(field=col, title=col) for col in df_spawn_end.columns if col not in no_cols] data_table = DataTable(columns=cols, source=source, width=1100, selectable=False) # ------------------------------------------------------------------------ # UPDATING FIRST TAB # ------------------------------------------------------------------------ # updating process of the data underlying the map depending on user actions. def update_map_se(attr, old, new): yr = slider_year.value month = slider_month.value zone = select_zone.value n = select_number.value n = int(n) if zone == 'All': df_temp = df_spawn_end.loc[(df_spawn_end['Year_start'] >= yr[0]) & (df_spawn_end['Year_start'] <= yr[1]) & (df_spawn_end['Month_start'] >= month[0]) & (df_spawn_end['Month_start'] <= month[1])] else: df_temp = df_spawn_end.loc[(df_spawn_end.Zones_start == zone) & (df_spawn_end['Year_start'] >= yr[0]) & (df_spawn_end['Year_start'] <= yr[1]) & (df_spawn_end['Month_start'] >= month[0]) & (df_spawn_end['Month_start'] <= month[1])] if n == -1: source.data = ColumnDataSource.from_df(df_temp) else: if n > len(df_temp): # For cases where there are not enough data points n = int(len(df_temp)) np.random.seed(42) select_list = list(np.random.choice(df_temp.index, size=n, replace=False)) filtr = df_temp.index.map(lambda x: x in select_list) source.data = ColumnDataSource.from_df(df_temp.loc[filtr]) def month_active(atrr, old, new): active = toggle_month.active dist = toggle_dist_month.active if not active: c2.visible, s1.visible = False, False toggle_month.label = "Show end points" else: c2.visible, s1.visible = True, True toggle_month.label= "Unshow end points" if not dist: c1.visible, d1.visible = True, False toggle_dist_month.label = "Show distance traveled" else: c1.visible, d1.visible = False, True toggle_dist_month.label = "Unshow distance traveled" # activation of the changes on user action select_number.on_change('value', update_map_se) slider_year.on_change('value', update_map_se) slider_month.on_change('value', update_map_se) select_zone.on_change('value', update_map_se) toggle_month.on_change('active', month_active) toggle_dist_month.on_change('active', month_active) # Make first tab tab_month = Panel(child=column(row(column(slider_year, slider_month, select_number, select_zone, toggle_month, toggle_dist_month), p, add_paragraph), data_table), title="Monthly") # ---------------------------------------------------------------------------- # SECOND TAB # ---------------------------------------------------------------------------- p_season = figure(tools='pan, wheel_zoom', x_range=(lon_boundaries[0], lon_boundaries[1]), y_range=(lat_boundaries[0], lat_boundaries[1]), x_axis_type="mercator", y_axis_type="mercator") p_season.add_tile(WMTSTileSource(url=url, attribution=attribution)) # Add data points # - Start # - End # - Start with size adjusted to the traveled distance c3 = p_season.circle(x='x_start', y='y_start', fill_color='green', size=8, source=source, legend_label='Start points') c4 = p_season.circle(x='x_end', y='y_end', fill_color='orange', size=8, source=source, legend_label='End points') d2 = p_season.circle(x='x_start', y='y_start', fill_color='green', radius='Distance_draw', source=source) # line between start and end points s2 = p_season.segment(x0='x_start', y0='y_start', x1='x_end', y1='y_end', line_dash='dashed', source=source) # Initial configuration of WIDGETS for SECOND TAB # - Don't show end points # - Don't show segments between start and end points # - Uniform size for starting points c4.visible, s2.visible, d2.visible = False, False, False # Configuration of the hovertool hover_season = HoverTool(tooltips=[("ID", "@ID"), ("Duration", "@Duration"), ("Distance", "@Distance")], renderers=[c3, c4], formatters={'Duration': 'printf'}) p_season.tools.append(hover_season) # Gulf Stream p_season.segment(x0=gulf_stream_lon1[:-1], y0=gulf_stream_lat1[:-1], x1=gulf_stream_lon1[1:], y1=gulf_stream_lat1[1:], legend_label='Gulf Stream', color='red', line_alpha=0.5, line_width=2) p_season.segment(x0=gulf_stream_lon2[:-1], y0=gulf_stream_lat2[:-1], x1=gulf_stream_lon2[1:], y1=gulf_stream_lat2[1:], color='red', line_alpha=0.5, line_width=2) p_season.legend.location = "top_left" # ------------------------------------------------------------------------ # UPDATING SECOND TAB # ------------------------------------------------------------------------ # updating process of the data underlying the map depending on user actions. def update_map_season(attr, old, new): yr = slider_year_season.value season = select_season.value zone = select_zone_season.value n = select_number_season.value n = int(n) if (zone == 'All') & (season == 'All'): df_temp = df_spawn_end.loc[(df_spawn_end['Year_start'] >= yr[0]) & (df_spawn_end['Year_start'] <= yr[1])] elif (zone != 'All') & (season == 'All'): df_temp = df_spawn_end.loc[(df_spawn_end.Zones_start == zone) & (df_spawn_end['Year_start'] >= yr[0]) & (df_spawn_end['Year_start'] <= yr[1])] elif (zone == 'All') & (season != 'All'): df_temp = df_spawn_end.loc[(df_spawn_end.Season_start == season) & (df_spawn_end['Year_start'] >= yr[0]) & (df_spawn_end['Year_start'] <= yr[1])] else: df_temp = df_spawn_end.loc[(df_spawn_end.Zones_start == zone) & (df_spawn_end.Season_start == season) & (df_spawn_end['Year_start'] >= yr[0]) & (df_spawn_end['Year_start'] <= yr[1])] if n == -1: source.data = ColumnDataSource.from_df(df_temp) else: if n > len(df_temp): # For cases where there are not enough data points n = int(len(df_temp)) np.random.seed(42) select_list = list(np.random.choice(df_temp.index, size=n, replace=False)) filtr = df_temp.index.map(lambda x: x in select_list) source.data = ColumnDataSource.from_df(df_temp.loc[filtr]) def season_active(atrr, old, new): active = toggle_season.active dist = toggle_dist_season.active if not active: c4.visible, s2.visible = False, False toggle_season.label = "Show end points" else: c4.visible, s2.visible = True, True toggle_season.label = "Show end points" if not dist: c3.visible, d2.visible = True, False toggle_dist_season.label = "Show distance traveled" else: c3.visible, d2.visible = False, True toggle_dist_season.label = "Unshow distance traveled" select_number_season.on_change('value', update_map_season) slider_year_season.on_change('value', update_map_season) select_season.on_change('value', update_map_season) select_zone_season.on_change('value', update_map_season) toggle_season.on_change('active', season_active) toggle_dist_season.on_change('active', season_active) # Make second tab tab_season = Panel(child=column(row(column(slider_year_season, select_number_season, select_season, select_zone_season,toggle_season, toggle_dist_season), p_season, add_paragraph), data_table), title="Seasonal") # ---------------------------------------------------------------------------- # FINAL SET UP # ---------------------------------------------------------------------------- tabs = Tabs(tabs=[tab_month, tab_season]) def tab_change(atrr, old, new): if tabs.active == 0: update_map_se('', '', '') else: update_map_season('', '', '') tabs.on_change('active', tab_change) # Make document doc.add_root(tabs) doc.title = 'Hurricanes' doc.theme = Theme(filename="theme.yaml")
class SoftFocus(object): """class to view and process bokeh sample data using a bokeh server. When within its parent folder, open your terminal and write: bokeh serve softfocus see module doc """ def __init__(self): # put the controls and the table in a layout and add to the document self.document = curdoc() #following method parses arguments and create the layout # (in self.layout) with the main tab self.create() logger.info('layout created') #add the layout to the document self.document.title = "Soft Focus" self.document.add_root(self.layout) #show main table # self.update() # logger.info('table shown') #add a callback called every hour to delete excessive amount of xlsx # in the /static/uploads folder, where uploads are self.document.add_periodic_callback(self._delete_excess_xlsx,3600000) #variable holding app status self.sel_csv = None#selected row from main table #dicts hold data from all opened tabs self.plot_dfs = dict() def create(self): """parse the bokeh serve arguments then create the main layout To create the main layout, the method _create_folder is called. Other methods could be called depending on the argument if we want to fetch data with different methods, e.g. _create_sql """ if len(sys.argv)>2: print('Syntax for default Bokeh sampledata' ' folder: bokeh serve {}'.format(sys.argv[0])) print('Syntax for own folder: bokeh serve' ' {} --args <folder/>'.format(sys.argv[0])) sys.exit(0) elif len(sys.argv)==1: data_dir = os.path.join(CURRENT_DIR,'..','tests') if (not os.path.exists(data_dir) or (len(os.listdir(data_dir))<1) ): logger.info('Creating new test folder...') logger.info('{0}'.format(data_dir)) os.mkdir(data_dir) from create_random import create_random create_random(data_dir) elif len(sys.argv)==2: data_dir = sys.argv[1] if not os.path.isdir(data_dir): print("fpath must be a string indicating" " a directory path") sys.exit(0) #other arguments could be processed to call different methods self._create_folder(data_dir) def _create_folder(self,data_dir): """ create softfocus instance based on folder data """ #list only csv files, populate a dict with general info about the files logger.info('Database in a csv folder: {0}'.format(data_dir)) list_dir = os.listdir(data_dir) csv_dic = {'CSV': [csv for csv in list_dir if csv.endswith('.csv')], 'size (kB)':[], 'last modification':[], 'number of columns':[], } if len(csv_dic)<1: logger.warning("no csv file found in folder. Exit") sys.exit(0) for csv in csv_dic['CSV']: csv_stat = os.stat(os.path.join(data_dir,csv)) csv_dic['size (kB)'].append(csv_stat.st_size/1024) csv_dic['last modification'].append( date.fromtimestamp(csv_stat.st_mtime) ) with open(os.path.join(data_dir,csv),'rb') as f: csv_dic['number of columns'].append( len(f.readline().decode().split(',')) ) #make bokeh source from the dic self.df = pd.DataFrame(csv_dic) self.main_source = ColumnDataSource(self.df) #### some widgets to filter the table #### #date selector last_date = self.df['last modification'].max() first_date = self.df['last modification'].min() if last_date == first_date: last_date = first_date + timedelta(days=1) self.date_slider = DateRangeSlider(title='Start date', start=first_date, end=last_date, value=(first_date,last_date), step=1) self.date_slider.on_change('value', lambda attr, old, new: self.update()) #byte size selection through text input self.size_inputtext = TextInput(title='size in kbytes') self.size_inputtext.value = "fmt: '100' or '10..200'" self.size_inputtext.on_change('value', lambda attr, old, new: self.update()) #filter by file name self.csvname_text = TextInput(title='Testname') self.csvname_text.on_change('value', lambda attr, old, new: self.update()) #button to plot self.plot_button = Button(label="Plot", button_type="success") self.plot_button.on_click(self.add_plot_tab) self.plot_button.disabled = True#active only when csv is selected #make table widget #table formatting columns = [] for c in self.df.columns.tolist(): if c in ['last modification']: columns.append(TableColumn(field=c,title=c, formatter=DateFormatter(format="ISO-8601"))) else: columns.append(TableColumn(field=c,title=c)) self.data_table = DataTable(source=self.main_source, columns=columns, width=800, index_position=None, editable=False, ) self.data_table.source.on_change('selected',self.sel_table) #controls in a box controls = widgetbox(self.date_slider, self.plot_button, self.size_inputtext, self.csvname_text, ) #data table in its own box table = widgetbox(self.data_table) #insert all widgets in a Panel tab1 = Panel(child=row(controls, table),title="CSVs",closable=False) #single tab for now self.tabs = Tabs(tabs=[tab1], sizing_mode = 'stretch_both') #need to add this callback otherwise the table will turn invisible #after coming back to this main tab self.tabs.on_change('active', self.changed_tab_cb) #add a status text above all tabs self.info_text = Div(text='<font color="green">ready.</font>', sizing_mode= "stretch_both", height=25) #main layout self.layout = column([self.info_text,self.tabs]) # main data folder self.data_dir = data_dir def _create_sql(self,fpath=r"sql_db.ini"): """NOT IMPLEMENTED, called to link to an SQL database""" pass def _wait_message_decorator(f): """prints loading status during loading time Add this decorator before any methods used as callbacks This will indicate the user to wait or outputs errors """ #https://stackoverflow.com/questions/1263451/python-decorators-in-classes def wait_please(*args,**kwargs): self = args[0] self.info_text.text = '<font color="orange">loading, please wait...</font>' try: r = f(*args,**kwargs) except: import traceback err, val, tb = sys.exc_info() logger.error(("Unexpected error:{0}\n" "Error value: {1}\n" "Error traceback: {2}\n" "In function {3}").format(err, val, ''.join(traceback.format_tb(tb)), f)) self.info_text.text = ( '<font color="red">' 'Error: {0}' '</font>').format(traceback.format_exception_only(err,val)[0]) return self.info_text.text = '<font color="green">ready.</font>' return r return wait_please def changed_tab_cb(self, attr, old, new): """ Callback called when another tab is selected """ if new ==0:#main tab self.update() #call function when selection on table def sel_table(self, attr, old, new): """ Selection of a cell/row in a tab """ sels = self.data_table.source.selected['1d']['indices'] if sels:#if not empty self.plot_button.disabled = False self.sel_csv = self.main_source.data['CSV'][sels[0]] else: self.sel_csv = None self.plot_button.disabled = True #define callback function to show new table @_wait_message_decorator def update(self, attr=None, old=None, new=None): """ Callback function to show the main table with all tests """ df = self.df filt = ((df['last modification'] >= self.date_slider.value_as_datetime[0]) & (df['last modification'] <= self.date_slider.value_as_datetime[1])) try: szfilt = [int(i) for i in self.size_inputtext.value.split('..')] if len(szfilt)==2: szfilt_max = max(szfilt) szfilt_min = min(szfilt) filt &= ((df['size(kB)'] >= szfilt_min) &(df['size(kB)'] <= szfilt_max)) elif len(szfilt)==1: szfilt = szfilt[0] filt &= (df['size(kB)'] == szfilt) else: self.size_inputtext.value = "fmt: '100' or '98..102'" except: self.size_inputtext.value = "fmt: '100' or '98..102'" try: filt &= df['CSV'].str.contains(self.csvname_text.value,na=False) except: self.csvname_text.value = '' current = df[filt] current = current.fillna('NaN') self.main_source.data = current.to_dict('list') #callback function to add a plot tab @_wait_message_decorator def add_plot_tab(self): """ Callback function to add a new tab with a plot. Each tab is differenciated by its name. The name is the csv file name """ #check if at least one line is selected if not self.sel_csv: self.sel_table(None,None,None) return #plot controls logger.info("adding plot of {0}".format(self.sel_csv)) plot_df = pd.read_csv(os.path.join(self.data_dir, self.sel_csv), parse_dates=True, infer_datetime_format=True) self.plot_dfs[self.sel_csv] = plot_df cols = plot_df.columns.tolist() x_sel = Select(title='X-Axis', value=cols[0], options=cols, name='x_sel') y_sel = Select(title='Y-Axis',value=cols[1],options=cols, name='y_sel') y_sel2 = Select(title='Y-Axis 2',value='None',options=cols+['None'], name='y_sel2') #exit button exit_b = Button(label="Exit", button_type="success") exit_b.on_click(self.remove_current_tab) #download button download_b = Button(label="Download", button_type="success", name='download_b') download_b.on_click(self.download) download_b.tags = [0] #plot button plot_b = Button(label="Plot", button_type="success",name='plot_b') plot_b.on_click(self.update_plot) #text to indicate widgets manipulating the plot only plot_group_text = Div(text='<b>Plot properties</b>') #dummy idea from https://stackoverflow.com/questions/44212250/bokeh-widgets-call-customjs-and-python-callback-for-single-event #the javascript callback is linked to the tag attribute of the download #button (download_b.tag). #To activate the download, download_b.tag needs to change, then #./static/uploads/sessionid_output.xlsx is downloaded, where sessionid #is the id of the current session. JScode_fetch = """ var filename = t.name;//file name on client side var get_path = '/softfocus/static/uploads/';//file path on server side var session_id = t.tags[0]; get_path = get_path.concat(session_id); get_path = get_path.concat('_output.xlsx') filename = filename.concat('.xlsx'); fetch(get_path, {cache: "no-store"}).then(response => response.blob()) .then(blob => { //addresses IE if (navigator.msSaveBlob) { navigator.msSaveBlob(blob, filename); } else { var link = document.createElement("a"); link = document.createElement('a') link.href = URL.createObjectURL(blob); window.open(link.href, '_blank'); link.download = filename link.target = "_blank"; link.style.visibility = 'hidden'; link.dispatchEvent(new MouseEvent('click')) URL.revokeObjectURL(url); } return response.text(); }); """ #plot controls together in a box controls = widgetbox(plot_group_text,x_sel,y_sel,y_sel2,plot_b) #tab panel for this plot, differenciated with its name plot_tab = Panel(child=row(column(controls,download_b,exit_b), Spacer(height=600, width=600) ), title="Plot {}".format(self.sel_csv), closable=True, name=str(self.sel_csv))#name of tab is csv filename session_id= str(self.document.session_context._id) plot_tab.tags = [session_id] download_b.js_on_change('tags',CustomJS(args=dict(t=plot_tab), code=JScode_fetch)) self.tabs.tabs.append(plot_tab) self.create_plot_figure(plot_tab) @_wait_message_decorator def update_plot_source(self, attr=None, old=None, new=None): """ filter source Not implemented yet """ tab_ix = self.tabs.active test = self.tabs.tabs[tab_ix].name source = self.ly[test].data_source pass @_wait_message_decorator def update_plot(self): """ Get active tab then create/update its plot """ tab_ix = self.tabs.active active_tab = self.tabs.tabs[tab_ix] #col of widgets in place 0, plot in place 1 self.create_plot_figure(active_tab) def create_plot_figure(self, active_tab): """ create a new plot and insert it in given tab. """ #find table name of active tab and its bokeh instances test = active_tab.name#contains csv filename x_sel=active_tab.select_one({'name':'x_sel'}) y_sel=active_tab.select_one({'name':'y_sel'}) y_sel2=active_tab.select_one({'name':'y_sel2'}) plot_df = self.plot_dfs[test] source = ColumnDataSource(plot_df) #Replace entirely p with a new plot p = Plot( x_range=DataRange1d(), y_range=DataRange1d(), plot_height=600, plot_width=600, title=Title(text=self.sel_csv), name='plot') p.add_tools(BoxZoomTool(), SaveTool(), ResetTool(), PanTool(), HoverTool(tooltips=[('x','$x'), ('y','$y')])) #see https://bokeh.github.io/blog/2017/7/5/idiomatic_bokeh/ x_axis = LinearAxis( axis_label = x_sel.value, ticker=BasicTicker(desired_num_ticks =10), name='x_axis') y_axis = LinearAxis( axis_label = y_sel.value, ticker=BasicTicker(desired_num_ticks =10), name='y_axis') #primary y-axis ly = p.add_glyph(source, Line(x=x_sel.value, y=y_sel.value, line_width=2, line_color='black'), name = 'ly' ) p.add_layout(x_axis,'below') p.add_layout(y_axis,'left') p.y_range.renderers = [ly] #secondary y-axis if y_sel2.value.strip() != 'None':#secondary y-axis y_axis2 = LinearAxis( axis_label = y_sel2.value, ticker=BasicTicker(desired_num_ticks=10), name='y_axis2', y_range_name='right_axis') p.add_layout(y_axis2,'right') p.extra_y_ranges = {"right_axis": DataRange1d()} ly2 = p.add_glyph(source, Line(x=x_sel.value, y=y_sel2.value, line_width=2, line_color='red'), y_range_name='right_axis', name = 'ly2' ) p.extra_y_ranges['right_axis'].renderers = [ly2] leg_items = [LegendItem(label=y_sel.value, renderers=[ly]), LegendItem(label=y_sel2.value, renderers=[ly2])] else: leg_items = [LegendItem(label=y_sel.value, renderers=[ly])] p.add_layout(Legend(items=leg_items, location='top_right') ) active_tab.child.children[1] = p return p #callback function to remove a tab def remove_current_tab(self): """ Callback function to remove a tab """ tab_ix = self.tabs.active if tab_ix == 0: return#do nothing if main tab where all tests are #self.tabs.tabs.pop(tab_ix) del self.tabs.tabs[tab_ix] @_wait_message_decorator def download(self): tab_ix = self.tabs.active active_tab = self.tabs.tabs[tab_ix] test = self.tabs.tabs[tab_ix].name#contains csv filename download_b = active_tab.select_one({'name':'download_b'}) p=active_tab.select_one({'name':'plot'}) session_id= str(self.document.session_context._id) ly = p.select_one({'name':'ly'}) data = pd.DataFrame(ly.data_source.data) dirpath = os.path.join(os.path.dirname(__file__),'static','uploads') if not os.path.exists(dirpath): os.makedirs(dirpath) xlsxpath = os.path.join(dirpath,session_id+'_output.xlsx') if os.path.exists(xlsxpath): os.remove(xlsxpath) writer = pd.ExcelWriter(xlsxpath, engine='xlsxwriter') logger.info('Test name: {0}'.format(test)) data.to_excel(writer,'data'+test) # infos.to_excel(writer,'info'+infos['Testname']) writer.close() #change tag to activate JS_fetch callback download_b.tags = [download_b.tags[0] + pd.np.random.choice([-1,1],size=1)[0]] # @gen.coroutine def _delete_excess_xlsx(self): """deletes all xlsx files in the upload static folder older than 24h""" dirpath = os.path.join(os.path.dirname(__file__),'static','uploads') now = time.time() for dirpath, dirnames, filenames in os.walk(dirpath,topdown=False): for fname in filenames: fpath = os.path.join(dirpath,fname) file_age = (now - os.path.getatime(fpath))/3600 if ((file_age>24) and fpath.endswith('output.xlsx')): os.remove(fpath)
line_alpha=0.6, legend='fourier series') plot.patch('x_patch', 'y_patch', source=source_interval_patch, alpha=.2) plot.line('x_min', 'y_minmax', source=source_interval_bound) plot.line('x_max', 'y_minmax', source=source_interval_bound) sample_controls = widgetbox(sample_function_type) default_controls = column(default_function_input, default_function_period_start, default_function_period_end) # Panels for sample functions or default functions sample_funs = Panel(child=sample_controls, title='sample function') default_funs = Panel(child=default_controls, title='default function') # Add panels to tabs fun_tabs = Tabs(tabs=[sample_funs, default_funs]) fun_tabs.on_change('active', type_input_change) # add callback for panel tabs # lists all the controls in our app controls = column(degree, fun_tabs) # initialize data function_change() # regularly update user view curdoc().add_periodic_callback(automatic_update, 100) # make layout curdoc().add_root(row(plot, controls, height=600, width=800))
def re_analyze_callback(): re_analyze() # set callbacks top_n_dropdown.on_change("value", top_n_phrases_changed_callback) top_n_clusters_dropdown.on_change("value", top_n_clusters_changed_callback) radio_group_area.on_change("active", selected_graph_changed_callback) # pylint: disable=no-member filter_topics_table_source.selected.on_change("indices", filter_topic_selected_callback) filter_custom_table_source.selected.on_change("indices", filter_custom_selected_callback) search_button.on_click(search_topic_callback) clear_button.on_click(clear_search_callback) filter_tabs.on_change("active", tab_changed_callback) analyse_button.on_click(re_analyze_callback) # start app draw_ui(top_n_dropdown.value, top_n_clusters_dropdown.value, radio_group_area.active) doc = curdoc() main_title = "Trend Analysis" doc.title = main_title doc.add_root(grid)
line_width=3, line_alpha=0.6, legend='fourier series' ) plot.patch('x_patch', 'y_patch', source=source_interval_patch, alpha=.2) plot.line('x_min', 'y_minmax', source=source_interval_bound) plot.line('x_max', 'y_minmax', source=source_interval_bound) sample_controls = widgetbox(sample_function_type) default_controls = column(default_function_input,default_function_period_start,default_function_period_end) # Panels for sample functions or default functions sample_funs = Panel(child=sample_controls, title='sample function') default_funs = Panel(child=default_controls, title='default function') # Add panels to tabs fun_tabs = Tabs(tabs=[sample_funs, default_funs]) fun_tabs.on_change('active', type_input_change) # add callback for panel tabs # lists all the controls in our app controls = column(degree,fun_tabs) # initialize data function_change() # regularly update user view curdoc().add_periodic_callback(automatic_update, 100) # make layout curdoc().add_root(row(plot, controls, height=600, width=800))
draw_block_plot_button = Button(label="Draw block plot", width=200, css_classes=['merge-button']) draw_block_plot_button.on_click(draw_block_plot) bubbles.on_change('value', draw_boxplot) markers.on_change('value', draw_boxplot) mean_or_median.on_change('active', draw_boxplot) layout3 = row(column(bubbles, markers, mean_or_median, filter_box_1, filter_box_2, draw_block_plot_button), column(row(boxplot.create_boxplot(), diff_plot.diff_plot()), block_plot.block_plot())) tab3 = Panel(child=layout3, title="statistics view") # FINAL LAYOUT ------------------------------------------------------------------------------------- FINAL LAYOUT tabs = Tabs(tabs=[tab1, tab2, tab3]) tabs.on_change('active', active_tab) curdoc().add_root(tabs) curdoc().title = "Flowexplore" def load_test_data(): global df_viz global source global populations global clinical_data # #################################################################### coordinates filename = 'coordinates.csv' df = pd.read_csv(join(dirname(__file__), 'data/coordinates.csv')) # if tree_dropdown.value == 'coordinates':