Spaces:
Running
Running
File size: 6,761 Bytes
fe69607 960f8ac fe69607 960f8ac fe69607 960f8ac fe69607 960f8ac fe69607 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
import pandas as pd
import streamlit as st
from pandas.api.types import (
is_categorical_dtype,
is_datetime64_any_dtype,
is_numeric_dtype,
is_object_dtype,
)
def make_hashable(x):
"""
Converte recursivamente listas (e, se necessário, dicionários) em tipos hashable.
"""
if isinstance(x, list):
return tuple(make_hashable(e) for e in x)
# Se precisar, trate dicionários também:
if isinstance(x, dict):
return tuple(sorted((k, make_hashable(v)) for k, v in x.items()))
return x
def flatten_unique_values(series: pd.Series) -> list:
"""
Achata os valores únicos de uma série.
Se um valor for uma tupla, extrai cada item individualmente.
"""
unique_values_set = set()
for val in series.dropna().unique():
# Se o valor for uma tupla, adicione cada item separadamente
if isinstance(val, tuple):
unique_values_set.update(val)
else:
unique_values_set.add(val)
return list(unique_values_set)
def filter_dataframe(df: pd.DataFrame, ignore_unique_limit = ["Alvo ou depósito"]) -> pd.DataFrame:
df = df.copy()
# Primeiro, converta todos os valores da DataFrame para hashable
for col in df.columns:
df[col] = df[col].apply(make_hashable)
# Tenta converter strings para datetime e remover fuso horário
for col in df.columns:
if is_object_dtype(df[col]):
try:
df[col] = pd.to_datetime(df[col], format="%d-%m-%Y")
except Exception:
pass
if is_datetime64_any_dtype(df[col]):
df[col] = df[col].dt.tz_localize(None)
modification_container = st.container()
with modification_container:
to_filter_columns = st.multiselect(
"Filtrar por valor",
[column for column in df.columns if column != 'id'],
placeholder="Selecione um ou mais itens para filtrar"
)
for column in to_filter_columns:
left, right = st.columns((1, 20))
left.write("↳")
# Para colunas categóricas ou com poucos valores únicos, use multiselect
if is_categorical_dtype(df[column]) or df[column].nunique() < 100 or column in ignore_unique_limit:
raw_unique_values = df[column].dropna().unique()
# Verifica se há valores do tipo tupla (decorrentes de listas convertidas)
if any(isinstance(val, tuple) for val in raw_unique_values):
unique_values = flatten_unique_values(df[column])
is_flattened = True
else:
unique_values = list(raw_unique_values)
is_flattened = False
user_cat_input = right.multiselect(
f"Valores para {column}",
unique_values,
default=[], # Sem valores pré-selecionados
placeholder="Escolha uma opção"
)
if user_cat_input: # Filtrar apenas se houver seleção
if is_flattened:
df = df[df[column].apply(
lambda x: any(item in x for item in user_cat_input) if isinstance(x, tuple) else x in user_cat_input
)]
else:
df = df[df[column].isin(user_cat_input)]
elif is_numeric_dtype(df[column]):
_min = float(df[column].min())
_max = float(df[column].max())
step = (_max - _min) / 100
user_num_input = right.slider(
f"Valores para {column}",
min_value=_min,
max_value=_max,
value=(_min, _max),
step=step,
)
df = df[df[column].between(*user_num_input)]
elif is_datetime64_any_dtype(df[column]):
user_date_input = right.date_input(
f"Valores para {column}",
value=(
df[column].min(),
df[column].max(),
),
format="YYYY-MM-DD",
)
if isinstance(user_date_input, tuple) and len(user_date_input) == 2:
start_date, end_date = map(pd.to_datetime, user_date_input)
df = df[df[column].between(start_date, end_date)]
else:
# Para colunas de texto
raw_unique_values = df[column].dropna().unique()
if any(isinstance(val, tuple) for val in raw_unique_values):
unique_values = flatten_unique_values(df[column])
is_flattened = True
else:
unique_values = list(raw_unique_values)
is_flattened = False
if len(unique_values) < 100:
user_text_input = right.multiselect(
f"Valores para {column}",
unique_values,
default=[],
placeholder="Escolha uma opção",
)
if user_text_input:
if is_flattened:
df = df[df[column].apply(
lambda x: any(item in x for item in user_text_input) if isinstance(x, tuple) else x in user_text_input
)]
else:
df = df[df[column].isin(user_text_input)]
else:
user_text_input = right.text_input(
f"Substring ou regex em {column}",
help="""
**Pesquise palavras ou padrões usando regex:**
- **Múltiplos termos:** `maçã|banana` (busca "maçã" ou "banana").
- **Início da palavra:** `^carro` (encontra "carro", "carroça", etc.).
- **Fim da palavra:** `casa$` (encontra "minha casa", "tua casa", etc.).
- **Números:** `\d+` (encontra qualquer número, como "123", "2024").
- **Número específico:** `123` (encontra exatamente o número "123").
- **Palavras e números:** `carro|123` (encontra "carro" ou "123").
Deixe vazio para não filtrar.
"""
)
if user_text_input:
df = df[df[column].astype(str).str.contains(user_text_input, na=False)]
return df
|