ESJL commited on
Commit
cb0f899
·
verified ·
1 Parent(s): 9f083ea

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +120 -54
app.py CHANGED
@@ -2,18 +2,23 @@ import gradio as gr
2
  import pandas as pd
3
  import geopandas as gpd
4
 
 
5
  # Carregamento único dos eixos
 
6
  gdf_eixos = gpd.read_file("EixosLogradouros.shp", engine="fiona")
7
  gdf_eixos = gdf_eixos.to_crs("EPSG:4326")
8
  eixos_por_cdlog = {cdlog: grupo.copy() for cdlog, grupo in gdf_eixos.groupby("CDLOG")}
9
 
 
10
  # Funções auxiliares
 
11
  def formatar_float_visualizacao(df, casas=4):
12
  df_visual = df.copy()
13
  float_cols = df_visual.select_dtypes(include=["float"]).columns
14
  df_visual[float_cols] = df_visual[float_cols].round(casas)
15
  return df_visual
16
 
 
17
  def carregar_abas(arquivo_excel):
18
  if arquivo_excel is None:
19
  return gr.update(choices=[]), None
@@ -21,28 +26,49 @@ def carregar_abas(arquivo_excel):
21
  abas = xls.sheet_names
22
  return gr.update(choices=abas, value=abas[0]), abas[0]
23
 
 
24
  def listar_colunas(arquivo_excel, aba):
25
  if arquivo_excel is None or aba is None:
26
  return gr.update(choices=[]), gr.update(choices=[])
 
27
  df = pd.read_excel(arquivo_excel.name, sheet_name=aba)
28
  colunas = df.columns.tolist()
29
  colunas_upper = {col.upper(): col for col in colunas}
30
 
31
  coluna_cdlog_pre = colunas_upper.get("CTM", colunas_upper.get("CDLOG", None))
32
- coluna_num_pre = next((colunas_upper[nome.upper()] for nome in ["Nº GEO", "NUM_GEO", "NUM"] if nome.upper() in colunas_upper), None)
 
 
 
 
 
 
 
 
 
33
 
34
- return gr.update(choices=colunas, value=coluna_cdlog_pre), gr.update(choices=colunas, value=coluna_num_pre)
35
 
36
  def exibir_tabela(arquivo_excel, aba, coluna_num):
37
  if arquivo_excel is None or aba is None:
38
  return None, ""
 
39
  df = pd.read_excel(arquivo_excel.name, sheet_name=aba)
40
  df["_idx"] = range(len(df))
 
41
  if coluna_num in df.columns:
42
- df[coluna_num] = pd.to_numeric(df[coluna_num], errors="coerce").fillna(0).astype(int)
 
 
 
 
 
43
  texto = f"O DataFrame possui {df.shape[0]} linhas e {df.shape[1]} colunas."
44
  return formatar_float_visualizacao(df), texto
45
 
 
 
 
 
46
  def interpolar(df, coluna_cdlog, coluna_num):
47
  df = df.copy()
48
  df[coluna_num] = pd.to_numeric(df[coluna_num], errors="coerce").fillna(0).astype(int)
@@ -50,7 +76,10 @@ def interpolar(df, coluna_cdlog, coluna_num):
50
  lons, lats, falhas = [], [], []
51
 
52
  for _, row in df.iterrows():
53
- idx, cdlog, numero = row["_idx"], row[coluna_cdlog], row[coluna_num]
 
 
 
54
  segmentos = eixos_por_cdlog.get(cdlog)
55
 
56
  if segmentos is None:
@@ -68,70 +97,76 @@ def interpolar(df, coluna_cdlog, coluna_num):
68
  continue
69
 
70
  lado = "Par" if numero % 2 == 0 else "Ímpar"
71
- ini_col, fim_col = ("NRPARINI", "NRPARFIN") if lado == "Par" else ("NRIMPINI", "NRIMPFIN")
 
 
 
 
 
72
  cond = (segmentos[ini_col] <= numero) & (segmentos[fim_col] >= numero)
73
  seg_validos = segmentos[cond]
74
 
75
  if seg_validos.empty:
76
  if not segmentos.empty:
77
  diffs = (segmentos[ini_col] - numero).abs()
