tx3bas commited on
Commit
93e61b0
·
verified ·
1 Parent(s): bbeded8

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +211 -57
app.py CHANGED
@@ -1,10 +1,11 @@
1
  import streamlit as st
2
  import plotly.express as px
3
  import pandas as pd
 
4
  from datetime import datetime
5
 
6
  # Configuración de la página
7
- st.set_page_config(page_title="Generador de Franjas de Tiempo Apiladas", layout="wide")
8
 
9
  # Función para convertir HEX a RGBA con transparencia
10
  def hex_to_rgba(hex_color, alpha=1.0):
@@ -26,66 +27,219 @@ font_options = [
26
  st.sidebar.header("Configuración del Gráfico")
27
 
28
  # Título del gráfico
29
- chart_title = st.sidebar.text_input("Título del Gráfico", "Gráfico de Franjas de Tiempo Apiladas")
30
-
31
- # Seleccionar formato de tiempo
32
- time_format = st.sidebar.selectbox("Formato de Tiempo", ["Día", "Mes", "Año"])
33
-
34
- # Ingresar valores para franjas de tiempo
35
- y_values = {
36
- 'Y-1': ('2021-01-01', '2022-12-31'),
37
- 'Y-2': ('2020-01-01', '2021-12-31'),
38
- 'Y-3': ('2023-01-01', '2024-12-31')
39
- }
40
-
41
- # Crear el DataFrame con franjas de tiempo
42
- data_list = []
43
- for y_name, (start_date, end_date) in y_values.items():
44
- data_list.append({
45
- 'Variable': y_name,
46
- 'Start': datetime.strptime(start_date, '%Y-%m-%d'),
47
- 'End': datetime.strptime(end_date, '%Y-%m-%d')
48
- })
49
-
50
- data = pd.DataFrame(data_list)
51
-
52
- # Convertir el DataFrame para el gráfico
53
- data['Duration'] = data['End'] - data['Start']
54
- data['Start'] = pd.to_datetime(data['Start'])
55
- data['End'] = pd.to_datetime(data['End'])
56
-
57
- # Crear gráfico
58
- fig = px.timeline(data, x_start="Start", x_end="End", y="Variable", color="Variable", title=chart_title)
59
- fig.update_yaxes(categoryorder="total ascending")
60
-
61
- # Personalizar el formato de tiempo en el eje X
62
- if time_format == "Día":
63
- tickformat = "%d-%m-%Y"
64
- elif time_format == "Mes":
65
- tickformat = "%Y-%m"
66
  else:
67
- tickformat = "%Y"
68
-
69
- fig.update_layout(
70
- xaxis_title="Tiempo",
71
- yaxis_title="Variables",
72
- xaxis=dict(
73
- tickformat=tickformat,
74
- titlefont=dict(size=14),
75
- tickfont=dict(size=12),
76
- ),
77
- yaxis=dict(
78
- titlefont=dict(size=14),
79
- tickfont=dict(size=12),
80
- ),
81
- width=800,
82
- height=600,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  margin=dict(l=60, r=40, t=100, b=40),
84
- font=dict(family="Times New Roman", size=18, color="black")
 
 
 
 
85
  )
86
 
87
- # Mostrar el gráfico
88
- st.plotly_chart(fig)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
89
 
90
  # Información adicional
91
  st.write("Aquí puede añadir información adicional sobre los gráficos generados.")
 
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")
9
 
10
  # Función para convertir HEX a RGBA con transparencia
11
  def hex_to_rgba(hex_color, alpha=1.0):
 
27
  st.sidebar.header("Configuración del Gráfico")
28
 
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
33
+ chart_type = st.sidebar.selectbox("Tipo de Gráfico", ["Línea", "Área", "Dispersión", "Barras", "Donut", "Línea temporal"])
34
+
35
+ # Función para generar rangos de fechas
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
+ if chart_type == "Línea temporal":
40
+ time_unit = st.sidebar.selectbox("Unidad de tiempo", ["Días", "Meses", "Años"])
41
+
42
+ if time_unit == "Días":
43
+ start_date = st.sidebar.date_input("Fecha de inicio", datetime(2023, 1, 1))
44
+ end_date = st.sidebar.date_input("Fecha de fin", datetime(2023, 12, 31))
45
+ x = generate_date_range(start_date, end_date, 'D')
46
+ elif time_unit == "Meses":
47
+ start_date = st.sidebar.date_input("Fecha de inicio", datetime(2023, 1, 1))
48
+ end_date = st.sidebar.date_input("Fecha de fin", datetime(2023, 12, 31))
49
+ x = generate_date_range(start_date, end_date, 'M')
50
+ elif time_unit == "Años":
51
+ start_year = st.sidebar.number_input("Año de inicio", min_value=2000, max_value=2100, value=2020)
52
+ end_year = st.sidebar.number_input("Año de fin", min_value=2000, max_value=2100, value=2023)
53
+ x = [str(year) for year in range(start_year, end_year + 1)]
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  else:
55
+ # Ingresar valores para los ejes
56
+ x_values = st.sidebar.text_area("Valores para X (separados por comas)", "2013,2014,2015,2016,2017,2018")
57
+ x = x_values.split(",")
58
+
59
+ # Selector de número de variables Y
60
+ num_y_vars = st.sidebar.number_input("Número de variables Y", min_value=1, max_value=100, value=1, step=1, key="num_y_vars")
61
+ y_values_list = []
62
+ y_names_list = []
63
+ for i in range(num_y_vars):
64
+ if f"y_values_{i}" not in st.session_state:
65
+ st.session_state[f"y_values_{i}"] = ','.join([str(np.random.randint(1, 25)) for _ in x])
66
+ y_values = st.sidebar.text_area(f"Valores para Y-{i+1} (separados por comas)", st.session_state[f"y_values_{i}"], key=f"y_values_{i}")
67
+ y_name = st.sidebar.text_input(f"Nombre de la Variable Y-{i+1}", f"Variable Y-{i+1}", key=f"y_name_{i}")
68
+ y_values_list.append(y_values)
69
+ y_names_list.append(y_name)
70
+
71
+ # Etiquetas personalizadas para los ejes
72
+ x_label = st.sidebar.text_input("Etiqueta para el eje X", "X")
73
+ y_label = st.sidebar.text_input("Etiqueta para el eje Y", "Y")
74
+
75
+ # Desplegable de opciones adicionales
76
+ with st.sidebar.expander("Opciones Adicionales"):
77
+ graph_width = st.slider("Ancho del Gráfico", min_value=400, max_value=1000, value=800, step=50)
78
+ graph_height = st.slider("Alto del Gráfico", min_value=300, max_value=800, value=600, step=50)
79
+ font_family = st.selectbox("Fuente", font_options, index=font_options.index("Times New Roman"))
80
+ show_legend = st.checkbox("Mostrar Leyenda", value=True)
81
+ opacity = st.slider("Opacidad (%)", min_value=0, max_value=100, value=30, step=1) / 100
82
+ border_width = st.slider("Grosor del Borde", min_value=0.0, max_value=3.0, value=1.5, step=0.1)
83
+ border_opacity = st.slider("Opacidad del Borde (%)", min_value=0, max_value=100, value=60, step=1) / 100
84
+ if chart_type == "Barras" and num_y_vars > 1:
85
+ stacked_bars = st.checkbox("Superpuestas", key="stacked_bars")
86
+ else:
87
+ stacked_bars = False
88
+ if chart_type == "Barras":
89
+ horizontal_bars = st.checkbox("Invertidas", key="horizontal_bars")
90
+ if chart_type == "Donut":
91
+ hole_size = st.slider("Tamaño del agujero (%)", min_value=0, max_value=100, value=30, step=1) / 100
92
+
93
+ # Opción para múltiples colores (siempre activada para Donut)
94
+ 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")
95
+
96
+ # Seleccionar color(es) para el gráfico
97
+ selected_color = st.sidebar.color_picker("Color", "#24CBA0", key="single_color")
98
+
99
+ # Definir colores
100
+ if use_multiple_colors:
101
+ num_colors = len(x)
102
+ colors = [hex_to_rgba(st.sidebar.color_picker(f"Color {i+1}", predefined_colors[i % len(predefined_colors)], key=f"color_{i}"), alpha=opacity)
103
+ for i in range(num_colors)]
104
+ border_colors = [hex_to_rgba(st.sidebar.color_picker(f"Color de Borde {i+1}", predefined_colors[i % len(predefined_colors)], key=f"border_color_{i}"), alpha=border_opacity)
105
+ for i in range(num_colors)]
106
+ else:
107
+ color = hex_to_rgba(selected_color, alpha=opacity)
108
+ border_color = hex_to_rgba(selected_color, alpha=border_opacity)
109
+ colors = [color] * len(x) # Definir colors para casos donde no se usa múltiple colores
110
+
111
+ # Procesar valores
112
+ y_values_lists = [[float(i) for i in y_values.split(",") if i.strip()] for y_values in y_values_list]
113
+
114
+ # Asegurar que todas las listas de Y tengan el mismo tamaño que X
115
+ for y_values in y_values_lists:
116
+ while len(y_values) < len(x):
117
+ y_values.append(0)
118
+ while len(y_values) > len(x):
119
+ y_values.pop()
120
+
121
+ # Crear un DataFrame
122
+ data = pd.DataFrame({"X": x})
123
+ for idx, y_set in enumerate(y_values_lists):
124
+ data[y_names_list[idx]] = y_set
125
+
126
+ # Configuración común para todos los gráficos
127
+ common_layout = dict(
128
+ xaxis_title=x_label,
129
+ yaxis_title=y_label,
130
+ plot_bgcolor="white",
131
+ hovermode="x unified",
132
+ width=graph_width,
133
+ height=graph_height,
134
  margin=dict(l=60, r=40, t=100, b=40),
135
+ xaxis=dict(showgrid=True, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True),
136
+ yaxis=dict(showgrid=True, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True),
137
+ font=dict(family=font_family, size=18, color="black"),
138
+ showlegend=show_legend,
139
+ legend=dict(orientation="v", yanchor="top", y=1, xanchor="left", x=1.02)
140
  )
141
 
142
+ # Personalizar el hovertemplate
143
+ hovertemplate = '<b>%{y}</b>'
144
+
145
+ # Generar el gráfico basado en el tipo seleccionado
146
+ if chart_type == "Línea":
147
+ fig = px.line(data, x="X", y=y_names_list, line_shape="spline")
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), line_color=colors[i % len(colors)])
152
+ else:
153
+ fig.update_traces(line_color=color)
154
+ elif chart_type == "Área":
155
+ fig = px.area(data, x="X", y=y_names_list, line_shape="spline")
156
+ fig.update_traces(hovertemplate=hovertemplate)
157
+ if use_multiple_colors:
158
+ for i, name in enumerate(y_names_list):
159
+ fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)], fillcolor=colors[i % len(colors)])
160
+ else:
161
+ fig.update_traces(line_color=color, fillcolor=color)
162
+ elif chart_type == "Dispersión":
163
+ fig = px.scatter(data, x="X", y=y_names_list)
164
+ fig.update_traces(hovertemplate=hovertemplate)
165
+ if use_multiple_colors:
166
+ for i, name in enumerate(y_names_list):
167
+ fig.update_traces(selector=dict(name=name), marker_color=colors[i % len(colors)], marker_line_color=border_colors[i % len(border_colors)], marker_line_width=border_width)
168
+ else:
169
+ fig.update_traces(marker_color=color, marker_line_color=border_color, marker_line_width=border_width)
170
+ elif chart_type == "Barras":
171
+ if horizontal_bars:
172
+ fig = px.bar(data, y="X", x=y_names_list, orientation='h', barmode='stack' if stacked_bars else 'group')
173
+ else:
174
+ fig = px.bar(data, x="X", y=y_names_list, barmode='stack' if stacked_bars else 'group')
175
+ fig.update_traces(hovertemplate=hovertemplate)
176
+ if use_multiple_colors:
177
+ if len(y_names_list) == 1: # Solo una variable Y
178
+ fig.update_traces(marker_color=colors[:len(x)], marker_line_color=border_colors[:len(x)], marker_line_width=border_width)
179
+ else:
180
+ for i, trace in enumerate(fig.data):
181
+ trace.marker.color = colors[i % len(colors)]
182
+ trace.marker.line.color = border_colors[i % len(border_colors)]
183
+ trace.marker.line.width = border_width
184
+ else:
185
+ fig.update_traces(marker_color=color, marker_line_color=border_color, marker_line_width=border_width)
186
+ fig.update_layout(bargap=0.2)
187
+ elif chart_type == "Donut":
188
+ figs = []
189
+ for i, y_name in enumerate(y_names_list):
190
+ fig = px.pie(data, values=y_name, names="X", hole=hole_size, color_discrete_sequence=colors[:len(x)])
191
+ fig.update_traces(hovertemplate='<b>%{label}</b>: %{value} (%{percent})', textinfo='percent+label')
192
+ fig.update_layout(
193
+ title=dict(
194
+ text=f"{chart_title}<br><sub>{y_name}</sub>" if len(y_names_list) > 1 else 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=18,
202
+ color="#374151",
203
+ weight="normal"
204
+ )
205
+ ),
206
+ **common_layout
207
+ )
208
+ figs.append(fig)
209
+ for fig in figs:
210
+ st.plotly_chart(fig)
211
+
212
+ # Añadir anotación para el título
213
+ if chart_type != "Donut":
214
+ fig.update_layout(
215
+ title=dict(
216
+ text=f"{chart_title}",
217
+ x=0.5,
218
+ y=0.95,
219
+ xanchor='center',
220
+ yanchor='top',
221
+ font=dict(
222
+ family=font_family,
223
+ size=18,
224
+ color="#374151",
225
+ weight="normal"
226
+ )
227
+ )
228
+ )
229
+
230
+ # Aplicar configuración común
231
+ fig.update_layout(**common_layout)
232
+
233
+ # Aplicar múltiples colores si se seleccionó la opción
234
+ if use_multiple_colors and chart_type != "Donut":
235
+ for i, trace in enumerate(fig.data):
236
+ trace.update(marker_color=colors[i % len(colors)], marker_line_color=border_colors[i % len(border_colors)], marker_line_width=border_width)
237
+
238
+ # Mostrar el gráfico
239
+ st.plotly_chart(fig)
240
+
241
+ # Forzar el autoescale
242
+ fig.update_layout(xaxis_autorange=True, yaxis_autorange=True)
243
 
244
  # Información adicional
245
  st.write("Aquí puede añadir información adicional sobre los gráficos generados.")