linea-temporal / app.py
tx3bas's picture
Update app.py
196411a verified
import streamlit as st
import plotly.express as px
import pandas as pd
from datetime import datetime, timedelta
# Configuración de la página
st.set_page_config(page_title="Generador de Franjas de Tiempo", layout="wide")
# Función para convertir HEX a RGBA con transparencia
def hex_to_rgba(hex_color, alpha=1.0):
hex_color = hex_color.lstrip('#')
return f'rgba({int(hex_color[0:2], 16)},{int(hex_color[2:4], 16)},{int(hex_color[4:6], 16)},{alpha})'
# Colores predefinidos
predefined_colors = [
"#FF5C5C", "#5CCFFF", "#FFA500", "#90EE90", "#9370DB", "#FFD700"
]
# Lista de fuentes más utilizadas
font_options = [
"Times New Roman", "Arial", "Helvetica", "Calibri", "Verdana",
"Tahoma", "Georgia", "Garamond", "Courier New", "Brush Script MT"
]
# Sidebar para la configuración del gráfico
st.sidebar.header("Configuración del Gráfico")
# Título del gráfico
chart_title = st.sidebar.text_input("Título del Gráfico", "Gráfico de Franjas de Tiempo")
# Seleccionar formato de tiempo
time_format = st.sidebar.selectbox("Formato de Tiempo", ["Año", "Mes y Año"])
# Ingresar valores para franjas de tiempo
num_y_vars = st.sidebar.number_input("Número de Variables Y", min_value=1, max_value=30, value=3, step=1)
y_values = {}
for i in range(num_y_vars):
year = 2020 + i % 10 # Esto asegura que el año sea siempre válido
y_start = st.sidebar.text_input(f"Fecha de Inicio para Y-{i+1} (YYYY-MM-DD)", key=f"y_start_{i}", value=f"{year}-01-01")
y_end = st.sidebar.text_input(f"Fecha de Fin para Y-{i+1} (YYYY-MM-DD)", key=f"y_end_{i}", value=f"{year + 1}-12-31")
y_name = st.sidebar.text_input(f"Nombre de la Variable Y-{i+1}", key=f"y_name_{i}", value=f"Y-{i+1}")
y_values[y_name] = (y_start, y_end)
# Personalizar las etiquetas de los ejes
x_axis_label = st.sidebar.text_input("Etiqueta para el Eje X", "Tiempo")
y_axis_label = st.sidebar.text_input("Etiqueta para el Eje Y", "Variables")
# Opciones adicionales
with st.sidebar.expander("Opciones Adicionales"):
superposed = st.checkbox("Superpuestas", value=False)
bar_width = st.slider("Ancho de la Barra de Variable", min_value=0.1, max_value=1.0, value=0.5, step=0.1)
show_grid = st.checkbox("Mostrar Líneas de Rejilla", value=True)
opacity = st.slider("Opacidad (%)", min_value=0, max_value=100, value=100, step=1) / 100
border_width = st.slider("Grosor del Borde", min_value=0.0, max_value=3.0, value=1.0, step=0.1)
border_opacity = st.slider("Opacidad del Borde (%)", min_value=0, max_value=100, value=100, step=1) / 100
# Opción para múltiples colores
use_multiple_colors = st.sidebar.checkbox("Usar múltiples colores", value=True, key="use_multiple_colors")
# Seleccionar color(es) para el gráfico
selected_color = st.sidebar.color_picker("Color", "#24CBA0", key="single_color")
# Definir colores
if use_multiple_colors:
colors = [st.sidebar.color_picker(f"Color {i+1}", predefined_colors[i % len(predefined_colors)], key=f"color_{i}")
for i in range(num_y_vars)]
else:
color = selected_color
colors = [color] * num_y_vars # Definir colors para casos donde no se usa múltiple colores
# Crear el DataFrame con franjas de tiempo
data_list = []
for idx, (y_name, (start_date, end_date)) in enumerate(y_values.items()):
if start_date and end_date and y_name:
color_with_opacity = hex_to_rgba(colors[idx], opacity)
border_color_with_opacity = hex_to_rgba(colors[idx], border_opacity)
data_list.append({
'Variable': y_name,
'Start': datetime.strptime(start_date, '%Y-%m-%d'),
'End': datetime.strptime(end_date, '%Y-%m-%d'),
'Category': '' if superposed else y_name, # Cambiar categoría dependiendo de la opción seleccionada
'Color': color_with_opacity, # Asignar color a cada variable con opacidad
'Border Width': border_width,
'Border Color': border_color_with_opacity, # Asignar color del borde con opacidad
'Custom Hover': f'{y_name} ({start_date} - {end_date})' # Texto personalizado para el hover
})
data = pd.DataFrame(data_list)
# Ajustar fechas para simular apilamiento si está activado
if superposed:
offset = timedelta(days=1) # Ajusta el offset según el tamaño de la columna seleccionado
for i in range(1, len(data)):
data.loc[i, 'Start'] = data.loc[i-1, 'End']
data.loc[i, 'End'] = data.loc[i, 'Start'] + (data.loc[i, 'End'] - data.loc[i, 'Start'])
data['Category'] = ' ' # Usar una cadena vacía para ocultar el texto "Superpuestas"
# Crear gráfico de franjas de tiempo
fig = px.timeline(data, x_start="Start", x_end="End", y="Category", color="Variable", title=chart_title,
hover_data={'Variable': False, 'Start': False, 'End': False, 'Category': False, 'Custom Hover': True})
# Actualizar los colores y estilos de las franjas
for idx, row in data.iterrows():
fig.data[idx].update(marker_color=row['Color'])
fig.data[idx].update(marker_line=dict(width=row['Border Width'], color=row['Border Color']))
fig.data[idx].update(hovertemplate=row['Custom Hover']) # Usar el texto personalizado para el hover
# Ajustar el ancho de las barras si están superpuestas
if superposed:
fig.update_traces(marker=dict(line_width=bar_width * 5)) # Ajusta el ancho de la barra en modo superpuesto
# Personalizar el formato de tiempo en el eje X
if time_format == "Año":
tickformat = "%Y"
dtick = "M12" # Intervalo de 1 año
else: # "Mes y Año"
tickformat = "%b %Y"
dtick = "M1" # Intervalo de 1 mes
# Configuración de líneas de rejilla
grid_style = dict(showgrid=show_grid)
fig.update_layout(
xaxis_title=x_axis_label,
yaxis_title=y_axis_label,
xaxis=dict(
tickformat=tickformat,
dtick=dtick,
titlefont=dict(size=14),
tickfont=dict(size=12),
**grid_style
),
yaxis=dict(
titlefont=dict(size=14),
tickfont=dict(size=12),
**grid_style
),
width=800,
height=600,
margin=dict(l=60, r=40, t=100, b=40),
bargap=1-bar_width, # Controlar el ancho de la barra con el bargap
font=dict(family="Times New Roman", size=18, color="#374151"), # Configuración de la fuente y color
title=dict(
text=chart_title,
x=0.5,
y=0.95,
xanchor='center',
yanchor='top',
font=dict(
family="Times New Roman",
size=18,
color="#374151",
weight="normal"
)
),
legend_title_text='' # Eliminar el texto del título de la leyenda
)
# Mostrar el gráfico
st.plotly_chart(fig)
# Información adicional
st.write("")