78
- if not diffs.empty:
79
- min_index = diffs.idxmin()
80
- linha_proxima = segmentos.loc[min_index]
81
- ini, fim = linha_proxima[ini_col], linha_proxima[fim_col]
82
- if pd.notna(ini) and pd.notna(fim):
83
- numeros_validos = list(range(int(ini), int(fim) + 1, 2))
84
- numeros_validos.sort(key=lambda x: abs(x - numero))
85
- falhas.append({
86
- "_idx": idx,
87
- "CDLOG": cdlog,
88
- "Numero Atual": numero,
89
- "Motivo": "Numeração fora do intervalo",
90
- "Lado": lado,
91
- "Intervalo": f"{int(ini)} até {int(fim)}",
92
- "Sugestões": numeros_validos[:10]
93
- })
94
- lons.append(None)
95
- lats.append(None)
96
- continue
 
97
  lons.append(None)
98
  lats.append(None)
99
- falhas.append({
100
- "_idx": idx,
101
- "CDLOG": cdlog,
102
- "Numero Atual": numero,
103
- "Motivo": "Numeração fora do intervalo",
104
- "Lado": lado,
105
- "Intervalo": "",
106
- "Sugestões": []
107
- })
108
  continue
109
 
110
  linha = seg_validos.iloc[0]
111
  geom = linha.geometry
112
- ini, fim = linha[ini_col], linha[fim_col]
 
 
113
  if fim == ini:
114
  lons.append(None)
115
  lats.append(None)
116
  continue
 
117
  frac = (numero - ini) / (fim - ini)
118
  frac = max(0, min(1, frac))
119
  ponto = geom.interpolate(geom.length * frac)
 
120
  lons.append(ponto.x)
121
  lats.append(ponto.y)
122
 
123
  df["lon"] = lons
124
  df["lat"] = lats
 
125
  output_path = "dados_interpolados.xlsx"
126
  df.to_excel(output_path, index=False)
127
 
128
  colunas_fixas = ["_idx", "CDLOG", "Numero Atual", "Motivo", "Lado", "Intervalo", "Sugestões"]
129
- df_falhas = pd.DataFrame(falhas, columns=colunas_fixas) if falhas else pd.DataFrame(columns=colunas_fixas)
130
 
131
  return formatar_float_visualizacao(df), output_path, df_falhas
132
 
 
 
 
 
133
  def preparar_sugestoes(df_falhas, evt: gr.SelectData):
134
- if df_falhas is None or evt is None or not hasattr(evt, "index") or not evt.index:
135
  return None, "", "", gr.update(choices=[], value=None)
136
 
137
  linha = df_falhas.iloc[evt.index[0]]
@@ -142,25 +177,32 @@ def preparar_sugestoes(df_falhas, evt: gr.SelectData):
142
  sugestoes = linha.get("Sugestões", [])
143
 
144
  if isinstance(sugestoes, str):
145
- sugestoes = [int(x.strip()) for x in sugestoes.split(",") if x.strip().isdigit()]
 
 
 
146
 
147
  return idx, lado, intervalo, gr.update(choices=sugestoes, value=None)
148
-
149
 
150
- def aplicar_sugestao(df_original, idx, numero_escolhido, coluna_num, df_falhas):
 
 
151
  if numero_escolhido is None:
152
- return df_original, df_falhas
 
153
  df_original = df_original.copy()
154
  df_original.loc[df_original["_idx"] == idx, coluna_num] = int(numero_escolhido)
155
 
156
- # Remove a linha corrigida do DataFrame de falhas
157
- df_falhas = df_falhas[df_falhas["_idx"] != idx]
158
 
159
- return df_original, df_falhas
160
 
161
- # Interface
 
 
162
  with gr.Blocks() as app:
 
163
  gr.Markdown("## DAI - Geolocalização com Correção Assistida")
 
164
  estado_tabela = gr.State()
165
 
166
  arquivo = gr.File(label="Arquivo Excel", file_types=[".xlsx"])
@@ -168,12 +210,17 @@ with gr.Blocks() as app:
168
  linhas_info = gr.Textbox(label="Linhas e Colunas", interactive=False)
169
  dropdown_cdlog = gr.Dropdown(label="Coluna CDLOG")
170
  dropdown_num = gr.Dropdown(label="Coluna Número")
 
171
  tabela = gr.Dataframe(label="Tabela Original", interactive=False)
