Example #1
0
def marshall(proto, spec=None, **kwargs):
    """Marshall a proto with DeckGL chart info.

    See DeltaGenerator.deck_gl_chart for docs.
    """
    if "data" in kwargs:
        # TODO: Remove this check after 2019-11-28.
        raise Exception(
            "The `data` parameter is deprecated. Use `st.map` or"
            "specify a spec dict in `st.deck_gl_chart`."
        )

    data = []

    if spec is None:
        spec = dict()

    # Merge spec with unflattened kwargs, where kwargs take precedence.
    # This only works for string keys, but kwarg keys are strings anyways.
    spec = dict(spec, **dicttools.unflatten(kwargs))

    if "layers" not in spec:
        spec["layers"] = []

        # Syntax sugar: if no layers defined and data is passed at the top
        # level, create a scatterplot layer with the top-level data by default.
        if data is not None:
            spec["layers"].append({"data": data, "type": "ScatterplotLayer"})

    for layer in spec["layers"]:
        # Don't add layers that have no data.
        if "data" not in layer:
            continue

        # Remove DataFrame because it's not JSON-serializable
        data = layer.pop("data")

        layer_proto = proto.layers.add()
        fixed_layer = case_converters.convert_dict_keys(
            case_converters.to_lower_camel_case, layer
        )
        layer_proto.spec = json.dumps(fixed_layer)
        # TODO: If several layers use the same data frame, the data gets resent
        # for each layer. Need to improve this.
        data_frame_proto.marshall_data_frame(data, layer_proto.data)

    del spec["layers"]

    # Dump JSON after removing DataFrames (see loop above), because DataFrames
    # are not JSON-serializable.
    proto.spec = json.dumps(spec)
Example #2
0
def marshall(proto, data=None, spec=None, **kwargs):
    """Marshall a proto with DeckGL chart info.

    See DeltaGenerator.deck_gl_chart for docs.
    """
    if data is None:
        data = []

    if spec is None:
        spec = dict()

    # Merge spec with unflattened kwargs, where kwargs take precedence.
    # This only works for string keys, but kwarg keys are strings anyways.
    spec = dict(spec, **dicttools.unflatten(kwargs))

    if 'layers' not in spec:
        spec['layers'] = []

        # Syntax sugar: if no layers defined and data is passed at the top
        # level, create a scatterplot layer with the top-level data by default.
        if data is not None:
            spec['layers'].append({
                'data': data,
                'type': 'ScatterplotLayer',
            })

    for layer in spec['layers']:
        # Don't add layers that have no data.
        if 'data' not in layer:
            continue

        # Remove DataFrame because it's not JSON-serializable
        data = layer.pop('data')

        layer_proto = proto.layers.add()
        fixed_layer = case_converters.convert_dict_keys(
            case_converters.to_lower_camel_case, layer)
        layer_proto.spec = json.dumps(fixed_layer)
        # TODO: If several layers use the same data frame, the data gets resent
        # for each layer. Need to improve this.
        data_frame_proto.marshall_data_frame(data, layer_proto.data)

    del spec['layers']

    # Dump JSON after removing DataFrames (see loop above), because DataFrames
    # are not JSON-serializable.
    proto.spec = json.dumps(spec)
Example #3
0
    def marshall(self, proto_chart):
        """Load this chart data into that proto_chart."""
        proto_chart.type = case_converters.to_upper_camel_case(self._type)
        data_frame_proto.marshall_data_frame(self._data, proto_chart.data)
        proto_chart.width = self._width
        proto_chart.height = self._height

        self._append_missing_data_components()

        for component in self._components:
            proto_component = proto_chart.components.add()
            component.marshall(proto_component)

        for (key, value) in self._props:
            proto_prop = proto_chart.props.add()
            proto_prop.key = case_converters.to_lower_camel_case(key)
            proto_prop.value = value
Example #4
0
# For the messages below, we don't really care about their contents so much as
# their general type.

INIT_MSG = ForwardMsg()
INIT_MSG.initialize.config.sharing_enabled = True
INIT_MSG.initialize.config.allow_run_on_save = True

TEXT_DELTA_MSG1 = ForwardMsg()
TEXT_DELTA_MSG1.delta.new_element.text.body = "text1"

TEXT_DELTA_MSG2 = ForwardMsg()
TEXT_DELTA_MSG2.delta.new_element.text.body = "text2"

DF_DELTA_MSG = ForwardMsg()
data_frame_proto.marshall_data_frame({
    "col1": [0, 1, 2],
    "col2": [10, 11, 12]
}, DF_DELTA_MSG.delta.new_element.data_frame)

