tx3bas commited on
Commit
d7dbf46
·
verified ·
1 Parent(s): c4c88ca

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +88 -67
app.py CHANGED
@@ -1,8 +1,10 @@
1
  import streamlit as st
2
  import plotly.express as px
3
  import pandas as pd
4
- import numpy as np
5
  from datetime import datetime
 
 
6
 
7
  # Configuración de la página
8
  st.set_page_config(page_title="Generador de Gráficos Personalizado", layout="wide")
@@ -29,13 +31,9 @@ st.sidebar.header("Configuración del Gráfico")
29
  # Título del gráfico
30
  chart_title = st.sidebar.text_input("Título del Gráfico", "Generador de Gráfico")
31
 
32
- # Tipo de gráfico (sin la opción de Línea temporal)
33
  chart_type = st.sidebar.selectbox("Tipo de Gráfico", ["Línea", "Área", "Dispersión", "Barras", "Donut"])
34
 
35
- # Función para generar rangos de fechas (eliminada la opción de línea temporal)
36
- def generate_date_range(start_date, end_date, freq):
37
- return pd.date_range(start=start_date, end=end_date, freq=freq).strftime('%Y-%m-%d').tolist()
38
-
39
  # Ingresar valores para los ejes
40
  x_values = st.sidebar.text_area("Valores para X (separados por comas)", "2013,2014,2015,2016,2017,2018")
41
  x = x_values.split(",")
@@ -58,22 +56,32 @@ y_label = st.sidebar.text_input("Etiqueta para el eje Y", "Y")
58
 
59
  # Desplegable de opciones adicionales
60
  with st.sidebar.expander("Opciones Adicionales"):
61
- graph_width = st.slider("Ancho del Gráfico", min_value=400, max_value=1000, value=800, step=50)
62
- graph_height = st.slider("Alto del Gráfico", min_value=300, max_value=800, value=600, step=50)
63
- font_family = st.selectbox("Fuente", font_options, index=font_options.index("Times New Roman"))
 
 
64
  show_legend = st.checkbox("Mostrar Leyenda", value=True)
 
 
 
 
 
65
  opacity = st.slider("Opacidad (%)", min_value=0, max_value=100, value=30, step=1) / 100
66
  border_width = st.slider("Grosor del Borde", min_value=0.0, max_value=3.0, value=1.5, step=0.1)
67
  border_opacity = st.slider("Opacidad del Borde (%)", min_value=0, max_value=100, value=60, step=1) / 100
68
  show_grid = st.checkbox("Activar rejilla", value=True)
 
69
  if chart_type == "Barras" and num_y_vars > 1:
70
  superposed_bars = st.checkbox("Superpuestas", value=True, key="superposed_bars")
71
  else:
72
  superposed_bars = False
73
  if chart_type == "Barras":
74
  horizontal_bars = st.checkbox("Invertidas", key="horizontal_bars")
 
75
  if chart_type == "Donut":
76
  hole_size = st.slider("Tamaño del agujero (%)", min_value=0, max_value=100, value=30, step=1) / 100
 
77
 
78
  # Opción para múltiples colores (siempre activada para Donut)
79
  use_multiple_colors = st.sidebar.checkbox("Usar múltiples colores", value=True if chart_type == "Donut" or num_y_vars > 1 else False, key="use_multiple_colors")
@@ -84,11 +92,10 @@ selected_color = st.sidebar.color_picker("Color", "#24CBA0", key="single_color")
84
  # Definir colores
85
  if use_multiple_colors:
86
  num_colors = len(x)
87
- colors = [hex_to_rgba(st.sidebar.color_picker(f"Color {i+1}", predefined_colors[i % len(predefined_colors)], key=f"color_{i}"), alpha=opacity)
88
- for i in range(num_colors)]
89
  else:
90
  color = hex_to_rgba(selected_color, alpha=opacity)
91
- colors = [color] * len(x) # Definir colors para casos donde no se usa múltiple colores
92
 
93
  # Procesar valores
94
  y_values_lists = [[float(i) for i in y_values.split(",") if i.strip()] for y_values in y_values_list]
@@ -113,21 +120,27 @@ common_layout = dict(
113
  hovermode="x unified",
114
  width=graph_width,
115
  height=graph_height,
116
- margin=dict(l=60, r=40, t=100, b=40),
117
- xaxis=dict(showgrid=show_grid, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True),
118
- yaxis=dict(showgrid=show_grid, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True),
119
- font=dict(family=font_family, size=18, color="#374151", weight="normal"),
 
 
120
  showlegend=show_legend,
121
- legend=dict(orientation="v", yanchor="top", y=1, xanchor="left", x=1.02)
 
 
 
 
 
 
 
122
  )
123
 