172
  btn_interpolar = gr.Button("Interpolar")
 
173
  tabela_resultado = gr.Dataframe(label="Com Coordenadas", interactive=False)
174
  arquivo_saida = gr.File(label="Arquivo Gerado")
175
- falhas = gr.Dataframe(label="Falhas (Editar Novo Número)", interactive=True)
 
 
176
  gr.Markdown("### Correção Assistida")
 
177
  idx_selecionado = gr.Number(visible=False)
178
  info_lado = gr.Textbox(label="Lado", interactive=False)
179
  info_intervalo = gr.Textbox(label="Intervalo Válido", interactive=False)
@@ -182,23 +229,42 @@ with gr.Blocks() as app:
182
 
183
  # Eventos
184
  arquivo.change(fn=carregar_abas, inputs=arquivo, outputs=[dropdown_abas, dropdown_abas])
185
- dropdown_abas.change(fn=exibir_tabela, inputs=[arquivo, dropdown_abas, dropdown_num], outputs=[tabela, linhas_info]).then(
186
- fn=lambda df: df, inputs=tabela, outputs=estado_tabela
187
- ).then(fn=listar_colunas, inputs=[arquivo, dropdown_abas], outputs=[dropdown_cdlog, dropdown_num])
188
 
189
- btn_interpolar.click(fn=interpolar, inputs=[tabela, dropdown_cdlog, dropdown_num], outputs=[tabela_resultado, arquivo_saida, falhas])
190
- falhas.select(fn=preparar_sugestoes, inputs=[falhas], outputs=[idx_selecionado, info_lado, info_intervalo, radio_sugestoes])
191
- btn_aplicar_sugestao.click(
192
- fn=aplicar_sugestao,
193
- inputs=[estado_tabela, idx_selecionado, radio_sugestoes, dropdown_num, falhas],
194
- outputs=[estado_tabela, falhas]
195
  ).then(
 
 
 
 
 
 
 
 
 
 
196
  fn=interpolar,
197
  inputs=[estado_tabela, dropdown_cdlog, dropdown_num],
198
  outputs=[tabela_resultado, arquivo_saida, falhas]
199
  )
200
 
 
 
 
 
 
201
 
 
 
 
 
 
 
 
 
 
202
 
203
 
204
  app.launch(server_name="0.0.0.0", server_port=7860)
 
2
  import pandas as pd
3
  import geopandas as gpd
4
 
5
+ # ==============================
6
  # Carregamento único dos eixos
7
+ # ==============================
8
  gdf_eixos = gpd.read_file("EixosLogradouros.shp", engine="fiona")
9
  gdf_eixos = gdf_eixos.to_crs("EPSG:4326")
10
  eixos_por_cdlog = {cdlog: grupo.copy() for cdlog, grupo in gdf_eixos.groupby("CDLOG")}
11
 
12
+ # ==============================
13
  # Funções auxiliares
14
+ # ==============================
15
  def formatar_float_visualizacao(df, casas=4):
16
  df_visual = df.copy()
17
  float_cols = df_visual.select_dtypes(include=["float"]).columns
18
  df_visual[float_cols] = df_visual[float_cols].round(casas)
19
  return df_visual
20
 
21
+
22
  def carregar_abas(arquivo_excel):
23
  if arquivo_excel is None:
24
  return gr.update(choices=[]), None
 
26
  abas = xls.sheet_names
27
  return gr.update(choices=abas, value=abas[0]), abas[0]
28
 
29
+
30
  def listar_colunas(arquivo_excel, aba):
31
  if arquivo_excel is None or aba is None:
32
  return gr.update(choices=[]), gr.update(choices=[])
33
+
34
  df = pd.read_excel(arquivo_excel.name, sheet_name=aba)
35
  colunas = df.columns.tolist()
36
  colunas_upper = {col.upper(): col for col in colunas}
37
 
38
  coluna_cdlog_pre = colunas_upper.get("CTM", colunas_upper.get("CDLOG", None))
39
+ coluna_num_pre = next(
40
+ (colunas_upper[nome.upper()] for nome in ["Nº GEO", "NUM_GEO", "NUM"]
41
+ if nome.upper() in colunas_upper),
42
+ None
43
+ )
44
+
45
+ return (
46
+ gr.update(choices=colunas, value=coluna_cdlog_pre),
47
+ gr.update(choices=colunas, value=coluna_num_pre),
48
+ )
49
 
 
50
 
