问题
I try to create a plotting script that plots my data in two 3d structures (with one variable as a color) that I use in a loop in which the data is supposed to converge. I would like to update the figure every iteration, instead of creating a new figure. Any ideas on how I can achieve this?
function:
import matplotlib.pyplot as plt
import numpy as np
def colorplot_3D(network, color_variable_1, color_variable_2):
net = network
X, Y, Z = net['pore.coords'][net.Ps].T
X_max, Y_max, Z_max = np.amax(X), np.amax(Y), np.amax(Z)
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(211, projection='3d')
plot_1 = ax.scatter(xs=X, ys=Y, zs=Z, c=color_variable_1)
plt.xlabel('x-position')
plt.ylabel('y-position')
cbar_1 = fig.colorbar(plot_1)
ax.text(X_max / 2, 0, Z_max * 1.2, 'membrane')
ax.text(X_max / 2, Y_max, Z_max * 1.2, 'current collector')
ax.text(-0.2 * X_max, Y_max / 2, Z_max * 1.2, 'flow inlet')
ax.text(1.3 * X_max, Y_max / 2, Z_max * 1.2, 'flow outlet')
cbar_1.ax.set_ylabel('pore concentration [mol/m3]')
ax2 = fig.add_subplot(212, projection='3d')
plot_2 = ax2.scatter(xs=X, ys=Y, zs=Z, c=color_variable_2)
cbar_2 = fig.colorbar(plot_2)
cbar_2.ax.set_ylabel('liquid potential [V]')
ax2.text(X_max / 2, 0, Z_max * 1.2, 'membrane')
ax2.text(X_max / 2, Y_max, Z_max * 1.2, 'current collector')
ax2.text(-0.2 * X_max, Y_max / 2, Z_max * 1.2, 'flow inlet')
ax2.text(1.3 * X_max, Y_max / 2, Z_max * 1.2, 'flow outlet')
plt.draw()
return fig
回答1:
Two ways you could do this would be
- Use a combination of
set_offsets()
andset_3d_properties
- Clear the
figure
and/oraxes
object(s) and plot a newscatter
every iteration
Example using set_offsets()
and set_3d_properties
:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np
x = np.linspace(0, np.pi*2, 25)
y = np.sin(x)
z = np.cos(x)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
def plot(ax):
return ax.scatter(x, y, z)
def update(s):
s.set_offsets(np.stack([x, y], 1))
s.set_3d_properties(z, 'z')
s = plot(ax)
plt.savefig("./before.png")
y = np.cos(x)
z = np.sin(x)
update(s)
plt.savefig("./after.png")
Example clearing and redrawing:
def plot(fig, ax):
ax.scatter(x, y, z)
plot(fig, ax)
plt.savefig("./before.png")
y = np.cos(x)
z = np.sin(x)
plt.cla()
plot(fig, ax)
plt.savefig("./after.png")
Or, if you want to accumulate the data from every iteration in the same scatter plot, you can just append the new data points to the x
, y
, and z
objects and use one of the above methods.
Example with accumulation:
def plot(ax):
return ax.scatter(x, y, z)
def update(s):
s.set_offsets(np.stack([x, y], 1))
s.set_3d_properties(z, 'z')
s = plot(ax)
plt.savefig("./before.png")
x = np.vstack([x,x])
y = np.vstack([y, np.cos(x)])
z = np.vstack([z, np.sin(x)])
update(s)
plt.savefig("./after.png")
I would recommend the combination of set_offsets()
and set_3d_properties()
. See this answer for more about scoping the figure
and axes
objects.
来源:https://stackoverflow.com/questions/59074143/updating-a-3d-python-plot-during-a-convergence-iteration