Eric2mangel commited on
Commit
44e2991
·
verified ·
1 Parent(s): 2fb7700

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -114
app.py CHANGED
@@ -1,206 +1,142 @@
1
- import streamlit as st
2
  import pandas as pd
3
  import duckdb
4
  import polars as pl
 
 
5
  import time
6
  import os
7
  import matplotlib.pyplot as plt
8
- import numpy as np
9
  import tempfile
10
  from io import BytesIO
11
 
12
- print("=== APP STARTING ===")
13
- st.write("Hello, world!")
 
14
 
15
  # Configuration de la page Streamlit
16
  st.set_page_config(
17
  page_title="Comparaison de vitesse de chargement des données",
18
  layout="wide"
 
 
19
  )
20
 
21
- # === CSS UNIQUEMENT POUR LES DEUX BOUTONS DE TEST (même hauteur) ===
22
- st.markdown("""
23
- <style>
24
- div[data-testid="column"]:nth-child(1) button[kind="secondary"] {
25
- height: 5rem !important;
26
- min-height: 5rem !important;
27
- }
28
- div[data-testid="column"]:nth-child(2) button[kind="secondary"] {
29
- height: 5rem !important;
30
- min-height: 5rem !important;
31
- }
32
- </style>
33
- """, unsafe_allow_html=True)
34
 
35
  # --- FONCTION DE CHARGEMENT TECHNIQUE ---
36
  def load_file_and_measure_time(file_path, library, file_ext, read_kwargs):
37
  try:
38
- start_time = time.time()
39
- df = None
40
-
41
- # --- PARQUET ---
42
- if file_ext == '.parquet':
43
- if library == 'pandas':
44
- df = pd.read_parquet(file_path)
45
- elif library == 'pyarrow':
46
- df = pd.read_parquet(file_path, engine='pyarrow')
47
- elif library == 'duckdb':
48
- con = duckdb.connect()
49
- df = con.execute(f"SELECT * FROM read_parquet('{file_path}')").fetchdf()
50
- con.close()
51
- elif library == 'polars':
52
- df = pl.read_parquet(file_path)
53
-
54
- # --- EXCEL ---
55
- elif file_ext in ['.xlsx', '.xls']:
56
- sheet_idx = read_kwargs.get('sheet_idx', 0)
57
- header = 0 if read_kwargs.get('header') else None
58
- if library in ['pandas', 'pyarrow']:
59
- df = pd.read_excel(file_path, sheet_name=sheet_idx, header=header)
60
- elif library == 'duckdb':
61
- df = pd.read_excel(file_path, sheet_name=sheet_idx, header=header)
62
- elif library == 'polars':
63
- df = pl.read_excel(file_path, sheet_id=sheet_idx + 1)
64
-
65
- # --- CSV ---
66
- else:
67
- header_val = 0 if read_kwargs.get('header') else None
68
- if library == 'pandas':
69
- df = pd.read_csv(file_path, sep=None, engine='python', header=header_val)
70
- elif library == 'pyarrow':
71
- df = pd.read_csv(file_path, sep=None, engine='python', header=header_val, dtype_backend='pyarrow')
72
- elif library == 'duckdb':
73
- con = duckdb.connect()
74
- header_flag = "TRUE" if read_kwargs.get('header') else "FALSE"
75
- df = con.execute(f"SELECT * FROM read_csv_auto('{file_path}', HEADER={header_flag})").fetchdf()
76
- con.close()
77
- elif library == 'polars':
78
- df = pl.read_csv(file_path, has_header=read_kwargs.get('header'))
79
-
80
- end_time = time.time()
81
- return end_time - start_time, len(df)
82
- except Exception as e:
83
- return f"Erreur: {e}", 0
84
-
85
 
86
  # --- FONCTION POUR CHARGER DEPUIS UN BUFFER UPLOADÉ ---
87
  def load_from_buffer(uploaded_file, library, file_ext, read_kwargs):
 
88
  try:
 
89
  with tempfile.NamedTemporaryFile(delete=False, suffix=file_ext) as tmp_file:
90
  tmp_file.write(uploaded_file.getvalue())
91
  tmp_path = tmp_file.name
92
 
 
93
  load_time, row_count = load_file_and_measure_time(tmp_path, library, file_ext, read_kwargs)
 
 
94
  os.unlink(tmp_path)
 