51
  def exibir_tabela(arquivo_excel, aba, coluna_num):
52
  if arquivo_excel is None or aba is None:
53
  return None, ""
54
+
55
  df = pd.read_excel(arquivo_excel.name, sheet_name=aba)
56
  df["_idx"] = range(len(df))
57
+
58
  if coluna_num in df.columns:
59
+ df[coluna_num] = (
60
+ pd.to_numeric(df[coluna_num], errors="coerce")
61
+ .fillna(0)
62
+ .astype(int)
63
+ )
64
+
65
  texto = f"O DataFrame possui {df.shape[0]} linhas e {df.shape[1]} colunas."
66
  return formatar_float_visualizacao(df), texto
67
 
68
+
69
+ # ==============================
70
+ # INTERPOLAÇÃO
71
+ # ==============================
72
  def interpolar(df, coluna_cdlog, coluna_num):
73
  df = df.copy()
74
  df[coluna_num] = pd.to_numeric(df[coluna_num], errors="coerce").fillna(0).astype(int)
 
76
  lons, lats, falhas = [], [], []
77
 
78
  for _, row in df.iterrows():
79
+ idx = row["_idx"]
80
+ cdlog = row[coluna_cdlog]
81
+ numero = row[coluna_num]
82
+
83
  segmentos = eixos_por_cdlog.get(cdlog)
84
 
85
  if segmentos is None:
 
97
  continue
98
 
99
  lado = "Par" if numero % 2 == 0 else "Ímpar"
100
+ ini_col, fim_col = (
101
+ ("NRPARINI", "NRPARFIN")
102
+ if lado == "Par"
103
+ else ("NRIMPINI", "NRIMPFIN")
104
+ )
105
+
106
  cond = (segmentos[ini_col] <= numero) & (segmentos[fim_col] >= numero)
107
  seg_validos = segmentos[cond]
108
 
109
  if seg_validos.empty:
110
  if not segmentos.empty:
111
  diffs = (segmentos[ini_col] - numero).abs()
112
+ min_index = diffs.idxmin()
113
+ linha_proxima = segmentos.loc[min_index]
114
+
115
+ ini = linha_proxima[ini_col]
116
+ fim = linha_proxima[fim_col]
117
+
118
+ if pd.notna(ini) and pd.notna(fim):
119
+ numeros_validos = list(range(int(ini), int(fim) + 1, 2))
120
+ numeros_validos.sort(key=lambda x: abs(x - numero))
121
+
122
+ falhas.append({
123
+ "_idx": idx,
124
+ "CDLOG": cdlog,
125
+ "Numero Atual": numero,
126
+ "Motivo": "Numeração fora do intervalo",
127
+ "Lado": lado,
128
+ "Intervalo": f"{int(ini)} até {int(fim)}",
129
+ "Sugestões": numeros_validos[:10]
130
+ })
131
+
132
  lons.append(None)
133
  lats.append(None)
 
 
 
 
 
 
 
 
 
134
  continue
135
 
136
  linha = seg_validos.iloc[0]
137
  geom = linha.geometry
138
+ ini = linha[ini_col]
139
+ fim = linha[fim_col]
140
+
141
  if fim == ini:
142
  lons.append(None)
143
  lats.append(None)
144
  continue
145
+
146
  frac = (numero - ini) / (fim - ini)
147
  frac = max(0, min(1, frac))
148
  ponto = geom.interpolate(geom.length * frac)
149
+
150
  lons.append(ponto.x)
151
  lats.append(ponto.y)
152
 
153
  df["lon"] = lons
154
  df["lat"] = lats
155
+
156
  output_path = "dados_interpolados.xlsx"
157
  df.to_excel(output_path, index=False)
158
 
159
  colunas_fixas = ["_idx", "CDLOG", "Numero Atual", "Motivo", "Lado", "Intervalo", "Sugestões"]
160
+ df_falhas = pd.DataFrame(falhas, columns=colunas_fixas)
161
 
162
  return formatar_float_visualizacao(df), output_path, df_falhas
163
 
