使用Canvas模拟伊辛模型时动态图像无法显示的技术求助
Hey Louise, let's work through the issues in your code step by step—there are a few bugs in the class implementation and plotting logic that are causing your dynamic visualization to fail, plus syntax errors breaking the Ising model behavior.
These issues are preventing your model from working correctly, which indirectly breaks the plotting too.
a. __init__ Method Shape Error
In your Ising constructor, np.ones(N,N) is invalid—np.ones expects a tuple for the shape. Also, you should use the passed nx/ny parameters instead of hardcoding N to keep the class flexible:
def __init__(self, nx, ny, random=False): if random: self._lattice = np.random.choice([-1, 1], size=(nx, ny)) else: self._lattice = np.ones((nx, ny)) # Fixed shape tuple
b. Broken flipspin Method
You used equality checks (==) instead of assignment (=) here—this means spins never actually flip! A simpler way to toggle between 1 and -1 is:
def flipspin(self, x, y): self._lattice[x, y] *= -1
c. nearestneighbours Method Fixes
- Your class doesn't have a
shape()method—access the lattice's shape directly withself._lattice.shape. - Periodic boundary conditions are cleaner with modulo arithmetic (no messy conditionals):
def nearestneighbours(self, x, y): nx, ny = self._lattice.shape # Auto-wrap boundaries using modulo return [ ((x + 1) % nx, y), ((x - 1) % nx, y), (x, (y + 1) % ny), (x, (y - 1) % ny) ]
d. Incorrect Hamiltonianenergy Function
Your function was passing wrong parameters to nearestneighbours and not summing neighbor spins properly. Here's the corrected version to calculate the energy change for a spin flip:
def Hamiltonianenergy(lattice, x, y): # Sum the spins of all nearest neighbors neighbor_spins = sum(lattice._lattice[coord] for coord in lattice.nearestneighbours(x, y)) # Energy change for flipping spin (x,y) (J=1) return 2 * lattice._lattice[x, y] * neighbor_spins
Your plotting logic had multiple issues preventing updates:
- You passed the
Isingclass instance toplt.imshow()instead of the actual lattice array (lattice._lattice). - Calling
plt.show()inside the loop creates a new window every time—initialize the plot once and update its data instead.
Here's the corrected metropolis function:
def metropolis(temperature, sweeps, nx, ny): beta = 1 / temperature # Initialize Ising lattice lattice = Ising(nx, ny, random=True) # Set up the plot once fig, ax = plt.subplots() im = ax.imshow(lattice._lattice, cmap='viridis', vmin=-1, vmax=1) plt.colorbar(im) plt.show(block=False) # Keep the window open for updates energycount = [] energies = 0 # Track total energy (initialize properly if needed) for t in range(sweeps): i = np.random.randint(nx) j = np.random.randint(ny) dH = Hamiltonianenergy(lattice, i, j) # Metropolis acceptance rule if dH <= 0 or np.random.uniform() < np.exp(-beta * dH): lattice.flipspin(i, j) energies += dH energycount.append(energies) # Update the plot data im.set_data(lattice._lattice) fig.canvas.draw() fig.canvas.flush_events() # Force the plot to update plt.pause(0.01) print(f"Iteration: {t}, Total Energy: {energies}") plt.close(fig) return energycount
- Removed the redundant
lattice = Ising(...)line insidemetropolis(you were overwriting the input parameter unnecessarily). - Fixed the spin flip call from
lattice.flip(i,j)tolattice.flipspin(i,j)to match the method name. - Removed unused variables like
switchandres, and the unnecessaryt +=1(the loop already incrementstviarange(sweeps)).
Call the function with your parameters to see the dynamic plot:
if __name__ == "__main__": T = 1.0 N = 5 sweeps = 50 energy_history = metropolis(T, sweeps, N, N)
The "local variable image is assigned to but never used" warning doesn't appear in the code you shared, but if you had an unused image variable elsewhere, just remove it to resolve the warning.
After these fixes, the dynamic plot should update with each sweep, showing your Ising lattice evolving over time.
内容的提问来源于stack exchange,提问作者Louise

