Пример #1
0
    def _init_sample_buttons(self):
        lg.info('-- SET SAMPLE BUTTONS')

        def next_sample():
            lg.info('>> NEXT SAMPLE')
            if self.s < self.ns:
                self.env.doc.hold('collect')
                self.s += 1
                self.sample_div.text = ' {} / {}'.format(self.s, self.ns)
                self.env.cur_nearby_prof = None  # to reset the extra stt profile to plot
                self.env.dt_next_sample = True
                self._update_dt_sample()
                self.env.doc.unhold()

        def previous_sample():
            lg.info('>> PREVIOUS SAMPLE')
            if self.s > 1:
                self.env.doc.hold('collect')
                self.s -= 1
                self.sample_div.text = ' {} / {}'.format(self.s, self.ns)
                self.env.cur_nearby_prof = None
                self.env.dt_previous_sample = True
                self._update_dt_sample()
                self.env.doc.unhold()

        self.next_bt = Button(label=">", button_type="success", width=30)
        self.sample_div = Div(
            text='0 / 0',
            width=100,
            height=30,
            css_classes=['sample_div'],
        )
        self.previous_bt = Button(label="<", button_type="success", width=30)
        self.next_bt.on_click(next_sample)
        self.previous_bt.on_click(previous_sample)
Пример #2
0
    def _init_profile_nav(self):
        def next_profile():
            if self.nearby_prof_cb:
                lg.info('-- NEXT PROFILE')
                s = self.env.stations
                next_pos = s.index(self.env.cur_nearby_prof) + 1
                if next_pos < len(self.env.stations):
                    if s[next_pos] == self.env.stt_to_select:
                        next_pos = next_pos + 1
                if next_pos < len(self.env.stations):
                    self.env.cur_nearby_prof = s[next_pos]
                    self.env.bk_sources._upd_prof_srcs(force_selection=True)
                    self.nearby_prof_div.text = str(
                        int(self.env.cur_nearby_prof))

                    # adjust disabled buttons
                    if next_pos + 1 == len(self.env.stations):
                        self.next_prof_bt.disabled = True
                    self.previous_prof_bt.disabled = False

        def previous_profile():
            lg.info('-- PREVIOUS PROFILE')
            if self.nearby_prof_cb:
                s = self.env.stations
                previous_pos = s.index(self.env.cur_nearby_prof) - 1
                if previous_pos >= 0:
                    if s[previous_pos] == self.env.stt_to_select:
                        previous_pos = previous_pos - 1
                if previous_pos >= 0:
                    self.env.cur_nearby_prof = s[previous_pos]
                    self.env.bk_sources._upd_prof_srcs(force_selection=True)
                    self.nearby_prof_div.text = str(
                        int(self.env.cur_nearby_prof))

                    # adjust disabled buttons
                    if previous_pos == 0:
                        self.previous_prof_bt.disabled = True
                    self.next_prof_bt.disabled = False

        self.next_prof_bt = Button(
            width=30,
            disabled=True,
            label=">",
            button_type="success",
        )
        self.nearby_prof_div = Div(
            width=100,
            height=30,
            text='None',
            css_classes=['cur_stt'],
        )
        self.previous_prof_bt = Button(
            width=30,
            disabled=True,
            label="<",
            button_type="success",
        )
        self.next_prof_bt.on_click(next_profile)
        self.previous_prof_bt.on_click(previous_profile)
Пример #3
0
    def _init_flags_control_header(self):
        lg.info('-- FLAGS CONTROL HEADER')
        self.all_flags_vb_bt = Button(
            name='all_flags_bt',
            label='',
            width=30,
            css_classes=['eye_bt'],
        )

        def all_flags_vb_bt_callback():
            lg.info('-- ALL FLAGS VISIBLE CALLBACK')
            self.env.bk_bridge.call_js({
                'object': 'tools',
                'function': 'show_wait_cursor',
            })
            all_flags_bt = self.env.doc.select_one(dict(name='all_flags_bt'))
            eye_slash_bt = True if 'eye_slash_bt' in all_flags_bt.css_classes else False
            if eye_slash_bt:
                self.env.doc.set_select(selector=dict(tags=['vb_bt']),
                                        updates=dict(css_classes=['eye_bt']))
            else:
                self.env.doc.set_select(
                    selector=dict(tags=['vb_bt']),
                    updates=dict(css_classes=['eye_slash_bt']))

            new_visible_flags = []
            if 'eye_bt' in all_flags_bt.css_classes:
                all_flags_bt.css_classes = ['eye_slash_bt']
            else:
                new_visible_flags = self.all_flags_list
                all_flags_bt.css_classes = ['eye_bt']
            lg.info('>> NEW VISIBLE FLAGS: {}'.format(new_visible_flags))
            self._update_visible_flags(new_visible_flags)
            self.env.bk_bridge.call_js({
                'object': 'tools',
                'function': 'show_default_cursor',
            })

        self.all_flags_vb_bt.on_click(all_flags_vb_bt_callback)

        # TODO: replace this div with the flag selection dropdown
        #       or maybe there would be too many control on one place

        flag_controls_title_div = Div(
            name='flag_controls_title',
            text='All the flags',
            width=100,
            height=25,
            css_classes=['flag_controls_title'],
        )

        self.flags_control_header_row = row(
            children=[self.all_flags_vb_bt, flag_controls_title_div],
            width=200,
            height=25,
        )
Пример #4
0
    def _init_edit_bt(self, flag_index):
        edit_flag_bt = Button(name='edit_flag_bt_{}'.format(flag_index),
                              label='',
                              width=30,
                              tags=['edit_flag_bt'],
                              css_classes=['edit_flag_bt'])

        def update_flag_value_edit_bt(flag_index=flag_index):
            self.update_flag_value(flag_value=flag_index,
                                   flag_to_update=None,
                                   row_indexes=self.env.selection)

        edit_flag_bt.on_click(update_flag_value_edit_bt)
        return edit_flag_bt
Пример #5
0
    def _init_profile_nav(self):
        def next_profile():
            lg.info('-- NEXT PROFILE')
            if self.nearby_prof_cb:
                s = self.nearby_prof_select.options
                next_pos = s.index(f'{self.env.cur_nearby_prof}') + 1
                if next_pos < len(s):
                    self.nearby_prof_select.value = s[next_pos]
                    self.env.cur_nearby_prof = float(s[next_pos])
                    if (self.env.cur_nearby_prof).is_integer():
                        self.env.cur_nearby_prof = int(
                            self.env.cur_nearby_prof)

        def previous_profile():
            lg.info('-- PREVIOUS PROFILE')
            if self.nearby_prof_cb:
                s = self.nearby_prof_select.options
                previous_pos = s.index(f'{self.env.cur_nearby_prof}') - 1
                if previous_pos >= 0:
                    self.nearby_prof_select.value = s[previous_pos]
                    self.env.cur_nearby_prof = float(s[previous_pos])
                    if (self.env.cur_nearby_prof).is_integer():
                        self.env.cur_nearby_prof = int(
                            self.env.cur_nearby_prof)

        self.next_prof_bt = Button(
            width=30,
            disabled=True,
            label=">",
            button_type="success",
        )
        self.nearby_prof_select = Select(
            width=80,
            value=None,
            options=['None'],
            css_classes=['nearby_prof_select'],
            disabled=True,
        )
        self.previous_prof_bt = Button(
            width=30,
            disabled=True,
            label="<",
            button_type="success",
        )
        self.next_prof_bt.on_click(next_profile)
        self.previous_prof_bt.on_click(previous_profile)
Пример #6
0
def init_widgets():
    global widgets
    widgets = WrapBokeh(PAGE_URL, app.logger)

    widgets.add(
        "tin_fname",
        TextInput(title="First Name:",
                  placeholder="first name",
                  css_classes=['tin_fname']))
    widgets.add(
        "tin_lname",
        TextInput(title="Last Name:",
                  placeholder="last name",
                  css_classes=['tin_lname']))
    widgets.add("b_submit", Button(label="Submit", css_classes=['b_submit']))

    countries = [('', 'Select Country')] + [(x, x) for x in geo_info.keys()]
    states = [('', 'Select State')] + [(x, x)
                                       for x in geo_info["United States"]]

    widgets.add(
        "sel_country",
        Select(options=countries,
               value=None,
               title="Select Country",
               css_classes=['sel_country']))
    widgets.add(
        "sel_state",
        Select(options=states,
               value=None,
               title="Select State",
               css_classes=['sel_state']))

    widgets.add(
        "sel_nexturl",
        Select(options=[('99', 'Select Next Page'), ('0', 'Home'),
                        ('1', 'Ajax Stream Example'), ('3', 'Page C'),
                        ('4', 'Page D')],
               value=None,
               title="Select URL",
               css_classes=['sel_nexturl']))

    widgets.init()
Пример #7
0
def index_toolbar_menu(w, doc_layout, args):
    w.add(
        "b_login",
        Button(label="LOGIN",
               width=GUI.TITLEBAR_LOGIN_BTN_WIDTH,
               css_classes=['b_submit']))

    title = app.config["app"]["title"]
    doc_layout.children.append(
        row(Div(text="""<h1>{}</h1>""".format(title),
                width=GUI.TITLEBAR_TITLE_WIDTH),
            Spacer(width=GUI.TITLEBAR_SPACER),
            w.get("b_login"),
            sizing_mode="fixed"))

    w.add_css("b_login",
              {'button': {
                  'background-color': '#98FB98',
                  'min-width': '50px'
              }})
    w.add_css("toolbarclass", {'div': {'background-color': '#5F9EA0'}})
Пример #8
0
def modify_doc(doc):
    """Create and modify the bokeh document. Later run by the tornado
    server."""
    city_1_title = 'Search for the first city'
    city_2_title = 'Search for the second city'
    # Adding selectors, essentially the controls, to the app.
    city_1_select = AutocompleteInput(value=city_1,
                                      completions=cities_list,
                                      min_characters=3,
                                      title=city_1_title)
    city_2_select = AutocompleteInput(value=city_2,
                                      completions=cities_list,
                                      min_characters=3,
                                      title=city_2_title)
    variable_select = Select(value=variable,
                             title='Variable',
                             options=list(variable_dict.keys()))
    method_select = Select(value=method, title='Period', options=methods_list)
    # And a button to toggle display of trend.
    display_trend = Button(label='Display trends',
                           button_type='success',
                           width=50)

    # Initial plot for startup of app.
    plot = create_plot(source_1, source_2, title, variable, trend)

    def trend_update():
        """Custom callback in the event of button changing state."""
        # Make use of global variables.
        global trend, source_1, source_2, title, variable
        # Switch state of trend(bool)
        trend = not trend
        if trend:
            display_trend.label = 'Hide trends'
        else:
            display_trend.label = 'Show trends'
        layout.children[1] = create_plot(source_1, source_2, title, variable,
                                         trend)

    def update_plot(attrname, old, new):
        """This is called when any of the widgets are changed, updates the
        plot"""
        # Need to access the value of the global variables.
        global city_1, city_2, source_1, source_2, title, variable, method
        # Get the new value of cities and variable.
        city_1 = city_1_select.value
        city_2 = city_2_select.value
        variable = variable_select.value
        method = method_select.value
        # Set new title of plot based on new variables.
        title = (method + ' ' + variable.lower() + ' data from ' + city_1 +
                 ' and ' + city_2 + '.')
        # Get new source data based on the new parameters.
        source_1 = get_data(city_1, variable, method)
        source_2 = get_data(city_2, variable, method)
        # This is what is actually updating the plot, the plot is the second
        # child of the layout.
        layout.children[1] = create_plot(source_1, source_2, title, variable,
                                         trend)

    # Looping through all the selectors to detect changes.
    control_list = [
        city_1_select, city_2_select, variable_select, method_select
    ]
    for w in control_list:
        w.on_change('value', update_plot)
    # Need to treat button differently.
    display_trend.on_click(trend_update)
    # Title displayed on page.
    text = ('<font size="5">Welcome to the climtrend visualization tool.'
            ' Compare the climate in two cities by using the controls'
            ' below.</font>')
    p = Div(text=text, width=300, height=200)
    controls = column(p, city_1_select, city_2_select, variable_select,
                      method_select, display_trend)
    # Add the controls of the app and the plot to the first row of the layout.
    layout = row(controls, plot)
    doc.add_root(layout)
    doc.title = 'ClimTrend'
Пример #9
0
labeling_input = widgetbox(labeling_x_mu, labeling_y_mu, labeling_x_var,
                           labeling_y_var, labeling_thr)
inputs = [hijacking_input, good_user_input, labeling_input]

# Plot the ROC curve

roc_source = ColumnDataSource(data=dict(x=[], y=[]))


def train_and_evaluate():
    global hijackers, good_users, labeling, roc_source
    fpr, tpr = calculate_roc(hijackers, good_users, labeling)
    roc_source.data = dict(x=fpr, y=tpr)


train_and_evaluate()
roc = figure(title='RoC', x_axis_label='False positive rate',
             y_axis_label='True Positive Rate', x_range=(0, 1), y_range=(0, 1),
             width=1000)
roc.line([0, 1], [0, 1], color='navy', line_width=1.0, line_dash='dashed')
roc.line(x='x', y='y', source=roc_source, color='darkorange', line_width=1.0,
         line_dash='dashed')

button = Button(label='Calculate ROC')
button.on_click(train_and_evaluate)

# Add the simulation and ROC curve to DOM.

curdoc().add_root(column(row(space_plot, *inputs), row(roc, widgetbox(button))))
curdoc().title = 'Recall vs accuracy trade-off'
Пример #10
0
gms=MultiSelect(title='Select genus',\
                options=[x[0] for x in collections.Counter(ptree.leaf_cds.data['genus']).most_common()],\
                width=200,height=70)
gms.on_change('value',lambda attr,old,new:gmsfunc())

kms=MultiSelect(title='Kingdom',\
                options=[x[0] for x in collections.Counter(ptree.leaf_cds.data['superkingdom']).most_common()],\
                width=200,height=70)
kms.on_change('value',lambda attr,old,new:kmsfunc())

sfms=MultiSelect(title='Subfams',\
                options=[x[0] for x in collections.Counter(ptree.leaf_cds.data['subfamstr']).most_common()],\
                width=150,height=70)