164
+
165
+ # ==============================
166
+ # CORREÇÃO ASSISTIDA
167
+ # ==============================
168
  def preparar_sugestoes(df_falhas, evt: gr.SelectData):
169
+ if df_falhas is None or evt is None or not evt.index:
170
  return None, "", "", gr.update(choices=[], value=None)
171
 
172
  linha = df_falhas.iloc[evt.index[0]]
 
177
  sugestoes = linha.get("Sugestões", [])
178
 
179
  if isinstance(sugestoes, str):
180
+ sugestoes = [
181
+ int(x.strip()) for x in sugestoes.split(",")
182
+ if x.strip().isdigit()
183
+ ]
184
 
185
  return idx, lado, intervalo, gr.update(choices=sugestoes, value=None)
 
186
 
187
+
188
+ # 🔥 ALTERAÇÃO PRINCIPAL AQUI
189
+ def aplicar_sugestao(df_original, idx, numero_escolhido, coluna_num):
190
  if numero_escolhido is None:
191
+ return df_original
192
+
193
  df_original = df_original.copy()
194
  df_original.loc[df_original["_idx"] == idx, coluna_num] = int(numero_escolhido)
195
 
196
+ return df_original
 
197
 
 
198
 
199
+ # ==============================
200
+ # INTERFACE
201
+ # ==============================
202
  with gr.Blocks() as app:
203
+
204
  gr.Markdown("## DAI - Geolocalização com Correção Assistida")
205
+
206
  estado_tabela = gr.State()
207
 
208
  arquivo = gr.File(label="Arquivo Excel", file_types=[".xlsx"])
 
210
  linhas_info = gr.Textbox(label="Linhas e Colunas", interactive=False)
211
  dropdown_cdlog = gr.Dropdown(label="Coluna CDLOG")
212
  dropdown_num = gr.Dropdown(label="Coluna Número")
213
+
214
  tabela = gr.Dataframe(label="Tabela Original", interactive=False)
215
  btn_interpolar = gr.Button("Interpolar")
216
+
217
  tabela_resultado = gr.Dataframe(label="Com Coordenadas", interactive=False)
218
  arquivo_saida = gr.File(label="Arquivo Gerado")
219
+
220
+ falhas = gr.Dataframe(label="Falhas", interactive=True)
221
+
222
  gr.Markdown("### Correção Assistida")
223
+
224
  idx_selecionado = gr.Number(visible=False)
225
  info_lado = gr.Textbox(label="Lado", interactive=False)
226
  info_intervalo = gr.Textbox(label="Intervalo Válido", interactive=False)
 
229
 
230
  # Eventos
231
  arquivo.change(fn=carregar_abas, inputs=arquivo, outputs=[dropdown_abas, dropdown_abas])
 
 
 
232
 
233
+ dropdown_abas.change(
234
+ fn=exibir_tabela,
235
+ inputs=[arquivo, dropdown_abas, dropdown_num],
236
+ outputs=[tabela, linhas_info],
 
 
237
  ).then(
238
+ fn=lambda df: df,
239
+ inputs=tabela,
240
+ outputs=estado_tabela
241
+ ).then(
242
+ fn=listar_colunas,
243
+ inputs=[arquivo, dropdown_abas],
244
+ outputs=[dropdown_cdlog, dropdown_num]
245
+ )
246
+
247
+ btn_interpolar.click(
248
  fn=interpolar,
249
  inputs=[estado_tabela, dropdown_cdlog, dropdown_num],
250
  outputs=[tabela_resultado, arquivo_saida, falhas]
251
  )
252
 
253
+ falhas.select(
254
+ fn=preparar_sugestoes,
255
+ inputs=[falhas],
256
+ outputs=[idx_selecionado, info_lado, info_intervalo, radio_sugestoes]
257
+ )
258
 
259
+ btn_aplicar_sugestao.click(
260
+ fn=aplicar_sugestao,
261
+ inputs=[estado_tabela, idx_selecionado, radio_sugestoes, dropdown_num],
262
+ outputs=estado_tabela
263
+ ).then(
264
+ fn=interpolar,
265
+ inputs=[estado_tabela, dropdown_cdlog, dropdown_num],
266
+ outputs=[tabela_resultado, arquivo_saida, falhas]
267
+ )
268
 
269
 
270
  app.launch(server_name="0.0.0.0", server_port=7860)