124
- # Personalizar el hovertemplate
125
- hovertemplate = '<b>%{y}</b>'
126
-
127
  # Generar el gráfico basado en el tipo seleccionado
128
  if chart_type == "Línea":
129
  fig = px.line(data, x="X", y=y_names_list, line_shape="spline")
130
- fig.update_traces(hovertemplate=hovertemplate)
131
  if use_multiple_colors:
132
  for i, name in enumerate(y_names_list):
133
  fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)])
@@ -136,7 +149,7 @@ if chart_type == "Línea":
136
 
137
  elif chart_type == "Área":
138
  fig = px.area(data, x="X", y=y_names_list, line_shape="spline")
139
- fig.update_traces(hovertemplate=hovertemplate)
140
  if use_multiple_colors:
141
  for i, name in enumerate(y_names_list):
142
  fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)], fillcolor=colors[i % len(colors)])
@@ -145,19 +158,19 @@ elif chart_type == "Área":
145
 
146
  elif chart_type == "Dispersión":
147
  fig = px.scatter(data, x="X", y=y_names_list)
148
- fig.update_traces(hovertemplate=hovertemplate)
149
  if use_multiple_colors:
150
  for i, name in enumerate(y_names_list):
151
- fig.update_traces(selector=dict(name=name), marker_color=colors[i % len(colors)], marker_line_color=colors[i % len(colors)], marker_line_width=border_width)
152
  else:
153
- fig.update_traces(marker_color=color, marker_line_color=color, marker_line_width=border_width)
154
 
155
  elif chart_type == "Barras":
156
  if horizontal_bars:
157
  fig = px.bar(data, x=y_names_list, y="X", orientation='h', barmode='overlay' if superposed_bars else 'group')
158
  else:
159
  fig = px.bar(data, x="X", y=y_names_list, barmode='overlay' if superposed_bars else 'group')
160
- fig.update_traces(hovertemplate=hovertemplate)
161
  if use_multiple_colors:
162
  for i, trace in enumerate(fig.data):
163
  trace.update(marker_color=colors[i % len(colors)])
@@ -165,34 +178,36 @@ elif chart_type == "Barras":
165
  fig.update_traces(marker_color=color)
166
  fig.update_layout(bargap=0.2)
167
 
168
-
169
  elif chart_type == "Donut":
170
- figs = []
171
- for i, y_name in enumerate(y_names_list):
172
- fig = px.pie(data, values=y_name, names="X", hole=hole_size, color_discrete_sequence=colors[:len(x)])
 
173
  fig.update_traces(hovertemplate='<b>%{label}</b>: %{value} (%{percent})', textinfo='percent+label')
174
- fig.update_layout(
175
- title=dict(
176
- text=f"{chart_title}<br><sub>{y_name}</sub>" if len(y_names_list) > 1 else chart_title,
177
- x=0.5,
178
- y=0.95,
179
- xanchor='center',
180
- yanchor='top',
181
- font=dict(
182
- family=font_family,
183
- size=18,
184
- color="#374151",
185
- weight="normal"
186
- )
187
- ),
188
- **common_layout
189
- )
190
- figs.append(fig)
191
- for fig in figs:
192
- st.plotly_chart(fig)
 
 
193
 
194
  # Añadir anotación para el título
195
- if chart_type != "Donut" and chart_type != "Enlace externo":
196
  fig.update_layout(
197
  title=dict(
198
  text=f"{chart_title}",
@@ -202,27 +217,33 @@ if chart_type != "Donut" and chart_type != "Enlace externo":
202
  yanchor='top',
203
  font=dict(
204
  family=font_family,
205
- size=18,
206
- color="#374151",
207
- weight="normal"
208
  )
209
  ),
210
  legend_title_text='' # Eliminar el texto del título de la leyenda
211
  )
212
-
213
- # Aplicar configuración común
214
- fig.update_layout(**common_layout)
215
-
216
- # Aplicar múltiples colores si se seleccionó la opción
217
- if use_multiple_colors and chart_type != "Donut":
218
- for i, trace in enumerate(fig.data):
219
- trace.update(marker_color=colors[i % len(colors)])
220
-
221
- # Mostrar el gráfico
222
- st.plotly_chart(fig)
223
 
