简介
基于 prettymaps 项目 Prettymapp 是对 @marceloprates 的精彩 prettymaps 项目的重写。 最初的想法、设计和实现都归功于他。 prettymapp 重写的重点是速度和与网络应用程序接口相匹配的配置。 它放弃了更复杂的配置选项,转而提高速度、降低代码复杂性并简化配置界面。 它已通过部分测试,并增加了一个流光网络应用程序组件。
代码
#导入库
import copy
import json
import streamlit as st
from streamlit_image_select import image_select
from utils import (
st_get_osm_geometries,
st_plot_all,
get_colors_from_style,
gdf_to_bytesio_geojson,
)
from prettymapp.geo import GeoCodingError, get_aoi
from prettymapp.settings import STYLES
#设定界面的小图片
st.set_page_config(
page_title="prettymapp", page_icon="🖼️", initial_sidebar_state="collapsed"
)
st.markdown("# Prettymapp")
with open("./streamlit-prettymapp/examples.json", "r", encoding="utf8") as f:
EXAMPLES = json.load(f)
if not st.session_state:
st.session_state.update(EXAMPLES["Macau"])
lc_class_colors = get_colors_from_style("Peach")
st.session_state.lc_classes = list(lc_class_colors.keys()) # type: ignore
st.session_state.update(lc_class_colors)
st.session_state["previous_style"] = "Peach"
st.session_state["previous_example_index"] = 0
example_image_pattern = "streamlit-prettymapp/example_prints/{}_small.png"
example_image_fp = [
example_image_pattern.format(name.lower()) for name in list(EXAMPLES.keys())[:4]
]
index_selected = image_select(
"",
images=example_image_fp,
captions=list(EXAMPLES.keys())[:4],
index=0,
return_value="index",
)
if index_selected != st.session_state["previous_example_index"]:
name_selected = list(EXAMPLES.keys())[index_selected]
st.session_state.update(EXAMPLES[name_selected].copy())
st.session_state["previous_example_index"] = index_selected
st.write("")
form = st.form(key="form_settings")
col1, col2, col3 = form.columns([3, 1, 1])
address = col1.text_input(
"Location address",
key="address",
)
radius = col2.slider(
"Radius (meter)",
100,
1500,
key="radius",
)
style: str = col3.selectbox(
"Color theme",
options=list(STYLES.keys()),
key="style",
)
expander = form.expander("Customize map style")
col1style, col2style, _, col3style = expander.columns([2, 2, 0.1, 1])
shape_options = ["circle", "rectangle"]
shape = col1style.radio(
"Map Shape",
options=shape_options,
key="shape",
)
bg_shape_options = ["rectangle", "circle", None]
bg_shape = col1style.radio(
"Background Shape",
options=bg_shape_options,
key="bg_shape",
)
bg_color = col1style.color_picker(
"Background Color",
key="bg_color",
)
bg_buffer = col1style.slider(
"Background Size",
min_value=0,
max_value=50,
help="How much the background extends beyond the figure.",
key="bg_buffer",
)
col1style.markdown("---")
contour_color = col1style.color_picker(
"Map contour color",
key="contour_color",
)
contour_width = col1style.slider(
"Map contour width",
0,
30,
help="Thickness of contour line sourrounding the map.",
key="contour_width",
)
name_on = col2style.checkbox(
"Display title",
help="If checked, adds the selected address as the title. Can be customized below.",
key="name_on",
)
custom_title = col2style.text_input(
"Custom title (optional)",
max_chars=30,
key="custom_title",
)
font_size = col2style.slider(
"Title font size",
min_value=1,
max_value=50,
key="font_size",
)
font_color = col2style.color_picker(
"Title font color",
key="font_color",
)
text_x = col2style.slider(
"Title left/right",
-100,
100,
key="text_x",
)
text_y = col2style.slider(
"Title top/bottom",
-100,
100,
key="text_y",
)
text_rotation = col2style.slider(
"Title rotation",
-90,
90,
key="text_rotation",
)
if style != st.session_state["previous_style"]:
st.session_state.update(get_colors_from_style(style)) # type: ignore
draw_settings = copy.deepcopy(STYLES[style])
for lc_class in st.session_state.lc_classes:
picked_color = col3style.color_picker(lc_class, key=lc_class)
if "_" in lc_class:
lc_class, idx = lc_class.split("_")
draw_settings[lc_class]["cmap"][int(idx)] = picked_color # type: ignore
else:
draw_settings[lc_class]["fc"] = picked_color
form.form_submit_button(label="Submit")
result_container = st.empty()
with st.spinner("Creating map... (may take up to a minute)"):
rectangular = shape != "circle"
try:
aoi = get_aoi(address=address, radius=radius, rectangular=rectangular)
except GeoCodingError as e:
st.error(f"ERROR: {str(e)}")
st.stop()
df = st_get_osm_geometries(aoi=aoi)
config = {
"aoi_bounds": aoi.bounds,
"draw_settings": draw_settings,
"name_on": name_on,
"name": address if custom_title == "" else custom_title,
"font_size": font_size,
"font_color": font_color,
"text_x": text_x,
"text_y": text_y,
"text_rotation": text_rotation,
"shape": shape,
"contour_width": contour_width,
"contour_color": contour_color,
"bg_shape": bg_shape,
"bg_buffer": bg_buffer,
"bg_color": bg_color,
}
fig = st_plot_all(_df=df, **config)
# result_container.write(html, unsafe_allow_html=True)
st.pyplot(fig, pad_inches=0, bbox_inches="tight", transparent=True, dpi=300)
# svg_string = plt_to_svg(fig)
# html = svg_to_html(svg_string)
# st.write("")
# fname = slugify(address)
# img_format = st.selectbox("Download image as", ["svg", "png", "jpg"], index=0)
# if img_format == "svg":
# data = svg_string
# elif img_format == "png":
# import io
#
# data = io.BytesIO()
# fig.savefig(data, pad_inches=0, bbox_inches="tight", transparent=True)
# st.download_button(label="Download image", data=data, file_name=f"{fname}.{img_format}")
st.markdown("</br>", unsafe_allow_html=True)
st.markdown("</br>", unsafe_allow_html=True)
ex1, ex2 = st.columns(2)
with ex1.expander("Export geometries as GeoJSON"):
st.write(f"{df.shape[0]} geometries")
st.download_button(
label="Download",
data=gdf_to_bytesio_geojson(df),
file_name=f"prettymapp_{address[:10]}.geojson",
mime="application/geo+json",
)
config = {"address": address, **config}
with ex2.expander("Export map configuration"):
st.write(config)
st.markdown("---")
st.write(
"Share on social media with the hashtag [#prettymaps](https://twitter.com/search?q=%23prettymaps&src=typed_query) !"
)
st.markdown(
"More infos and :star: at [github.com/chrieke/prettymapp](https://github.com/chrieke/prettymapp)"
)
st.session_state["previous_style"] = style
函数
st.set_page_config
Function signature[source] | |
---|---|
st.set_page_config(page_title=None, page_icon=None, layout="centered", initial_sidebar_state="auto", menu_items=None) | |
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, str, or None) | The page favicon. If page_icon is None (default), the favicon will be a monochrome Streamlit logo. In addition to the types supported by st.image (like URLs or numpy arrays), the following strings are valid:
Note Colors are not supported for Material icons. When you use a Material icon for favicon, it will be black, regardless of browser theme. |
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", "expanded", or "collapsed") | How the sidebar should start out. Defaults to "auto", which hides the sidebar on small devices and shows it otherwise. "expanded" shows the sidebar initially; "collapsed" hides it. In most cases, you should just use "auto", otherwise the app will look bad when embedded and viewed on mobile. |
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:
The URL may also refer to an email address e.g. mailto:john@example.com. |
import streamlit as st
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!"
}
)
st.radio
Function signature[source] | |
---|---|
st.radio(label, options, index=0, format_func=special_internal_function, key=None, help=None, on_change=None, args=None, kwargs=None, *, disabled=False, horizontal=False, captions=None, label_visibility="visible") | |
Returns | |
(any) | The selected option or None if no option is selected. |
Parameters | |
label (str) | A short label explaining to the user what this radio group is for. The label can optionally contain GitHub-flavored Markdown of the following types: Bold, Italics, Strikethroughs, Inline Code, and Links. Unsupported Markdown elements are unwrapped so only their children (text contents) render. Display unsupported elements as literal characters by backslash-escaping them. E.g., "1\. Not an ordered list". See the body parameter of st.markdown for additional, supported Markdown directives. For accessibility reasons, you should never set an empty label (label="") but hide it with label_visibility if needed. In the future, we may disallow empty labels by raising an exception. |
options (Iterable) | Labels for the select options in an Iterable. For example, this can be a list, numpy.ndarray, pandas.Series, pandas.DataFrame, or pandas.Index. For pandas.DataFrame, the first column is used. Labels can include markdown as described in the label parameter and will be cast to str internally by default. |
index (int or None) | The index of the preselected option on first render. If None, will initialize empty and return None until the user selects an option. Defaults to 0 (the first option). |
format_func (function) | Function to modify the display of radio options. It receives the raw option as an argument and should output the label to be shown for that option. This has no impact on the return value of the radio. |
key (str or int) | An optional string or integer to use as the unique key for the widget. If this is omitted, a key will be generated for the widget based on its content. Multiple widgets of the same type may not share the same key. |
help (str) | An optional tooltip that gets displayed next to the radio. |
on_change (callable) | An optional callback invoked when this radio's value changes. |
args (tuple) | An optional tuple of args to pass to the callback. |
kwargs (dict) | An optional dict of kwargs to pass to the callback. |
disabled (bool) | An optional boolean, which disables the radio button if set to True. The default is False. |
horizontal (bool) | An optional boolean, which orients the radio group horizontally. The default is false (vertical buttons). |
captions (iterable of str or None) | A list of captions to show below each radio button. If None (default), no captions are shown. |
label_visibility ("visible", "hidden", or "collapsed") | The visibility of the label. If "hidden", the label doesn't show but there is still empty space for it above the widget (equivalent to label=""). If "collapsed", both the label and the space are removed. Default is "visible". |
st.pyplot
Function signature[source] | |
---|---|
st.pyplot(fig=None, clear_figure=None, use_container_width=True, **kwargs) | |
Parameters | |
fig (Matplotlib Figure) | The Matplotlib Figure object to render. See https://matplotlib.org/stable/gallery/index.html for examples. Note When this argument isn't specified, this function will render the global Matplotlib figure object. However, this feature is deprecated and will be removed in a later version. |
clear_figure (bool) | If True, the figure will be cleared after being rendered. If False, the figure will not be cleared after being rendered. If left unspecified, we pick a default based on the value of fig.
|
use_container_width (bool) | Whether to override the figure's native width with the width of the parent container. If use_container_width is True (default), Streamlit sets the width of the figure to match the width of the parent container. If use_container_width is False, Streamlit sets the width of the chart to fit its contents according to the plotting library, up to the width of the parent container. |
**kwargs (any) | Arguments to pass to Matplotlib's savefig function. |