|
|
import pandas as pd |
|
|
import plotly.express as px |
|
|
import plotly.graph_objects as go |
|
|
import gradio as gr |
|
|
from math import radians, sin, cos, sqrt, atan2 |
|
|
import googlemaps |
|
|
import locale |
|
|
from .shared_state import state |
|
|
|
|
|
|
|
|
gmaps = googlemaps.Client(key='AIzaSyDoJ6C7NE2CHqFcaHTnhreOfgJeTk4uSH0') |
|
|
|
|
|
try: |
|
|
locale.setlocale(locale.LC_ALL, 'pt_BR.UTF-8') |
|
|
except locale.Error: |
|
|
|
|
|
locale.setlocale(locale.LC_ALL, 'C') |
|
|
|
|
|
|
|
|
data_path = 'data_2.xlsx' |
|
|
df = pd.read_excel(data_path, sheet_name='Planilha1') |
|
|
|
|
|
df['Data'] = pd.to_datetime(df['Data'], errors='coerce') |
|
|
|
|
|
|
|
|
def haversine(lat1, lon1, lat2, lon2): |
|
|
raio_terra = 6371000 |
|
|
dlat = radians(lat2 - lat1) |
|
|
dlon = radians(lon2 - lon1) |
|
|
a = sin(dlat / 2)**2 + cos(radians(lat1)) * cos(radians(lat2)) * sin(dlon / 2)**2 |
|
|
c = 2 * atan2(sqrt(a), sqrt(1 - a)) |
|
|
return raio_terra * c |
|
|
|
|
|
|
|
|
def unified_action(selected_types, selected_bairros, selected_fonte, min_atotal, max_atotal, min_apriv, max_apriv, min_ater, max_ater, min_date, max_date, address=None, radius=None): |
|
|
filtered_df = df.copy() |
|
|
|
|
|
|
|
|
if "Todos" not in selected_types: |
|
|
filtered_df = filtered_df[filtered_df['Tipo'].isin(selected_types)] |
|
|
|
|
|
|
|
|
if "Todos" not in selected_bairros: |
|
|
filtered_df = filtered_df[filtered_df['Bairro'].isin(selected_bairros)] |
|
|
|
|
|
|
|
|
if "Todos" not in selected_fonte: |
|
|
filtered_df = filtered_df[filtered_df['Fonte'].isin(selected_fonte)] |
|
|
|
|
|
|
|
|
if min_atotal is not None: |
|
|
filtered_df = filtered_df[filtered_df['Atotal'] >= min_atotal] |
|
|
if max_atotal is not None: |
|
|
filtered_df = filtered_df[filtered_df['Atotal'] <= max_atotal] |
|
|
|
|
|
|
|
|
if min_apriv is not None: |
|
|
filtered_df = filtered_df[filtered_df['Apriv'] >= min_apriv] |
|
|
if max_apriv is not None: |
|
|
filtered_df = filtered_df[filtered_df['Apriv'] <= max_apriv] |
|
|
|
|
|
|
|
|
if min_ater is not None: |
|
|
filtered_df = filtered_df[filtered_df['Ater'] >= min_ater] |
|
|
if max_ater is not None: |
|
|
filtered_df = filtered_df[filtered_df['Ater'] <= max_ater] |
|
|
|
|
|
|
|
|
if min_date is not None: |
|
|
filtered_df = filtered_df[filtered_df['Data'] >= pd.to_datetime(min_date)] |
|
|
|
|
|
if max_date is not None: |
|
|
filtered_df = filtered_df[filtered_df['Data'] <= pd.to_datetime(max_date)] |
|
|
|
|
|
|
|
|
if address: |
|
|
try: |
|
|
result = gmaps.geocode(address) |
|
|
if result: |
|
|
coordinates = result[0]['geometry']['location'] |
|
|
center_lat = coordinates['lat'] |
|
|
center_lon = coordinates['lng'] |
|
|
|
|
|
if radius: |
|
|
|
|
|
filtered_df['Distance'] = filtered_df.apply( |
|
|
lambda row: haversine(center_lat, center_lon, row['Latitude'], row['Longitude']), |
|
|
axis=1 |
|
|
) |
|
|
filtered_df = filtered_df[filtered_df['Distance'] <= radius] |
|
|
else: |
|
|
|
|
|
address_components = result[0]['address_components'] |
|
|
street = None |
|
|
neighborhood = None |
|
|
|
|
|
for component in address_components: |
|
|
if 'route' in component['types']: |
|
|
street = component['long_name'] |
|
|
if 'sublocality' in component['types'] or 'locality' in component['types']: |
|
|
neighborhood = component['long_name'] |
|
|
|
|
|
if street: |
|
|
filtered_df = filtered_df[filtered_df['Localização'].str.contains(street, na=False)] |
|
|
elif neighborhood: |
|
|
filtered_df = filtered_df[filtered_df['Bairro'].str.contains(neighborhood, na=False)] |
|
|
except Exception as e: |
|
|
print(f"Erro ao filtrar pelo endereço: {e}") |
|
|
|
|
|
|
|
|
|
|
|
fig = px.scatter_mapbox( |
|
|
filtered_df, |
|
|
lat="Latitude", |
|
|
lon="Longitude", |
|
|
hover_name="Localização", |
|
|
hover_data={ |
|
|
"Valor": True, |
|
|
"Vunit_priv": True, |
|
|
"Tipo": True, |
|
|
"url": True, |
|
|
}, |
|
|
color="Tipo", |
|
|
size="Valor", |
|
|
size_max=30, |
|
|
zoom=10 |
|
|
) |
|
|
|
|
|
fig.update_layout( |
|
|
mapbox_style="open-street-map", |
|
|
autosize=True, |
|
|
height=600, |
|
|
margin={"r": 0, "t": 0, "l": 0, "b": 0}, |
|
|
) |
|
|
|
|
|
|
|
|
if address and radius: |
|
|
try: |
|
|
raio_terra = 6371000 |
|
|
pontos_lat = [] |
|
|
pontos_lon = [] |
|
|
for angulo in range(360): |
|
|
ang_rad = radians(angulo) |
|
|
d_lat = (radius / raio_terra) * cos(ang_rad) |
|
|
d_lon = (radius / (raio_terra * cos(radians(center_lat)))) * sin(ang_rad) |
|
|
pontos_lat.append(center_lat + d_lat * (180 / 3.141592653589793)) |
|
|
pontos_lon.append(center_lon + d_lon * (180 / 3.141592653589793)) |
|
|
|
|
|
fig.add_trace(go.Scattermapbox( |
|
|
lat=pontos_lat, |
|
|
lon=pontos_lon, |
|
|
mode='lines', |
|
|
fill='toself', |
|
|
fillcolor='rgba(0, 0, 255, 0.2)', |
|
|
line=dict(color='blue', width=2), |
|
|
name='Raio' |
|
|
)) |
|
|
|
|
|
fig.add_trace(go.Scattermapbox( |
|
|
lat=[center_lat], |
|
|
lon=[center_lon], |
|
|
mode='markers', |
|
|
marker=dict(size=10, color='red'), |
|
|
name='Centro' |
|
|
)) |
|
|
except Exception as e: |
|
|
print(f"Erro ao adicionar o círculo no mapa: {e}") |
|
|
|
|
|
|
|
|
if filtered_df.empty: |
|
|
stats_text = "Nenhum dado disponível." |
|
|
else: |
|
|
stats_text = (f"Quantidade de Dados: {len(filtered_df):n}\n" |
|
|
f"Média do Valor: {locale.format_string('%.2f', filtered_df['Valor'].mean(), grouping=True)}\n" |
|
|
f"Máximo do Valor: {locale.format_string('%.2f', filtered_df['Valor'].max(), grouping=True)}\n" |
|
|
f"Mínimo do Valor: {locale.format_string('%.2f', filtered_df['Valor'].min(), grouping=True)}") |
|
|
|
|
|
|
|
|
file_path = "dados_filtrados.xlsx" |
|
|
filtered_df.to_excel(file_path) |
|
|
|
|
|
return fig, stats_text, filtered_df, file_path |
|
|
|
|
|
|
|
|
property_types = ["Todos"] + sorted(df['Tipo'].dropna().unique().tolist()) |
|
|
bairro_list = ["Todos"] + sorted(df['Bairro'].dropna().unique().tolist()) |
|
|
fonte_list = ["Todos"] + sorted(df['Fonte'].dropna().unique().tolist()) |
|
|
|
|
|
|
|
|
|
|
|
min_data = df['Data'].min() |
|
|
max_data = df['Data'].max() |
|
|
|
|
|
def dados_tab(): |
|
|
with gr.Tab("Pesquisar Dados"): |
|
|
toggle_filters = gr.Checkbox(label="Exibir Campos de Pesquisa", value=True) |
|
|
with gr.Row(visible=True) as filters: |
|
|
tipo_filter = gr.Dropdown(label="Selecione os Tipos de Imóvel", choices=property_types, value=["Todos"], multiselect=True) |
|
|
bairro_filter = gr.Dropdown(label="Selecione os Bairros", choices=bairro_list, value=["Todos"], multiselect=True) |
|
|
fonte_filter = gr.Dropdown(label="Selecione a Fonte", choices=fonte_list, value=["Todos"], multiselect=True) |
|
|
with gr.Row(visible=True) as area_filters: |
|
|
min_atotal = gr.Number(label="Área Total Mínima", value=None) |
|
|
max_atotal = gr.Number(label="Área Total Máxima", value=None) |
|
|
min_apriv = gr.Number(label="Área Privativa Mínima", value=None) |
|
|
max_apriv = gr.Number(label="Área Privativa Máxima", value=None) |
|
|
min_ater = gr.Number(label="Área Terreno Mínima", value=None) |
|
|
max_ater = gr.Number(label="Área Terreno Máxima", value=None) |
|
|
|
|
|
with gr.Row(visible=True) as date_filters: |
|
|
min_date = gr.Textbox(label="Data Inicial (AAAA-MM-DD)", value=min_data.strftime('%Y-%m-%d')) |
|
|
max_date = gr.Textbox(label="Data Final (AAAA-MM-DD)", value=max_data.strftime('%Y-%m-%d')) |
|
|
|
|
|
with gr.Row(visible=True) as address_filters: |
|
|
address_input = gr.Textbox(label="Endereço (Opcional)") |
|
|
radius_input = gr.Number(label="Raio em metros (Opcional)") |
|
|
with gr.Row(): |
|
|
search_button = gr.Button("Pesquisar") |
|
|
clear_button = gr.Button("Limpar") |
|
|
map_output = gr.Plot() |
|
|
stats_output = gr.Textbox(lines=4, label="Estatísticas") |
|
|
filtered_df_output = gr.DataFrame(label="Dados Filtrados") |
|
|
download_output = gr.File(label="Baixar Dados Filtrados") |
|
|
|
|
|
def clear_action(): |
|
|
return (["Todos"], ["Todos"], ["Todos"], None, None, None, None, None, None, min_data.strftime('%Y-%m-%d'), max_data.strftime('%Y-%m-%d'), "", None, None, "", pd.DataFrame(), None) |
|
|
|
|
|
toggle_filters.change( |
|
|
lambda show: ( |
|
|
gr.update(visible=show), |
|
|
gr.update(visible=show), |
|
|
gr.update(visible=show), |
|
|
gr.update(visible=show) |
|
|
), |
|
|
inputs=[toggle_filters], |
|
|
outputs=[filters, area_filters, address_filters, date_filters] |
|
|
) |
|
|
|
|
|
search_button.click( |
|
|
unified_action, |
|
|
inputs=[tipo_filter, bairro_filter, fonte_filter, min_atotal, max_atotal, min_apriv, max_apriv, |
|
|
min_ater, max_ater, min_date, max_date, address_input, radius_input], |
|
|
outputs=[map_output, stats_output, filtered_df_output, download_output] |
|
|
) |
|
|
|
|
|
clear_button.click( |
|
|
clear_action, |
|
|
outputs=[tipo_filter, bairro_filter, fonte_filter, min_atotal, max_atotal, min_apriv, max_apriv, |
|
|
min_ater, max_ater, min_date, max_date, address_input, radius_input, |
|
|
map_output, stats_output, filtered_df_output, download_output] |
|
|
) |
|
|
|
|
|
return locals(), filtered_df_output |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|