ADD_ROWS_MSG = ForwardMsg()
data_frame_proto.marshall_data_frame({
    "col1": [3, 4, 5],
    "col2": [13, 14, 15]
}, ADD_ROWS_MSG.delta.add_rows.data)


class ReportQueueTest(unittest.TestCase):
    def test_simple_enqueue(self):
        rq = ReportQueue()
        self.assertTrue(rq.is_empty())

        rq.enqueue(INIT_MSG)
Example #5
0
def marshall(proto, data=None, spec=None, use_container_width=False, **kwargs):
    """Construct a Vega-Lite chart object.

    See DeltaGenerator.vega_lite_chart for docs.
    """
    # Support passing data inside spec['datasets'] and spec['data'].
    # (The data gets pulled out of the spec dict later on.)
    if isinstance(data, dict) and spec is None:
        spec = data
        data = None

    # Support passing no spec arg, but filling it with kwargs.
    # Example:
    #   marshall(proto, baz='boz')
    if spec is None:
        spec = dict()
    else:
        # Clone the spec dict, since we may be mutating it.
        spec = dict(spec)

    # Support passing in kwargs. Example:
    #   marshall(proto, {foo: 'bar'}, baz='boz')
    if len(kwargs):
        # Merge spec with unflattened kwargs, where kwargs take precedence.
        # This only works for string keys, but kwarg keys are strings anyways.
        spec = dict(spec, **dicttools.unflatten(kwargs, _CHANNELS))

    if len(spec) == 0:
        raise ValueError("Vega-Lite charts require a non-empty spec dict.")

    if "autosize" not in spec:
        spec["autosize"] = {"type": "fit", "contains": "padding"}

    # Pull data out of spec dict when it's in a 'dataset' key:
    #   marshall(proto, {datasets: {foo: df1, bar: df2}, ...})
    if "datasets" in spec:
        for k, v in spec["datasets"].items():
            dataset = proto.datasets.add()
            dataset.name = str(k)
            dataset.has_name = True
            data_frame_proto.marshall_data_frame(v, dataset.data)
        del spec["datasets"]

    # Pull data out of spec dict when it's in a top-level 'data' key:
    #   marshall(proto, {data: df})
    #   marshall(proto, {data: {values: df, ...}})
    #   marshall(proto, {data: {url: 'url'}})
    #   marshall(proto, {data: {name: 'foo'}})
    if "data" in spec:
        data_spec = spec["data"]

        if isinstance(data_spec, dict):
            if "values" in data_spec:
                data = data_spec["values"]
                del data_spec["values"]
        else:
            data = data_spec
            del spec["data"]

    proto.spec = json.dumps(spec)
    proto.use_container_width = use_container_width

    if data is not None:
        data_frame_proto.marshall_data_frame(data, proto.data)
def _create_dataframe_msg(df, id=1):
    msg = ForwardMsg()
    msg.metadata.delta_id = id
    msg.metadata.parent_block.container = BlockPath.SIDEBAR
    data_frame_proto.marshall_data_frame(df, msg.delta.new_element.data_frame)
    return msg
