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
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'
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
Existem algumas funções básicas do Streamlit que podem ajudar a exibir o layout de forma organizada e rápida.
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
)
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)
Com isso, a tela com o dataframe é exibida:
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()))
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))
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.
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.
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.
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)
O st.plotly_chart
facilita a visualização do gráfico, criando um Plotly Interativo.
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/