Criando um dashboard interativo com Streamlit

O Streamlit é uma ferramenta incrível que permite criar rapidamente aplicações web altamente interativos em torno de seus dados, e não requer nenhum conhecimento de desenvolvimento web!

June 22, 2021

O Streamlit é um framework open-source que permite construir aplicações web interativas sem precisar ter nenhum conhecimento prévio em HTML ou CSS, somente Python!

Existem várias bibliotecas de visualização que o Streamlit suporta como Plotly, Altair, Bokeh, etc.

Nesse post iremos utilizar o Streamlit junto do Plotly e da biblioteca Folium para visualizar um mapa interativo com dados do Airbnb do Rio de Janeiro.

Link com o código completo da aplicação: https://github.com/andmonteiro/streamlit-airbnb

Instalação

Para utilização do Streamlit e as outras bibliotecas, deve-se instalar usando o comando:

pip install streamlit
pip install geopandas
pip install pandas
pip install folium
pip install dash

Importamos as seguintes bibliotecas:

import pandas as pd
import geopandas
import streamlit as st
import folium
import plotly.express as px

from streamlit_folium import folium_static
from folium.plugins import MarkerCluster

Utilizaremos dois arquivos para esse projeto:

DATA_URL - dataset devidamente tratado.

GEOJSON_URL - arquivo GEOJSON com os limites dos bairros para utilizar com a biblioteca Folium.

DATA_URL = "https://raw.githubusercontent.com/anssodre/datasets/master/airbnb_rj.csv"
GEOJSON_URL = 'https://raw.githubusercontent.com/anssodre/datasets/master/Limite_de_Bairros.geojson'

Cache de Dados

O Streamlit fornece um mecanismo de cache que permite que os dados sejam baixados apenas uma vez e armazenados para uso futuro. Assim, cada vez que for feita uma consulta não será necessário carregar todo o dataset novamente.

Isso é feito utilizando o @st.cache() antes da função.

Para mais detalhes de como funciona você pode ver na documentação do Streamlit:

https://docs.streamlit.io/en/stable/caching.html

@st.cache(allow_output_mutation=True)
def main():
    data = pd.read_csv(DATA_URL)
    return data


def get_geofile():
    geo = geopandas.read_file(GEOJSON_URL)
    return geo

Construção do Dashboard

Existem algumas funções básicas do Streamlit que podem ajudar a exibir o layout de forma organizada e rápida.

  • st.title(): inserir um título principal
  • st.header() e st.subheader(): inserir cabeçalho
  • st.markdown(): inserir um markdown
  • st.dataframe() e st.write(): exibe o dataframe
  • st.plotly_chart(): plotar um gráfico do Plotly

Selecionando um subconjunto de colunas

O Streamlit possui um widget de multiseleção que permite selecionar ou remover de uma lista de itens, permitindo construir um widget seletor de coluna para um dataframe.

Construiremos um widget para seleção do tipo de acomodação:

room_type_filter = st.sidebar.multiselect(
    label="Escolha o tipo de lugar",
    options=rtype_label,
    default=rtype_label
)

multiselect.png

Exibir o Dataframe

Para a tela não ficar com muita informação, colocaremos um st.checkbox e st.write para exibir o dataframe.

if table.checkbox("Exibir tabela de dados"):
    st.write(tb)

dataframe.png

Com isso, a tela com o dataframe é exibida:

dataframe na tela.png

Slider de faixa de preço

Usaremos st.slider() para fornecer um controle deslizante que permite selecionar um valor máximo para o preço da acomodação. A barra lateral st.sidebar.empty() será utilizada para armazenar as opções do menu de navegação.

info_sidebar = st.sidebar.empty()
price_filter = st.sidebar.slider('Escolha o valor máximo por noite: ', int(df.price.min()), int(df.price.max()))

slider.png

Mapa interativo utilizando o Folium

O Streamlit tem uma função chamada st.map() que permite exibir no mapa a localização das hospedagens utilizando a latitude e longitude. Como essa opção não é tão interativa, utilizaremos a biblioteca Folium para exibir os nossos dados.

Criaremos dois mapas: Um com a localização das hospedagens e o outro será um mapa de densidade de preço por bairro.

Para exibir os dois mapas lado a lado usaremos a função st.beta_columns()

Para mais informações sobre essa função: https://docs.streamlit.io/en/stable/api.html?highlight=beta#streamlit.beta_columns

c1, c2 = st.beta_columns((1, 1))