sfms.on_change('value',lambda attr,old,new:sfmsfunc())

tcb=Button(label='CalcTC',width=80,height=40)
tcb.on_click(tcbfunc)
#splist=list(set(ptree.leaf_cds.data['species']))
#splist.sorted(key=ptree.leaf_cds.data['species'])
#acw=AutocompleteInput(title='Organism name',completions=list(set(ptree.leaf_cds.data['species'])),width=200,height=50)
acw=AutocompleteInput(title='Organism name',\
    completions=[x[0] for x in collections.Counter(ptree.leaf_cds.data['species']).most_common()],\
    width=200,height=50)
acw.on_change('value',lambda attr,old,new:acfunc())

accacw=AutocompleteInput(title='Accession',\
    completions=ptree.leaf_cds.data['gbacc'][:],width=200,height=50)
accacw.on_change('value',lambda attr,old,new:accacfunc())


if len(sys.argv)>3:
Пример #11
0
## there is a bug in bokeh image_rgba to be used later that requires the following flipping
## https://github.com/bokeh/bokeh/issues/1666
logo = logo[::-1]
plogo = figure(x_range=(0, 25),
               y_range=(0, 15),
               tools=[],
               plot_width=333,
               plot_height=250)
plogo.xgrid.grid_line_color = None
plogo.ygrid.grid_line_color = None
plogo.image_rgba(image=[logo], x=[0], y=[0], dw=[25], dh=[15])
plogo.xaxis.visible = False
plogo.yaxis.visible = False

div1 = Div(
    text=
    """<font size=6><b><h>EuroLeague in a Spreadsheet</b></h></font></br></br><font size=5>With COVID-19 hitting sports hard - just as with everything else - spreadsheets finally get the position they deserve in sports. Euroleague was suspended before the regular season ended. Simulate the rest of the regular season and the playoffs to get your sports fix <br><br>Basketball Guru (@wiseballsguru), K. Pelechrinis (@kpelechrinis). </font><br></br></br><br></br></br>""",
    width=800,
    height=250)

button = Button(label="Simulate", button_type="success", width=250)
button.on_click(sim_callback)

div2 = Div(text="""""", width=350)
div3 = Div(text="""""", width=100)

#layout = layout([[div1,],[button,],[table_standings,table_playoffs]])
layout = (column(row(div1, div3, plogo), row(button),
                 row(table_standings, div2, table_playoffs)))
curdoc().add_root(layout)
def login_signup():

    w = WrapBokeh(PAGE_URL, logger)

    w.add(
        "tin_fname",
        TextInput(title="First Name:",
                  placeholder="",
                  css_classes=['tin_fname']))
    w.add(
        "tin_lname",
        TextInput(title="Last Name:",
                  placeholder="",
                  css_classes=['tin_lname']))
    w.add(
        "tin_uname",
        TextInput(title="User Name:",
                  placeholder="",
                  css_classes=['tin_uname']))
    w.add(
        "tin_lpw",
        PasswordInput(title="Password:"******"",
                      css_classes=['tin_lpw']))
    w.add(
        "tin_lpw_confirm",
        PasswordInput(title="Confirm Password:"******"",
                      css_classes=['tin_lpw_confirm']))
    w.add("tin_email",
          TextInput(title="Email:", placeholder="", css_classes=['tin_email']))
    w.add("b_submit", Button(label="Submit", css_classes=['b_submit']))

    w.init()

    # Create a dominate document, see https://github.com/Knio/dominate
    # this line should go after any "return redirect" statements
    w.dominate_document()
    url_page_css(w.dom_doc, PAGE_URL)

    args, _redirect_page_metrics = w.process_req(request)
    if not args: return _redirect_page_metrics
    logger.info("{} : args {}".format(PAGE_URL, args))

    redir, url = index_menu_redirect(args)
    if redir: return redirect(url)

    error_fields = {}
    submitted = args.get("b_submit", False)
    if submitted:
        validated, error_fields = User.validate(args)

    # on submit, validate form contents, show errors...
    if submitted and validated:
        logger.info("validated: {}".format(args))
        User.add(first=args["tin_fname"],
                 last=args["tin_lname"],
                 username=args["tin_uname"],
                 password=args["tin_lpw"],
                 email=args["tin_email"])
        return redirect(COMMON_URL_INDEX)

    doc_layout = layout(sizing_mode='scale_width')
    index_toolbar_menu(w, doc_layout, args)

    # show error fields... if any
    if submitted and not validated:
        for key, value in error_fields.items():
            error = User.get_form_error_handle_from_err(
                key, value[0])  # process first error only
            w.add_css(key, error["css"])
            w.get(key).title = error.get('msg', "!NO MSG!")

    w.add_css("tin_fname", {'input': {'width': '90%'}})
    w.add_css("tin_lname", {'input': {'width': '90%'}})
    w.add_css("tin_uname", {'input': {'width': '90%'}})
    w.add_css("tin_lpw", {'input': {'width': '90%'}})
    w.add_css("tin_lpw_confirm", {'input': {'width': '90%'}})
    w.add_css("tin_email", {'input': {'width': '90%'}})

    wbox = widgetbox(w.get("tin_fname"), w.get("tin_lname"),
                     w.get("tin_uname"), w.get("tin_lpw"),
                     w.get("tin_lpw_confirm"), w.get("tin_email"),
                     w.get("b_submit"))
    left_margin = int(int(args.get("windowWidth", 800)) * 0.2)
    doc_layout.children.append(row([Spacer(width=left_margin), wbox]))

    return w.render(doc_layout)
Пример #13
0
    plot.children[1] = column(create_plots(Estimators))

#lowecase innerscope variables
variable1, variable2 = Variable1, Variable2

#Create the widgets
drop1 = Select(title="Variable 1",
               options=list(X.columns.values),
               value=variable1)

drop2 = Select(title="Variable 2",
               options=list(X.columns.values),
               value=variable2)

drop3 = Select(title="variable 3", options=list(X.columns.values), value=y)

estimator_names = [str(estimator).split("(")[0] for estimator in Estimators]
estimator_indices = [str(i) for i, name in enumerate(estimator_names)]
estimator_select = MultiSelect(title="Estimators",
                               options=estimator_names,
                               value=estimator_names[0:5])

button = Button(label="Update", button_type="success")
button.on_click(update)

plot = row(widgetbox(drop1, drop2, drop3, estimator_select, button),
           column(create_plots(Estimators)))

curdoc().add_root(plot)
curdoc().title = "Wage Data Visualisation"
Пример #14
0
def common__account_add():

    # TODO: This needs to be a decorator
    if not session.get('user_id', False): return redirect(COMMON_URL_LOGIN)
    user = User.get_by_id(session['user_id'])
    if user is None or not RolesUsers.user_has_role(user,
                                                    ["ADMIN", "ADD-USER"]):
        # this should never happen... logout if it does...
        logger.error("Unable to find user id {}".format(session['user_id']))
        session.pop('user_id', None)
        redirect(COMMON_URL_INDEX)

    w = WrapBokeh(PAGE_URL, logger)

    w.add(
        "tin_fname",
        TextInput(title="First Name:",
                  placeholder="",
                  css_classes=['tin_fname']))
    w.add(
        "tin_lname",
        TextInput(title="Last Name:",
                  placeholder="",
                  css_classes=['tin_lname']))
    w.add(
        "tin_uname",
        TextInput(title="User Name:",
                  placeholder="",
                  css_classes=['tin_uname']))
    w.add(
        "tin_lpw",
        PasswordInput(title="Password:"******"",
                      css_classes=['tin_lpw']))
    w.add(
        "tin_lpw_confirm",
        PasswordInput(title="Confirm Password:"******"",
                      css_classes=['tin_lpw_confirm']))
    w.add("tin_email",
          TextInput(title="Email:", placeholder="", css_classes=['tin_email']))
    w.add("b_submit", Button(label="Submit", css_classes=['b_submit']))

    w.init()

    # Create a dominate document, see https://github.com/Knio/dominate
    # this line should go after any "return redirect" statements
    w.dominate_document()
    url_page_css(w.dom_doc, PAGE_URL)

    args, _redirect_page_metrics = w.process_req(request)
    if not args: return _redirect_page_metrics
    logger.info("{} : args {}".format(PAGE_URL, args))

    redir, url = toolbar_menu_redirect(args)
    if redir: return redirect(url)

    error_fields = {}
    submitted = args.get("b_submit", False)
    if submitted:
        validated, error_fields = User.validate(args)

    # on submit, validate form contents, show errors...
    if submitted and validated:
        logger.info("validated: {}".format(args))
        User.add(first=args["tin_fname"],
                 last=args["tin_lname"],
                 username=args["tin_uname"],
                 password=args["tin_lpw"],
                 email=args["tin_email"])
        return redirect(COMMON_URL_ACCOUNT_ADD)

    doc_layout = layout(sizing_mode='scale_width')
    page_toolbar_menu(w, doc_layout, args, user)

    # show error fields... if any
    if submitted and not validated:
        for key, value in error_fields.items():
            error = User.get_form_error_handle_from_err(
                key, value[0])  # process first error only
            w.add_css(key, error["css"])
            w.get(key).title = error.get('msg', "!NO MSG!")

    w.add_css("tin_fname", {'input': {'width': '90%'}})
    w.add_css("tin_lname", {'input': {'width': '90%'}})
    w.add_css("tin_uname", {'input': {'width': '90%'}})
    w.add_css("tin_lpw", {'input': {'width': '90%'}})
    w.add_css("tin_lpw_confirm", {'input': {'width': '90%'}})
    w.add_css("tin_email", {'input': {'width': '90%'}})

    wbox = widgetbox(w.get("tin_fname"), w.get("tin_lname"),
                     w.get("tin_uname"), w.get("tin_lpw"),
                     w.get("tin_lpw_confirm"), w.get("tin_email"),
                     w.get("b_submit"))
    left_margin = int(int(args.get("windowWidth", 800)) * 0.2)
    doc_layout.children.append(row([Spacer(width=left_margin), wbox]))

    return w.render(doc_layout)
Пример #15
0
    def _init_flags_control_table(self):
        ''' Reminder:
                self.env.all_flags = {
                    2: 'FLAG 2',
                    3: 'FLAG 3',
                    ...
                }
        '''
        lg.info('-- INIT FLAGS CONTROL TABLE')
        # lg.info('-- ALL FLAGS DICTIONARY: {}'.format(self.env.all_flags))

        for flag_index, str_value in self.env.all_flags.items():

            def change_flag_vb(flag_index=flag_index):
                self.env.bk_bridge.call_js({
                    'object': 'tools',
                    'function': 'show_wait_cursor',
                })
                vb_bt_to_change = self.env.doc.select_one(
                    dict(name='flag_vb_bt_{}'.format(flag_index)))
                lg.info('>> CHANGING VISIBILITY: {}'.format(
                    'flag_vb_bt_{}'.format(flag_index)))

                new_visible_flags = self.env.visible_flags.copy()
                if 'eye_bt' in vb_bt_to_change.css_classes:
                    new_visible_flags.remove(flag_index)
                    vb_bt_to_change.css_classes = ['eye_slash_bt']
                else:
                    new_visible_flags.append(flag_index)
                    vb_bt_to_change.css_classes = ['eye_bt']
                self._update_visible_flags(new_visible_flags)
                self.env.bk_bridge.call_js({
                    'object': 'tools',
                    'function': 'show_default_cursor',
                })

            vb_bt = Button(
                name='flag_vb_bt_{}'.format(flag_index),
                label='',
                width=30,
                tags=['vb_bt'],
                css_classes=['eye_bt'],
            )
            vb_bt.on_click(change_flag_vb)

            edit_flag_bt = self._init_edit_bt(flag_index)

            fg_str_div = Div(name='fg_str_div_{}'.format(flag_index),
                             text='{}'.format(str_value),
                             width=100,
                             height=25,
                             tags=['fg_str_div'],
                             css_classes=['fg_str_div'],
                             style={
                                 'color': CIRCLE_COLORS[flag_index],
                                 'font-weight': 'bold',
                             })

            flag_row = row(
                name='flag_row_{}'.format(flag_index),
                children=[vb_bt, edit_flag_bt, fg_str_div],
                width=200,
                height=25,
            )

            # self.env.flag_vb_bts.append(vb_bt)
            self.flag_rows.append(flag_row)

        self.env.flags_control_col = column(
            name='flags_control_col',
            children=[self.flags_control_header_row] + self.flag_rows,
            css_classes=['flags_control_col'],
        )
