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)
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)
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
# 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)
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
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
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
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)