224
- # Forzar el autoescale
225
- fig.update_layout(xaxis_autorange=True, yaxis_autorange=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
 
227
  # Información adicional
228
- st.write("")
 
1
  import streamlit as st
2
  import plotly.express as px
3
  import pandas as pd
4
+ import numpy as np # Asegúrate de importar numpy
5
  from datetime import datetime
6
+ import plotly.io as pio
7
+ import io
8
 
9
  # Configuración de la página
10
  st.set_page_config(page_title="Generador de Gráficos Personalizado", layout="wide")
 
31
  # Título del gráfico
32
  chart_title = st.sidebar.text_input("Título del Gráfico", "Generador de Gráfico")
33
 
34
+ # Tipo de gráfico
35
  chart_type = st.sidebar.selectbox("Tipo de Gráfico", ["Línea", "Área", "Dispersión", "Barras", "Donut"])
36
 
 
 
 
 
37
  # Ingresar valores para los ejes
38
  x_values = st.sidebar.text_area("Valores para X (separados por comas)", "2013,2014,2015,2016,2017,2018")
39
  x = x_values.split(",")
 
56
 
57
  # Desplegable de opciones adicionales
58
  with st.sidebar.expander("Opciones Adicionales"):
59
+ graph_width = st.slider("Ancho del Gráfico", min_value=400, max_value=1200, value=1000, step=50)
60
+ graph_height = st.slider("Alto del Gráfico", min_value=300, max_value=900, value=700, step=50)
61
+ font_family = st.selectbox("Fuente del Gráfico", font_options, index=font_options.index("Times New Roman"))
62
+ axis_font_size = st.slider("Tamaño de la Fuente de los Ejes", min_value=10, max_value=30, value=24, step=1)
63
+ tick_font_size = st.slider("Tamaño de los Números de los Ejes", min_value=8, max_value=24, value=19, step=1)
64
  show_legend = st.checkbox("Mostrar Leyenda", value=True)
65
+
66
+ # Configuración de la leyenda
67
+ legend_font_family = st.selectbox("Fuente de la Leyenda", font_options, index=font_options.index("Arial"))
68
+ legend_font_size = st.slider("Tamaño de la Fuente de la Leyenda", min_value=10, max_value=30, value=22, step=1)
69
+
70
  opacity = st.slider("Opacidad (%)", min_value=0, max_value=100, value=30, step=1) / 100
71
  border_width = st.slider("Grosor del Borde", min_value=0.0, max_value=3.0, value=1.5, step=0.1)
72
  border_opacity = st.slider("Opacidad del Borde (%)", min_value=0, max_value=100, value=60, step=1) / 100
73
  show_grid = st.checkbox("Activar rejilla", value=True)
74
+
75
  if chart_type == "Barras" and num_y_vars > 1:
76
  superposed_bars = st.checkbox("Superpuestas", value=True, key="superposed_bars")
77
  else:
78
  superposed_bars = False
79
  if chart_type == "Barras":
80
  horizontal_bars = st.checkbox("Invertidas", key="horizontal_bars")
81
+
82
  if chart_type == "Donut":
83
  hole_size = st.slider("Tamaño del agujero (%)", min_value=0, max_value=100, value=30, step=1) / 100
84
+ show_values = st.checkbox("Mostrar valores en el gráfico", value=False)
85
 
86
  # Opción para múltiples colores (siempre activada para Donut)
87
  use_multiple_colors = st.sidebar.checkbox("Usar múltiples colores", value=True if chart_type == "Donut" or num_y_vars > 1 else False, key="use_multiple_colors")
 
92
  # Definir colores
93
  if use_multiple_colors:
94
  num_colors = len(x)
95
+ colors = [hex_to_rgba(st.sidebar.color_picker(f"Color {i+1}", predefined_colors[i % len(predefined_colors)], key=f"color_{i}"), alpha=opacity) for i in range(num_colors)]
 
96
  else:
97
  color = hex_to_rgba(selected_color, alpha=opacity)
98
+ colors = [color] * len(x)
99
 
100
  # Procesar valores
101
  y_values_lists = [[float(i) for i in y_values.split(",") if i.strip()] for y_values in y_values_list]
 
120
  hovermode="x unified",
121
  width=graph_width,
122
  height=graph_height,
123
+ margin=dict(l=80, r=40, t=100, b=60), # Ajustar los márgenes para separar el texto de los ejes
124
+ xaxis=dict(showgrid=show_grid, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True,
125
+ tickfont=dict(size=tick_font_size), title_font=dict(size=axis_font_size)),
126
+ yaxis=dict(showgrid=show_grid, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True,
127
+ tickfont=dict(size=tick_font_size), title_font=dict(size=axis_font_size)),
128
+ font=dict(family=font_family, size=axis_font_size, color="#374151"),
129
  showlegend=show_legend,
130
+ legend=dict(
131
+ orientation="v",
132
+ yanchor="top",
133
+ y=1,
134
+ xanchor="left",
135
+ x=1.02,
136
+ font=dict(family=legend_font_family, size=legend_font_size)
137
+ )
138
  )
139
 
 
 
 
140
  # Generar el gráfico basado en el tipo seleccionado
141
  if chart_type == "Línea":
142
  fig = px.line(data, x="X", y=y_names_list, line_shape="spline")
