Esempio n. 1
0
def test_get_modelid_messagename_type():
    class FakeVal():
        def __init__(self, v):
            self.value = v

    class FakeDoc():
        def __init__():
            pass

        def get_model_by_name(arg):
            if arg == MODEL_SELECTION:
                return FakeVal("protobuf_amazing_model")
            if arg == MESSAGE_SELECTION:
                return FakeVal("amazing_message")

    assert ("amazing_model", "amazing_message",
            "protobuf") == get_modelid_messagename_type(FakeDoc)

    class FakeDoc2():
        def __init__():
            pass

        def get_model_by_name(arg):
            if arg == MODEL_SELECTION:
                return FakeVal("topic_amazing_model")

    assert ("amazing_model", "amazing_model_messages",
            "jsonschema") == get_modelid_messagename_type(FakeDoc2)
Esempio n. 2
0
def _install_callback_and_cds(sind,
                              model_id,
                              message_name,
                              field_transforms={},
                              stream_limit=None):
    """
    Set up a new column_data_source, install a callback to update it
    If it already exists do nothing
    """
    d = curdoc()
    _remove_callback(d)
    model_id, message_name, model_type = run_handlers.get_modelid_messagename_type(
        d)
    emptyd = {
        k: []
        for k in run_handlers.get_model_properties(model_id, message_name,
                                                   model_type)
    }
    if d.get_model_by_name(sind) is None:
        d.add_root(ColumnDataSource(emptyd, name=sind, tags=[0]))
    func = partial(_bokeh_periodic_update, sind, model_id, message_name,
                   field_transforms, stream_limit)
    global _last_callback
    _last_callback = func
    d.add_periodic_callback(func, CBF)
    _logger.debug(
        "_install_callback_and_cds: callback {0} added for sind {1}".format(
            func, sind))
Esempio n. 3
0
def _bokeh_periodic_update(sind,
                           model_id,
                           message_name,
                           field_transforms={},
                           stream_limit=None):
    """
    Callback that gets called periodically *for each session*. That is, each session 
    (user connecting via browser) will register a callback of this for their session.
    Here we will update the data source with new points
    https://bokeh.pydata.org/en/latest/docs/reference/models/sources.html

    field_transforms is a dict {k : [func, kwargs]} where func(k, **kwargs) will be 
    applied for all k in the raw data before going into the column_data_source

    PLEASE READ ABOUT DATA REDUNDANCY:
        https://groups.google.com/a/continuum.io/forum/#!topic/bokeh/m91Y2La6fS0
    """
    d = curdoc()
    column_data_source = d.get_model_by_name(sind)
    seq = column_data_source.tags[0]
    # _logger.debug("_bokeh_periodic_update: model_id {0}, message {1}, seq {2}".format(model_id, message_name, seq))
    model_id, message_name, model_type = run_handlers.get_modelid_messagename_type(
        d)
    source = data.get_raw_data(model_id, message_name, seq, -1)
    # _logger.debug("_bokeh_periodic_update: source length {0}".format(len(source)))
    if source != []:  # might be no data, exit callback immediately if so
        # this has all the properties, even ones we don't want to display
        # these keys may be dotted pairs
        sinit = {
            k: []
            for k in run_handlers.get_model_properties(model_id, message_name,
                                                       model_type)
        }
        # _logger.debug("_bokeh_periodic_update: sinit {0}".format(sinit))
        newdata = sinit
        num_data = 0
        for msg in source:  # from where we left off to the end
            for mk in sinit.keys():
                val = get_message_data(msg, mk)
                if val is None:
                    pass  # Ignore.  For example, model_as_string property is defined but not pushed to Redis.
                    # _logger.warning("_bokeh_periodic_update: failed to get value from message {0}, field {1}".format(message_name, mk))
                elif mk in field_transforms:
                    val = field_transforms[mk][0](val,
                                                  **field_transforms[mk][1])
                if isinstance(val, bytes):
                    # this can happen in rare cases, like RAW being used to try to display an image
                    # bokeh internally does a JSON serialization so we can't let bytes slip through
                    # this does not affect image rendering is that is not put into the bokeh CDS, only the URL is
                    val = "<RAW BYTES>"
                newdata[mk].append(val)
            num_data += 1

        # Warning, don't check newdata = sinit because it's not a deep copy!!!!!11!
        d.get_model_by_name(sind).stream(
            newdata, stream_limit
        )  # after the data source is updated, some magic happens such that the new data is streamed via web socket to the browser
        column_data_source.tags = [seq + num_data]