Пример #16
0
class BokehFlags(Environment):
    ''' Class to manage Flag Controls and its Events
    '''
    env = Environment

    @property
    def all_flags_list(self):
        # NOTE: current available flags on the CDS plus flags with 0 elements
        return sorted([i for i, fg_str in self.env.all_flags.items()])

        # TODO: If you want to assign a new flag value out of this list,
        #       a mechanism to add a new value should be added

    def __init__(self, **kwargs):
        self.env.bk_flags = self
        self.env.visible_flags = self.all_flags_list
        self.all_flags_vb_bt = None
        self.flags_control_header_row = None
        self.flag_rows = []

        self._init_flagger_select()
        self._init_flags_control_header()
        self._init_flags_control_table()

    def _init_flagger_select(self):
        lg.info('-- INIT FLAGGER SELECT')
        options = self.env.cruise_data.get_cols_by_type(
            ['param_flag', 'qc_param_flag'])
        options = sorted(options)
        self.env.flagger_select = Select(
            value=self.env.cur_flag,
            options=options,
            css_classes=['flagger_select'],
        )

        def update_select_flag_value(attr, old, new):
            lg.info('-- SELECT VALUE | OLD: {} | NEW: {}'.format(old, new))
            self.env.cur_flag = new
            if self.env.tab_change:
                self.env.tab_change = False
            else:
                lg.info('-- SELECT CHANGE')
                self.env.bk_bridge.call_js({
                    'object': 'tools',
                    'function': 'show_wait_cursor',
                })
                self.env.tabs_flags_plots[self.env.cur_tab]['flag'] = new

                # TODO: replot of all the colors of the tab
                #       some of the glyphs could be invisible
                #       only an indices update is needed

                cur_plot_list = self.env.tabs_flags_plots[
                    self.env.cur_tab]['plots']
                self.env.doc.hold('collect')
                self.env.bk_plots_handler.replot_color_circles(
                    only_cur_tab=True)
                self.env.bk_sources._upd_prof_srcs(
                )  # TODO: keep the selection as it is >> keep_selection = True
                #       I do this here because some point could be invisible for
                #       other tab
                self.env.doc.unhold()
                self.env.bk_bridge.call_js({
                    'object': 'tools',
                    'function': 'show_default_cursor',
                })

        self.env.flagger_select.on_change('value', update_select_flag_value)

    def _init_flags_control_header(self):
        lg.info('-- FLAGS CONTROL HEADER')
        self.all_flags_vb_bt = Button(
            name='all_flags_bt',
            label='',
            width=30,
            css_classes=['eye_bt'],
        )

        def all_flags_vb_bt_callback():
            lg.info('-- ALL FLAGS VISIBLE CALLBACK')
            self.env.bk_bridge.call_js({
                'object': 'tools',
                'function': 'show_wait_cursor',
            })
            all_flags_bt = self.env.doc.select_one(dict(name='all_flags_bt'))
            eye_slash_bt = True if 'eye_slash_bt' in all_flags_bt.css_classes else False
            if eye_slash_bt:
                self.env.doc.set_select(selector=dict(tags=['vb_bt']),
                                        updates=dict(css_classes=['eye_bt']))
            else:
                self.env.doc.set_select(
                    selector=dict(tags=['vb_bt']),
                    updates=dict(css_classes=['eye_slash_bt']))

            new_visible_flags = []
            if 'eye_bt' in all_flags_bt.css_classes:
                all_flags_bt.css_classes = ['eye_slash_bt']
            else:
                new_visible_flags = self.all_flags_list
                all_flags_bt.css_classes = ['eye_bt']
            lg.info('>> NEW VISIBLE FLAGS: {}'.format(new_visible_flags))
            self._update_visible_flags(new_visible_flags)
            self.env.bk_bridge.call_js({
                'object': 'tools',
                'function': 'show_default_cursor',
            })

        self.all_flags_vb_bt.on_click(all_flags_vb_bt_callback)

        # TODO: replace this div with the flag selection dropdown
        #       or maybe there would be too many control on one place

        flag_controls_title_div = Div(
            name='flag_controls_title',
            text='All the flags',
            width=100,
            height=25,
            css_classes=['flag_controls_title'],
        )

        self.flags_control_header_row = row(
            children=[self.all_flags_vb_bt, flag_controls_title_div],
            width=200,
            height=25,
        )

    def _init_flags_control_table(self):
        ''' Reminder:
                self.env.all_flags = {
                    2: 'FLAG 2',
                    3: 'FLAG 3',
                    ...
                }
        '''
        lg.info('-- INIT FLAGS CONTROL TABLE')
        # lg.info('-- ALL FLAGS DICTIONARY: {}'.format(self.env.all_flags))

        for flag_index, str_value in self.env.all_flags.items():

            def change_flag_vb(flag_index=flag_index):
                self.env.bk_bridge.call_js({
                    'object': 'tools',
                    'function': 'show_wait_cursor',
                })
                vb_bt_to_change = self.env.doc.select_one(
                    dict(name='flag_vb_bt_{}'.format(flag_index)))
                lg.info('>> CHANGING VISIBILITY: {}'.format(
                    'flag_vb_bt_{}'.format(flag_index)))

                new_visible_flags = self.env.visible_flags.copy()
                if 'eye_bt' in vb_bt_to_change.css_classes:
                    new_visible_flags.remove(flag_index)
                    vb_bt_to_change.css_classes = ['eye_slash_bt']
                else:
                    new_visible_flags.append(flag_index)
                    vb_bt_to_change.css_classes = ['eye_bt']
                self._update_visible_flags(new_visible_flags)
                self.env.bk_bridge.call_js({
                    'object': 'tools',
                    'function': 'show_default_cursor',
                })

            vb_bt = Button(
                name='flag_vb_bt_{}'.format(flag_index),
                label='',
                width=30,
                tags=['vb_bt'],
                css_classes=['eye_bt'],
            )
            vb_bt.on_click(change_flag_vb)

            edit_flag_bt = self._init_edit_bt(flag_index)

            fg_str_div = Div(name='fg_str_div_{}'.format(flag_index),
                             text='{}'.format(str_value),
                             width=100,
                             height=25,
                             tags=['fg_str_div'],
                             css_classes=['fg_str_div'],
                             style={
                                 'color': CIRCLE_COLORS[flag_index],
                                 'font-weight': 'bold',
                             })

            flag_row = row(
                name='flag_row_{}'.format(flag_index),
                children=[vb_bt, edit_flag_bt, fg_str_div],
                width=200,
                height=25,
            )

            # self.env.flag_vb_bts.append(vb_bt)
            self.flag_rows.append(flag_row)

        self.env.flags_control_col = column(
            name='flags_control_col',
            children=[self.flags_control_header_row] + self.flag_rows,
            css_classes=['flags_control_col'],
        )

    def _init_edit_bt(self, flag_index):
        edit_flag_bt = Button(name='edit_flag_bt_{}'.format(flag_index),
                              label='',
                              width=30,
                              tags=['edit_flag_bt'],
                              css_classes=['edit_flag_bt'])

        def update_flag_value_edit_bt(flag_index=flag_index):
            self.update_flag_value(flag_value=flag_index,
                                   flag_to_update=None,
                                   row_indexes=self.env.selection)

        edit_flag_bt.on_click(update_flag_value_edit_bt)
        return edit_flag_bt

    def update_flag_value(self,
                          flag_value=None,
                          flag_to_update=None,
                          row_indexes=[]):
        lg.info('-- UPDATE FLAG VALUE')
        self.env.bk_bridge.call_js({
            'object': 'tools',
            'function': 'show_wait_cursor',
        })
        if flag_value is None:
            lg.error(
                '>> An empty flag value got to `self.env.bk_flags.update_flag_value()`'
            )
        if flag_to_update is None:
            flag_to_update = self.env.cur_flag
        if row_indexes == []:
            lg.error('>> NO row_indexes selected')

        self.env.cruise_data.update_flag_values(
            column=flag_to_update,
            new_flag_value=flag_value,
            row_indices=row_indexes,
        )
        new_values = np.array(self.env.source.data[flag_to_update],
                              dtype=int)  # TODO: Int8 or Int64
        new_values[row_indexes] = flag_value
        self.env.source.data[flag_to_update] = new_values
        self.env.bk_sources.cds_df[flag_to_update] = new_values

        # Updating flag colors
        self.env.doc.hold('collect')
        self.env.bk_plots_handler.replot_color_circles()

        # NOTE: update datatable and prof sources is needed because the new flag could be invisible,
        #       then the profiles should be invisible as well
        # self.env.bk_table.update_dt_source()
        self.env.bk_sources._upd_prof_srcs(force_selection=True)

        self.env.doc.unhold()

        self.env.bk_bridge.call_js({
            'object': 'tools',
            'function': 'show_default_cursor',
        })
        self.env.bk_bridge.call_js({
            'object':
            'tools',
            'function':
            'show_snackbar',
            'params': [
                '{} values of {} updated with the flag value {}'.format(
                    len(row_indexes),
                    flag_to_update,
                    flag_value,
                )
            ],
        })

    def _update_visible_flags(self, to_visible_flags=[]):
        ''' Makes visible the flags passed as argument, and make invisible the rest
                @to_visible_flags: all the visible (or to make visible) flags indices
        '''
        lg.info('-- UPDATE VISIBLE FLAGS')

        to_visible = []
        to_invisible = []
        for flag_index, flag_str in self.env.all_flags.items():
            if flag_index in self.env.visible_flags and flag_index not in to_visible_flags:
                to_invisible.append('GR_FLAG_{}'.format(flag_index))
            if flag_index not in self.env.visible_flags and flag_index in to_visible_flags:
                to_visible.append('GR_FLAG_{}'.format(flag_index))

        # lg.info('>> TO VISIBLE FLAGS: {}'.format(to_visible_flags))
        # lg.info('>> TO VISIBLE: {}'.format(to_visible))
        # lg.info('>> TO INVISIBLE: {}'.format(to_invisible))

        self.env.doc.hold('collect')
        if to_visible != []:
            self.env.doc.set_select(selector=dict(tags=to_visible),
                                    updates=dict(visible=True))
        if to_invisible != []:
            self.env.doc.set_select(selector=dict(tags=to_invisible),
                                    updates=dict(visible=False))

        all_flags_bt = self.env.doc.select_one(dict(name='all_flags_bt'))
        if to_visible_flags == []:
            all_flags_bt.css_classes = ['eye_slash_bt']
        else:
            all_flags_bt.css_classes = ['eye_bt']

        self.env.visible_flags = to_visible_flags.copy()
        self.env.bk_sources._upd_prof_srcs(force_selection=True)
        self.env.doc.unhold()

    def reset_all_flags(self):
        lg.info('-- RESET ALL FLAGS')
        if sorted(self.env.visible_flags) != self.all_flags_list:
            self.env.doc.set_select(selector=dict(tags=['vb_bt']),
                                    updates=dict(css_classes=['eye_bt']))

            to_visible = []
            for flag_index, flag_str in self.env.all_flags.items():
                if flag_index not in self.env.visible_flags:
                    to_visible.append('GR_FLAG_{}'.format(flag_index))

            self.env.doc.set_select(selector=dict(tags=to_visible),
                                    updates=dict(visible=True))
            self.env.visible_flags = self.all_flags_list

            all_flags_bt = self.env.doc.select_one(dict(name='all_flags_bt'))
            all_flags_bt.css_classes = ['eye_bt']
Пример #17
0
def roles_edit():
    logger = logging.getLogger("TMI.roles_edit")

    def pop_session():
        session.pop("roles_initial", None)
        session.pop("roles", None)

    # TODO: This needs to be a decorator
    if not session.get('user_id', False): return redirect(COMMON_URL_LOGIN)
    user = User.get_by_id(session['user_id'])
    if user is None or not RolesUsers.user_has_role(user,
                                                    ["EDIT-ROLE", "ADD-USER"]):
        # this should never happen... logout if it does...
        logger.error("Unable to find user id {}".format(session['user_id']))
        session.pop('user_id', None)
        redirect(COMMON_URL_INDEX)

    w = WrapBokeh(PAGE_URL, logger)

    w.add(
        "sel_uname",
        Select(options=[],
               value=None,
               title="Select User",
               css_classes=['sel_uname']))
    w.add("cbg_roles",
          CheckboxGroup(labels=[], active=[], css_classes=['cbg_roles']))
    w.add("b_submit", Button(label="Update", css_classes=['b_submit']))
    w.add("b_cancel", Button(label="Cancel", css_classes=['b_cancel']))

    w.init()

    user = User.get_by_id(session['user_id'])
    if user is None:
        logger.error("Unable to find user id {}".format(session['user_id']))
        session.pop('user_id')
        redirect(COMMON_URL_INDEX)

    # Create a dominate document, see https://github.com/Knio/dominate
    # this line should go after any "return redirect" statements
    w.dominate_document()
    url_page_css(w.dom_doc, PAGE_URL)

    args, _redirect_page_metrics = w.process_req(request)
    if not args: return _redirect_page_metrics
    logger.info("{} : args {}".format(PAGE_URL, args))

    redir, url = toolbar_menu_redirect(args)
    if redir:
        pop_session()
        return redirect(url)

    if args.get("b_cancel", False):
        pop_session()
        return redirect(COMMON_URL_LAND)

    updated = False
    if args.get(
            "b_submit",
            False) and session["roles_initial"] != w.get("cbg_roles").active:
        # need to convert the CheckboxGroup list indexes to Role IDs
        selected_idexes = w.get("cbg_roles").active
        if selected_idexes == [None]: selected_idexes = []
        selected_roles = []
        for idx in selected_idexes:
            selected_roles.append(session["roles"][idx])

        edit_user = User.get_username(w.get("sel_uname").value)
        logger.info("{} updated roles {}".format(edit_user.username,
                                                 selected_roles))
        success = User.update_roles(edit_user.username, selected_roles)
        if success: updated = True

    doc_layout = layout(sizing_mode="fixed")
    page_toolbar_menu(w, doc_layout, args, user)

    # populate users
    all_users = User.get_username(None, all=True)
    sel_users = [("Select", "Select User")]
    for u in all_users:
        if u.username in app.config["app"]["user"]["protected"]: continue
        sel_users.append((u.username, u.username))
    w.get("sel_uname").options = sel_users
    w.get("sel_uname").value = args.get("sel_uname",
                                        None)  # last value or none
    session["roles_initial"] = []

    # new selection was done, update the roles
    if w.get("sel_uname").value not in ['Select', None]:
        edit_user = User.get_username(w.get("sel_uname").value)
        roles = []
        user_ids = []
        session["roles"] = []
        for _id, _name, _desc in Role.get_all():
            session["roles"].append(_name)
            roles.append(_desc)
            if RolesUsers.user_has_role(edit_user, _name):
                user_ids.append(roles.index(_desc))
        w.get("cbg_roles").labels = roles

        w.get("cbg_roles").active = user_ids

        if args['callerWidget'] == 'sel_uname' or updated:
            session["roles_initial"] = w.get("cbg_roles").active

    if args["callerWidget"] == 'cbg_roles':
        if len(args['cbg_roles']) == 0: w.get("cbg_roles").active = []
        else:
            w.get("cbg_roles").active = [
                int(i) for i in args['cbg_roles'].split(",")
            ]

    # change submit button if there is a change in roles
    if session["roles_initial"] == w.get("cbg_roles").active:
        w.add_css(
            "b_submit", {
                'button': {
                    'background-color': GUI.BUTTON_DISABLED_GRAY,
                    'pointer-events': None
                }
            })
    else:
        w.add_css("b_submit",
                  {'button': {
                      'background-color': GUI.BUTTON_ENABLED_GREEN
                  }})

    w.add_css("b_cancel", {'button': {'background-color': GUI.BUTTON_CANCEL}})

    wbox = widgetbox(w.get("sel_uname"), w.get("cbg_roles"), w.get("b_submit"),
                     w.get("b_cancel"))
    left_margin = int(int(args.get("windowWidth", 800)) * 0.2)
    doc_layout.children.append(row([Spacer(width=left_margin), wbox]))

    return w.render(doc_layout)
