import folium import geopandas as gpd import pandas as pd import plotly.express as px import plotly.graph_objects as go import streamlit as st from branca.colormap import LinearColormap from folium.plugins import HeatMap from streamlit_extras.add_vertical_space import add_vertical_space from streamlit_extras.stylable_container import stylable_container from streamlit_folium import folium_static from streamlit_option_menu import option_menu 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") 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("views/flamengo_ibge2022.geojson").to_crs(epsg=4326) gdf = load_data() LATITUDE = -19.965591804 LONGITUDE = -44.057912815 lat = -19.96214 long = -44.05603 total_pop = gdf["População"].sum() num_setores = len(gdf) 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) with st.expander("Visualização", expanded=True): selected_tab = option_menu( menu_title=None, options=[ "Mapa IBGE", "Equipe Azul", "Equipe Vermelha", ], 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, 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 É a menor unidade territorial utilizada pelo IBGE para a coleta de dados em censos demográficos. Cada setor é delimitado por características físicas e populacionais. Geralmente contém entre 250 e 350 domicílios. Fundamentais em pesquisas, elaboração de políticas públicas, planejamento urbano, e atividades que dependem de informações demográficas precisas. Permitem uma análise granular da distribuição populacional, socioeconômica e das condições de moradia. É fundamental . """) with row3: st.write('') add_vertical_space(3) 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 = "População" caption = "Pop. residente UBS Flamengo IBGE 2022" else: gdf["DENSIDADE"] = gdf["População"] / gdf["Área em km²"] 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.6, }, highlight_function=lambda feature: { "fillColor": "#ffaf00", "color": "green", "weight": 3, "fillOpacity": 0.9, } if feature else {}, tooltip=folium.GeoJsonTooltip( fields=["Setor", column, "Área em km²"], 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["População"], ] 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 = ( "") # folium.LayerControl().add_to(m) # Adding Layer Control is good practice. # Display the map folium_static(m) # m.get_root().html.add_child(folium.Element(STYLE_STATEMENT)) # folium_static(m) with col2: fig = px.bar( gdf, x="Setor", y="População", title="Distribuição da População por Setor Censitário", color="População", color_continuous_scale=px.colors.sequential.Viridis, ) st.plotly_chart(fig) age_columns = [ "População_0A4", "População_5A9", "População_10A14", "População_15A19", "População_20A24", "População_25A29", "População_30A34", "População_35A39", "População_40A44", "População_45A49", "População_50A54", "População_55A59", "População_60A64", "População_65A69", "População_70A74", "População_75A79", "População_80A84", "População_85A89", "População_90A94", "População_95A99", "População_100OUMAIS", ] fig = px.bar() elif selected_tab == "Equipe Azul": st.subheader("Crescimento populacional - UBS Flamengo - Equipe Azul") with stylable_container( key="exp1", css_styles=""" img { width: 200px; height: 200px; 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/blue.png", caption='Equipe Azul') # st.image("src/Images/pop.jpg") raw_data = [ { "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": 5680, "Domicílios": 2200, "Famílias": 1961 }, { "Mês": "ago-23", "Usuários": 5727, "Domicílios": 2208, "Famílias": 1972 }, { "Mês": "set-23", "Usuários": 5772, "Domicílios": 2228, "Famílias": 1983 }, { "Mês": "out-23", "Usuários": 5839, "Domicílios": 2245, "Famílias": 2007 }, { "Mês": "nov-23", "Usuários": 5889, "Domicílios": 2297, "Famílias": 2027 }, { "Mês": "dez-23", "Usuários": 5932, "Domicílios": 2281, "Famílias": 2036 }, { "Mês": "jan-24", "Usuários": 5980, "Domicílios": 2307, "Famílias": 2050 }, { "Mês": "fev-24", "Usuários": 6003, "Domicílios": 2333, "Famílias": 2057 }, { "Mês": "mar-24", "Usuários": 6018, "Domicílios": 2327, "Famílias": 2070 }, { "Mês": "abr-24", "Usuários": 6072, "Domicílios": 2370, "Famílias": 2095 }, { "Mês": "mai-24", "Usuários": 6080, "Domicílios": 2357, "Famílias": 2097 }, { "Mês": "jun-24", "Usuários": 6112, "Domicílios": 2372, "Famílias": 2108 }, { "Mês": "jul-24", "Usuários": 6130, "Domicílios": 2413, "Famílias": 2110 }, { "Mês": "ago-24", "Usuários": 6169, "Domicílios": 2397, "Famílias": 2118 }, ] 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) # 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" } 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={ "color": cores[m], "width": 3 }, marker={ "size": 12, "symbol": "circle", "line": { "width": 2, "color": "white" } }, )) fig.update_layout( hoverlabel={ "bgcolor": "white", "font_size": 16, "font_family": "Arial", }, hovermode="x unified", ) fig.update_traces(hovertemplate="%{y}
%{x}") st.plotly_chart(fig, use_container_width=True) elif selected_tab == "Equipe Vermelha": st.subheader("Crescimento populacional - UBS Flamengo - Equipe Vermelha") with stylable_container( key="exp1", css_styles=""" img { width: 200px; height: 200px; 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/red.png", caption='Equipe Vermelha') # st.image("src/Images/pop.jpg") raw_red = [{ "Mês": "set-21", "Usuários": 3542, "Domicílios": 1243, "Famílias": 1191 }, { "Mês": "out-21", "Usuários": 3647, "Domicílios": 1240, "Famílias": 1204 }, { "Mês": "nov-21", "Usuários": 3730, "Domicílios": 1267, "Famílias": 1227 }, { "Mês": "dez-21", "Usuários": 3847, "Domicílios": 1307, "Famílias": 1267 }, { "Mês": "jan-22", "Usuários": 3895, "Domicílios": 1328, "Famílias": 1284 }, { "Mês": "fev-22", "Usuários": 3937, "Domicílios": 1342, "Famílias": 1297 }, { "Mês": "mar-22", "Usuários": 4082, "Domicílios": 1393, "Famílias": 1348 }, { "Mês": "abr-22", "Usuários": 4248, "Domicílios": 1434, "Famílias": 1375 }, { "Mês": "mai-22", "Usuários": 4440, "Domicílios": 1509, "Famílias": 1442 }, { "Mês": "jun-22", "Usuários": 4646, "Domicílios": 1575, "Famílias": 1499 }, { "Mês": "jul-22", "Usuários": 4783, "Domicílios": 1616, "Famílias": 1539 }, { "Mês": "ago-22", "Usuários": 4909, "Domicílios": 1670, "Famílias": 1567 }, { "Mês": "set-22", "Usuários": 5008, "Domicílios": 1720, "Famílias": 1609 }, { "Mês": "out-22", "Usuários": 5017, "Domicílios": 1721, "Famílias": 1610 }, { "Mês": "nov-22", "Usuários": 5037, "Domicílios": 1742, "Famílias": 1613 }, { "Mês": "dez-22", "Usuários": 5060, "Domicílios": 1742, "Famílias": 1615 }, { "Mês": "jan-23", "Usuários": 5107, "Domicílios": 1708, "Famílias": 1563 }, { "Mês": "fev-23", "Usuários": 5127, "Domicílios": 1631, "Famílias": 1496 }, { "Mês": "mar-23", "Usuários": 5262, "Domicílios": 1667, "Famílias": 1533 }, { "Mês": "abr-23", "Usuários": 5279, "Domicílios": 1682, "Famílias": 1545 }, { "Mês": "mai-23", "Usuários": 5361, "Domicílios": 1719, "Famílias": 1575 }, { "Mês": "jun-23", "Usuários": 5381, "Domicílios": 1728, "Famílias": 1591 }, { "Mês": "jul-23", "Usuários": 5429, "Domicílios": 1766, "Famílias": 1609 }, { "Mês": "ago-23", "Usuários": 5417, "Domicílios": 1743, "Famílias": 1618 }, { "Mês": "set-23", "Usuários": 5447, "Domicílios": 1748, "Famílias": 1632 }, { "Mês": "out-23", "Usuários": 5495, "Domicílios": 1772, "Famílias": 1646 }, { "Mês": "nov-23", "Usuários": 5496, "Domicílios": 1775, "Famílias": 1650 }, { "Mês": "dez-23", "Usuários": 5519, "Domicílios": 1767, "Famílias": 1657 }, { "Mês": "jan-24", "Usuários": 5560, "Domicílios": 1793, "Famílias": 1673 }, { "Mês": "fev-24", "Usuários": 5574, "Domicílios": 1795, "Famílias": 1679 }, { "Mês": "mar-24", "Usuários": 5576, "Domicílios": 1789, "Famílias": 1676 }, { "Mês": "abr-24", "Usuários": 5624, "Domicílios": 1824, "Famílias": 1696 }, { "Mês": "mai-24", "Usuários": 5699, "Domicílios": 1827, "Famílias": 1713 }, { "Mês": "jun-24", "Usuários": 5739, "Domicílios": 1843, "Famílias": 1733 }, { "Mês": "jul-24", "Usuários": 5739, "Domicílios": 1877, "Famílias": 1742 }, { "Mês": "ago-24", "Usuários": 5760, "Domicílios": 1881, "Famílias": 1757 }] df = pd.DataFrame(raw_red) @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_red, intervalo) # 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" } 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={ "color": cores[m], "width": 3 }, marker={ "size": 12, "symbol": "circle", "line": { "width": 2, "color": "white" } }, )) fig.update_layout( hoverlabel={ "bgcolor": "white", "font_size": 16, "font_family": "Arial", }, hovermode="x unified", ) fig.update_traces(hovertemplate="%{y}
%{x}") st.plotly_chart(fig, use_container_width=True) add_vertical_space(10) st.write('----')