# importando bibliotecas necessárias import pandas as pd import numpy as np import gradio as gr from gradio import components from gradio import Interface import xlsxwriter from reportlab.lib.pagesizes import letter from reportlab.platypus import SimpleDocTemplate, Paragraph from reportlab.lib.styles import getSampleStyleSheet import shutil import os import plotly.express as px #-----------------# # Function to save results in a PDF file def save_results_to_pdf(results_formatados, intervalo_confiança, valores_finais): doc = SimpleDocTemplate("resultados.pdf", pagesize=letter) styles = getSampleStyleSheet() # Create a list of elements to include in the PDF elements = [] # Add the formatted results to the PDF formatted_results = Paragraph(results_formatados, styles["Normal"]) elements.append(formatted_results) # Add the intervalo de confianca to the PDF confianca = Paragraph(intervalo_confiança, styles["Normal"]) elements.append(confianca) # Add the valores calculados to the PDF calculados = Paragraph(valores_finais, styles["Normal"]) elements.append(calculados) # Build the PDF doc.build(elements) #-----------------# def renderizar_dataframe(df): try: # Renderize o DataFrame como uma tabela HTML com rolagem horizontal df_html = df.to_html(classes='table table-striped', table_id='planilha', escape=False) # Não escapar caracteres especiais # Use uma div com estilo CSS para permitir a rolagem horizontal tabela_com_rolagem = f'
{df_html}
' # Retorna a tabela com rolagem como HTML return tabela_com_rolagem except Exception as e: return f"Erro ao processar o DataFrame: {str(e)}" #-----------------# def plotar_mapa_com_dois_dataframes(df1, df2): fig1 = px.scatter_mapbox( df1, lat='lat', lon='lon', zoom=15, center={"lat": df1['lat'].mean(), "lon": df1['lon'].mean()}, color_discrete_sequence=['#008B8B'], ) fig1.update_traces(marker=dict(size=10)) # Define o tamanho dos marcadores para o DataFrame 1 fig2 = px.scatter_mapbox( df2, lat='lat', lon='lon', color_discrete_sequence=['orange'], ) fig2.update_traces(marker=dict(size=20)) # Define o tamanho dos marcadores para o DataFrame 2 # Combine as duas figuras em uma única figura for data in fig2.data: fig1.add_trace(data) # Personalize o layout do mapa, se desejar fig1.update_layout( mapbox_style="carto-positron", ) # Mostrar o mapa fig1.show() return fig1 #-----------------# # Função de avaliação do imóvel def avaliacao_imovel(planilha, num_linhas_desejadas=10): # Lendo a aba 'avaliando' da planilha df_avaliando = pd.read_excel(planilha.name, 'avaliando') # Lendo a aba 'dados' da planilha, limitando o número de linhas df_dados = pd.read_excel(planilha.name, 'dados').iloc[:int(num_linhas_desejadas)] #-----------------# # fator de atratividade local (fal) df_transp = df_dados.copy() df_transp = df_transp[['Atratividade local']] df_transp['fal'] = round(df_avaliando['Atratividade local'][0] / df_transp['Atratividade local'], 2) df_transp = df_transp[['fal']] #-----------------# # fator de correção da área construída (fac) df_area_const = df_dados.copy() df_area_const = df_area_const[['Área Construída']] df_area_const['razao'] = (df_area_const['Área Construída'] / df_avaliando['Área Construída'][0]) df_area_const['dif'] = abs(df_area_const['Área Construída'] - df_avaliando['Área Construída'][0]) # 30% da área do terreno do avaliando x_ac = 0.3 * df_avaliando['Área Construída'][0] # coeficiente n conforme a diferença entre a área do avaliando e dos dados df_area_const['n'] = df_area_const['dif'].apply(lambda dif: 0.250 if dif <= x_ac else 0.125) df_area_const['fac'] = round((df_area_const['razao']) ** (df_area_const['n']), 2) df_area_const = df_area_const[['fac']] #-----------------# # fator de correção da área do terreno (fat) df_area_terreno = df_dados.copy() df_area_terreno = df_area_terreno[['Área Terreno']] df_area_terreno['razao'] = (df_area_terreno['Área Terreno'] / df_avaliando['Área Terreno'][0]) df_area_terreno['dif'] = abs(df_area_terreno['Área Terreno'] - df_avaliando['Área Terreno'][0]) # 30% da área do terreno do avaliando x_at = 0.3 * df_avaliando['Área Terreno'][0] # coeficiente n conforme a diferença entre a área do avaliando e dos dados df_area_terreno['n'] = df_area_terreno['dif'].apply(lambda dif: 0.250 if dif <= x_at else 0.125) df_area_terreno['fat'] = round((df_area_terreno['razao']) ** (df_area_terreno['n']), 2) df_area_terreno = df_area_terreno[['fat']] #-----------------# # fator topografia (ftp) # dicionário topografia dict_topo = { 'plano <5%': 1, 'aclive_leve 5% e 30%': 0.95, 'declive_leve 5% e 30%': 0.90, 'aclive_acentuado >30%': 0.85, 'declive_acentuado >30%': 0.80, } # cria dataframe apenas com as colunas necessárias a partir do dataframe dos dados df_topografia = df_dados.copy() df_topografia = df_topografia[['Topografia']] # cria dataframe apenas com as colunas necessárias a partir do dataframe do avaliando df_topografia_aval = df_avaliando.copy() df_topografia_aval = df_topografia_aval[['Topografia']] # Função para mapear os valores de Topografia para cod_topo usando o dicionário def mapear_cod_topo(topografia): return dict_topo.get(topografia, 0) # 0 como valor padrão caso a topografia não esteja no dicionário # Aplicando a função para criar a coluna cod_topo em df_dados e df_avaliando df_topografia['coef_tp'] = df_topografia['Topografia'].apply(mapear_cod_topo) df_topografia_aval['coef_tp'] = df_topografia_aval['Topografia'].apply(mapear_cod_topo) df_topografia['ftp'] = round(df_topografia_aval['coef_tp'][0]/df_topografia['coef_tp'],2) df_topografia = df_topografia[['ftp']] #-----------------# # fator idade aparente e conservação (fic) # dicionário padrão construtivo dict_ic = { 'id<5_novo': 1.00, 'id<5_bom': 0.95, 'id<5_reparos simples': 0.80, 'id<5_reparos importantes': 0.45, 'id entre 6 e 10_novo': 0.95, 'id entre 6 e 10_bom': 0.90, 'id entre 6 e 10_reparos simples': 0.75, 'id entre 6 e 10_reparos importantes': 0.40, 'id entre 11 e 30_novo': 0.85, 'id entre 11 e 30_bom': 0.80, 'id entre 11 e 30_reparos simples': 0.65, 'id entre 11 e 30_reparos importantes': 0.35, 'id entre 31 e 50_novo': 0.55, 'id entre 31 e 50_bom': 0.50, 'id entre 31 e 50_reparos simples': 0.45, 'id entre 31 e 50_reparos importantes': 0.25, 'id>50_novo': 0.30, 'id>50_bom': 0.20, 'id>50_reparos simples': 0.15, 'id>50_reparos importantes': 0.10 } # cria dataframe apenas com as colunas necessárias a partir do dataframe dos dados df_idade_cons = df_dados.copy() df_idade_cons = df_idade_cons[['Idade aparente e conservação']] # cria dataframe apenas com as colunas necessárias a partir do dataframe do avaliando df_idade_cons_aval = df_avaliando.copy() df_idade_cons_aval = df_idade_cons_aval[['Idade aparente e conservação']] # Função para mapear os valores de idade aparente e conservação para cod_id_cons usando o dicionário def mapear_cod_id_cons(id_cons): return dict_ic.get(id_cons, 0) # Aplicando a função para criar a coluna cod_topo em df_dados e df_avaliando df_idade_cons['coef_ic'] = df_idade_cons['Idade aparente e conservação'].apply(mapear_cod_id_cons) df_idade_cons_aval['coef_ic'] = df_idade_cons_aval['Idade aparente e conservação'].apply(mapear_cod_id_cons) df_idade_cons['fic'] = round(df_idade_cons_aval['coef_ic'][0] / df_idade_cons['coef_ic'],2) df_idade_cons = df_idade_cons[['fic']] #-----------------# # fator padrão construtivo (fpd) # dicionário padrão construtivo dict_pad = { 'baixo_residencial': 1.00, 'médio/baixo_residencial': 1.15, 'médio_residencial': 1.30, 'médio/alto_residencial': 1.45, 'alto_residencial': 1.65, 'baixo_comercial': 1.00, 'médio/baixo_comercial': 1.08, 'médio_comercial': 1.15, 'médio/alto_comercial': 1.25, 'alto_comercial': 1.40 } # cria dataframe apenas com as colunas necessárias a partir do dataframe dos dados df_padrao = df_dados.copy() df_padrao = df_padrao[['Padrão construtivo']] # cria dataframe apenas com as colunas necessárias a partir do dataframe do avaliando df_padrao_aval = df_avaliando.copy() df_padrao_aval = df_padrao_aval[['Padrão construtivo']] # Função para mapear os valores de padrão construtivo para cod_pad usando o dicionário def mapear_cod_pad(padrao): return dict_pad.get(padrao, 0) # 0 como valor padrão caso a topografia não esteja no dicionário # Aplicando a função para criar a coluna cod_topo em df_dados e df_avaliando df_padrao['coef_pd'] = df_padrao['Padrão construtivo'].apply(mapear_cod_pad) df_padrao_aval['coef_pd'] = df_padrao_aval['Padrão construtivo'].apply(mapear_cod_pad) df_padrao['fpd'] = round(df_padrao_aval['coef_pd'][0]/df_padrao['coef_pd'],2) df_padrao = df_padrao[['fpd']] #-----------------# # fator vagas de estacionamento (fvg) df_vaga = df_dados[['Vagas']].copy() df_vaga_aval = df_avaliando[['Vagas']].copy() # Calcular a diferença entre as colunas 'Vagas' nos dois DataFrames df_vaga['dif'] = df_vaga['Vagas'] - df_vaga_aval['Vagas'][0] # Definir a função para o cálculo da coluna 'fvg' def calculate_fcg(dif, vagas): if dif == 0: return 1 else: return 1 - 0.067 * dif # Aplicar a função para calcular a coluna 'fcg' df_vaga['fvg'] = round(df_vaga.apply(lambda row: calculate_fcg(row['dif'], row['Vagas']), axis=1), 2) df_vaga = df_vaga[['fvg']] #-----------------# # fator extra (à critério do avaliador) (fex) df_exc = df_dados.copy() df_exc = df_exc[['Coeficiente extra']] df_exc['fex'] = round(df_avaliando['Coeficiente extra'][0] / df_exc['Coeficiente extra'], 2) df_exc = df_exc[['fex']] #-----------------# # concatemando o dataframe principal com as dataframes dos fatores result = pd.concat([df_dados, df_transp, df_area_const, df_area_terreno, df_topografia, df_idade_cons, df_padrao, df_vaga, df_exc], axis=1) result['Valor_desc'] = round(result['Valor']*(result['fof']), 2) result['Vunit'] = round((result['Valor_desc']/result['Área Construída']), 2) result = result[['lat','lon','Atratividade local', 'Área Construída', 'Área Terreno', 'Topografia', 'Idade aparente e conservação', 'Padrão construtivo', 'Vagas', 'Coeficiente extra', 'Valor', 'fof','Valor_desc', 'Vunit','fal', 'fac', 'fat', 'ftp', 'fic', 'fpd', 'fvg', 'fex']] result['Vunit_hom'] = round(result['Vunit'] * result['fal'] * \ result['fac'] * \ result['fat'] * \ result['ftp'] * \ result['fic'] * \ result['fpd'] * \ result['fvg'] * \ result['fex'], 2) # RESULTADOS ESTATÍSTICOS INICIAIS num = len(result) media = round(result['Vunit_hom'].mean(), 2) valor_hom_máximo = round(result['Vunit_hom'].max(), 2) valor_hom_mínimo = round(result['Vunit_hom'].min(), 2) limite_superior = round(media * 1.3 ,2) limite_inferior = round(media * 0.7 ,2) desvio_padrao = round(result['Vunit_hom'].std(), 2) coef_variacao = round((desvio_padrao / media)*100, 2) # CRITÉRIO DE CHAUVENET dict_vc = { 2: 1.15,3: 1.38,4: 1.54,5: 1.65,6: 1.73,7: 1.80,8: 1.85,9: 1.91,10: 1.96,11: 1.99, 12: 2.03,13: 2.06,14: 2.10,15: 2.13,16: 2.16,17: 2.18,18: 2.20,19: 2.21,20: 2.24, 21: 2.26,22: 2.28,23: 2.30,24: 2.31,25: 2.33,26: 2.35,27: 2.36,28: 2.37,29: 2.38, 30: 2.93 } vc = dict_vc[num] vc result['z-score'] = abs((result['Vunit_hom'] - media) / desvio_padrao) result['Status'] = np.where(result['z-score'] > vc, 'rejeitado', 'aceito') # para gerar uma tabela na interface result_render = renderizar_dataframe(result) # DADOS REMOVIDOS outliers = result[result['Status'] == 'rejeitado'] # REMOÇÃO DE OUTLIERS PELO CRITÉRIO DE CHAUVENET result = result[result['Status'] != 'rejeitado'] # RESULTADOS ESTATÍSTICOS FINAIS num = len(result) dados_outliers = len(outliers) media = round(result['Vunit_hom'].mean(), 2) valor_hom_máximo = round(result['Vunit_hom'].max(), 2) valor_hom_mínimo = round(result['Vunit_hom'].min(), 2) limite_superior = round(media * 1.3 ,2) limite_inferior = round(media * 0.7 ,2) desvio_padrao = round(result['Vunit_hom'].std(), 2) coef_variacao = round((desvio_padrao / media)*100, 2) # Crie uma string formatada com os RESULTADOS ESTATÍSTICOS FINAIS resultados_formatados = f""" Número de dados: {num} dados Valor Crítico (Chauvenet): {vc} Outliers: {dados_outliers} dado(s) Média saneada: {media} R$/m² Valor máximo: {valor_hom_máximo} R$/m² Valor mínimo: {valor_hom_mínimo} R$/m² Lim superior (Média*1,3): {limite_superior} R$/m² Lim inferior (Média*0,7): {limite_inferior} R$/m² Desvio padrão: {desvio_padrao} R$/m² Coeficiente variação: {coef_variacao} % """ # INTEREVALO DE CONFIANÇA DE 80% # importando a tabela de t de student df_t = pd.read_excel('TABELAS.xlsx','t') # número de dados n = result.shape[0]-1 # "t" de student gl = df_t[df_t['gl (n-1)'] == n] tc = gl.iloc[0, 3] # limites infeiror e superior do IC de 80% e amplitude li_IC = round(media - tc * ((desvio_padrao/(num-1)**0.5)), 2) ls_IC = round(media + tc * ((desvio_padrao/(num-1)**0.5)), 2) A = round(ls_IC - li_IC, 2) A_perc = round((A / media)*100, 2) def calcular_grau(a): if a <= 30: return "Grau III" elif a <= 40: return "Grau II" elif a <= 50: return "Grau I" else: return "Fora dos critérios" precisao = calcular_grau(A_perc) # Crie uma string formatada com o INTEREVALO DE CONFIANÇA DE 80% intervalo_confiança = f""" t student: {tc} Média saneada: {media} R$/m² limite infeiror IC_80%: {li_IC} R$/m² limite superior IC_80%: {ls_IC} R$/m² Aplitude: {A} R$/m² Aplitude percentual: {A_perc} % Grau de Precisão: {precisao} """ # VALOR CALCULADO A PARTIR DOS VALORES HOMOGENEIZADOS UTILIZANDO O CRITÉRIO DE CLASSAS D0 ABUNAHMAN # dividindo a amplitude em 3 classes C = round((A / 3), 2) # calculando os intervalos das 3 classes C1 = round(result[(result['Vunit_hom'] >= li_IC) & (result['Vunit_hom'] <= li_IC + C)]['Vunit_hom'].count(), 2) C2 = round(result[(result['Vunit_hom'] >= li_IC + C) & (result['Vunit_hom'] <= ls_IC - C)]['Vunit_hom'].count(), 2) C3 = round(result[(result['Vunit_hom'] >= ls_IC - C) & (result['Vunit_hom'] <= ls_IC)]['Vunit_hom'].count(), 2) # crinado listas com os valores encontrados nos intervalos list_C1 = result[(result['Vunit_hom'] >= li_IC) & (result['Vunit_hom'] <= li_IC + C)]['Vunit_hom'].tolist() list_C2 = result[(result['Vunit_hom'] >= li_IC + C) & (result['Vunit_hom'] <= ls_IC - C)]['Vunit_hom'].tolist() list_C3 = result[(result['Vunit_hom'] >= ls_IC - C) & (result['Vunit_hom'] <= ls_IC)]['Vunit_hom'].tolist() pC1 = round(sum(C1 * elemento for elemento in list_C1), 2) pC2 = round(sum(C2 * elemento for elemento in list_C2), 2) pC3 = round(sum(C3 * elemento for elemento in list_C3), 2) divisor = ((C1 * C1) if C1 != 0 else 0) +((C2 * C2) if C2 != 0 else 0) + ((C3 * C3) if C3 != 0 else 0) media_pond = round((pC1 + pC2 + pC3) / divisor, 2) # VALORES CALCULADOS Valor_imóvel = round(media * df_avaliando['Área Construída'], 2).item() LI = round(Valor_imóvel* 0.85, 2) LS = round(Valor_imóvel* 1.15, 2) Valor_imóvel_2 = round((media_pond) * df_avaliando['Área Construída'], 2).item() LI_classes = round(Valor_imóvel_2* 0.85, 2) LS_classes = round(Valor_imóvel_2* 1.15, 2) # Crie uma string formatada com os VALORES CALCULADOS valores_finais = f""" Área avaliando: {df_avaliando['Área Construída'].item()} m² --------- Valor (média simples): R$ {Valor_imóvel} LI: R$ {LI} LS: R$ {LS} Vu (média simples): R$/m² {media} --------- Valor (critério classes): R$ {Valor_imóvel_2} LI: R$ {LI_classes} LS: R$ {LS_classes} Vu (critério classes): R$/m² {media_pond} """ #-----------------# # OUTPUTS # Crie um objeto ExcelWriter para escrever no arquivo Excel nome_com_extensao = os.path.basename(planilha.name) nome_do_arquivo = os.path.splitext(nome_com_extensao)[0] # Defina o nome da planilha de saída com base no nome da planilha de entrada output_file = f"{nome_do_arquivo}_relatório.xlsx" #output_file = 'relatório.xlsx' (substituído pelo código acima) with pd.ExcelWriter(output_file, engine='xlsxwriter') as writer: # Salve o DataFrame 'avaliando' na planilha 'relatório' df_avaliando.to_excel(writer, sheet_name='avaliando', index=False) #-----------------# # Salve o DataFrame 'result' na planilha 'relatório' df_dados.to_excel(writer, sheet_name='dados', index=False) #-----------------# # Salve o DataFrame 'dado_hom' na planilha 'relatório' result.to_excel(writer, sheet_name='dados_hom', index=False) #-----------------# # Salve o DataFrame 'outliers' na planilha 'relatório' outliers.to_excel(writer, sheet_name='outliers', index=False) #-----------------# # Crie um novo DataFrame com os resultados estatísticos result_estatisticos = pd.DataFrame({ 'Número de dados': [num], 'Média': [media], 'Valor homogeneizado máximo': [valor_hom_máximo], 'Valor homogeneizado mínimo': [valor_hom_mínimo], 'Limite superior (Média x 1,3)': [limite_superior], 'Limite inferior (Média x 0,7)': [limite_inferior], 'Desvio padrão': [desvio_padrao], 'Coeficiente_variacao (%)': [coef_variacao] }) # Transponha o DataFrame result_estatisticos = result_estatisticos.T.reset_index() # Defina os nomes das colunas do novo DataFrame result_estatisticos.columns = ['Nome da Coluna', 'Valor'] result_estatisticos.to_excel(writer, sheet_name='resultados', index=False) #-----------------# # Crie um novo DataFrame com os resultados do IC result_ic = pd.DataFrame({ 'Número de dados': [n], 't student': [tc], 'Limite superior do IC de 80%': [ls_IC], 'Limite inferior do IC de 80%': [li_IC], 'Amplitude': [A], 'Amplitude%':[A_perc], 'Grau de Precisão': [precisao] }) # Transponha o DataFrame result_ic = result_ic.T.reset_index() # Defina os nomes das colunas do novo DataFrame result_ic.columns = ['Nome da Coluna', 'Valor'] result_ic.to_excel(writer, sheet_name='IC', index=False) #-----------------# # Crie um novo DataFrame com os resultados do cálculo das classes de Abunahman result_classes = pd.DataFrame({ 'C = Amplitude / 3': [round(C, 2)], 'li_IC = limite inferior do IC': [round(li_IC, 2)], 'li_IC + C = limite inferior do IC + C': [round(li_IC + C, 2)], 'ls_IC - C = limite superior do IC + C': [round(ls_IC - C, 2)], 'ls_IC = limite superior do IC': [round(ls_IC, 2)], 'C1 = quantidade de dados na classe 1': [C1], 'C2 = quantidade de dados na classe 2': [C2], 'C3 = quantidade de dados na classe 3': [C3], 'list_C1 = listagem de dados na classe 1': [list_C1], 'list_C2 = listagem de dados na classe 2': [list_C2], 'list_C3 = listagem de dados na classe 3': [list_C3], 'Soma da multiplicação dos valor pelos pesos - classe 1': [pC1], 'Soma da multiplicação dos valor pelos pesos - classe 2': [pC2], 'Soma da multiplicação dos valor pelos pesos - classe 3': [pC3], 'Divisor da somas das classes': [divisor], 'Média ponderada': [media_pond] }) # Transponha o DataFrame result_classes = result_classes.T.reset_index() # Defina os nomes das colunas do novo DataFrame result_classes.columns = ['Nome da Coluna', 'Valor'] result_classes.to_excel(writer, sheet_name='classes', index=False) #-----------------# # Crie um novo DataFrame com os resultados do valor do imóvel result_valores = pd.DataFrame({ 'Valor (média simples): R$': [Valor_imóvel], 'LI: R$': [LI], 'LS: R$': [LS], 'Vu (média simples): R$/m²': [media], 'Valor (critério classes) R$:': [Valor_imóvel_2], 'Vu (critério classes): R$/m²': [media_pond], 'LI_classes: R$': [LI_classes], 'LS_classes: R$': [LS_classes] }) # Transponha o DataFrame result_valores = result_valores.T.reset_index() # Defina os nomes das colunas do novo DataFrame result_valores.columns = ['Nome da Coluna', 'Valor'] result_valores.to_excel(writer, sheet_name='valor', index=False) #-----------------# mapa = plotar_mapa_com_dois_dataframes(result, df_avaliando) #mapa = criar_mapa(df_avaliando) #novo #-----------------# # Salve o DataFrame 'result' em uma planilha result.to_excel(output_file, index=False) #result.to_excel('relatório.xlsx', index=False) (substituído pelo código acima) #-----------------# save_results_to_pdf(resultados_formatados, intervalo_confiança, valores_finais) result.to_excel(output_file, index=False) #-----------------# # Retorna tanto a planilha quanto os resultados formatados return output_file, 'resultados.pdf', result_render, resultados_formatados, intervalo_confiança, valores_finais, mapa #novo # Interface do Gradio com input como arquivo XLS ou XLSX interface = gr.Interface( fn=avaliacao_imovel, inputs=[ gr.components.File(label="Upload planilha", type="file"), gr.inputs.Number(label="Número de linhas desejadas", default=10), ], outputs=[ gr.components.File(label="Download planilha"), gr.components.File(label="Download Relatório em PDF"), gr.outputs.HTML(label="Resultado Renderizado"), gr.components.Textbox(label="Resultados estatísticos"), gr.components.Textbox(label="Intervalo de confiança de 80%"), gr.components.Textbox(label="Valores Calculados"), gr.Plot(label="Geolocalização da amostra"), #novo ], live=True, capture_session=True, theme=gr.themes.Soft(), title="avaliaFACTOR", description="Aplicativo MCDDM com tratamento por fatores / Faça o upload de uma planilha XLS ou XLSX com os dados / Para um exemplo de estrutura de planilha, você pode baixar aqui.") # Executar o aplicativo Gradio if __name__ == "__main__": interface.launch(debug=True)