def _block(self, block_proto=Block_pb2.Block()): # Switch to the active DeltaGenerator, in case we're in a `with` block. self = self._active_dg if self._container is None or self._cursor is None: return self msg = ForwardMsg_pb2.ForwardMsg() msg.metadata.parent_block.container = self._container msg.metadata.parent_block.path[:] = self._cursor.path msg.metadata.delta_id = self._cursor.index msg.delta.add_block.CopyFrom(block_proto) # Normally we'd return a new DeltaGenerator that uses the locked cursor # below. But in this case we want to return a DeltaGenerator that uses # a brand new cursor for this new block we're creating. block_cursor = cursor.RunningCursor(path=self._cursor.path + (self._cursor.index, )) block_dg = DeltaGenerator(container=self._container, cursor=block_cursor, parent=self) # Must be called to increment this cursor's index. self._cursor.get_locked_cursor(last_index=None) _enqueue_message(msg) return block_dg
def experimental_set_query_params(**query_params): """Set the query parameters that are shown in the browser's URL bar. Parameters ---------- **query_params : dict The query parameters to set, as key-value pairs. Example ------- To point the user's web browser to something like "http://localhost:8501/?show_map=True&selected=asia&selected=america", you would do the following: >>> st.experimental_set_query_params( ... show_map=True, ... selected=["asia", "america"], ... ) """ ctx = _get_report_ctx() if ctx is None: return ctx.query_string = _parse.urlencode(query_params, doseq=True) msg = _ForwardMsg_pb2.ForwardMsg() msg.page_info_changed.query_string = ctx.query_string ctx.enqueue(msg)
def _block(self, block_proto=Block_pb2.Block()) -> "DeltaGenerator": # Operate on the active DeltaGenerator, in case we're in a `with` block. dg = self._active_dg # Prevent nested columns & expanders by checking all parents. block_type = block_proto.WhichOneof("type") # Convert the generator to a list, so we can use it multiple times. parent_block_types = frozenset(dg._parent_block_types) if block_type == "column" and block_type in parent_block_types: raise StreamlitAPIException( "Columns may not be nested inside other columns." ) if block_type == "expandable" and block_type in parent_block_types: raise StreamlitAPIException( "Expanders may not be nested inside other expanders." ) if dg._root_container is None or dg._cursor is None: return dg msg = ForwardMsg_pb2.ForwardMsg() msg.metadata.delta_path[:] = dg._cursor.delta_path msg.delta.add_block.CopyFrom(block_proto) # Normally we'd return a new DeltaGenerator that uses the locked cursor # below. But in this case we want to return a DeltaGenerator that uses # a brand new cursor for this new block we're creating. block_cursor = cursor.RunningCursor( root_container=dg._root_container, parent_path=dg._cursor.parent_path + (dg._cursor.index,), ) block_dg = DeltaGenerator( root_container=dg._root_container, cursor=block_cursor, parent=dg, block_type=block_type, ) # Blocks inherit their parent form ids. # NOTE: Container form ids aren't set in proto. block_dg._form_data = FormData(current_form_id(dg)) # Must be called to increment this cursor's index. dg._cursor.get_locked_cursor(last_index=None) _enqueue_message(msg) return block_dg
def _block(self, block_proto=Block_pb2.Block()): # Switch to the active DeltaGenerator, in case we're in a `with` block. self = self._active_dg # Prevent nested columns & expanders by checking all parents. block_type = block_proto.WhichOneof("type") # Convert the generator to a list, so we can use it multiple times. parent_block_types = [t for t in self._parent_block_types] if block_type == "column" and block_type in parent_block_types: raise StreamlitAPIException( "Columns may not be nested inside other columns.") if block_type == "expandable" and block_type in parent_block_types: raise StreamlitAPIException( "Expanders may not be nested inside other expanders.") if self._container is None or self._cursor is None: return self msg = ForwardMsg_pb2.ForwardMsg() msg.metadata.parent_block.container = self._container msg.metadata.parent_block.path[:] = self._cursor.path msg.metadata.delta_id = self._cursor.index msg.delta.add_block.CopyFrom(block_proto) # Normally we'd return a new DeltaGenerator that uses the locked cursor # below. But in this case we want to return a DeltaGenerator that uses # a brand new cursor for this new block we're creating. block_cursor = cursor.RunningCursor(path=self._cursor.path + (self._cursor.index, )) block_dg = DeltaGenerator( container=self._container, cursor=block_cursor, parent=self, block_type=block_type, ) # Must be called to increment this cursor's index. self._cursor.get_locked_cursor(last_index=None) _enqueue_message(msg) return block_dg
def _block(self): if self._container is None or self._cursor is None: return self msg = ForwardMsg_pb2.ForwardMsg() msg.delta.new_block = True msg.metadata.parent_block.container = self._container msg.metadata.parent_block.path[:] = self._cursor.path msg.metadata.delta_id = self._cursor.index # Normally we'd return a new DeltaGenerator that uses the locked cursor # below. But in this case we want to return a DeltaGenerator that uses # a brand new cursor for this new block we're creating. block_cursor = cursor.RunningCursor( path=self._cursor.path + (self._cursor.index,) ) block_dg = DeltaGenerator(container=self._container, cursor=block_cursor) # Must be called to increment this cursor's index. self._cursor.get_locked_cursor(None) _enqueue_message(msg) return block_dg
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 _enqueue( self, delta_type, element_proto, return_value=None, last_index=None, element_width=None, element_height=None, ): """Create NewElement delta, fill it, and enqueue it. Parameters ---------- delta_type: string The name of the streamlit method being called element_proto: proto The actual proto in the NewElement type e.g. Alert/Button/Slider return_value: any or None The value to return to the calling script (for widgets) element_width : int or None Desired width for the element element_height : int or None Desired height for the element Returns ------- DeltaGenerator A DeltaGenerator that can be used to modify the newly-created element. """ # Operate on the active DeltaGenerator, in case we're in a `with` block. dg = self._active_dg # Warn if we're called from within an @st.cache function caching.maybe_show_cached_st_function_warning(dg, delta_type) # Some elements have a method.__name__ != delta_type in proto. # This really matters for line_chart, bar_chart & area_chart, # since add_rows() relies on method.__name__ == delta_type # TODO: Fix for all elements (or the cache warning above will be wrong) proto_type = delta_type if proto_type in DELTAS_TYPES_THAT_MELT_DATAFRAMES: proto_type = "vega_lite_chart" # Copy the marshalled proto into the overall msg proto msg = ForwardMsg_pb2.ForwardMsg() msg_el_proto = getattr(msg.delta.new_element, proto_type) msg_el_proto.CopyFrom(element_proto) # Only enqueue message and fill in metadata if there's a container. msg_was_enqueued = False if dg._root_container is not None and dg._cursor is not None: msg.metadata.delta_path[:] = dg._cursor.delta_path if element_width is not None: msg.metadata.element_dimension_spec.width = element_width if element_height is not None: msg.metadata.element_dimension_spec.height = element_height _enqueue_message(msg) msg_was_enqueued = True if msg_was_enqueued: # Get a DeltaGenerator that is locked to the current element # position. new_cursor = (dg._cursor.get_locked_cursor(delta_type=delta_type, last_index=last_index) if dg._cursor is not None else None) output_dg = DeltaGenerator( root_container=dg._root_container, cursor=new_cursor, parent=dg, ) else: # If the message was not enqueued, just return self since it's a # no-op from the point of view of the app. output_dg = dg return _value_or_dg(return_value, output_dg)
def beta_set_page_config(page_title=None, page_icon=None, layout="centered", initial_sidebar_state="auto"): """ Configures the default settings of the page. .. note:: This must be the first Streamlit command used in your app, and must only be set once. This is a beta feature. See https://docs.streamlit.io/en/latest/pre_release_features.html for more information. Parameters ---------- page_title: str or None The page title, shown in the browser tab. If None, defaults to the filename of the script ("app.py" would show "app • Streamlit"). page_icon : Anything supported by st.image or str or None The page favicon. Besides the types supported by `st.image` (like URLs or numpy arrays), you can pass in an emoji as a string ("🦈") or a shortcode (":shark:"). Emoji icons are courtesy of Twemoji and loaded from MaxCDN. layout: "centered" or "wide" How the page content should be laid out. Defaults to "centered", which constrains the elements into a centered column of fixed width; "wide" uses the entire screen. initial_sidebar_state: "auto" or "expanded" or "collapsed" How the sidebar should start out. Defaults to "auto", which hides the sidebar on mobile-sized devices, and shows it otherwise. "expanded" shows the sidebar initially; "collapsed" hides it. Example ------- >>> st.beta_set_page_config( ... page_title="Ex-stream-ly Cool App", ... page_icon="🧊", ... layout="wide", ... initial_sidebar_state="expanded", ... ) """ msg = ForwardMsg_pb2.ForwardMsg() if page_title: msg.page_config_changed.title = page_title if page_icon: msg.page_config_changed.favicon = image_proto.image_to_url( page_icon, width=-1, # Always use full width for favicons clamp=False, channels="RGB", output_format="JPEG", image_id="favicon", allow_emoji=True, ) if layout == "centered": layout = PageConfig_pb2.PageConfig.CENTERED elif layout == "wide": layout = PageConfig_pb2.PageConfig.WIDE else: raise StreamlitAPIException( f'`layout` must be "centered" or "wide" (got "{layout}")') msg.page_config_changed.layout = layout if initial_sidebar_state == "auto": initial_sidebar_state = PageConfig_pb2.PageConfig.AUTO elif initial_sidebar_state == "expanded": initial_sidebar_state = PageConfig_pb2.PageConfig.EXPANDED elif initial_sidebar_state == "collapsed": initial_sidebar_state = PageConfig_pb2.PageConfig.COLLAPSED else: raise StreamlitAPIException( '`initial_sidebar_state` must be "auto" or "expanded" or "collapsed" ' + f'(got "{initial_sidebar_state}")') msg.page_config_changed.initial_sidebar_state = initial_sidebar_state ctx = get_report_ctx() if ctx is None: return ctx.enqueue(msg)
def set_page_config( page_title=None, page_icon=None, layout="centered", initial_sidebar_state="auto", menu_items=None, ): """ Configures the default settings of the page. .. note:: This must be the first Streamlit command used in your app, and must only be set once. Parameters ---------- page_title: str or None The page title, shown in the browser tab. If None, defaults to the filename of the script ("app.py" would show "app • Streamlit"). page_icon : Anything supported by st.image or str or None The page favicon. Besides the types supported by `st.image` (like URLs or numpy arrays), you can pass in an emoji as a string ("🦈") or a shortcode (":shark:"). If you're feeling lucky, try "random" for a random emoji! Emoji icons are courtesy of Twemoji and loaded from MaxCDN. layout: "centered" or "wide" How the page content should be laid out. Defaults to "centered", which constrains the elements into a centered column of fixed width; "wide" uses the entire screen. initial_sidebar_state: "auto" or "expanded" or "collapsed" How the sidebar should start out. Defaults to "auto", which hides the sidebar on mobile-sized devices, and shows it otherwise. "expanded" shows the sidebar initially; "collapsed" hides it. menu_items: dict Configure the menu that appears on the top-right side of this app. The keys in this dict denote the menu item you'd like to configure: - "Get help": str or None The URL this menu item should point to. If None, hides this menu item. - "Report a Bug": str or None The URL this menu item should point to. If None, hides this menu item. - "About": str or None A markdown string to show in the About dialog. If None, only shows Streamlit's default About text. Example ------- >>> st.set_page_config( ... page_title="Ex-stream-ly Cool App", ... page_icon="🧊", ... layout="wide", ... initial_sidebar_state="expanded", ... menu_items={ ... 'Get Help': 'https://www.extremelycoolapp.com/help', ... 'Report a bug': "https://www.extremelycoolapp.com/bug", ... 'About': "# This is a header. This is an *extremely* cool app!" ... } ... ) """ msg = ForwardMsg_pb2.ForwardMsg() if page_title: msg.page_config_changed.title = page_title if page_icon: if page_icon == "random": page_icon = get_random_emoji() msg.page_config_changed.favicon = image.image_to_url( page_icon, width=-1, # Always use full width for favicons clamp=False, channels="RGB", output_format="JPEG", image_id="favicon", allow_emoji=True, ) if layout == "centered": layout = PageConfig_pb2.PageConfig.CENTERED elif layout == "wide": layout = PageConfig_pb2.PageConfig.WIDE else: raise StreamlitAPIException( f'`layout` must be "centered" or "wide" (got "{layout}")' ) msg.page_config_changed.layout = layout if initial_sidebar_state == "auto": initial_sidebar_state = PageConfig_pb2.PageConfig.AUTO elif initial_sidebar_state == "expanded": initial_sidebar_state = PageConfig_pb2.PageConfig.EXPANDED elif initial_sidebar_state == "collapsed": initial_sidebar_state = PageConfig_pb2.PageConfig.COLLAPSED else: raise StreamlitAPIException( '`initial_sidebar_state` must be "auto" or "expanded" or "collapsed" ' + f'(got "{initial_sidebar_state}")' ) msg.page_config_changed.initial_sidebar_state = initial_sidebar_state if menu_items is not None: lowercase_menu_items = lower_clean_dict_keys(menu_items) validate_menu_items(lowercase_menu_items) menu_items_proto = msg.page_config_changed.menu_items set_menu_items_proto(lowercase_menu_items, menu_items_proto) ctx = get_report_ctx() if ctx is None: return ctx.enqueue(msg)