Пример #18
0
    def visualize(self):
        """
        Generates a plot using bokeh, which displays the initial trajectory and
        the optimized trajectory of the cutting tool.
        """

        # Tools that will be displayed on the plots
        tools = "pan,wheel_zoom,reset,save"

        # Plot displaying the optimized path
        result_plot = figure(plot_width=1000,
                             plot_height=500,
                             tools=tools,
                             active_scroll='wheel_zoom')
        result_plot.title.text = "Optimized Path"

        # Plot displaying the non optimized path
        initial_plot = figure(plot_width=1000,
                              plot_height=500,
                              tools=tools,
                              active_scroll='wheel_zoom')
        initial_plot.title.text = "Initial Path"

        # Add the data to the result plot
        result_plot = self.populate_plot(result_plot, self.result)
        result_plot.legend.location = "bottom_right"

        # Add the data to the initial plot
        initial_plot = self.populate_plot(initial_plot, self.initial)
        initial_plot.legend.location = "bottom_right"

        # Add cutting tool to plots
        # Generate the points on which the triangle should move on
        result_lines_x, result_lines_y = self.generate_tool_path(
            self.result, 1)
        initial_lines_x, initial_lines_y = self.generate_tool_path(
            self.initial, 1)

        # Add cutting tool triangle to optimized path
        result_triangle_position = ColumnDataSource(
            data=dict(x=[result_lines_x[0]], y=[result_lines_y[0]]))
        result_triangle = Triangle(x='x',
                                   y='y',
                                   line_color=Category10_4[3],
                                   line_width=3,
                                   size=20,
                                   fill_alpha=0)
        result_plot.add_glyph(result_triangle_position, result_triangle)

        # Add cutting tool triangle to initial path
        initial_triangle_position = ColumnDataSource(
            data=dict(x=[initial_lines_x[0]], y=[initial_lines_y[0]]))
        initial_triangle = Triangle(x='x',
                                    y='y',
                                    line_color=Category10_4[3],
                                    line_width=3,
                                    size=20,
                                    fill_alpha=0)
        initial_plot.add_glyph(initial_triangle_position, initial_triangle)

        # Add button to start moving the triangle
        button = Button(label='Start')
        result_num_steps = result_lines_x.shape[0]
        initial_num_steps = initial_lines_x.shape[0]
        num_steps = max(result_num_steps, initial_num_steps)

        # JavaScript callback which will be called once the button is pressed
        callback = CustomJS(args=dict(
            result_triangle_position=result_triangle_position,
            result_lines_x=result_lines_x,
            result_lines_y=result_lines_y,
            result_num_steps=result_num_steps,
            initial_triangle_position=initial_triangle_position,
            initial_lines_x=initial_lines_x,
            initial_lines_y=initial_lines_y,
            initial_num_steps=initial_num_steps,
            num_steps=num_steps),
                            code="""
            // Animate optimal path plot
            for(let i = 0; i < num_steps; i += 50) {
                setTimeout(function() {
                    if (i < result_num_steps) {
                        result_triangle_position.data['x'][0] = result_lines_x[i]
                        result_triangle_position.data['y'][0] = result_lines_y[i]
                    }

                    if (i < initial_num_steps) {
                        initial_triangle_position.data['x'][0] = initial_lines_x[i]
                        initial_triangle_position.data['y'][0] = initial_lines_y[i]
                    }

                    result_triangle_position.change.emit()
                    initial_triangle_position.change.emit()

                }, i)
            }
        """)
        # Add callback function to button, which starts the whole animation
        button.js_on_click(callback)

        # Save the plot
        result_plot = row([result_plot, button])
        plot = column([result_plot, initial_plot])
        output_file("visualization.html", title="CNC Path Optimization")
        save(plot)
Пример #19
0
def common__login():

    w = WrapBokeh(PAGE_URL, logger)

    w.add(
        "tin_uname",
        TextInput(title="Login Name:",
                  placeholder="",
                  css_classes=['tin_lname']))
    w.add(
        "tin_lpw",
        PasswordInput(title="Password:"******"",
                      css_classes=['tin_lpw']))
    w.add("b_submit", Button(label="Submit", css_classes=['b_submit']))
    w.add("b_signup", Button(label="Sign Up", css_classes=['b_signup']))
    w.add("b_recover",
          Button(label="Recover Password", css_classes=['b_recover']))

    w.init()

    # Create a dominate document, see https://github.com/Knio/dominate
    # this line should go after any "return redirect" statements
    w.dominate_document(title=session["title"])
    url_page_css(w.dom_doc, PAGE_URL)

    args, _redirect_page_metrics = w.process_req(request)
    if not args: return _redirect_page_metrics
    logger.info("{} : args {}".format(PAGE_URL, args))
    left_margin = int(int(args.get("windowWidth", 800)) * 0.1)

    redir, url = index_menu_redirect(args)
    if redir: return redirect(url)

    if args.get("b_signup", False): return redirect(COMMON_URL_LOGIN_SIGNUP)
    if args.get("b_recover", False): return redirect(COMMON_URL_LOGIN_RECOVER)

    login_failed = False
    if args.get("b_submit", False):
        uname = args.get("tin_uname", None)
        pw = w.get("tin_lpw").value

        if uname is not None and pw is not None:
            user = User.login(uname, pw)
            if user is not None:
                logger.info("{} {}".format(user.username, user.id))
                session['user_id'] = user.id
                login(user.id)
                return redirect(COMMON_URL_LAND)
            else:
                logger.info("Login failed for {}".format(uname))
                login_failed = True

    doc_layout = layout(sizing_mode='scale_width')
    index_toolbar_menu(w, doc_layout, args)

    if login_failed:
        doc_layout.children.append(
            row(
                Spacer(width=left_margin),
                column([
                    Div(text="""<p>Login failed, Recover Password?</p>"""),
                    w.get("b_recover")
                ])))

    w.add_css("b_submit",
              {'button': {
                  'background-color': '#98FB98',
                  'min-width': '60px'
              }})
    w.add_css("b_signup",
              {'button': {
                  'background-color': '#98FB98',
                  'min-width': '60px'
              }})
    w.add_css("tin_uname", {'input': {'width': '90%'}})
    w.add_css("tin_lpw", {'input': {'width': '90%'}})

    if app.config["app"]["user"]["signup_enabled"]:
        wbox = widgetbox(w.get("tin_uname"), w.get("tin_lpw"),
                         w.get("b_submit"), w.get("b_signup"))
    else:
        wbox = widgetbox(w.get("tin_uname"), w.get("tin_lpw"),
                         w.get("b_submit"))

    doc_layout.children.append(row([Spacer(width=left_margin), wbox]))

    return w.render(doc_layout)
Пример #20
0
    def plot(self, pm: PrettyMIDI):
        """
        Plots the pretty midi object as a plot object.

          :param pm: the PrettyMIDI instance to plot
          :return: the bokeh plot layout
        """
        preset = self._preset

        # Calculates the QPM from the MIDI file, might raise exception if confused
        qpm = self._get_qpm(pm)

        # Initialize the tools, those are present on the right hand side
        plot = bokeh.plotting.figure(tools="reset,hover,save,wheel_zoom,pan",
                                     toolbar_location=preset.toolbar_location)

        # Setup the hover and the data dict for bokeh,
        # each property must match a property in the data dict
        plot.select(dict(type=bokeh.models.HoverTool)).tooltips = ({
            "program":
            "@program",
            "pitch":
            "@top",
            "velocity":
            "@velocity",
            "duration":
            "@duration",
            "start_time":
            "@left",
            "end_time":
            "@right"
        })
        data = dict(program=[],
                    top=[],
                    bottom=[],
                    left=[],
                    right=[],
                    duration=[],
                    velocity=[],
                    color=[])

        # Puts the notes in the dict for bokeh and saves first
        # and last note time, bigger and smaller pitch
        pitch_min = None
        pitch_max = None
        first_note_start = None
        last_note_end = None
        index_instrument = 0
        for instrument in pm.instruments:
            for note in instrument.notes:
                pitch_min = min(pitch_min or self._MAX_PITCH, note.pitch)
                pitch_max = max(pitch_max or self._MIN_PITCH, note.pitch)
                color = self._get_color(index_instrument, note)
                note_start = note.start
                note_end = note.start + (note.end - note.start)
                data["program"].append(instrument.program)
                data["top"].append(note.pitch)
                if self._show_velocity:
                    data["bottom"].append(note.pitch + (note.velocity / 127))
                else:
                    data["bottom"].append(note.pitch + 1)
                data["left"].append(note_start)
                data["right"].append(note_end)
                data["duration"].append(note_end - note_start)
                data["velocity"].append(note.velocity)
                data["color"].append(color)
                first_note_start = min(first_note_start or sys.maxsize,
                                       note_start)
                last_note_end = max(last_note_end or 0, note_end)
            index_instrument = index_instrument + 1

        # Shows an empty plot even if there are no notes
        if first_note_start is None or last_note_end is None or pitch_min is None or pitch_max is None:
            pitch_min = self._MIN_PITCH
            pitch_max = pitch_min + 5
            first_note_start = 0
            last_note_end = 0

        # Gets the pitch range (min, max) from either the provided arguments
        # or min and max values from the notes
        if self._plot_pitch_range_start is not None:
            pitch_min = self._plot_pitch_range_start
        else:
            pitch_min = min(self._MAX_PITCH, pitch_min)
        if self._plot_pitch_range_stop is not None:
            pitch_max = self._plot_pitch_range_stop
        else:
            pitch_max = max(self._MIN_PITCH, pitch_max)

        pitch_range = pitch_max + 1 - pitch_min

        # Draws the rectangles on the plot from the data
        source = ColumnDataSource(data=data)
        plot.quad(left="left",
                  right="right",
                  top="top",
                  bottom="bottom",
                  line_alpha=1,
                  line_color="black",
                  color="color",
                  source=source)

        # Draws the y grid by hand, because the grid has label on the ticks, but
        # for a plot like this, the labels needs to fit in between the ticks.
        # Also useful to change the background of the grid each line
        for pitch in range(pitch_min, pitch_max + 1):
            # Draws the background box and contours, on the underlay layer, so
            # that the rectangles and over the box annotations
            fill_alpha = (0.15 if pitch % 2 == 0 else 0.00)
            box = BoxAnnotation(bottom=pitch,
                                top=pitch + 1,
                                fill_color="gray",
                                fill_alpha=fill_alpha,
                                line_color="black",
                                line_alpha=0.3,
                                line_width=1,
                                level="underlay")
            plot.add_layout(box)
            label = Label(x=preset.label_y_axis_offset_x,
                          y=pitch + preset.label_y_axis_offset_y,
                          x_units="screen",
                          text=str(pitch),
                          render_mode="css",
                          text_font_size=preset.label_text_font_size,
                          text_font_style=preset.label_text_font_style)
            plot.add_layout(label)

        # Gets the time signature from pretty midi, or 4/4 if none
        if self._midi_time_signature:
            numerator, denominator = self._midi_time_signature.split("/")
            time_signature = TimeSignature(int(numerator), int(denominator), 0)
        else:
            if pm.time_signature_changes:
                if len(pm.time_signature_changes) > 1:
                    raise Exception(
                        "Multiple time signatures are not supported")
                time_signature = pm.time_signature_changes[0]
            else:
                time_signature = TimeSignature(4, 4, 0)

        # Gets seconds per bar and seconds per beat
        if len(pm.get_beats()) >= 2:
            seconds_per_beat = pm.get_beats()[1] - pm.get_beats()[0]
        else:
            seconds_per_beat = 0.5
        if len(pm.get_downbeats()) >= 2:
            seconds_per_bar = pm.get_downbeats()[1] - pm.get_downbeats()[0]
        else:
            seconds_per_bar = 2.0

        # Defines the end time of the plot in seconds
        if self._plot_bar_range_stop is not None:
            plot_end_time = self._plot_bar_range_stop * seconds_per_bar
        else:
            # Calculates the plot start and end time, the start time can start after
            # notes or truncate notes if the plot is too long (we left truncate the
            # plot with the bounds)
            # The plot start and plot end are a multiple of seconds per bar (closest
            # smaller value for the start time, closest higher value for the end time)
            plot_end_time = int(
                (last_note_end) / seconds_per_bar) * seconds_per_bar
            # If the last note end is exactly on a multiple of seconds per bar,
            # we don't start a new one
            is_on_bar = math.isclose(last_note_end % seconds_per_bar,
                                     seconds_per_bar)
            is_on_bar_exact = math.isclose(last_note_end % seconds_per_bar,
                                           0.0)
            if not is_on_bar and not is_on_bar_exact:
                plot_end_time += seconds_per_bar

        # Defines the start time of the plot in seconds
        if self._plot_bar_range_start is not None:
            plot_start_time = self._plot_bar_range_start * seconds_per_bar
        else:
            start_time = int(
                first_note_start / seconds_per_bar) * seconds_per_bar
            plot_max_length_time = self._plot_max_length_bar * seconds_per_bar
            plot_start_time = max(plot_end_time - plot_max_length_time,
                                  start_time)

        # Draws the vertical bar grid, with a different background color
        # for each bar
        if preset.show_bar:
            bar_count = 0
            for bar_time in pm.get_downbeats():
                fill_alpha_index = bar_count % len(self._bar_fill_alphas)
                fill_alpha = self._bar_fill_alphas[fill_alpha_index]
                box = BoxAnnotation(left=bar_time,
                                    right=bar_time + seconds_per_bar,
                                    fill_color="gray",
                                    fill_alpha=fill_alpha,
                                    line_color="black",
                                    line_width=2,
                                    line_alpha=0.5,
                                    level="underlay")
                plot.add_layout(box)
                bar_count += 1

        # Draws the vertical beat grid, those are only grid lines
        if preset.show_beat:
            for beat_time in pm.get_beats():
                box = BoxAnnotation(left=beat_time,
                                    right=beat_time + seconds_per_beat,
                                    fill_color=None,
                                    line_color="black",
                                    line_width=1,
                                    line_alpha=0.4,
                                    level="underlay")
                plot.add_layout(box)

        # Configure x axis
        plot.xaxis.bounds = (plot_start_time, plot_end_time)
        plot.xaxis.axis_label = "time (SEC)"
        plot.xaxis.axis_label_text_font_size = preset.axis_label_text_font_size
        plot.xaxis.ticker = bokeh.models.SingleIntervalTicker(interval=1)
        plot.xaxis.major_tick_line_alpha = 0.9
        plot.xaxis.major_tick_line_width = 1
        plot.xaxis.major_tick_out = preset.axis_x_major_tick_out
        plot.xaxis.minor_tick_line_alpha = 0
        plot.xaxis.major_label_text_font_size = preset.label_text_font_size
        plot.xaxis.major_label_text_font_style = preset.label_text_font_style

        # Configure y axis
        plot.yaxis.bounds = (pitch_min, pitch_max + 1)
        plot.yaxis.axis_label = "pitch (MIDI)"
        plot.yaxis.axis_label_text_font_size = preset.axis_label_text_font_size
        plot.yaxis.ticker = bokeh.models.SingleIntervalTicker(interval=1)
        plot.yaxis.major_label_text_alpha = 0
        plot.yaxis.major_tick_line_alpha = 0.9
        plot.yaxis.major_tick_line_width = 1
        plot.yaxis.major_tick_out = preset.axis_y_major_tick_out
        plot.yaxis.minor_tick_line_alpha = 0
        plot.yaxis.axis_label_standoff = preset.axis_y_label_standoff
        plot.outline_line_width = 1
        plot.outline_line_alpha = 1
        plot.outline_line_color = "black"

        # The x grid is deactivated because is draw by hand (see x grid code)
        plot.xgrid.grid_line_color = None

        # The y grid is deactivated because is draw by hand (see y grid code)
        plot.ygrid.grid_line_color = None

        # Configure the plot size and range
        plot_title_text = "Visual MIDI (%s QPM, %s/%s)" % (str(
            int(qpm)), time_signature.numerator, time_signature.denominator)
        plot.title = Title(text=plot_title_text,
                           text_font_size=preset.title_text_font_size)
        plot.plot_width = preset.plot_width
        if preset.row_height:
            plot.plot_height = pitch_range * preset.row_height
        else:
            plot.plot_height = preset.plot_height
        plot.x_range = Range1d(plot_start_time, plot_end_time)
        plot.y_range = Range1d(pitch_min, pitch_max + 1)
        plot.min_border_right = 50

        if self._live_reload and preset.stop_live_reload_button:
            callback = CustomJS(code="clearInterval(liveReloadInterval)")
            button = Button(label="stop live reload")
            button.js_on_click(callback)
            layout = column(button, plot)
        else:
            layout = column(plot)

        return layout