95
  return load_time, row_count
 
96
  except Exception as e:
97
  return f"Erreur: {e}", 0
98
 
99
-
100
- # --- GESTION DU FICHIER CIBLE DANS LE SESSION STATE ---
101
- if 'target_file' not in st.session_state:
102
- st.session_state.target_file = None
103
- if 'file_ext' not in st.session_state:
104
- st.session_state.file_ext = None
105
  if 'uploaded_buffer' not in st.session_state:
106
  st.session_state.uploaded_buffer = None
107
 
108
- st.title("Comparaison de vitesse de chargement des données")
109
  st.markdown("Téléchargez un fichier **CSV, Excel ou Parquet** pour comparer **Pandas**, **PyArrow**, **DuckDB** et **Polars**.")
110
 
111
  # --- SIDEBAR ---
112
- st.sidebar.header("Paramètres du fichier")
113
 
114
  # Boutons de démo
115
- st.sidebar.subheader("Fichiers de test (30Mo)")
116
  c1, c2 = st.sidebar.columns(2)
117
- if c1.button("Faker Text"):
118
  if os.path.exists("faker_text.csv"):
119
  st.session_state.target_file = "faker_text.csv"
120
  st.session_state.file_ext = ".csv"
 
121
  try:
122
  test_df = pd.read_csv("faker_text.csv", nrows=5)
123
- st.sidebar.info(f"Fichier détecté : {len(pd.read_csv('faker_text.csv'))} lignes, {len(test_df.columns)} colonnes")
124
  except:
125
  pass
126
  else:
127
- st.sidebar.error("Fichier faker_text.csv introuvable à la racine")
128
 
129
- if c2.button("Numeric Only"):
130
  if os.path.exists("numeric_only.csv"):
131
  st.session_state.target_file = "numeric_only.csv"
132
  st.session_state.file_ext = ".csv"
 
133
  try:
134
  test_df = pd.read_csv("numeric_only.csv", nrows=5)
135
- st.sidebar.info(f"Fichier détecté : {len(pd.read_csv('numeric_only.csv'))} lignes, {len(test_df.columns)} colonnes")
136
  except:
137
  pass
138
  else:
139
- st.sidebar.error("Fichier numeric_only.csv introuvable à la racine")
140
 
141
  # Uploader manuel
142
  uploaded_file = st.sidebar.file_uploader("Ou choisissez un fichier", type=["csv", "parquet", "xlsx", "xls"])
143
  if uploaded_file is not None:
144
  try:
145
  file_ext = os.path.splitext(uploaded_file.name)[1].lower()
 
 
146
  st.session_state.uploaded_buffer = uploaded_file
147
- st.session_state.target_file = "uploaded_file"
148
  st.session_state.file_ext = file_ext
 
 
149
  file_size_mb = uploaded_file.size / (1024 * 1024)
150
- st.sidebar.success(f"Fichier uploadé : {uploaded_file.name} ({file_size_mb:.2f} Mo)")
151
  except Exception as e:
152
- st.sidebar.error(f"Erreur lors de l'upload : {str(e)}")
153
 
154
  # --- ACTIONS ET AFFICHAGE ---
155
  if st.session_state.target_file is not None:
156
- st.sidebar.success(f"Actif : **{st.session_state.target_file}**")
157
-
158
- has_header = st.sidebar.radio("Ligne de titres en première ligne ?", ["Oui", "Non"], index=0) == "Oui"
159
- read_kwargs = {'header': has_header}
160
-
161
- if st.session_state.file_ext in ['.xlsx', '.xls']:
162
- sheet_num = st.sidebar.number_input("Numéro de l'onglet (1 = premier)", min_value=1, value=1)
163
- read_kwargs['sheet_idx'] = sheet_num - 1
164
-
165
  run_comparison = st.sidebar.button("Lancer la comparaison")
166
 
167
  if run_comparison:
168
- st.subheader("Résultats de la vitesse de chargement")
169
  libraries = {'Pandas (Baseline)': 'pandas', 'PyArrow': 'pyarrow', 'DuckDB': 'duckdb', 'Polars': 'polars'}
170
  results = []
171
 
172
  for lib_name, lib_key in libraries.items():
173
  with st.spinner(f"Test en cours : **{lib_name}**..."):
 
174
  if st.session_state.target_file == "uploaded_file" and st.session_state.uploaded_buffer is not None:
 