Esempio n. 4
0
def image_selection_change():
    """Callback for changing the image field or mime field"""
    def return_image(val, model_id, message_name, field_name, mime, sind):
        """Returns a URL resolvable by the probe"""
        column_data_source = curdoc().get_model_by_name(sind)
        index = column_data_source.tags[0]
        url = "http://{0}/image/".format(_host) + "---".join(
            [model_id, message_name, field_name, mime, sind,
             str(index)])
        return url

    d = curdoc()
    _remove_fig(d)
    model_id, message_name, _ = run_handlers.get_modelid_messagename_type(d)
    image_field = d.get_model_by_name(IMAGE_SELECTION).value.split(" :")[0]
    mime = d.get_model_by_name(MIME_SELECTION).value

    if image_field != DEFAULT_UNSELECTED and mime != DEFAULT_UNSELECTED:
        plot = figure(plot_width=500,
                      plot_height=500,
                      title="",
                      x_range=Range1d(start=0, end=1),
                      y_range=Range1d(start=0, end=1),
                      name=FIGURE_MODEL)
        sind = run_handlers.get_source_index(d.session_context.id, model_id,
                                             message_name, image_field + mime)

        _install_callback_and_cds(sind,
                                  model_id,
                                  message_name, {
                                      image_field: [
                                          return_image, {
                                              "model_id": model_id,
                                              "message_name": message_name,
                                              "field_name": image_field,
                                              "mime": mime,
                                              "sind": sind
                                          }
                                      ]
                                  },
                                  stream_limit=1)
        plot.image_url(url=image_field,
                       x=0,
                       y=1,
                       h=1,
                       w=1,
                       source=d.get_model_by_name(sind))
        d.add_root(plot)
Esempio n. 5
0
def column_selection_change():
    """Creates a datatable when user changes the selected table column(s)"""
    d = curdoc()
    _remove_fig(d)
    model_id, message_name, _ = run_handlers.get_modelid_messagename_type(d)
    sind = run_handlers.get_source_index(d.session_context.id, model_id,
                                         message_name)
    source = d.get_model_by_name(sind)
    _install_callback_and_cds(sind, model_id, message_name, stream_limit=1)
    sel_cols = d.get_model_by_name(COLUMN_MULTISELECT).value
    columns = [TableColumn(field=c, title=c) for c in sel_cols]
    data_table = DataTable(source=source,
                           columns=columns,
                           width=500,
                           height=500)
    table_widget = widgetbox(data_table, name=FIGURE_MODEL)
    d.add_root(table_widget)
Esempio n. 6
0
def make_2axis_graph():
    """Makes a 2 axis graph when user changes the X or Y axis selection"""
    d = curdoc()
    _remove_fig(d)
    graph_val = d.get_model_by_name(GRAPH_SELECTION).value
    model_id, message_name, _ = run_handlers.get_modelid_messagename_type(d)

    xval = d.get_model_by_name(X_AXIS_SELECTION).value
    yval = d.get_model_by_name(Y_AXIS_SELECTION).value

    if xval != DEFAULT_UNSELECTED and yval != DEFAULT_UNSELECTED:
        plot = figure(plot_width=400, plot_height=400, name=FIGURE_MODEL)
        sind = run_handlers.get_source_index(d.session_context.id, model_id,
                                             message_name)
        _install_callback_and_cds(sind,
                                  model_id,
                                  message_name,
                                  stream_limit=100000)

        # get the field name back from the pretty field : meta string formed above
        x = xval.split(" :")[0]
        y = yval.split(" :")[0]

        if graph_val == "line":
            plot.line(x=x,
                      y=y,
                      color="firebrick",
                      line_width=2,
                      source=d.get_model_by_name(sind))
            plot.x_range.follow = "end"  # don't jam all the data into the graph; "window" it
            plot.x_range.follow_interval = 100
            plot.x_range.range_padding = 0
        if graph_val == "scatter":
            plot.cross(x=x,
                       y=y,
                       size=20,
                       color="firebrick",
                       line_width=2,
                       source=d.get_model_by_name(sind))
        if graph_val == "step":
            plot.step(x=x,
                      y=y,
                      color="#FB8072",
                      source=d.get_model_by_name(sind))

        d.add_root(plot)
Esempio n. 7
0
def modelselec_change():
    """Callback on change of selected model/topic"""
    d = curdoc()
    _remove_fig(d)
    _remove_selection(d)
    d.remove_root(d.get_model_by_name(AFTER_MODEL_SELECTION))
    modelselec = d.get_model_by_name(MODEL_SELECTION)
    msv = modelselec.value
    if msv != DEFAULT_UNSELECTED:
        model_id, message_name, model_type = run_handlers.get_modelid_messagename_type(
            d)
        if model_type == "protobuf":
            message = Select(
                title="Message Selection",
                value=DEFAULT_UNSELECTED,
                options=list(
                    data.proto_data_structure[model_id]["messages"].keys()) +
                [DEFAULT_UNSELECTED],
                name=MESSAGE_SELECTION)
            graphs = Select(title="Graph Selection",
                            value=DEFAULT_UNSELECTED,
                            options=[],
                            name=GRAPH_SELECTION)
            message.on_change('value', lambda attr, old, new: message_change())
            graphs.on_change('value', lambda attr, old, new: graphs_change())
            selec = row(widgetbox([message]),
                        widgetbox([graphs]),
                        name=AFTER_MODEL_SELECTION)
        else:  # there is no message selection here
            graphs = Select(title="Graph Selection",
                            value=DEFAULT_UNSELECTED,
                            options=GRAPH_OPTIONS,
                            name=GRAPH_SELECTION)
            graphs.on_change('value', lambda attr, old, new: graphs_change())
            selec = row(widgetbox([graphs]), name=AFTER_MODEL_SELECTION)
        d.add_root(selec)
        d.add_root(selec)