Пример #21
0
def login_recover():

    w = WrapBokeh(PAGE_URL, logger)

    w.add(
        "tin_uname_only",
        TextInput(title="User Name:",
                  placeholder="",
                  css_classes=['tin_uname_only']))
    w.add(
        "tin_email_only",
        TextInput(title="Email:",
                  placeholder="",
                  css_classes=['tin_email_only']))
    w.add("b_submit", Button(label="Submit", css_classes=['b_submit']))
    w.add("b_ok", Button(label="Ok", css_classes=['b_ok']))

    w.init()

    # Create a dominate document, see https://github.com/Knio/dominate
    # this line should go after any "return redirect" statements
    w.dominate_document()
    url_page_css(w.dom_doc, PAGE_URL)

    args, _redirect_page_metrics = w.process_req(request)
    if not args: return _redirect_page_metrics
    logger.info("{} : args {}".format(PAGE_URL, args))
    left_margin = int(int(args.get("windowWidth", 800)) * 0.2)

    if args.get("b_ok", False): return redirect(COMMON_URL_INDEX)

    redir, url = index_menu_redirect(args)
    if redir: return redirect(url)

    failed_credentials_match = False
    recovery_email_sent = False
    error_fields = {}
    submitted = args.get("b_submit", False)
    if submitted:
        validated, error_fields = User.validate(args)
        if validated:
            # uname, email format is valid, now lets see if it exists
            user = User.get_username(args.get("tin_uname_only"))
            if user in [None, []] or user.email != args.get("tin_email_only"):
                logger.error(
                    "Invalid username/pw ({}/{}) for login recovery".format(
                        user.username, args.get("tin_email_only")))
                failed_credentials_match = True

            if not failed_credentials_match:
                logger.info("user validated, sending recovery email")
                temp_pw = "12345"  # FIXME: make a random password

                # TODO: send email

                User.update(original_username=user.username,
                            first=user.fname,
                            last=user.lname,
                            username=user.username,
                            password=temp_pw,
                            email=user.email)
                recovery_email_sent = True

    doc_layout = layout(sizing_mode='scale_width')
    index_toolbar_menu(w, doc_layout, args)

    doc_layout = layout(sizing_mode='scale_width')

    # show error fields... if any
    if submitted and not validated:
        for key, value in error_fields.items():
            error = User.get_form_error_handle_from_err(
                key, value[0])  # process first error only
            w.add_css(key, error["css"])
            w.get(key).title = error.get('msg', "!NO MSG!")

    if recovery_email_sent:
        doc_layout.children.append(
            row([
                Spacer(width=left_margin),
                Div(text="""<h1>An Email has been sent!</h1>""")
            ]))
        doc_layout.children.append(
            row([Spacer(width=left_margin),
                 w.get("b_ok")]))

    elif failed_credentials_match:
        doc_layout.children.append(
            row([
                Spacer(width=left_margin),
                Div(text=
                    """<h1>Those credentials did not match a known user.</h1>""",
                    height=150)
            ]))
        doc_layout.children.append(
            row([Spacer(width=left_margin),
                 w.get("b_ok")]))

    else:
        w.add_css("tin_uname_only", {'input': {'width': '90%'}})
        w.add_css("tin_email_only", {'input': {'width': '90%'}})

        wbox = widgetbox(w.get("tin_uname_only"), w.get("tin_email_only"),
                         w.get("b_submit"))
        doc_layout.children.append(row([Spacer(width=left_margin), wbox]))

    return w.render(doc_layout)
Пример #22
0
class BokehEvents(Environment):
    ''' Controls and events. The widgets and buttons are created here
        Also some other events and triggers such as update points selections
    '''
    env = Environment

    def __init__(self, **kwargs):
        lg.info('-- INIT BOKEH EVENTS')
        self.env.bk_events = self

        self.env.source.selected.on_change('indices', self._update_selection)
        self.env.wmts_map_source.selected.on_change('indices',
                                                    self._update_map_selection)

        self._init_cb_prof_invsbl_points()
        self._init_profile_nav()
        self._init_nearby_prof_cb()
        self._init_tabs()

    def _update_selection(self, attr, old, new_indices):
        ''' This is run when some elements are selected:
                @attr: 'selected'
                @old: >> does not work well yet with the new Selection class?
                @new: >> new_indices store the new selection indices list
        '''
        lg.info('-- UPDATE SELECTION: {}'.format(new_indices))
        self.env.dt_manual_update = False
        if self.env.selection != new_indices and new_indices != []:
            self.env.selection = new_indices
            self.env.sample_to_select = None  # this is reselected later on `_upd_prof_srcs`
            self.env.stt_to_select = None
            self.env.cur_nearby_prof = None
            self.env.cur_partial_stt_selection = []

            self._update_map_selection_prog(new_indices)
            self.env.bk_table.update_dt_source(
            )  # prof sources is updated inside
            self.env.reset_selection = False
        elif self.env.selection != [] and new_indices == []:
            # NOTE: Keeps the selection when the user click on a space without any sample
            if self.env.reset_selection:
                lg.info('>> RESET SELECTION')
                self.env.selection = []
                self.env.sample_to_select = None  # this is reselected later on `_upd_prof_srcs`
                self.env.stt_to_select = None
                self.env.cur_nearby_prof = None
                self.env.cur_partial_stt_selection = []
                self.env.reset_selection = False
            else:
                lg.info('>> KEEP SELECTION')
                self.env.source.selected.indices = self.env.selection  # keep selection
        self.env.dt_manual_update = True  # reactivate the manual update of the datatable

    def _update_map_selection(self, attr, old, new_indices):
        lg.info('-- UPDATE MAP SELECTION')
        if self.env.map_selection != new_indices and new_indices != []:  # this can be triggered by the user, and programmatically??
            lg.info('>> NEW MAP SELECTION: {}'.format(new_indices))
            self.env.map_selection = new_indices

            # triggers the _update_selection
            # lg.info('>> MAP SOURCE: {}'.format(self.env.wmts_map_source.data))
            selected_stts = list(
                self.env.wmts_map_source.data[STNNBR][new_indices])
            # self.env.cur_partial_stt_selection = selected_stts

            # TODO: how to get all the indices of the current selected stations?? by self.env.cds_df is updated??
            sel_inds = list(self.env.cds_df[self.env.cds_df[STNNBR].isin(
                selected_stts)].index)

            self.env.source.selected.indices = sel_inds
            self._update_selection(
                attr='selected',
                old=None,
                new_indices=self.env.source.selected.
                indices  # I need to trigger this manually as well
            )

        elif self.env.map_selection != [] and new_indices == []:
            if self.env.reset_selection:
                lg.info('>> RESET MAP SELECTION')
                self.env.map_selection = []
                self.env.wmts_map_source.selected.indices = []
            else:
                lg.info('>> KEEP MAP SELECTION')
                self.env.wmts_map_source.selected.indices = self.env.map_selection

    def _update_map_selection_prog(self, new_indices):
        ''' Updates the map selection programmatically with the stations of the selected samples
                @new_indices: list of indices of the selected samples (cds_df)
        '''
        lg.info('-- UPDATE MAP SELECTION PROGRAMMATICALLY')
        if self.env.map_selection != new_indices and new_indices != []:  # this can be triggered by the user, and programmatically??
            stt_to_select = list(self.env.cds_df.loc[new_indices, STNNBR])
            indices_to_select = list(self.env.wmts_map_df[
                self.env.wmts_map_df[STNNBR].isin(stt_to_select)].index)
            self.env.map_selection = indices_to_select
            self.env.wmts_map_source.selected.indices = indices_to_select
        elif self.env.map_selection != [] and new_indices == []:
            if self.env.reset_selection:
                lg.info('>> RESET MAP SELECTION')
                self.env.map_selection = []
                self.env.wmts_map_source.selected.indices = []

    def _init_cb_prof_invsbl_points(self):
        ''' Plot the profiles with the visible points or with the invisible as well
        '''
        def on_click_cb_prof_invsbl_points(active_list):
            if active_list == [0]:
                self.env.plot_prof_invsbl_points = True
            else:
                self.env.plot_prof_invsbl_points = False
            self.env.bk_sources._upd_prof_srcs()

        self.cb_prof_invsbl_points = CheckboxGroup(
            width=200,
            height=10,
            labels=['Fixed profiles'],  # Plot invisible points on profiles
            active=[],
            css_classes=['fixed_profiles_cb', 'bokeh_hidden'])
        self.cb_prof_invsbl_points.on_click(on_click_cb_prof_invsbl_points)

    def _init_profile_nav(self):
        def next_profile():
            if self.nearby_prof_cb:
                lg.info('-- NEXT PROFILE')
                s = self.env.stations
                next_pos = s.index(self.env.cur_nearby_prof) + 1
                if next_pos < len(self.env.stations):
                    if s[next_pos] == self.env.stt_to_select:
                        next_pos = next_pos + 1
                if next_pos < len(self.env.stations):
                    self.env.cur_nearby_prof = s[next_pos]
                    self.env.bk_sources._upd_prof_srcs(force_selection=True)
                    self.nearby_prof_div.text = str(
                        int(self.env.cur_nearby_prof))

                    # adjust disabled buttons
                    if next_pos + 1 == len(self.env.stations):
                        self.next_prof_bt.disabled = True
                    self.previous_prof_bt.disabled = False

        def previous_profile():
            lg.info('-- PREVIOUS PROFILE')
            if self.nearby_prof_cb:
                s = self.env.stations
                previous_pos = s.index(self.env.cur_nearby_prof) - 1
                if previous_pos >= 0:
                    if s[previous_pos] == self.env.stt_to_select:
                        previous_pos = previous_pos - 1
                if previous_pos >= 0:
                    self.env.cur_nearby_prof = s[previous_pos]
                    self.env.bk_sources._upd_prof_srcs(force_selection=True)
                    self.nearby_prof_div.text = str(
                        int(self.env.cur_nearby_prof))

                    # adjust disabled buttons
                    if previous_pos == 0:
                        self.previous_prof_bt.disabled = True
                    self.next_prof_bt.disabled = False

        self.next_prof_bt = Button(
            width=30,
            disabled=True,
            label=">",
            button_type="success",
        )
        self.nearby_prof_div = Div(
            width=100,
            height=30,
            text='None',
            css_classes=['cur_stt'],
        )
        self.previous_prof_bt = Button(
            width=30,
            disabled=True,
            label="<",
            button_type="success",
        )
        self.next_prof_bt.on_click(next_profile)
        self.previous_prof_bt.on_click(previous_profile)

    def _init_nearby_prof_cb(self):
        def on_click_nearby_prof(active_list):
            lg.info('-- ONCLICK NEARBY PROF')
            lg.info('>> SELECTED STT: {}'.format(self.env.stt_to_select))
            if 0 in active_list:
                self.env.plot_nearby_prof = True
                self.set_cur_nearby_prof()
                self.env.bk_sources._upd_prof_srcs(force_selection=True)
            else:
                self.env.plot_nearby_prof = False
                self.next_prof_bt.disabled = True
                self.previous_prof_bt.disabled = True
                self.env.cur_nearby_prof = None
                self.nearby_prof_div.text = 'None'
                self.env.bk_sources._upd_prof_srcs(force_selection=True)

        self.nearby_prof_cb = CheckboxGroup(
            width=200,
            height=20,
            labels=['Show nearby station'],
            active=[],
            css_classes=['show_nearby_station_cb', 'bokeh_hidden'])
        self.nearby_prof_cb.on_click(on_click_nearby_prof)

    def set_cur_nearby_prof(self):
        lg.info('-- SET CUR NEARBY PROF')
        self.next_prof_bt.disabled = False  # TODO: if the database has only one station?
        self.previous_prof_bt.disabled = False

        # NOTE: get the default extra station: the next one if exists
        #       if not, the previous one
        if self.env.stt_to_select is not None:
            next_pos = self.env.stations.index(self.env.stt_to_select) + 1
            if next_pos < len(self.env.stations):
                self.env.cur_nearby_prof = self.env.stations[next_pos]
                self.nearby_prof_div.text = str(int(self.env.cur_nearby_prof))
            else:
                previous_pos = self.env.stations.index(
                    self.env.stt_to_select) - 1
                if previous_pos >= 0:
                    self.env.cur_nearby_prof = self.env.stations[previous_pos]
                    self.nearby_prof_div.text = str(
                        int(self.env.cur_nearby_prof))

    def _init_tabs(self):
        lg.info('-- INIT TABS')
        panel_list = []
        # lg.info('>> self.env.TABS_FLAGS_PLOTS: {}'.format(self.env.tabs_flags_plots))
        SORT_TABS = False
        if SORT_TABS:
            ordered_tab_list = sorted(self.env.tabs_flags_plots)
        else:
            ordered_tab_list = list(self.env.tabs_flags_plots.keys())
        self.env.cur_tab = ordered_tab_list[
            0]  # self.env.cur_tab initialization
        self.env.cur_flag = self.env.cur_tab + FLAG_END  # self.env.cur_tab initialization

        ly_settings = self.env.f_handler.get_layout_settings()
        for tab in ordered_tab_list:
            indices = self.env.tabs_flags_plots[tab]['plots']
            children = [
                x.plot for x in self.env.bk_plots if x.n_plot in indices
            ]
            # lg.info('>> CHILDREN: {}'.format(children))
            gp = gridplot(
                children=children,
                ncols=ly_settings['ncols'],
                plot_width=ly_settings[
                    'plot_width'],  # if 350 then the points are blurred
                plot_height=ly_settings['plot_height'],
                toolbar_location=
                'left',  # TODO: separate the toolbars to set some tools active by default,
                #       like this the hover icon can be shown as well
            )
            name = 'panel_{}'.format(tab.lower())
            panel_list.append(
                Panel(
                    name='panel_{}'.format(tab.lower()),
                    child=gp,
                    title=tab,
                ))  # TODO: closable=True

        lg.info('>> TABS WIDGET: {}'.format(self.env.tabs_widget))
        if self.env.tabs_widget is None:
            self.env.tabs_widget = Tabs(
                name='tabs_widget',
                tabs=panel_list,
                width=1250,
            )
        else:
            self.env.tabs_widget.tabs.clear()
            self.env.tabs_widget.tabs = panel_list

        def update_active_tab(attr, old, new):
            lg.info('-- UPDATE ACTIVE TAB | OLD: {} | NEW: {}'.format(
                old, new))
            self.env.cur_tab = self.env.tabs_widget.tabs[new].title
            lg.info('>> CUR TAB: {}'.format(self.env.cur_tab))
            flag = self.env.tabs_flags_plots[self.env.cur_tab]['flag']
            if self.env.flagger_select.value != flag:
                self.env.tab_change = True
                self.env.flagger_select.value = flag  # if they concide the update of the select is not triggered

        self.env.tabs_widget.on_change('active', update_active_tab)