175
  load_time, row_count = load_from_buffer(st.session_state.uploaded_buffer, lib_key, st.session_state.file_ext, read_kwargs)
176
  else:
 
177
  load_time, row_count = load_file_and_measure_time(st.session_state.target_file, lib_key, st.session_state.file_ext, read_kwargs)
178
  results.append({'Librairie': lib_name, 'Temps de chargement (s)': load_time, 'Nombre de lignes': row_count})
179
 
180
- results_df = pd.DataFrame(results)
181
 
182
  valid_counts = results_df[results_df['Nombre de lignes'] > 0]['Nombre de lignes']
183
  if not valid_counts.empty:
184
- st.markdown(f"**Nombre de lignes détectées :** **{int(valid_counts.iloc[0]):,}**")
185
 
186
  chart_data = results_df[results_df['Temps de chargement (s)'].apply(lambda x: isinstance(x, (int, float)))]
187
-
188
- if not chart_data.empty:
189
- chart_data = chart_data.sort_values(by='Temps de chargement (s)', ascending=True)
190
- fig, ax = plt.subplots(figsize=(8, 2.5))
191
- bars = ax.barh(chart_data['Librairie'], chart_data['Temps de chargement (s)'],
192
- color=['#4CAF50', '#2196F3', '#FFC107', '#E91E63'])
193
-
194
- max_time = chart_data['Temps de chargement (s)'].max()
195
- ax.set_xlim(right=max_time * 1.35)
196
- for bar in bars:
197
- ax.text(bar.get_width() + (max_time * 0.03), bar.get_y() + bar.get_height()/2,
198
- f'{bar.get_width():.4f}s', va='center', fontsize=10, fontweight='bold')
199
-
200
- ax.set_xlabel('Temps (secondes)')
201
- ax.set_title('Comparaison des vitesses de lecture')
202
- st.pyplot(fig)
203
- plt.close(fig)
204
-
205
- else:
206
- st.info("Veuillez charger un fichier ou utiliser un bouton de test à gauche.")
 
 
1
  import pandas as pd
2
  import duckdb
3
  import polars as pl
4
+
5
+
6
  import time
7
  import os
8
  import matplotlib.pyplot as plt
 
9
  import tempfile
10
  from io import BytesIO
11
 
12
+ print("=== APP STARTING ===") # Ça apparaîtra dans les logs
13
+ st.write("Hello, world!") # Un truc simple pour tester
14
+
15
 
16
  # Configuration de la page Streamlit
17
  st.set_page_config(
18
  page_title="Comparaison de vitesse de chargement des données",
19
  layout="wide"
20
+
21
+
22
  )
23
 
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
 
38
  # --- FONCTION DE CHARGEMENT TECHNIQUE ---
39
  def load_file_and_measure_time(file_path, library, file_ext, read_kwargs):
40
  try:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
 
42
  # --- FONCTION POUR CHARGER DEPUIS UN BUFFER UPLOADÉ ---
43
  def load_from_buffer(uploaded_file, library, file_ext, read_kwargs):
44
+ """Charge un fichier depuis un buffer Streamlit et mesure le temps"""
45
  try:
46
+ # Créer un fichier temporaire
47
  with tempfile.NamedTemporaryFile(delete=False, suffix=file_ext) as tmp_file:
48
  tmp_file.write(uploaded_file.getvalue())
49
  tmp_path = tmp_file.name
50
 
51
+ # Utiliser la fonction existante avec le fichier temporaire
52
  load_time, row_count = load_file_and_measure_time(tmp_path, library, file_ext, read_kwargs)
53
+
54
+ # Nettoyer le fichier temporaire
55
  os.unlink(tmp_path)
56
+
57
  return load_time, row_count
58
+
59
  except Exception as e:
60
  return f"Erreur: {e}", 0
61
 
 
 
 
 
 
 
62
  if 'uploaded_buffer' not in st.session_state:
63
  st.session_state.uploaded_buffer = None
64
 
65
+ st.title("Comparaison de vitesse de chargement des données")
66
  st.markdown("Téléchargez un fichier **CSV, Excel ou Parquet** pour comparer **Pandas**, **PyArrow**, **DuckDB** et **Polars**.")
67
 
68
  # --- SIDEBAR ---
69
+ st.sidebar.header("⚙️ Paramètres du fichier")
70
 
