File size: 10,653 Bytes
3673dd2 714173e ab48cc8 d7dbf46 e1489da d7dbf46 3673dd2 e00bb68 8334d77 e00bb68 8b89324 7990606 8b89324 56a6c9f a0ce4b4 8334d77 a0ce4b4 3673dd2 7202737 3673dd2 0c855e3 d7dbf46 568549b 144a23b 2fbd308 fbed860 f92e2b1 db67b39 f92e2b1 db67b39 f92e2b1 d7dbf46 f92e2b1 d7dbf46 f92e2b1 1e48da9 d7dbf46 f92e2b1 1e48da9 ec86661 f92e2b1 db67b39 d7dbf46 f92e2b1 d7dbf46 f92e2b1 ebc180d f92e2b1 e1489da d7dbf46 f92e2b1 d7dbf46 f92e2b1 d6dece7 d7dbf46 d6dece7 d7dbf46 d6dece7 d7dbf46 d6dece7 175c721 d6dece7 d7dbf46 d6dece7 175c721 d6dece7 d7dbf46 d6dece7 d7dbf46 d6dece7 d7dbf46 175c721 d6dece7 ec86661 d6dece7 ec86661 d7dbf46 d6dece7 175c721 d6dece7 175c721 d6dece7 175c721 d6dece7 d7dbf46 d6dece7 d7dbf46 3673dd2 d6dece7 d7dbf46 d6dece7 d7dbf46 d6dece7 c4c88ca d6dece7 d7dbf46 5ca2a0d 3673dd2 d7dbf46 |
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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 |
import streamlit as st
import plotly.express as px
import pandas as pd
import numpy as np # Asegúrate de importar numpy
from datetime import datetime
import plotly.io as pio
import io
# Configuración de la página
st.set_page_config(page_title="Generador de Gráficos Personalizado", 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", "Generador de Gráfico")
# Tipo de gráfico
chart_type = st.sidebar.selectbox("Tipo de Gráfico", ["Línea", "Área", "Dispersión", "Barras", "Donut"])
# Ingresar valores para los ejes
x_values = st.sidebar.text_area("Valores para X (separados por comas)", "2013,2014,2015,2016,2017,2018")
x = x_values.split(",")
# Selector de número de variables Y
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")
y_values_list = []
y_names_list = []
for i in range(num_y_vars):
if f"y_values_{i}" not in st.session_state:
st.session_state[f"y_values_{i}"] = ','.join([str(np.random.randint(1, 25)) for _ in x])
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}")
y_name = st.sidebar.text_input(f"Nombre de la Variable Y-{i+1}", f"Variable Y-{i+1}", key=f"y_name_{i}")
y_values_list.append(y_values)
y_names_list.append(y_name)
# Etiquetas personalizadas para los ejes
x_label = st.sidebar.text_input("Etiqueta para el eje X", "X")
y_label = st.sidebar.text_input("Etiqueta para el eje Y", "Y")
# Desplegable de opciones adicionales
with st.sidebar.expander("Opciones Adicionales"):
graph_width = st.slider("Ancho del Gráfico", min_value=400, max_value=1200, value=1000, step=50)
graph_height = st.slider("Alto del Gráfico", min_value=300, max_value=900, value=700, step=50)
font_family = st.selectbox("Fuente del Gráfico", font_options, index=font_options.index("Times New Roman"))
axis_font_size = st.slider("Tamaño de la Fuente de los Ejes", min_value=10, max_value=30, value=24, step=1)
tick_font_size = st.slider("Tamaño de los Números de los Ejes", min_value=8, max_value=24, value=19, step=1)
show_legend = st.checkbox("Mostrar Leyenda", value=True)
# Configuración de la leyenda
legend_font_family = st.selectbox("Fuente de la Leyenda", font_options, index=font_options.index("Arial"))
legend_font_size = st.slider("Tamaño de la Fuente de la Leyenda", min_value=10, max_value=30, value=22, step=1)
opacity = st.slider("Opacidad (%)", min_value=0, max_value=100, value=30, step=1) / 100
border_width = st.slider("Grosor del Borde", min_value=0.0, max_value=3.0, value=1.5, step=0.1)
border_opacity = st.slider("Opacidad del Borde (%)", min_value=0, max_value=100, value=60, step=1) / 100
show_grid = st.checkbox("Activar rejilla", value=True)
if chart_type == "Barras" and num_y_vars > 1:
superposed_bars = st.checkbox("Superpuestas", value=True, key="superposed_bars")
else:
superposed_bars = False
if chart_type == "Barras":
horizontal_bars = st.checkbox("Invertidas", key="horizontal_bars")
if chart_type == "Donut":
hole_size = st.slider("Tamaño del agujero (%)", min_value=0, max_value=100, value=30, step=1) / 100
show_values = st.checkbox("Mostrar valores en el gráfico", value=False)
# Opción para múltiples colores (siempre activada para Donut)
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")
# Seleccionar color(es) para el gráfico
selected_color = st.sidebar.color_picker("Color", "#24CBA0", key="single_color")
# Definir colores
if use_multiple_colors:
num_colors = len(x)
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)]
else:
color = hex_to_rgba(selected_color, alpha=opacity)
colors = [color] * len(x)
# Procesar valores
y_values_lists = [[float(i) for i in y_values.split(",") if i.strip()] for y_values in y_values_list]
# Asegurar que todas las listas de Y tengan el mismo tamaño que X
for y_values in y_values_lists:
while len(y_values) < len(x):
y_values.append(0)
while len(y_values) > len(x):
y_values.pop()
# Crear un DataFrame
data = pd.DataFrame({"X": x})
for idx, y_set in enumerate(y_values_lists):
data[y_names_list[idx]] = y_set
# Configuración común para todos los gráficos
common_layout = dict(
xaxis_title=x_label,
yaxis_title=y_label,
plot_bgcolor="white",
hovermode="x unified",
width=graph_width,
height=graph_height,
margin=dict(l=80, r=40, t=100, b=60), # Ajustar los márgenes para separar el texto de los ejes
xaxis=dict(showgrid=show_grid, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True,
tickfont=dict(size=tick_font_size), title_font=dict(size=axis_font_size)),
yaxis=dict(showgrid=show_grid, zeroline=True, gridcolor='rgba(211,211,211,0.5)', zerolinecolor='rgba(128,128,128,0.5)', autorange=True,
tickfont=dict(size=tick_font_size), title_font=dict(size=axis_font_size)),
font=dict(family=font_family, size=axis_font_size, color="#374151"),
showlegend=show_legend,
legend=dict(
orientation="v",
yanchor="top",
y=1,
xanchor="left",
x=1.02,
font=dict(family=legend_font_family, size=legend_font_size)
)
)
# Generar el gráfico basado en el tipo seleccionado
if chart_type == "Línea":
fig = px.line(data, x="X", y=y_names_list, line_shape="spline")
fig.update_traces(hovertemplate='<b>%{y}</b>', line=dict(width=border_width)) # Aplicar el grosor del borde a línea
if use_multiple_colors:
for i, name in enumerate(y_names_list):
fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)])
else:
fig.update_traces(line_color=color)
elif chart_type == "Área":
fig = px.area(data, x="X", y=y_names_list, line_shape="spline")
fig.update_traces(hovertemplate='<b>%{y}</b>', line=dict(width=border_width), fillcolor=color)
if use_multiple_colors:
for i, name in enumerate(y_names_list):
fig.update_traces(selector=dict(name=name), line_color=colors[i % len(colors)], fillcolor=colors[i % len(colors)])
else:
fig.update_traces(line_color=color, fillcolor=color)
elif chart_type == "Dispersión":
fig = px.scatter(data, x="X", y=y_names_list)
fig.update_traces(hovertemplate='<b>%{y}</b>', marker=dict(size=10, line=dict(width=border_width, color=hex_to_rgba('#000000', border_opacity))))
if use_multiple_colors:
for i, name in enumerate(y_names_list):
fig.update_traces(selector=dict(name=name), marker_color=colors[i % len(colors)], marker_line_color=colors[i % len(colors)])
else:
fig.update_traces(marker_color=color, marker_line_color=color)
elif chart_type == "Barras":
if horizontal_bars:
fig = px.bar(data, x=y_names_list, y="X", orientation='h', barmode='overlay' if superposed_bars else 'group')
else:
fig = px.bar(data, x="X", y=y_names_list, barmode='overlay' if superposed_bars else 'group')
fig.update_traces(hovertemplate='<b>%{y}</b>', marker=dict(line=dict(width=border_width, color=hex_to_rgba('#000000', border_opacity))))
if use_multiple_colors:
for i, trace in enumerate(fig.data):
trace.update(marker_color=colors[i % len(colors)])
else:
fig.update_traces(marker_color=color)
fig.update_layout(bargap=0.2)
elif chart_type == "Donut":
# Generar solo un gráfico Donut y asegurarse de que no haya duplicados
fig = px.pie(data, values=y_values_lists[0], names="X", hole=hole_size, color_discrete_sequence=colors[:len(x)])
if show_values:
fig.update_traces(hovertemplate='<b>%{label}</b>: %{value} (%{percent})', textinfo='percent+label')
else:
fig.update_traces(hovertemplate='<b>%{label}</b>', textinfo='none') # Ocultar valores y etiquetas
fig.update_traces(marker=dict(colors=colors[:len(x)])) # Aplicar múltiples colores
fig.update_layout(
title=dict(
text=f"{chart_title}",
x=0.5,
y=0.95,
xanchor='center',
yanchor='top',
font=dict(
family=font_family,
size=axis_font_size,
color="#374151"
)
),
**common_layout
)
st.plotly_chart(fig)
# Añadir anotación para el título
if chart_type != "Donut":
fig.update_layout(
title=dict(
text=f"{chart_title}",
x=0.5,
y=0.95,
xanchor='center',
yanchor='top',
font=dict(
family=font_family,
size=axis_font_size,
color="#374151"
)
),
legend_title_text='' # Eliminar el texto del título de la leyenda
)
# Aplicar configuración común
fig.update_layout(**common_layout)
# Aplicar múltiples colores si se seleccionó la opción
if use_multiple_colors and chart_type != "Donut":
for i, trace in enumerate(fig.data):
trace.update(marker_color=colors[i % len(colors)])
# Mostrar el gráfico
st.plotly_chart(fig)
# Descargar gráfico con mayor resolución usando los valores personalizados
export_as_png = st.button("Descargar gráfico en alta calidad")
if export_as_png:
img_bytes = pio.to_image(fig, format="png", width=graph_width, height=graph_height, scale=6)
st.download_button(label="Descargar imagen", data=img_bytes, file_name="grafico_personalizado.png", mime="image/png")
# Forzar el autoescale
fig.update_layout(xaxis_autorange=True, yaxis_autorange=True)
# Información adicional
st.write("") |