Пример #23
0
    def _getPlotPanel(self):
        """@brief Add tab that shows plot data updates."""

        self._figTable.append([])
        self._voltsSource = ColumnDataSource({'x': [], 'y': []})
        self._ampsSource = ColumnDataSource({'x': [], 'y': []})
        self._wattsSource = ColumnDataSource({'x': [], 'y': []})
        fig = figure(toolbar_location='above',
                     x_axis_type="datetime",
                     x_axis_location="below")
        fig.line(source=self._voltsSource,
                 line_color="blue",
                 legend_label="Volts")
        fig.line(source=self._ampsSource,
                 line_color="green",
                 legend_label="Amps")
        fig.line(source=self._wattsSource,
                 line_color="red",
                 legend_label="Watts")
        fig.legend.location = 'top_left'
        self._figTable[-1].append(fig)
        self._grid = gridplot(children=self._figTable,
                              sizing_mode='scale_both',
                              toolbar_location='right')

        self.selectSerialPort = Select(title="Serial Port:")
        self.selectSerialPort.options = glob.glob('/dev/ttyU*')

        self.outputVoltageSpinner = Spinner(title="Output Voltage (Volts)",
                                            low=0,
                                            high=40,
                                            step=0.5,
                                            value=self._pconfig.getAttr(
                                                PSUGUI.VOLTS))
        self.currentLimitSpinner = Spinner(title="Currnet Limit (Amps)",
                                           low=0,
                                           high=10,
                                           step=0.25,
                                           value=self._pconfig.getAttr(
                                               PSUGUI.AMPS))
        self.plotHistorySpinner = Spinner(title="Plot History (Seconds)",
                                          low=1,
                                          high=10000,
                                          step=1,
                                          value=self._pconfig.getAttr(
                                              PSUGUI.PLOT_SECONDS))

        self._setButton = Button(label="Set")
        self._setButton.on_click(self._setHandler)
        self._setButton.disabled = True

        self._onButton = Button(label="On")
        self._onButton.on_click(self._psuOnHandler)

        shutdownButtonWrapper = ShutdownButtonWrapper(self._quit)
        controlPanel = column([
            self.selectSerialPort, self._onButton, self.outputVoltageSpinner,
            self.currentLimitSpinner, self._setButton, self.plotHistorySpinner,
            shutdownButtonWrapper.getWidget()
        ])

        self._opTableWrapper = ReadOnlyTableWrapper(("volts", "amps", "watts"),
                                                    heightPolicy="fixed",
                                                    height=65,
                                                    showLastRows=0)

        plotPanel = column([self._grid, self._opTableWrapper.getWidget()])
        panel2 = row([controlPanel, plotPanel])
        plotPanel = column([panel2, self.statusBarWrapper.getWidget()])
        return plotPanel
Пример #24
0
class BokehDataTable(Environment):
    ''' DataTable Controls and events '''
    env = Environment

    def __init__(self, **kwargs):
        lg.info('-- INIT BOKEH DATATABLE')
        self.env.bk_table = self

        self.s = 0  # current sample
        self.ns = 0  # number of samples
        self.table_df = None
        self.update_params()

        self.flag_formatter = None
        self.value_formatter = None
        self.param_formatter = None
        self.env.dt_manual_update = True

        self._init_templates()
        self._init_datatable()
        self._init_sample_buttons()

    def _init_templates(self):
        switch_case = ''
        for c, v in CIRCLE_COLORS.items():
            switch_case += "case '{}': return('{}'); break;\n".format(
                str(c), v)
        flag_template = """
            <div style="font-weight: bold; color: <%=
                (function colorfromint() {{
                    switch (value) {{
                        {}
                        default: return('black');
                    }}
                }}()) %>; " ><%= value %>
            </div>
        """.format(switch_case)
        self.flag_formatter = HTMLTemplateFormatter(
            template=flag_template
        )  # TODO: to show float numbers NumberFormatter should be used

        value_template = """
            <div style="font-weight: <%=
                (function colorfromint() {
                    switch (value) {
                        case 'NaN': return('bold'); break
                        default: return('normal');
                    }
                }()) %>; color: <%=
                (function colorfromint() {
                    switch (value) {
                        case 'NaN': return('red'); break
                        default: return('black');
                    }
                }()) %>; " ><%= value %>
            </div>
        """
        # lg.info('>> TEMPLATE: {}'.format(value_template))
        self.value_formatter = HTMLTemplateFormatter(template=value_template)

        param_template = """
            <div style="font-weight: bold;"><%= value %></div>
        """
        # lg.info('>> TEMPLATE: {}'.format(param_template))
        self.param_formatter = HTMLTemplateFormatter(template=param_template)

    def _init_datatable(self):
        columns = [
            TableColumn(
                width=80,
                field="parameter",
                title="Parameter",
                formatter=self.param_formatter,
                editor=CellEditor()  # non editable
            ),
            TableColumn(width=50,
                        field="value",
                        title="Value",
                        formatter=self.value_formatter,
                        editor=CellEditor()),
            TableColumn(width=40,
                        field="flag",
                        title="Flag",
                        formatter=self.flag_formatter,
                        editor=StringEditor()),
        ]
        self.table_df = pd.DataFrame(
            dict(
                parameter=self.params,
                value=[''] * len(self.params),
                flag=[''] * len(self.params),
            ))
        table_cds = ColumnDataSource(self.table_df)
        self.data_table = DataTable(
            width=190,
            height=125,
            source=table_cds,
            columns=columns,
            editable=
            True,  # TODO: check if there is a better way than https://stackoverflow.com/a/49424647/4891717
            fit_columns=False,  # avoids horizontal scrolls bar
            index_position=None,  # hides index column
            selectable=True,  # this is needed to edit cells
            reorderable=
            False,  # NOTE: this needs jquery ui, but it is not needed
            scroll_to_selection=False,  # not needed
            sortable=False,  # not needed
        )

        self.data_table.source.on_change('data', self.on_change_data_source)

    def _init_sample_buttons(self):
        lg.info('-- SET SAMPLE BUTTONS')

        def next_sample():
            lg.info('>> NEXT SAMPLE')
            if self.s < self.ns:
                self.env.doc.hold('collect')
                self.s += 1
                self.sample_div.text = ' {} / {}'.format(self.s, self.ns)
                self.env.cur_nearby_prof = None  # to reset the extra stt profile to plot
                self.env.dt_next_sample = True
                self._update_dt_sample()
                self.env.doc.unhold()

        def previous_sample():
            lg.info('>> PREVIOUS SAMPLE')
            if self.s > 1:
                self.env.doc.hold('collect')
                self.s -= 1
                self.sample_div.text = ' {} / {}'.format(self.s, self.ns)
                self.env.cur_nearby_prof = None
                self.env.dt_previous_sample = True
                self._update_dt_sample()
                self.env.doc.unhold()

        self.next_bt = Button(label=">", button_type="success", width=30)
        self.sample_div = Div(
            text='0 / 0',
            width=100,
            height=30,
            css_classes=['sample_div'],
        )
        self.previous_bt = Button(label="<", button_type="success", width=30)
        self.next_bt.on_click(next_sample)
        self.previous_bt.on_click(previous_sample)

    def update_params(self):
        self.params = self.env.cruise_data.get_cols_by_type(['param'])
        self.params.insert(0, STNNBR)

    def update_dt_source(self):
        ''' Updates the datatable source depending on the selected samples
        '''
        lg.info('-- UPDATE DATATABLE SOURCE')
        self.update_params()
        df = self.env.cds_df.iloc[self.env.selection]
        df_filter = self.env.cruise_data.get_cols_by_type(
            ['param', 'param_flag', 'qc_param_flag'])
        df_filter.insert(0, STNNBR)
        df = df.filter(df_filter)
        self.table_df = df  # TODO: check if it has the same order as the selection)
        self.ns = len(self.env.selection)
        self.s = 1 if self.env.selection != [] else 0
        self.sample_div.text = ' {} / {}'.format(self.s, self.ns)
        self._update_dt_sample()

    def _update_dt_sample(self):
        ''' Updates the datatable with the data of the self.s
        '''
        lg.info('-- UPDATE DT SAMPLE')
        flag_values = []
        param_values = []
        if self.s != 0:
            self.env.sample_to_select = self.env.selection[self.s - 1]

            for p in self.params:
                v = self.table_df.loc[self.env.sample_to_select, p]
                # lg.info('>> V: {} | TYPE: {}'.format(v, type(v)))
                if not isinstance(v, str):
                    if np.isnan(v):
                        v = 'NaN'
                    else:
                        v = str(v)
                param_values.append(v)

                fp = p + FLAG_END
                if fp in self.table_df.columns:
                    fv = self.table_df.loc[self.env.sample_to_select, fp]
                    if not isinstance(fv, str):
                        if np.isnan(fv):
                            fv = 'NaN'
                        else:
                            fv = str(fv)
                    flag_values.append(fv)
                else:
                    flag_values.append('-')
        else:
            self.env.sample_to_select = None
            param_values = [''] * len(self.params)
            flag_values = [''] * len(self.params)
        new_vals_dict = {
            'parameter': self.params,
            'value': param_values,
            'flag': flag_values
        }
        lg.info('>> NEW VALS DICT: \n\n{}'.format(new_vals_dict))
        lg.info('>> LENS (PARAMETER, VALUE, FLAG) = ({}, {}, {})'.format(
            len(self.params), len(param_values), len(flag_values)))

        lg.info('>> DT_MANUAL_UPDATE IN _UPDATE_DT_SAMPLE: {}'.format(
            self.env.dt_manual_update))
        # self.env.dt_manual_update = False  # just in case
        self.data_table.source.data = new_vals_dict
        # self.env.dt_manual_update = True

        self.env.bk_sources.update_prof_sources(force_selection=True)

    def on_change_data_source(self, attr, old, new):
        indices = list(range(self.table_df.size))
        # changes = [(param_name, index, old_value, new_value)]
        changes = [(self.params[i], i, j, k)
                   for i, j, k in zip(indices, old['flag'], new['flag'])
                   if j != k]

        # lg.info('>> CHANGES: {}'.format(changes))
        # lg.info('>> SELECTION = {} | DF_MANUAL_UPDATE = {}'.format(self.env.selection, self.env.dt_manual_update))
        # lg.info('>> DT_NEXT_SAMPLE = {} | DF_PREVIOUS_SAMPLE = {}'.format(self.env.dt_next_sample, self.env.dt_previous_sample))

        error = False

        # This happens when the DataFrame is empty (Reset button or the initial state)
        if self.env.selection == [] and self.env.dt_manual_update:
            error = True

        if self.env.selection != [] and self.env.dt_manual_update and changes != []:
            # if len(changes) == 1:  # NOTE: if it is a manual update the length should be 1
            #       but I am getting size 1 when the whole DataTable CDS is updated
            #       I do not why is this happening
            if not (self.env.dt_next_sample or self.env.dt_previous_sample):
                for t in changes:
                    if t[2] == '-':
                        error = True
                        self.env.bk_bridge.error_js(
                            'This parameter does not have any flag column associated.'
                        )
                    else:
                        try:
                            new_flag_val = int(t[3])
                        except:
                            error = True
                            self.env.bk_bridge.error_js(
                                'The value should be an integer.')
                        else:
                            if new_flag_val not in self.env.bk_flags.all_flags_list:
                                error = True
                                self.env.bk_bridge.error_js(
                                    'The cell value should be a valid flag value.'
                                )
                            else:
                                self.env.dt_manual_update = False
                                self.env.bk_flags.update_flag_value(
                                    flag_to_update=t[0] + FLAG_END,
                                    flag_value=new_flag_val,
                                    row_indexes=[self.env.sample_to_select])
                                self.env.dt_manual_update = True
            else:
                self.env.dt_next_sample = False
                self.env.dt_previous_sample = False

        if error:
            self.rollback(changes)

    def rollback(self, changes):
        lg.info('-- DATATABLE ROLLBACK')
        if self.env.selection != []:
            for t in changes:
                patch = {
                    'flag': [
                        (t[1], t[2]),
                    ]
                }  # rollback to the old value
                self.env.dt_manual_update = False
                self.data_table.source.patch(patch)
                self.env.dt_manual_update = True
        else:
            if changes != []:
                for t in changes:
                    patch = {
                        'flag': [
                            (t[1], ''),
                        ]
                    }  # rollback to the initial value
                    self.env.dt_manual_update = False
                    self.data_table.source.patch(patch)
                    self.env.dt_manual_update = True
            else:
                self.env.dt_manual_update = False
                self.table_df = pd.DataFrame(
                    dict(
                        parameter=self.params,  # remove flags from here
                        value=[''] * len(self.params),
                        flag=[''] * len(self.params),
                    ))
                self.data_table.source.data = self.table_df.to_dict('list')
                self.env.dt_manual_update = True