71
  # Boutons de démo
72
+ st.sidebar.subheader("🧪 Fichiers de test (30Mo)")
73
  c1, c2 = st.sidebar.columns(2)
74
+ if c1.button("📄 Faker Text"):
75
  if os.path.exists("faker_text.csv"):
76
  st.session_state.target_file = "faker_text.csv"
77
  st.session_state.file_ext = ".csv"
78
+ # Vérification des dimensions
79
  try:
80
  test_df = pd.read_csv("faker_text.csv", nrows=5)
81
+ st.sidebar.info(f"Fichier détecté : {len(pd.read_csv('faker_text.csv'))} lignes, {len(test_df.columns)} colonnes")
82
  except:
83
  pass
84
  else:
85
+ st.sidebar.error("Fichier faker_text.csv introuvable à la racine")
86
 
87
+ if c2.button("📊 Numeric Only"):
88
  if os.path.exists("numeric_only.csv"):
89
  st.session_state.target_file = "numeric_only.csv"
90
  st.session_state.file_ext = ".csv"
91
+ # Vérification des dimensions
92
  try:
93
  test_df = pd.read_csv("numeric_only.csv", nrows=5)
94
+ st.sidebar.info(f"Fichier détecté : {len(pd.read_csv('numeric_only.csv'))} lignes, {len(test_df.columns)} colonnes")
95
  except:
96
  pass
97
  else:
98
+ st.sidebar.error("Fichier numeric_only.csv introuvable à la racine")
99
 
100
  # Uploader manuel
101
  uploaded_file = st.sidebar.file_uploader("Ou choisissez un fichier", type=["csv", "parquet", "xlsx", "xls"])
102
  if uploaded_file is not None:
103
  try:
104
  file_ext = os.path.splitext(uploaded_file.name)[1].lower()
105
+
106
+ # Stockage du buffer dans session_state
107
  st.session_state.uploaded_buffer = uploaded_file
108
+ st.session_state.target_file = "uploaded_file" # Marqueur pour savoir qu'on a un upload
109
  st.session_state.file_ext = file_ext
110
+
111
+ # Afficher la taille du fichier uploadé
112
  file_size_mb = uploaded_file.size / (1024 * 1024)
113
+ st.sidebar.success(f"Fichier uploadé : {uploaded_file.name} ({file_size_mb:.2f} Mo)")
114
  except Exception as e:
115
+ st.sidebar.error(f"Erreur lors de l'upload : {str(e)}")
116
 
117
  # --- ACTIONS ET AFFICHAGE ---
118
  if st.session_state.target_file is not None:
 
 
 
 
 
 
 
 
 
119
  run_comparison = st.sidebar.button("Lancer la comparaison")
120
 
121
  if run_comparison:
122
+ st.subheader("⏱️ Résultats de la vitesse de chargement")
123
  libraries = {'Pandas (Baseline)': 'pandas', 'PyArrow': 'pyarrow', 'DuckDB': 'duckdb', 'Polars': 'polars'}
124
  results = []
125
 
126
  for lib_name, lib_key in libraries.items():
127
  with st.spinner(f"Test en cours : **{lib_name}**..."):
128
+ # Choix de la fonction selon la source
129
  if st.session_state.target_file == "uploaded_file" and st.session_state.uploaded_buffer is not None:
130
+ # Fichier uploadé : passer directement l'objet uploaded_file
131
  load_time, row_count = load_from_buffer(st.session_state.uploaded_buffer, lib_key, st.session_state.file_ext, read_kwargs)
132
  else:
133
+ # Fichier de test : utiliser le chemin
134
  load_time, row_count = load_file_and_measure_time(st.session_state.target_file, lib_key, st.session_state.file_ext, read_kwargs)
135
  results.append({'Librairie': lib_name, 'Temps de chargement (s)': load_time, 'Nombre de lignes': row_count})
136
 
 
137
 
138
  valid_counts = results_df[results_df['Nombre de lignes'] > 0]['Nombre de lignes']
139
  if not valid_counts.empty:
140
+ st.markdown(f"**Nombre de lignes détectées :** **{int(valid_counts.iloc[0]):,}**".replace(',', ' '))
141
 
142
  chart_data = results_df[results_df['Temps de chargement (s)'].apply(lambda x: isinstance(x, (int, float)))]