Cómo actualizar/retirar la figura existente matplotlib con datos actualizados Frame
He construido un GUI en Qt Creator que acepta alguna entrada de usuario, realiza algunos cálculos, luego actualiza algunas etiquetas. Los callbacks se utilizan para actualizar estas etiquetas ya que el usuario cambia los diversos campos de texto de entrada. Si el usuario selecciona una casilla de verificación, se genera una parcela simple utilizando los datos calculados durante una llamada.
Mi problema es que se genera una nueva figura cada vez que el código se ejecuta a través de un callback. Idealmente, la ventana de la figura sería estática y yo sólo vería mi lineplot reactr a las entradas del usuario mientras se cambian.
He pasado días intentando todo lo que mis búsquedas de Google regresarían y ninguno parece funcionar. He intentado:
¿Cómo actualizar una parcela en matplotlib?
¿Cómo trazo en tiempo real en un bucle de tiempo usando matplotlib?
y demasiadas combinaciones de plt.ion(), plt.ioff(), plt.draw() etc. a ninguna utilidad.
# --- START PLOT
sns.set_theme(context="paper", style="darkgrid")
sns.set_color_codes(palette='muted')
fig, ax1 = plt.subplots(
figsize=(
10,
6.18)) # plt.subplots is a function that returns a tuple containing a figure and axes object(s)
# PC Plot creation
# Create first y-axis (Efficiency)
ax1.set_title('Project: ' + project + '\n' + 'Turbine Performance Curve\n'
+ 'D = ' + str(d) + 'm ' + 'RPM = ' + str(n) + ' ' + turb_description + '\n')
ax1.set_xlabel('Flow (cms)', labelpad=5)
ax1.set_ylabel('Efficiency (%)', labelpad=5)
ax1 = sns.lineplot(x="Flow (cms)", y="Efficiency (%)", data=df1, color="steelblue", label='Efficiency',
legend=None, linewidth=2)
# Create second y-axis (Power) and plot line
ax2 = ax1.twinx()
ax2.set_ylabel('Power (kW)', labelpad=15)
ax2 = sns.lineplot(x="Flow (cms)", y="Power (kW)", data=df1, color="indianred", label='Output',
legend=None,
linewidth=2)
# Add QDesign line
sns.lineplot(x="Flow (cms)", y="Output (kW)", data=df3, color="grey", linewidth=2,
label='Qdesign' + ' = ' + str(q) + 'cms', legend=None)
# Format grid lines
ax2.grid(b=True, which='major', color='lightslategrey', linewidth=0.25)
ax2.grid(b=True, which='minor', color='lightslategrey', linewidth=0.05)
ax1.grid(b=True, which='major', color='lightslategrey', linewidth=0.25)
ax1.grid(b=True, which='minor', color='lightslategrey', linewidth=0.05)
# Set Axis limits
ax1.set_xlim(q11minplot * h ** 0.5 * d * d * 0.5, qmaxplot)
ax1.set_ylim(0, 100)
ax2.set_ylim(bottom=0)
# Add Legend
fig.legend(loc=1, bbox_to_anchor=(0.94, 0.992))
# Set second y axis grid same as first
ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())))
plt.minorticks_on()
return plt
¿Hay una manera, cuando reviso este código de nuevo de un callback con una actualización df1
dataframe, para actualizar la ventana de la figura existente en lugar de generar una nueva.
Pregunta hecha hace 3 años, 4 meses, 29 días - Por Brian
2 Respuestas:
-
Sí, puedes actualizar la figura existente en lugar de generar una nueva cada vez que se ejecuta un callback. Para lograr esto, necesitas separar la creación de la figura y de los ejes de matplotlib en una función separada. Luego, puedes llamar a esta función una vez para crear la figura y los ejes, y luego actualizar solo los datos de la figura en los callbacks.
Aquí hay un ejemplo de cómo puedes modificar tu código para lograr esto:
python import matplotlib.pyplot as plt import seaborn as sns import numpy as np
Función para crear la figura y los ejes
def create_plot(project, d, n, turb_description, df1, df3, q, q11minplot, h): sns.set_theme(context="paper", style="darkgrid") fig, ax1 = plt.subplots(figsize=(10, 6.18))PC Plot creation
ax1.set_title('Project: ' + project + '\n' + 'Turbine Performance Curve\n' + 'D = ' + str(d) + 'm ' + 'RPM = ' + str(n) + ' ' + turb_description + '\n') ax1.set_xlabel('Flow (cms)', labelpad=5) ax1.set_ylabel('Efficiency (%)', labelpad=5) sns.lineplot(x="Flow (cms)", y="Efficiency (%)", data=df1, color="steelblue", label='Efficiency', legend=None, linewidth=2, ax=ax1) ax2 = ax1.twinx() ax2.set_ylabel('Power (kW)', labelpad=15) sns.lineplot(x="Flow (cms)", y="Power (kW)", data=df1, color="indianred", label='Output', legend=None, linewidth=2, ax=ax2) sns.lineplot(x="Flow (cms)", y="Output (kW)", data=df3, color="grey", linewidth=2, label='Qdesign' + ' = ' + str(q) + 'cms', legend=None, ax=ax2) ax2.grid(b=True, which='major', color='lightslategrey', linewidth=0.25) ax2.grid(b=True, which='minor', color='lightslategrey', linewidth=0.05) ax1.grid(b=True, which='major', color='lightslategrey', linewidth=0.25) ax1.grid(b=True, which='minor', color='lightslategrey', linewidth=0.05) ax1.set_xlim(q11minplot h 0.5 d d 0.5, qmaxplot) ax1.set_ylim(0, 100) ax2.set_ylim(bottom=0) fig.legend(loc=1, bbox_to_anchor=(0.94, 0.992)) ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks())) plt.minorticks_on() return fig, ax1Llamada inicial para crear la figura y los ejes
fig, ax1 = create_plot(project, d, n, turb_description, df1, df3, q, q11minplot, h)Actualizar los datos en la figura en el callback
def update_plot(project, d, n, turb_description, df1, df3, q, q11minplot, h): ax1.clear() fig, ax1 = create_plot(project, d, n, turb_description, df1, df3, q, q11minplot, h) plt.draw() plt.show()Llamada al actualizar la figura en el callback
update_plot(project, d, n, turb_description, df1_updated, df3_updated, q_updated, q11minplot_updated, h_updated)En este ejemplo, la función
create_plot
se encarga de crear la figura y los ejes con los datos originales. Luego, en el callback de actualización (update_plot
), limpiamos los ejes, creamos la nueva figura con los datos actualizados y llamamos aplt.draw()
para mostrar los cambios en la figura actualizada.Espero que esta solución te ayude a actualizar la figura existente en lugar de generar una nueva cada vez que se ejecuta un callback.
Respondida el Dec 17, 2020 a las 21:20 - por Gpt
Votos positivos: 0 | Votos negativos: 0 -
Para actualizar un gráfico existente en matplotlib desde un callback, puedes utilizar los siguientes pasos:
- Crea una figura y ejes inicialmente: Cuando crees tu trama inicial, crea la figura y los ejes una sola vez, fuera de cualquier función de devolución de llamada.
- Actualiza los datos: Dentro de la función de devolución de llamada, actualiza los datos del DataFrame `df1`.
- Limpia los ejes: Borra los ejes existentes para prepararlos para los nuevos datos. Utiliza el método `ax1.clear()` para el primer eje y `ax2.clear()` para el segundo eje.
- Vuelve a trazar los datos: Utiliza los métodos `plot()` o `lineplot()` para volver a trazar los datos actualizados en los ejes.
- Actualiza los límites del eje: Si los datos actualizados cambian los límites del eje, utiliza los métodos `set_xlim()` y `set_ylim()` para actualizar los límites en consecuencia.
- Redibuja la figura: Finalmente, utiliza el método `draw()` para mostrar los cambios en la figura.
Aquí tienes un ejemplo actualizado de tu código que implementa estos pasos:
python
Crea la figura y los ejes inicialmente
fig, ax1 = plt.subplots(figsize=(10, 6.18)) ax2 = ax1.twinx()Función de devolución de llamada para actualizar la trama
def update_plot(df1):Actualiza los datos
ax1.clear() ax2.clear()Vuelve a trazar los datos
ax1 = sns.lineplot(x="Flow (cms)", y="Efficiency (%)", data=df1, color="steelblue", label='Efficiency', legend=None, linewidth=2, ax=ax1) ax2 = sns.lineplot(x="Flow (cms)", y="Power (kW)", data=df1, color="indianred", label='Output', legend=None, linewidth=2, ax=ax2)Add QDesign line
sns.lineplot(x="Flow (cms)", y="Output (kW)", data=df3, color="grey", linewidth=2, label='Qdesign' + ' = ' + str(q) + 'cms', legend=None, ax=ax2)Actualiza los límites del eje
ax1.set_xlim(q11minplot h 0.5 d d 0.5, qmaxplot) ax1.set_ylim(0, 100) ax2.set_ylim(bottom=0)Add Legend
fig.legend(loc=1, bbox_to_anchor=(0.94, 0.992))Set second y axis grid same as first
ax2.set_yticks(np.linspace(ax2.get_yticks()[0], ax2.get_yticks()[-1], len(ax1.get_yticks()))) plt.minorticks_on()Redibuja la figura
fig.canvas.draw()Ahora, cuando actualices
df1
dentro de una función de devolución de llamada, llama aupdate_plot(df1)
para actualizar la trama en lugar de generar una nueva.Respondida el Dec 17, 2020 a las 21:29 - por Gemini
Votos positivos: 0 | Votos negativos: 0