Пример #25
0
class PSUGUI(TabbedGUI):
    """@brief Responsible for plotting data on tab 0 with no other tabs."""

    CFG_FILENAME = ".RS310P_GUI.cfg"
    AMPS = "amps"
    VOLTS = "volts"
    PLOT_SECONDS = "plotSeconds"
    CFG_DICT = {VOLTS: "5", AMPS: "1", PLOT_SECONDS: 300}

    def __init__(self, docTitle, bokehPort=12000):
        """@Constructor"""
        super().__init__(docTitle, bokehPort=bokehPort)
        self._figTable = [[]]
        self._grid = None
        self._textBuffer = ""
        self._psu = None
        self._on = False

    def info(self, msg):
        """@brief Display an info level message."""
        self.statusBarWrapper.setStatus("INFO:  " + msg)

    def error(self, msg):
        """@brief Display an error level message."""
        self.statusBarWrapper.setStatus("ERROR: " + msg)

    def debug(self, msg):
        """@brief Display an error level message."""
        pass

    def addRow(self):
        """@brief Add an empty row to the figures."""
        self._figTable.append([])

    def addToRow(self, fig):
        """@brief Add a figure to the end of the current row of figues.
           @param fig The figure to add."""
        self._figTable[-1].append(fig)

    def createPlot(
        self,
        doc,
    ):
        """@brief create a plot figure.
           @param doc The document to add the plot to."""
        self._doc = doc
        self._doc.title = "RS310P PSU Controller"

        self.statusBarWrapper = StatusBarWrapper()
        self._pconfig = ConfigManager(self, PSUGUI.CFG_FILENAME,
                                      PSUGUI.CFG_DICT)
        self._pconfig.load()

        plotPanel = self._getPlotPanel()

        self._tabList.append(
            Panel(child=plotPanel, title="DC Power Supply Control"))
        self._doc.add_root(Tabs(tabs=self._tabList))
        self._doc.add_periodic_callback(self._viewUpdate, 500)

    def _viewUpdate(self):
        if self._on:
            volts, amps, watts = self._psu.getOutputStats()
            self._opTableWrapper.setRows([[volts, amps, watts]])
            self._updatePlot(volts, amps, watts)

    def _updatePlot(self, volts, amps, watts):
        """@brief called periodically to update the plot trace."""
        plotPoints = self.plotHistorySpinner.value * 2
        now = datetime.now()
        newVolts = {'x': [now], 'y': [volts]}
        self._voltsSource.stream(newVolts, rollover=plotPoints)

        newAmps = {'x': [now], 'y': [amps]}
        self._ampsSource.stream(newAmps, rollover=plotPoints)

        newWatts = {'x': [now], 'y': [watts]}
        self._wattsSource.stream(newWatts, rollover=plotPoints)

    def _getPlotPanel(self):
        """@brief Add tab that shows plot data updates."""

        self._figTable.append([])
        self._voltsSource = ColumnDataSource({'x': [], 'y': []})
        self._ampsSource = ColumnDataSource({'x': [], 'y': []})
        self._wattsSource = ColumnDataSource({'x': [], 'y': []})
        fig = figure(toolbar_location='above',
                     x_axis_type="datetime",
                     x_axis_location="below")
        fig.line(source=self._voltsSource,
                 line_color="blue",
                 legend_label="Volts")
        fig.line(source=self._ampsSource,
                 line_color="green",
                 legend_label="Amps")
        fig.line(source=self._wattsSource,
                 line_color="red",
                 legend_label="Watts")
        fig.legend.location = 'top_left'
        self._figTable[-1].append(fig)
        self._grid = gridplot(children=self._figTable,
                              sizing_mode='scale_both',
                              toolbar_location='right')

        self.selectSerialPort = Select(title="Serial Port:")
        self.selectSerialPort.options = glob.glob('/dev/ttyU*')

        self.outputVoltageSpinner = Spinner(title="Output Voltage (Volts)",
                                            low=0,
                                            high=40,
                                            step=0.5,
                                            value=self._pconfig.getAttr(
                                                PSUGUI.VOLTS))
        self.currentLimitSpinner = Spinner(title="Currnet Limit (Amps)",
                                           low=0,
                                           high=10,
                                           step=0.25,
                                           value=self._pconfig.getAttr(
                                               PSUGUI.AMPS))
        self.plotHistorySpinner = Spinner(title="Plot History (Seconds)",
                                          low=1,
                                          high=10000,
                                          step=1,
                                          value=self._pconfig.getAttr(
                                              PSUGUI.PLOT_SECONDS))

        self._setButton = Button(label="Set")
        self._setButton.on_click(self._setHandler)
        self._setButton.disabled = True

        self._onButton = Button(label="On")
        self._onButton.on_click(self._psuOnHandler)

        shutdownButtonWrapper = ShutdownButtonWrapper(self._quit)
        controlPanel = column([
            self.selectSerialPort, self._onButton, self.outputVoltageSpinner,
            self.currentLimitSpinner, self._setButton, self.plotHistorySpinner,
            shutdownButtonWrapper.getWidget()
        ])

        self._opTableWrapper = ReadOnlyTableWrapper(("volts", "amps", "watts"),
                                                    heightPolicy="fixed",
                                                    height=65,
                                                    showLastRows=0)

        plotPanel = column([self._grid, self._opTableWrapper.getWidget()])
        panel2 = row([controlPanel, plotPanel])
        plotPanel = column([panel2, self.statusBarWrapper.getWidget()])
        return plotPanel

    def _quit(self):
        if self._on:
            self._psuOff()
        self._run(self._delayedShutdown)
        self._doc.clear()

    def _delayedShutdown(self):
        """@brief Allow time for browser page to clear before shutdown."""
        volts = self.outputVoltageSpinner.value
        amps = self.currentLimitSpinner.value
        self._pconfig.addAttr(PSUGUI.VOLTS, volts)
        self._pconfig.addAttr(PSUGUI.AMPS, amps)
        self._pconfig.addAttr(PSUGUI.PLOT_SECONDS,
                              self.plotHistorySpinner.value)
        self._pconfig.store()
        sleep(0.5)
        self._sendUpdateEvent(
            PSUGUIUpdateEvent(PSUGUIUpdateEvent.SHUTDOWN_SERVER))

    def _psuOnHandler(self):
        """@brief event handler."""
        #Stop the user from clicking the button again until this click has been processed.
        self._onButton.disabled = True
        #Turn the PSUon/off method outside GUI thread
        self._run(self._powerOnOff)

    def _setHandler(self):
        """@brief event handler."""
        #Turn the PSUon/off method outside GUI thread
        self._run(self._setPSU)

    def _rxUpdateEvent(self, updateEvent):
        """@brief Receive an event into the GUI context to update the GUI.
           @param updateEvent An PSUGUIUpdateEvent instance."""
        if updateEvent.id == PSUGUIUpdateEvent.UPDATE_STATUS_TEXT:
            self.statusBarWrapper.setStatus(updateEvent.argList[0])

        elif updateEvent.id == PSUGUIUpdateEvent.CONNECTING_TO_PSU:
            self._onButton.button_type = "success"
            self._onButton.disabled = True
            self.statusBarWrapper.setStatus(updateEvent.argList[0])

        elif updateEvent.id == PSUGUIUpdateEvent.PSU_CONNECT_FAILED:
            self._onButton.button_type = "default"
            self._onButton.disabled = False
            self._setButton.disabled = True
            self._setButton.button_type = "default"
            self.statusBarWrapper.setStatus(updateEvent.argList[0])

        elif updateEvent.id == PSUGUIUpdateEvent.CONNECTED_TO_PSU:
            self._setButton.button_type = "success"
            self._setButton.disabled = False
            self._onButton.button_type = "success"
            self._onButton.disabled = False
            self._onButton.label = "Off"
            self.statusBarWrapper.setStatus("PSU ON")
            self._pconfig.addAttr(PSUGUI.VOLTS,
                                  self.outputVoltageSpinner.value)
            self._pconfig.addAttr(PSUGUI.AMPS, self.currentLimitSpinner.value)
            self._pconfig.addAttr(PSUGUI.PLOT_SECONDS,
                                  self.plotHistorySpinner.value)
            self._pconfig.store()

        elif updateEvent.id == PSUGUIUpdateEvent.TURNING_PSU_OFF:
            self._onButton.button_type = "default"
            self._setButton.disabled = True
            self._onButton.disabled = True
            self._setButton.button_type = "default"
            self.statusBarWrapper.setStatus("Turning PSU OFF")

        elif updateEvent.id == PSUGUIUpdateEvent.PSU_OFF:
            self._onButton.button_type = "default"
            self._onButton.disabled = False
            self._onButton.label = "On"
            self.statusBarWrapper.setStatus("PSU OFF")

        elif updateEvent.id == PSUGUIUpdateEvent.SET_PSU_STATE:
            volts = self.outputVoltageSpinner.value
            amps = self.currentLimitSpinner.value
            self._pconfig.addAttr(PSUGUI.VOLTS, volts)
            self._pconfig.addAttr(PSUGUI.AMPS, amps)
            self._pconfig.addAttr(PSUGUI.PLOT_SECONDS,
                                  self.plotHistorySpinner.value)
            self._pconfig.store()
            self.statusBarWrapper.setStatus(
                "Set {:.2f} volts with a {:.3f} amp current limit".format(
                    volts, amps))

        elif updateEvent.id == PSUGUIUpdateEvent.SHUTDOWN_SERVER:
            self.stopServer()
            print("PJA: SERVER SHUTDOWN.")

    def _powerOnOff(self):
        """@brief Called to turn the PSU on/off"""
        if self._on:
            self._psuOff()
        else:
            self._psuOn()

    def _setPSU(self):
        """@brief Called when the PSU is on to set the state of the PSU."""
        volts = self.outputVoltageSpinner.value
        amps = self.currentLimitSpinner.value
        self._psu.setVoltage(volts)
        self._psu.setCurrentLimit(amps)
        self._sendUpdateEvent(UpdateEvent(PSUGUIUpdateEvent.SET_PSU_STATE))

    def getSelectedSerialPort(self):
        """@brief Get the selected serial port.
           @return the selected Serial port or None if not selected."""
        selectedSerialPort = None
        if len(self.selectSerialPort.options) == 1:
            selectedSerialPort = self.selectSerialPort.options[0]
        elif self.selectSerialPort.value:
            selectedSerialPort = self.selectSerialPort.value

        if not selectedSerialPort and len(self.selectSerialPort.options) > 0:
            selectedSerialPort = self.selectSerialPort.options[0]

        return selectedSerialPort

    def _psuOff(self):
        """@brief Turn the PSU off."""
        self._sendUpdateEvent(UpdateEvent(PSUGUIUpdateEvent.TURNING_PSU_OFF))
        self._on = False
        self._psu.setOutput(False)
        self._psu.disconnect()
        self._psu = None
        self._sendUpdateEvent(UpdateEvent(PSUGUIUpdateEvent.PSU_OFF))

    def _psuOn(self):
        """@brief Connect to the PDU.
           @return True if successfully connected to a PSU."""
        serialPort = None
        try:
            serialPort = self.getSelectedSerialPort()
            if serialPort:
                self._sendUpdateEvent(
                    UpdateEvent(PSUGUIUpdateEvent.CONNECTING_TO_PSU,
                                ("Connecting to {}".format(serialPort), )))
                self._psu = ETMXXXXP(serialPort)
                self._psu.connect()
                self._psu.getOutput()
                #Ensure the voltage comes up from a low voltage rather than down
                #from a previously higher voltage
                self._psu.setVoltage(0)
                self._psu.setVoltage(self.outputVoltageSpinner.value)
                self._psu.setCurrentLimit(self.currentLimitSpinner.value)
                self._psu.setOutput(True)
                self._on = True
                self._sendUpdateEvent(
                    UpdateEvent(PSUGUIUpdateEvent.CONNECTED_TO_PSU))
            else:
                self._sendUpdateEvent(
                    UpdateEvent(PSUGUIUpdateEvent.PSU_CONNECT_FAILED, (
                        "Failed to to connect to PSU as no serial port was selected.",
                    )))
        except Exception as ex:
            print(ex)
            if self._psu:
                self._psu.disconnect()
                self._psu = None
            if serialPort:
                self._sendUpdateEvent(
                    UpdateEvent(
                        PSUGUIUpdateEvent.PSU_CONNECT_FAILED,
                        ("Failed to connect to PSU on {}".format(serialPort),
                         )))
            else:
                self._sendUpdateEvent(
                    UpdateEvent(
                        PSUGUIUpdateEvent.PSU_CONNECT_FAILED,
                        ("Failed to connect to PSU on {}".format(serialPort),
                         )))
                self.setStatus("Failed to connect to PSU.")