143
+ fig.update_traces(hovertemplate='<b>%{y}</b>', line=dict(width=border_width)) # Aplicar el grosor del borde a línea
144
  if use_multiple_colors:
145
  for i, name in enumerate(y_names_list):
146
  fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)])
 
149
 
150
  elif chart_type == "Área":
151
  fig = px.area(data, x="X", y=y_names_list, line_shape="spline")
152
+ fig.update_traces(hovertemplate='<b>%{y}</b>', line=dict(width=border_width), fillcolor=color)
153
  if use_multiple_colors:
154
  for i, name in enumerate(y_names_list):
155
  fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)], fillcolor=colors[i % len(colors)])
 
158
 
159
  elif chart_type == "Dispersión":
160
  fig = px.scatter(data, x="X", y=y_names_list)
161
+ fig.update_traces(hovertemplate='<b>%{y}</b>', marker=dict(size=10, line=dict(width=border_width, color=hex_to_rgba('#000000', border_opacity))))
162
  if use_multiple_colors:
163
  for i, name in enumerate(y_names_list):
164
+ fig.update_traces(selector=dict(name=name), marker_color=colors[i % len(colors)], marker_line_color=colors[i % len(colors)])
165
  else:
166
+ fig.update_traces(marker_color=color, marker_line_color=color)
167
 
168
  elif chart_type == "Barras":
169
  if horizontal_bars:
170
  fig = px.bar(data, x=y_names_list, y="X", orientation='h', barmode='overlay' if superposed_bars else 'group')
171
  else:
172
  fig = px.bar(data, x="X", y=y_names_list, barmode='overlay' if superposed_bars else 'group')
173
+ fig.update_traces(hovertemplate='<b>%{y}</b>', marker=dict(line=dict(width=border_width, color=hex_to_rgba('#000000', border_opacity))))
174
  if use_multiple_colors:
175
  for i, trace in enumerate(fig.data):
176
  trace.update(marker_color=colors[i % len(colors)])
 
178
  fig.update_traces(marker_color=color)
179
  fig.update_layout(bargap=0.2)
180
 
 
181
  elif chart_type == "Donut":
182
+ # Generar solo un gráfico Donut y asegurarse de que no haya duplicados
183
+ fig = px.pie(data, values=y_values_lists[0], names="X", hole=hole_size, color_discrete_sequence=colors[:len(x)])
184
+
185
+ if show_values:
186
  fig.update_traces(hovertemplate='<b>%{label}</b>: %{value} (%{percent})', textinfo='percent+label')
187
+ else:
188
+ fig.update_traces(hovertemplate='<b>%{label}</b>', textinfo='none') # Ocultar valores y etiquetas
189
+
190
+ fig.update_traces(marker=dict(colors=colors[:len(x)])) # Aplicar múltiples colores
191
+
192
+ fig.update_layout(
193
+ title=dict(
194
+ text=f"{chart_title}",
195
+ x=0.5,
196
+ y=0.95,
197
+ xanchor='center',
198
+ yanchor='top',
199
+ font=dict(
200
+ family=font_family,
201
+ size=axis_font_size,
202
+ color="#374151"
203
+ )
204
+ ),
205
+ **common_layout
206
+ )
207
+ st.plotly_chart(fig)
208
 
209
  # Añadir anotación para el título
210
+ if chart_type != "Donut":
211
  fig.update_layout(
212
  title=dict(
213
  text=f"{chart_title}",
 
217
  yanchor='top',
218
  font=dict(
219
  family=font_family,
220
+ size=axis_font_size,
221
+ color="#374151"
 
222
  )
223
  ),
224
  legend_title_text='' # Eliminar el texto del título de la leyenda
225
  )
 
 
 
 
 
 
 
 
 
 
 
226
 
227
+ # Aplicar configuración común
228
+ fig.update_layout(**common_layout)
229
+
230
+ # Aplicar múltiples colores si se seleccionó la opción
231
+ if use_multiple_colors and chart_type != "Donut":
232
+ for i, trace in enumerate(fig.data):
233
+ trace.update(marker_color=colors[i % len(colors)])
234
+
235
+ # Mostrar el gráfico
236
+ st.plotly_chart(fig)
237
+
238
+ # Descargar gráfico con mayor resolución usando los valores personalizados
239
+ export_as_png = st.button("Descargar gráfico en alta calidad")
240
+
241
+ if export_as_png:
242
+ img_bytes = pio.to_image(fig, format="png", width=graph_width, height=graph_height, scale=6)
243
+ st.download_button(label="Descargar imagen", data=img_bytes, file_name="grafico_personalizado.png", mime="image/png")
244
+
245
+ # Forzar el autoescale
246
+ fig.update_layout(xaxis_autorange=True, yaxis_autorange=True)
247
 
248
  # Información adicional
249
+ st.write("")