Mapa de hospedagens

Criaremos o primeiro mapa no “contêiner” c1

c1.header('Mapa das hospedagens')
marker_map = folium.Map(location=[filtered_df['latitude'].mean(), filtered_df['longitude'].mean()],
                        tiles='cartodbpositron',
                        default_zoom_start=10,
                        )

marker_cluster = MarkerCluster().add_to(marker_map)
for name, row in filtered_df.iterrows():
    folium.Marker([row['latitude'], row['longitude']],
                  popup='Valor: R${0}/noite'.format(row['price'])
                  ).add_to(marker_cluster)

with c1:
    folium_static(marker_map, width=550)

O folium.Map gera o mapa, basta inserir as coordenadas iniciais. Como estamos lidando com uma diferente quantidade de latitude e longitude, usaremos a média da mesma. Utilizamos o parâmetro tiles para o estilo do mapa e default_zoom_start para o zoom inicial.

O plugin MarkerCluster() fornece a opção de inserir pontos no mapa, fazendo um cluster por bairro, melhorando a visualização. Quanto maior a quantidade de hospedagens, mais “quente” fica o cluster.

markercluster.png

Quando damos zoom máximo em um local, a função folium.Marker permite ver mais opções relacionadas aquela hospedagem como valor por noite. Outras opções poderiam ser inseridas quando clicamos no pin.

marker.png

Mapa de densidade de preço

No mapa de densidade de preço podemos ver melhor a média de preço por bairro. De acordo com a média de preço, mais quente ou mais frio pode ser a cor do bairro.

Atenção: alguns bairros que tem valor mais baixo de hospedagem podem ter sua densidade mais elevada que bairros mais caros, dependendo do valor máximo por noite e ou tipo de hospedagem. Por exemplo, bairros da Zona Norte e Zona Oeste que tem sua densidade de preço mais altos que os da Zona Sul. Isso pode ser por conta da quantidade de hospedagens no local ser muito menor, valor elevado dessas poucas hospedagens, causando essa distorção na densidade.

map_density = folium.Map(location=[filtered_df['latitude'].mean(), filtered_df['longitude'].mean()],
                         tiles='cartodbpositron',
                         default_zoom_start=10)
map_density.choropleth(data=filtered_df,
                       geo_data=geo,
                       columns=['neighbourhood', 'price', 'latitude', 'longitude'],
                       key_on='feature.properties.NOME',
                       fill_color='YlOrRd',
                       fill_opacity=0.5,
                       line_opacity=0.2,
                       legend_name='Média de preço',
                       popup='Valor: R${0}/noite'.format(['price']))
with c2:
    folium_static(map_density, width=550)

Novamente, o mapa é gerado utilizando o folium.Map.

Utilizamos o folium.choropleth para marcar no mapa os diferentes tons de cores de acordo com a média de preço. No parâmetro geo_data utilizaremos os dados do arquivo geo para demarcar os limites dos bairros.

O parâmetro columns seleciona as colunas que serão utilizadas no mapa, sendo a primeira que vai fazer a ligação com o json, e a segunda coluna é de onde deve tirar os números para criar a escala de cores.

O parâmetro key_on diz ao Folium como fazer a ligação entre a coluna df.neighbourhood e o json.

O parâmetro fill_color será os tons de cores utilizados. Nesse mapa utilizaremos YlOrRd (Amarelo, Laranja e Vermelho).

Os outros parâmetros são opcionais.

densidade.png

Gerando gráficos com Plotly

Vamos utilizar o Plotly para gerar alguns gráficos.

Utilizaremos um checkbox para quando for selecionado exibir os gráficos.

table_room_type = st.sidebar.empty()
if table_room_type.checkbox("Total por tipo de hospedagem"):
    fig = px.histogram(filtered_df, x='room_type',
                       labels={
                           'room_type': 'Tipo de hospedagem'
                       },
                       title='Tipo de hospedagem')
    st.plotly_chart(fig, use_container_width=True)

tipo hospedagem.png

O st.plotly_chart facilita a visualização do gráfico, criando um Plotly Interativo.

Conclusão

Foram abordados alguns widgets interativos do Streamlit, plotagem de gráficos com Plotly e um mapa interativo utilizando o Folium. O Streamlit tem uma grande quantidade de conteúdo para ser explorado, podendo servir até para aplicações de Machine Learning!

Para concluir, foi feito o deploy da aplicação no Heroku que pode ser visto em: http://analytics-airbnb-rio.herokuapp.com/