Пример #26
0
def interactive_hist(adata, keys=['n_counts', 'n_genes'],
                     bins='auto',  max_bins=100,
                     groups=None, fill_alpha=0.4,
                     palette=None, display_all=True,
                     tools='pan, reset, wheel_zoom, save',
                     legend_loc='top_right',
                     plot_width=None, plot_height=None, save=None,
                     *args, **kwargs):
    """Utility function to plot distributions with variable number of bins.

    Params
    --------
    adata: AnnData object
        annotated data object
    keys: list(str), optional (default: `['n_counts', 'n_genes']`)
        keys in `adata.obs` or `adata.var` where the distibutions are stored
    bins: int; str, optional (default: `auto`)
        number of bins used for plotting or str from numpy.histogram
    max_bins: int, optional (default: `1000`)
        maximum number of bins possible
    groups: list(str), (default: `None`)
        keys in `adata.obs.obs_keys()`, groups by all possible combinations of values, e.g. for
        3 plates and 2 time points, we would create total of 6 groups
    fill_alpha: float[0.0, 1.0], (default: `0.4`)
        alpha channel of the fill color
    palette: list(str), optional (default: `None`)
        palette to use
    display_all: bool, optional (default: `True`)
        display the statistics for all data
    tools: str, optional (default: `'pan,reset, wheel_zoom, save'`)
        palette of interactive tools for the user
    legend_loc: str, (default: `'top_right'`)
        position of the legend
    legend_loc: str, default(`'top_left'`)
        position of the legend
    plot_width: int, optional (default: `None`)
        width of the plot
    plot_height: int, optional (default: `None`)
        height of the plot
    save: Union[os.PathLike, Str, NoneType], optional (default: `None`)
        path where to save the plot
    *args, **kwargs: arguments, keyword arguments
        addition argument to bokeh.models.figure

    Returns
    --------
    None
    """

    if max_bins < 1:
        raise ValueError(f'`max_bins` must >= 1')

    palette = Set1[9] + Set2[8] + Set3[12] if palette is None else palette

    # check the input
    for key in keys:
        if key not in adata.obs.keys() and \
           key not in adata.var.keys() and \
           key not in adata.var_names:
            raise ValueError(f'The key `{key}` does not exist in `adata.obs`, `adata.var` or `adata.var_names`.')

    def _create_adata_groups():
        if groups is None:
            return [adata], [('all',)]

        combs = list(product(*[set(adata.obs[g]) for g in groups]))
        adatas= [adata[reduce(lambda l, r: l & r,
                              (adata.obs[k] == v for k, v in zip(groups, vals)), True)]
                 for vals in combs] + [adata]

        if display_all:
            combs += [('all',)]
            adatas += [adata]

        return adatas, combs

    # group_v_combs contains the value combinations
    ad_gs = _create_adata_groups()
    
    cols = []
    for key in keys:
        callbacks = []
        fig = figure(*args, tools=tools, **kwargs)
        slider = Slider(start=1, end=max_bins, value=0, step=1,
                        title='Bins')

        plots = []
        for j, (ad, group_vs) in enumerate(filter(lambda ad_g: ad_g[0].n_obs > 0, zip(*ad_gs))):

            if key in ad.obs.keys():
                orig = ad.obs[key]
                hist, edges = np.histogram(orig, density=True, bins=bins)
            elif key in ad.var.keys():
                orig = ad.var[key]
                hist, edges = np.histogram(orig, density=True, bins=bins)
            else:
                orig = ad[:, key].X
                hist, edges = np.histogram(orig, density=True, bins=bins)

            slider.value = len(hist)
            # case when automatic bins
            max_bins = max(max_bins, slider.value)

            # original data, used for recalculation of histogram in JS code
            orig = ColumnDataSource(data=dict(values=orig))
            # data that we update in JS code
            source = ColumnDataSource(data=dict(hist=hist, l_edges=edges[:-1], r_edges=edges[1:]))

            legend = ', '.join(': '.join(map(str, gv)) for gv in zip(groups, group_vs)) \
                    if groups is not None else 'all'
            p = fig.quad(source=source, top='hist', bottom=0,
                         left='l_edges', right='r_edges',
                         fill_color=palette[j], legend_label=legend if legend_loc is not None else None,
                         muted_alpha=0,
                         line_color="#555555", fill_alpha=fill_alpha)

            # create callback and slider
            callback = CustomJS(args=dict(source=source, orig=orig), code=_inter_hist_js_code)
            callback.args['bins'] = slider
            callbacks.append(callback)

            # add the current plot so that we can set it
            # visible/invisible in JS code
            plots.append(p)

        slider.end = max_bins

        # slider now updates all values
        slider.js_on_change('value', *callbacks)

        button = Button(label='Toggle', button_type='primary')
        button.callback = CustomJS(
            args={'plots': plots},
            code='''
                 for (var i = 0; i < plots.length; i++) {
                     plots[i].muted = !plots[i].muted;
                 }
                 '''
        )

        if legend_loc is not None:
            fig.legend.location = legend_loc
            fig.legend.click_policy = 'mute'

        fig.xaxis.axis_label = key
        fig.yaxis.axis_label = 'normalized frequency'
        _set_plot_wh(fig, plot_width, plot_height)

        cols.append(column(slider, button, fig))

    if _bokeh_version > (1, 0, 4):
        from bokeh.layouts import grid
        plot = grid(children=cols, ncols=2)
    else:
        cols = list(map(list, np.array_split(cols, np.ceil(len(cols) / 2))))
        plot = layout(children=cols, sizing_mode='fixed', ncols=2)

    if save is not None:
        save = save if str(save).endswith('.html') else str(save) + '.html'
        bokeh_save(plot, save)
    else:
        show(plot)
Пример #27
0
def init_widgets():
    global widgets

    widgets = WrapBokeh(PAGE_URL, app.logger)
    widgets.add(
        "s_age",
        Slider(title='Age',
               value=25,
               start=1,
               end=99,
               step=1,
               callback_policy='mouseup',
               width=200,
               css_classes=['s_age']))

    widgets.add(
        "dp_birthday",
        DatePicker(title="Birthday",
                   min_date=None,
                   max_date=datetime.today(),
                   value=datetime.today(),
                   width=300,
                   css_classes=['dp_birthday']))

    widgets.add(
        "msel_fruit",
        MultiSelect(options=[('Apples', 'Apples'),
                             ('Strawberries', 'Strawberries'),
                             ('Oranges', 'Oranges'),
                             ('Grapefruit', 'Grapefruit'),
                             ('Banannas', 'Banannas')],
                    value=[],
                    title="Fruit",
                    css_classes=['msel_fruit']))

    widgets.add(
        "ds_birthday",
        DateSlider(title="Birthday",
                   end=datetime.today(),
                   start=datetime.today() - timedelta(days=30),
                   step=1,
                   value=datetime.today(),
                   callback_policy='mouseup',
                   css_classes=['ds_birthday']))

    widgets.add(
        "s_amp",
        Slider(title='Amplitude',
               value=1,
               start=0,
               end=2,
               step=0.1,
               callback_policy='mouseup',
               width=200,
               css_classes=['s_amp']))

    widgets.add("b_test", Button(label="Press me!", css_classes=['b_test']))
    widgets.add("toggle_1", Toggle(label="Toggle me!",
                                   css_classes=['toggle_1']))
    widgets.add(
        "dropdn_1",
        Dropdown(label="Menu",
                 menu=[("First", '0'), ("Second", '1'), None, ("End", '2')],
                 css_classes=['dropdn_1']))

    widgets.add(
        "sel_nexturl",
        Select(options=[('99', 'Select Next Page'),
                        ('1', 'Ajax Stream Example'), ('2', 'Form Example'),
                        ('3', 'Page C'), ('4', 'Page D')],
               value=None,
               title="Select URL",
               css_classes=['sel_nexturl']))

    widgets.add(
        "cbbg_music",
        CheckboxButtonGroup(labels=["Rock0", "Country0", "Classical0"],
                            active=[],
                            css_classes=['cbbg_music']))
    widgets.add(
        "cbg_music",
        CheckboxGroup(labels=["Rock1", "Country1", "Classical1"],
                      active=[],
                      css_classes=['cbg_music']))
    widgets.add(
        "rbg_music",
        RadioButtonGroup(labels=["Rock2", "Country2", "Classical2"],
                         active=None,
                         css_classes=['rbg_music']))
    widgets.add(
        "rg_music",
        RadioGroup(labels=["Rock3", "Country3", "Classical3"],
                   active=None,
                   css_classes=['rg_music']))

    widgets.add(
        "rslider_amp",
        RangeSlider(title='Amplitude',
                    value=(0.5, 1.5),
                    start=0,
                    end=2,
                    step=0.1,
                    callback_policy='mouseup',
                    width=200,
                    css_classes=['rslider_amp']))

    widgets.init()
Пример #28
0
OPTIONS = [str(i) for i in range(20)]
multi_choice = MultiChoice(value=["foo", "baz"], options=OPTIONS)
multi_choice.js_on_change(
    "value",
    CustomJS(code="""
    console.log('multi_choice: value=' + this.value, this.toString())
"""))

# # SELECT menu GUI
# selectoptions = ["Postive tested on Covid-19 virus", "Negative tested on Covid-19 virus", "Show both"]
# resultSelect = Select(title="What to show", options=selectoptions)

# TOOL BUTTON CALLBACKS -----------------------------------------------------------------------------------------------
# Test button GUI
lab = "Click me!"
but = Button(label=lab)


def callback_button1(
):  # simple test callback -> changes lable on button and reports a click to the console
    print("button was clicked!")


but.on_click(callback_button1)  # links the clickedcode to the button

# [END] TOOL BUTTON CALLBACKS -----------------------------------------------------------------------------------------

# general webpage & plots
title = Div(
    text=
    "<b>Visualisation tool of patients tested for Covid-19 of the Hospital Israelita Albert Einstein, at São Paulo, Brazil</b>",
def highlight_indices(adata, key, basis='diffmap', components=[1, 2], cell_keys='',
                     legend_loc='top_right', plot_width=None, plot_height=None,
                     tools='pan, reset, wheel_zoom, save'):
    """
    Plot cell indices. Useful when trying to set adata.uns['iroot'].

    Params
    --------
    adata: AnnData Object
        annotated data object
    key: str
        key in `adata.obs_keys()` to color
    basis: str, optional (default: `'diffmap'`)
        basis to use
    cell_keys: str, list(str), optional (default: `''`)
        keys to display from `adata.obs_keys()` when hovering over cell
    components: list[int], optional (default: `[1, 2]`)
        which components of the basis to use
    legend_loc: str, optional (default `'top_right'`)
        location of the legend
    tools: str, optional (default: `'pan, reset, wheel_zoom, save'`)
        tools for the plot
    plot_width: int, optional (default: `None`)
        width of the plot
    plot_width: int, optional (default: `None`)
        height of the plot

    Returns
    --------
    None
    """

    if key not in adata.obs:
        raise ValueError(f'{key} not found in `adata.obs`')

    if f'X_{basis}' not in adata.obsm_keys():
        raise ValueError(f'basis `X_{basis}` not found in `adata.obsm`')

    if not isinstance(components, type(np.array)):
        components = np.array(components)

    if isinstance(cell_keys, str):
        cell_keys = list(dict.fromkeys(map(str.strip, cell_keys.split(','))))
        if cell_keys != ['']:
            assert all(map(lambda k: k in adata.obs.keys(), cell_keys)), 'Not all keys are in `adata.obs.keys()`.'
        else:
            cell_keys = []

    df = pd.DataFrame(adata.obsm[f'X_{basis}'][:, components - (basis != 'diffmap')], columns=['x', 'y'])

    for k in cell_keys:
        df[k] = list(map(str, adata.obs[k]))

    df['index'] = range(len(df))
    df[key] = list(adata.obs[key])

    if hasattr(adata, 'obs_names'):
        cell_keys.insert(0, 'name')
        df['name'] = list(adata.obs_names)

    if 'index' not in cell_keys:
        cell_keys.insert(0, 'index')

    palette = adata.uns.get(f'{key}_colors', viridis(len(df[key].unique())))

    p = figure(title=f'{key}', tools=tools)
    _set_plot_wh(p, plot_width, plot_height)

    key_col = adata.obs[key].astype('category') if adata.obs[key].dtype.name != 'category' else  adata.obs[key]
    renderers = []
    for c, color in zip(key_col.cat.categories, palette):
        data = ColumnDataSource(df[df[key] == c])
        renderers.append([p.scatter(x='x', y='y', size=10, color=color, source=data, muted_alpha=0)])
    hover_cell = HoverTool(renderers=list(np.ravel(renderers)), tooltips=[(f'{k}', f'@{k}') for k in cell_keys])

    if legend_loc is not None:
        legend = Legend(items=list(zip(map(str, key_col.cat.categories), renderers)), location=legend_loc, click_policy='mute')
        p.add_layout(legend)
        p.legend.location = legend_loc

    p.xaxis.axis_label = f'{basis}_{components[0]}'
    p.yaxis.axis_label = f'{basis}_{components[1]}'

    source = ColumnDataSource(df)
    labels = LabelSet(x='x', y='y', text='index',
                      x_offset=4, y_offset=4,
                      level='glyph', source=source, render_mode='canvas')

    labels.visible = False
    p.add_tools(hover_cell)
    p.add_layout(labels)

    button = Button(label='Toggle Indices', button_type='primary')
    button.callback = CustomJS(args=dict(l=labels), code='l.visible = !l.visible;')

    show(column(button, p))