import folium
import geopandas as gpd
import plotly.express as px
from branca.colormap import LinearColormap
from folium.plugins import HeatMap
from streamlit_folium import folium_static
import streamlit as st
from streamlit_extras.stylable_container import stylable_container
from streamlit_extras.add_vertical_space import add_vertical_space
#import streamlit_shadcn_ui as ui
from streamlit_option_menu import option_menu
import pandas as pd
import plotly.graph_objects as go
with stylable_container(
key="banner",
css_styles="""
img {
width: 1800px;
height: 250px;
overflow: hidden;
position: relative;
object-fit: cover;
border-radius: 20px; /* Adiciona bordas arredondadas */
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
-webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); /* For Safari */
}
""",
):
st.image("src/Images/mp.jpg")
st.title("Mapas da área")
add_vertical_space(2)
st.markdown(""" ### :world_map: **UBS Flamengo: (IBGE 2022)** """)
@st.cache_resource
def load_data():
"""
A function that loads and reads geojson data for UBS Flamengo and converts it to the specified coordinate reference system.
"""
return gpd.read_file("flamengo_ibge2022.geojson").to_crs(epsg=4326)
gdf = load_data()
LATITUDE = -19.971591804
LONGITUDE = -44.057912815
lat = -19.96214
long = -44.05603
total_pop = gdf["POP"].sum()
col1, col2, col3 = st.columns([1, 1, 5])
STYLE = "static/style.css"
STYLES = "static/styles.html"
with open(STYLE, "r", encoding="utf-8") as f:
st.markdown(f"", unsafe_allow_html=True)
with open(STYLES, "r", encoding="utf-8") as f:
st.markdown(f"", unsafe_allow_html=True)
@st.cache_resource
def load_data():
"""
A function that loads and reads geojson data for UBS Flamengo and converts it to the specified coordinate reference system.
"""
return gpd.read_file("views/flamengo_ibge2022.geojson").to_crs(epsg=4326)
gdf = load_data()
LATITUDE = -19.971591804
LONGITUDE = -44.057912815
lat = -19.96214
long = -44.05603
total_pop = gdf["POP"].sum()
num_setores = len(gdf)
with st.expander("Visualização", expanded=True):
selected_tab = option_menu(
menu_title=None,
options=[
"Mapa IBGE",
"Área",
"População",
],
icons=[
"person",
"geo-alt",
"capsule-pill"
],
menu_icon="cast",
default_index=0,
orientation="horizontal",
styles={
"container": {
"padding": "5px",
"background-color": "#1E1E28",
"border-radius": "8px",
},
"icon": {
"color": "#64B5F6",
"font-size": "20px",
"padding-right": "8px",
},
"nav-link": {
"font-size": "16px",
"text-align": "center",
"margin": "5px",
"padding": "12px",
"background-color": "#2A2B3D",
"--hover-color": "#4B4B4B",
"color": "#FFFFFF",
"border-radius": "4px",
},
"nav-link-selected": {
"background-color": "#007BB5",
"color": "#FFFFFF",
"font-weight": "bold",
},
"separator": {
"border-color": "#303030",
"margin": "0 10px",
},
},
)
if selected_tab == "Mapa IBGE":
col1, col2, col3, col4, col5 = st.columns([1.5, 1.5, 0.8, 5, 0.5])
with col1:
st.metric(label="👪 População Total", value=f"{total_pop:,} habitantes", help="Dados do Censo 2022 IBGE")
map_type = st.selectbox("Tipo de mapa", ["População", "Densidade", "Heatmap"])
with col2:
st.metric(label="🗺️ Número de Setores Censitários", value=f"{num_setores}", help="Dados do Censo 2022 IBGE")
base_map = st.selectbox("Mapa base", ["Cartodb Positron", "OpenStreetMap"])
with col4:
with st.container(border=False, height=400):
row1, row2, row3 = st.columns([0.5, 3, 0.9])
with row1:
st.write('')
with row2:
st.write("""
### Definição de Setor Censitário
Um **setor censitário** é a menor unidade territorial utilizada pelo
IBGE para a coleta de dados em censos demográficos.
Cada setor censitário é uma área contínua dentro de um município, delimitado
por características físicas e populacionais. Geralmente contém entre 250 e
350 domicílios.
Os setores censitários são fundamentais em pesquisas mais elaboradas.
Permitem uma análise granular da distribuição populacional, socioeconômica
e das condições de moradia em diferentes regiões do país. Essa unidade de
medida é fundamental para a elaboração de políticas públicas, planejamento
urbano, e outras atividades que dependem de informações demográficas precisas.
""")
with row3:
st.write('')
col1, col2 = st.columns(2)
with col1:
m = folium.Map(
location=[LATITUDE, LONGITUDE], tiles=base_map, zoom_start=15
)
dns_p = "Densidade pop. (hab/km²) UBS Flamengo - IBGE 2022"
if map_type in ["População", "Densidade"]:
if map_type == "População":
column = "POP"
caption = "Pop. residente UBS Flamengo IBGE 2022"
else:
gdf["DENSIDADE"] = gdf["POP"] / gdf["AREA_KM2"]
column = "DENSIDADE"
caption = dns_p
colorscale = px.colors.sequential.Viridis
colormap = LinearColormap(
colors=colorscale,
vmin=gdf[column].min(),
vmax=gdf[column].max(),
caption=caption,
)
folium.GeoJson(
gdf,
style_function=lambda feature: {
"fillColor": colormap(feature["properties"][column]),
"color": "black",
"weight": 1,
"fillOpacity": 0.7,
},
highlight_function=lambda feature: {
"fillColor": "#ffaf00",
"color": "green",
"weight": 3,
"fillOpacity": 0.9,
},
tooltip=folium.features.GeoJsonTooltip(
fields=["CD_SETOR", column, "AREA_KM2"],
aliases=[
"Setor Censitário:",
f"{caption}:",
"Área (km²):",
],
style=(
"background-color: white; color: #333333;"
"font-family: calibri; font-size: 12px;"
"padding: 10px;"
),
),
).add_to(m)
colormap.add_to(m)
elif map_type == "Heatmap":
heat_data = [
[
row["geometry"].centroid.y,
row["geometry"].centroid.x,
row["POP"],
]
for idx, row in gdf.iterrows()
]
HeatMap(heat_data).add_to(m)
folium.Marker(
[lat, long],
popup="UBS Flamengo",
tooltip="UBS Flamengo",
icon=folium.Icon(color="red", icon="info-sign"),
).add_to(m)
STYLE_STATEMENT = (
""
)
m.get_root().html.add_child(folium.Element(STYLE_STATEMENT))
folium_static(m)
with col2:
fig = px.bar(
gdf,
x="CD_SETOR",
y="POP",
title="Distribuição da População por Setor Censitário",
color="POP",
color_continuous_scale=px.colors.sequential.Viridis,
)
st.plotly_chart(fig)
age_columns = [
"POP_0A4", "POP_5A9", "POP_10A14", "POP_15A19", "POP_20A24",
"POP_25A29", "POP_30A34", "POP_35A39", "POP_40A44", "POP_45A49",
"POP_50A54", "POP_55A59", "POP_60A64", "POP_65A69", "POP_70A74",
"POP_75A79", "POP_80A84", "POP_85A89", "POP_90A94", "POP_95A99",
"POP_100OUMAIS",
]
fig = px.bar()
elif selected_tab == "Área":
st.subheader("Crescimento populacional - UBS Flamengo")
with stylable_container(
key="banner",
css_styles="""
img {
width: 1800px;
height: 340px;
overflow: hidden;
position: relative;
object-fit: cover;
border-radius: 20px; /* Adiciona bordas arredondadas */
mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
-webkit-mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0)); /* For Safari */
}
""",
):
st.image("src/Images/pop.jpg")
st.title("Crescimento populacional - UBS Flamengo")
raw_data = [
{"Mês": "mai-21", "Usuários": 3402, "Domicílios": 1440, "Famílias": 1269},
{"Mês": "jun-21", "Usuários": 3503, "Domicílios": 1462, "Famílias": 1304},
{"Mês": "jul-21", "Usuários": 3559, "Domicílios": 1478, "Famílias": 1323},
{"Mês": "ago-21", "Usuários": 3592, "Domicílios": 1490, "Famílias": 1338},
{"Mês": "set-21", "Usuários": 3755, "Domicílios": 1573, "Famílias": 1380},
{"Mês": "out-21", "Usuários": 3776, "Domicílios": 1533, "Famílias": 1384},
{"Mês": "nov-21", "Usuários": 3839, "Domicílios": 1553, "Famílias": 1397},
{"Mês": "dez-21", "Usuários": 3926, "Domicílios": 1581, "Famílias": 1423},
{"Mês": "jan-22", "Usuários": 3951, "Domicílios": 1596, "Famílias": 1437},
{"Mês": "fev-22", "Usuários": 4035, "Domicílios": 1638, "Famílias": 1465},
{"Mês": "mar-22", "Usuários": 4131, "Domicílios": 1672, "Famílias": 1500},
{"Mês": "abr-22", "Usuários": 4306, "Domicílios": 1723, "Famílias": 1555},
{"Mês": "mai-22", "Usuários": 4553, "Domicílios": 1795, "Famílias": 1625},
{"Mês": "jun-22", "Usuários": 4639, "Domicílios": 1817, "Famílias": 1653},
{"Mês": "jul-22", "Usuários": 4719, "Domicílios": 1848, "Famílias": 1676},
{"Mês": "ago-22", "Usuários": 4776, "Domicílios": 1869, "Famílias": 1687},
{"Mês": "set-22", "Usuários": 4831, "Domicílios": 1883, "Famílias": 1699},
{"Mês": "out-22", "Usuários": 4871, "Domicílios": 1900, "Famílias": 1709},
{"Mês": "nov-22", "Usuários": 4874, "Domicílios": 1906, "Famílias": 1708},
{"Mês": "dez-22", "Usuários": 4920, "Domicílios": 1914, "Famílias": 1720},
{"Mês": "jan-23", "Usuários": 5135, "Domicílios": 2006, "Famílias": 1776},
{"Mês": "fev-23", "Usuários": 5396, "Domicílios": 2084, "Famílias": 1848},
{"Mês": "mar-23", "Usuários": 5544, "Domicílios": 2127, "Famílias": 1893},
{"Mês": "abr-23", "Usuários": 5546, "Domicílios": 2140, "Famílias": 1910},
{"Mês": "mai-23", "Usuários": 5579, "Domicílios": 2164, "Famílias": 1920},
{"Mês": "jun-23", "Usuários": 5642, "Domicílios": 2181, "Famílias": 1946},
{"Mês": "jul-23", "Usuários": 5681, "Domicílios": 2200, "Famílias": 1961},
{"Mês": "ago-23", "Usuários": 5728, "Domicílios": 2208, "Famílias": 1972},
{"Mês": "set-23", "Usuários": 5774, "Domicílios": 2228, "Famílias": 1983},
{"Mês": "out-23", "Usuários": 5841, "Domicílios": 2245, "Famílias": 2007},
{"Mês": "nov-23", "Usuários": 5891, "Domicílios": 2297, "Famílias": 2027},
{"Mês": "dez-23", "Usuários": 5933, "Domicílios": 2281, "Famílias": 2036},
{"Mês": "jan-24", "Usuários": 5982, "Domicílios": 2307, "Famílias": 2050},
{"Mês": "fev-24", "Usuários": 6005, "Domicílios": 2333, "Famílias": 2057},
{"Mês": "mar-24", "Usuários": 6020, "Domicílios": 2327, "Famílias": 2070},
{"Mês": "abr-24", "Usuários": 6074, "Domicílios": 2370, "Famílias": 2095},
]
df = pd.DataFrame(raw_data)
@st.cache_data
def processar_dados(dados, intervalo):
"""
Process data based on the specified interval and return the aggregated data.
Parameters:
- dados: List of dictionaries containing data for each month.
- intervalo: String indicating the interval for data aggregation.
Returns:
- List of dictionaries with aggregated data based on the specified interval.
"""
if intervalo == "Mensal":
return dados
agrupamentos = {"Trimestral": 3, "Semestral": 6, "Anual": 12}
dados_agrupados = []
for i in range(0, len(dados), agrupamentos[intervalo]):
grupo = dados[i : i + agrupamentos[intervalo]]
ultimo_Mês = grupo[-1]["Mês"]
dados_agrupados.append(
{
"Mês": ultimo_Mês,
"Usuários": max(d["Usuários"] for d in grupo),
"Domicílios": max(d["Domicílios"] for d in grupo),
"Famílias": max(d["Famílias"] for d in grupo),
}
)
return dados_agrupados
@st.cache_data
def formatar_data(Mês):
"""
A function that formats the data based on the input Mês parameter.
Parameters:
- Mês (str): A string containing the month and year separated by a hyphen.
Returns:
- str: A formatted string in the format "month/year".
"""
m, a = Mês.split("-")
return f"{m}/{a}"
# Adicionando estilo personalizado
st.markdown(
"""
""",
unsafe_allow_html=True,
)
# Criando duas colunas para os menus de opções
col1, col2, col3 = st.columns([3, 2, 2])
with col1:
st.dataframe(df, use_container_width=True, height=250, hide_index=True)
with col2:
intervalo = option_menu(
"Intervalo de Tempo",
["Mensal", "Trimestral", "Semestral", "Anual"],
icons=["calendar-month", "calendar-quarter", "calendar-half", "calendar-year"],
menu_icon="cast",
default_index=0,
styles={
"container": {"padding": "0!important", "background-color": "#f0f0f3", "border-radius": "15px", "box-shadow": "5px 5px 10px #d1d1d4, -5px -5px 10px #ffffff"},
"icon": {"color": "#007bff", "font-size": "18px"},
"nav-link": {
"font-size": "14px",
"text-align": "center",
"margin": "5px",
"padding": "10px",
"--hover-color": "#e6e6e9",
"color": "#333333",
"border-radius": "10px",
"transition": "all 0.3s ease",
},
"nav-link-selected": {"background-color": "#ffffff", "box-shadow": "inset 3px 3px 5px #d1d1d4, inset -3px -3px 5px #ffffff"},
"separator": {"border-color": "#e0e0e3"},
},
)
with col3:
metrica = option_menu(
"Métrica",
["Todos", "Usuários", "Domicílios", "Famílias"],
icons=["list", "person", "house", "people"],
menu_icon="cast",
default_index=0,
styles={
"container": {"padding": "0!important", "background-color": "#f0f0f3", "border-radius": "15px", "box-shadow": "5px 5px 10px #d1d1d4, -5px -5px 10px #ffffff"},
"icon": {"color": "#007bff", "font-size": "18px"},
"nav-link": {
"font-size": "14px",
"text-align": "center",
"margin": "5px",
"padding": "10px",
"--hover-color": "#e6e6e9",
"color": "#333333",
"border-radius": "10px",
"transition": "all 0.3s ease",
},
"nav-link-selected": {"background-color": "#ffffff", "box-shadow": "inset 3px 3px 5px #d1d1d4, inset -3px -3px 5px #ffffff"},
"separator": {"border-color": "#e0e0e3"},
},
)
dados_processados = processar_dados(raw_data, intervalo)
# Switch para mostrar valores nos pontos
mostrar_valores = st.checkbox("Mostrar valores nos pontos", value=True)
# Criação do gráfico
fig = go.Figure()
metricas = ["Usuários", "Domicílios", "Famílias"] if metrica == "Todos" else [metrica]
cores = {"Usuários": "#007bff", "Domicílios": "#28a745", "Famílias": "#ffc107"}
# Slider Component
# st.sidebar.header("Ajustes dos Balões")
# balloon_positions = {}
# for m in metricas:
# balloon_positions[m] = st.sidebar.slider(
# f"Posição do balão para {m}", min_value=-100, max_value=0, value=-40, step=5
# )
annotations = []
for m in metricas:
x_data = [formatar_data(d["Mês"]) for d in dados_processados]
y_data = [d[m] for d in dados_processados]
fig.add_trace(
go.Scatter(
x=x_data,
y=y_data,
mode="lines+markers",
name=m,
line=dict(color=cores[m], width=3),
marker=dict(size=10, symbol="circle", line=dict(width=2, color="white")),
)
)
if mostrar_valores:
for i, (x, y) in enumerate(zip(x_data, y_data)):
annotations.append(
dict(
x=x,
y=y,
xref="x",
yref="y",
text=f"{y:,.0f}",
showarrow=True,
arrowhead=2,
ax=0,
ay=balloon_positions[m],
bgcolor=cores[m],
opacity=0.8,
bordercolor="white",
borderwidth=2,
borderpad=4,
font=dict(color="white", size=10),
boxshadow=dict(x=2, y=2, blur=3, color='rgba(0,0,0,0.3)'),
)
)
fig.update_layout(
title={
"text": "Crescimento na Área de Saúde",
"y": 0.95,
"x": 0.5,
"xanchor": "center",
"yanchor": "top",
"font": dict(size=24, color="#333333"),
},
xaxis_title="Mês",
yaxis_title="Quantidade",
legend_title="Métricas",
template="plotly_white",
plot_bgcolor="#f0f0f3",
paper_bgcolor="#f0f0f3",
font=dict(color="#333333"),
xaxis=dict(showgrid=True, gridcolor="#e0e0e3", tickangle=45),
yaxis=dict(showgrid=True, gridcolor="#e0e0e3"),
legend=dict(
bgcolor="rgba(255,255,255,0.8)",
bordercolor="#e0e0e3",
borderwidth=1,
font=dict(size=12, color="#333333"),
),
margin=dict(l=50, r=50, t=80, b=50),
annotations=annotations,
shapes=[
dict(
type="rect",
xref="paper", yref="paper",
x0=0, y0=0, x1=1, y1=1,
line=dict(color="#e0e0e3", width=2),
fillcolor="#f0f0f3",
layer="below"
)
]
)
fig.add_shape(
type="rect",
xref="paper", yref="paper",
x0=-0.05, y0=-0.05, x1=1.05, y1=1.05,
line=dict(color="rgba(0,0,0,0.1)", width=5),
fillcolor="rgba(0,0,0,0)",
layer="below"
)
fig.update_layout(
updatemenus=[
dict(
type="buttons",
direction="left",
buttons=[
dict(args=[{"visible": [True, True, True]}], label="Mostrar Tudo", method="restyle"),
dict(args=[{"visible": [True, False, False]}], label="Usuários", method="restyle"),
dict(args=[{"visible": [False, True, False]}], label="Domicílios", method="restyle"),
dict(args=[{"visible": [False, False, True]}], label="Famílias", method="restyle")
],
pad={"r": 10, "t": 10},
showactive=True,
x=0.1,
xanchor="left",
y=1.1,
yanchor="top",
bgcolor="#ffffff",
bordercolor="#e0e0e3",
borderwidth=1,
font=dict(color="#333333"),
),
]
)
st.plotly_chart(fig, use_container_width=True)
add_vertical_space(10)
st.write('----')