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)
示例#2
0

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")
示例#4
0
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)
示例#5
0
          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))
示例#6
0

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))
示例#8
0
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':