Esempio n. 8
0
def graphs_change():
    """Callback on change of selected graph type"""
    d = curdoc()
    _remove_fig(d)
    _remove_selection(d)
    graph_val = d.get_model_by_name(GRAPH_SELECTION).value
    model_id, message_name, model_type = run_handlers.get_modelid_messagename_type(
        d)
    props = run_handlers.get_model_properties(model_id, message_name,
                                              model_type)

    if graph_val in ["line", "scatter", "step"]:
        # never want to plot this special string field
        field_options = [
            "{0} : {1}".format(k, props[k]) for k in props
            if not any(apv in k for apv in [APV_MODEL])
        ]
        xselect = Select(title="X Axis",
                         value=DEFAULT_UNSELECTED,
                         options=field_options + [DEFAULT_UNSELECTED],
                         name=X_AXIS_SELECTION)
        yselect = Select(title="Y Axis",
                         value=DEFAULT_UNSELECTED,
                         options=field_options + [DEFAULT_UNSELECTED],
                         name=Y_AXIS_SELECTION)
        xselect.on_change('value', lambda attr, old, new: make_2axis_graph())
        yselect.on_change('value', lambda attr, old, new: make_2axis_graph())
        d.add_root(
            column(Div(text=""),
                   row(widgetbox([xselect]), widgetbox([yselect])),
                   name=FIELD_SELECTION))

    if graph_val in ["image"]:
        # alter the field options for known non-image fields
        field_options = [
            "{0} : {1}".format(k, props[k]) for k in props
            if not any(apv in k for apv in [APV_RECVD, APV_SEQNO, APV_MODEL])
        ]
        imageselect = Select(title="Image Field",
                             value=DEFAULT_UNSELECTED,
                             options=[DEFAULT_UNSELECTED] + field_options,
                             name=IMAGE_SELECTION)
        mimeselect = Select(title="MIME Type",
                            value=DEFAULT_UNSELECTED,
                            options=[DEFAULT_UNSELECTED] +
                            SUPPORTED_MIME_TYPES,
                            name=MIME_SELECTION)
        imageselect.on_change('value',
                              lambda attr, old, new: image_selection_change())
        mimeselect.on_change('value',
                             lambda attr, old, new: image_selection_change())
        d.add_root(
            column(Div(text=""),
                   widgetbox([imageselect, mimeselect]),
                   name=IMAGE_MIME_SELECTION))

    if graph_val in ["table"]:
        # TODO: limit selectable columns to whose of the same size (table height)
        # use just the field name; don't show properties in the multi-select box
        col_options = [
            k for k in props
            if not any(apv in k for apv in [APV_RECVD, APV_SEQNO, APV_MODEL])
        ]
        columnmultiselect = MultiSelect(title="Columns:",
                                        value=[],
                                        options=col_options,
                                        name=COLUMN_MULTISELECT)
        columnmultiselect.on_change(
            'value', lambda attr, old, new: column_selection_change())
        d.add_root(
            column(Div(text=""),
                   widgetbox([columnmultiselect]),
                   name=COLUMN_SELECTION))

    if graph_val in ["raw"]:
        p = figure(plot_width=500,
                   plot_height=500,
                   background_fill_color="white",
                   y_range=(-40, 0),
                   title="",
                   name=FIGURE_MODEL)
        p.xaxis.visible = False
        p.yaxis.visible = False
        sind = run_handlers.get_source_index(d.session_context.id, model_id,
                                             message_name)
        _install_callback_and_cds(sind, model_id, message_name, stream_limit=1)
        p.text(x='apv_sequence_number',
               y=0,
               text='apv_model_as_string',
               source=d.get_model_by_name(sind),
               text_font_size="10pt",
               text_line_height=0.7,
               text_baseline="top",
               text_align="left")
        p.x_range.follow = "end"  # don't jam all the data into the graph; "window" it
        p.x_range.follow_interval = 1  # don't jam all the data into the graph; "window" it
        p.x_range.range_padding = 0
        d.add_root(p)