Example #7
0
    def add_rows(self, data=None, **kwargs):
        """Concatenate a dataframe to the bottom of the current one.

        Parameters
        ----------
        data : pandas.DataFrame, pandas.Styler, numpy.ndarray, Iterable, dict,
        or None
            Table to concat. Optional.

        **kwargs : pandas.DataFrame, numpy.ndarray, Iterable, dict, or None
            The named dataset to concat. Optional. You can only pass in 1
            dataset (including the one in the data parameter).

        Example
        -------
        >>> df1 = pd.DataFrame(
        ...    np.random.randn(50, 20),
        ...    columns=('col %d' % i for i in range(20)))
        ...
        >>> my_table = st.table(df1)
        >>>
        >>> df2 = pd.DataFrame(
        ...    np.random.randn(50, 20),
        ...    columns=('col %d' % i for i in range(20)))
        ...
        >>> my_table.add_rows(df2)
        >>> # Now the table shown in the Streamlit app contains the data for
        >>> # df1 followed by the data for df2.

        You can do the same thing with plots. For example, if you want to add
        more data to a line chart:

        >>> # Assuming df1 and df2 from the example above still exist...
        >>> my_chart = st.line_chart(df1)
        >>> my_chart.add_rows(df2)
        >>> # Now the chart shown in the Streamlit app contains the data for
        >>> # df1 followed by the data for df2.

        And for plots whose datasets are named, you can pass the data with a
        keyword argument where the key is the name:

        >>> my_chart = st.vega_lite_chart({
        ...     'mark': 'line',
        ...     'encoding': {'x': 'a', 'y': 'b'},
        ...     'datasets': {
        ...       'some_fancy_name': df1,  # <-- named dataset
        ...      },
        ...     'data': {'name': 'some_fancy_name'},
        ... }),
        >>> my_chart.add_rows(some_fancy_name=df2)  # <-- name used as keyword

        """
        if self._root_container is None or self._cursor is None:
            return self

        if not self._cursor.is_locked:
            raise StreamlitAPIException(
                "Only existing elements can `add_rows`.")

        # Accept syntax st.add_rows(df).
        if data is not None and len(kwargs) == 0:
            name = ""
        # Accept syntax st.add_rows(foo=df).
        elif len(kwargs) == 1:
            name, data = kwargs.popitem()
        # Raise error otherwise.
        else:
            raise StreamlitAPIException(
                "Wrong number of arguments to add_rows()."
                "Command requires exactly one dataset")

        # When doing add_rows on an element that does not already have data
        # (for example, st.line_chart() without any args), call the original
        # st.foo() element with new data instead of doing an add_rows().
        if (self._cursor.props["delta_type"]
                in DELTAS_TYPES_THAT_MELT_DATAFRAMES
                and self._cursor.props["last_index"] is None):
            # IMPORTANT: This assumes delta types and st method names always
            # match!
            st_method_name = self._cursor.props["delta_type"]
            st_method = getattr(self, st_method_name)
            st_method(data, **kwargs)
            return

        data, self._cursor.props["last_index"] = _maybe_melt_data_for_add_rows(
            data, self._cursor.props["delta_type"],
            self._cursor.props["last_index"])

        msg = ForwardMsg_pb2.ForwardMsg()
        msg.metadata.delta_path[:] = self._cursor.delta_path

        import streamlit.elements.data_frame_proto as data_frame_proto

        data_frame_proto.marshall_data_frame(data, msg.delta.add_rows.data)

        if name:
            msg.delta.add_rows.name = name
            msg.delta.add_rows.has_name = True

        _enqueue_message(msg)

        return self
Example #8
0
def _create_dataframe_msg(df, id=1) -> ForwardMsg:
    msg = ForwardMsg()
    msg.metadata.delta_path[:] = make_delta_path(RootContainer.SIDEBAR, (), id)
    data_frame_proto.marshall_data_frame(df, msg.delta.new_element.data_frame)
    return msg
Example #9
0
def marshall(proto, data=None, spec=None, width=0, **kwargs):
    """Construct a Vega-Lite chart object.

    See DeltaGenerator.vega_lite_chart for docs.
    """
    # Support passing data inside spec['datasets'] and spec['data'].
    # (The data gets pulled out of the spec dict later on.)
    if type(data) in dict_types and spec is None:
        spec = data
        data = None

    # Support passing no spec arg, but filling it with kwargs.
    # Example:
    #   marshall(proto, baz='boz')
    if spec is None:
        spec = dict()
    else:
        # Clone the spec dict, since we may be mutating it.
        spec = dict(spec)

    # Support passing in kwargs. Example:
    #   marshall(proto, {foo: 'bar'}, baz='boz')
    if len(kwargs):
        # Merge spec with unflattened kwargs, where kwargs take precedence.
        # This only works for string keys, but kwarg keys are strings anyways.
        spec = dict(spec, **dicttools.unflatten(kwargs, _CHANNELS))

    if len(spec) == 0:
        raise ValueError('Vega-Lite charts require a non-empty spec dict.')

    # TODO: Improve autosizing code. It doesn't work with some kinds of charts,
    # like composed charts, for example.
    if width >= 0 and 'width' not in spec:
        spec['width'] = width
        if 'autosize' not in spec:
            spec['autosize'] = {'type': 'fit', 'contains': 'padding'}

    # Pull data out of spec dict when it's in a 'dataset' key:
    #   marshall(proto, {datasets: {foo: df1, bar: df2}, ...})
    if 'datasets' in spec:
        for k, v in spec['datasets'].items():
            dataset = proto.datasets.add()
            dataset.name = str(k)
            dataset.has_name = True
            data_frame_proto.marshall_data_frame(v, dataset.data)
        del spec['datasets']

    # Pull data out of spec dict when it's in a top-level 'data' key:
    #   marshall(proto, {data: df})
    #   marshall(proto, {data: {values: df, ...}})
    #   marshall(proto, {data: {url: 'url'}})
    #   marshall(proto, {data: {name: 'foo'}})
    if 'data' in spec:
        data_spec = spec['data']

        if type(data_spec) in dict_types:
            if 'values' in data_spec:
                data = data_spec['values']
                del data_spec['values']
        else:
            data = data_spec
            del spec['data']

    proto.spec = json.dumps(spec)

    if data is not None:
        data_frame_proto.marshall_data_frame(data, proto.data)