I am trying to make a simple animation for a stochastic process (just black and white dots randomly changing their colors). To simulate that, I have basically plotted the dots over a grid. However, the important parameter for me being the rate of black dots, I'd like to draw under this grid a progressive bar showing the rate #blackdots/#totaldots looking approximately like this : [///////////////////////_____] 70% (simply just like a power charge bar).
I tried this but the bars are overlaid, and I don't think that Slider is meant to do such animations.
import numpy as np
import matplotlib.pyplot as plt
import random
from matplotlib.widgets import Slider
t=1500
d=5
n=10
raws = [i for i in range(n)]
config = [[2*random.randrange(2)-1 for i in range(n)] for i in range(n)]
def color(op):
if op == 1:
return 'white'
return 'black'
nbblack = 0
for i in config:
for j in i :
nbblack += (j==-1)
blackrate = nbblack/(n**2)
plt.subplots_adjust(bottom=0.25)
for line in range(n):
colors = [color(config[line][raw]) for raw in raws]
plt.scatter([line]*n,raws,c=colors,edgecolors='black',s=50)
plt.title('t=0',fontdict={'size': 16},x=-0.20,y=25)
samp = Slider(axamp, 'Rate', 0, 1, valinit=blackrate,color='black')
for step in range(t):
plt.pause(0.001)
xpick = random.randrange(n)
ypick = random.randrange(n)
opinion_picked = config[xpick][ypick]
for j in range(d) :
neighboor = random.randrange(n),random.randrange(n)
opinion_neig = config[neighboor[0]][neighboor[1]]
if opinion_neig == opinion_picked :
break
elif j == d-1 :
config[xpick][ypick]=-config[xpick][ypick]
nbblack-=config[xpick][ypick]
blackrate = nbblack/(n**2)
plt.title('t={}'.format(step),fontdict={'size': 16},x=-0.20,y=25)
for line in range(n):
colors = [color(config[line][raw]) for raw in raws]
plt.scatter([line]*n,raws,c=colors,edgecolors='black',s=50)
axamp = plt.axes([0.28, 0.15, 0.48, 0.03])
samp = Slider(axamp, 'Rate', 0, 1, valinit=blackrate,color='black')
plt.show()
I am not very familiar with maplot so please let me know if there is a better way to do things and thanks a lot for your help !
I don't think that Slider is meant to do such animations ... please let me know if there is a better way to do things ...
Maybe using a custom colorbar would work. I adapted from the Discrete Intervals colorbar example.
The following uses the percentage of black dots to decide which portion of the color bar should be black or white.
Here is an example without animation: five successive plots drawn by a loop. I tried to keep it as close to your example as possible.
import matplotlib as mpl
from matplotlib import pyplot as plt
import random
t = 1500
d = 5
n = 10
raws = [i for i in range(n)]
def f(t=t, d=d, n=n, raws=raws):
# try to get more skew in the data
mode = random.random()
config = [[random.triangular(mode=mode) > 0.5 for i in range(n)] for i in range(n)]
config = [[int(item) or -1 for item in row] for row in config]
# config = [[2*random.randrange(2)-1 for i in range(n)] for i in range(n)]
def color(op):
if op == 1:
return "white"
return "black"
nbblack = 0
for i in config:
for j in i:
nbblack += j == -1
blackrate = nbblack / (n ** 2)
fig, ax = plt.subplots()
fig.subplots_adjust(bottom=0.25)
# plt.subplots_adjust(bottom=0.25)
for line in range(n):
colors = [color(config[line][raw]) for raw in raws]
plt.scatter([line] * n, raws, c=colors, edgecolors="black", s=50)
plt.title("t=0", fontdict={"size": 16}, x=-0.20, y=25)
cmap = mpl.colors.ListedColormap(["black", "white"])
bounds = [0, int(blackrate * 100), 100]
norm = mpl.colors.BoundaryNorm(bounds, cmap.N)
fig.colorbar(
mpl.cm.ScalarMappable(cmap=cmap, norm=norm),
# cax=ax,
# boundaries=[0] + bounds + [13], # Adding values for extensions.
# extend='both',
ticks=bounds,
spacing="proportional",
orientation="horizontal",
label="Percentage Black",
)
plt.show()
plt.close()
for _ in range(5):
f()
BoundaryNorm determines how the colors are distributed. The example uses two colors, black/white, and defines two bins between 0 and 100 using the percentage of black dots for the bin edge.
The spacing="proportional"
argument to Figure.colorbar ensures the black/white area is proportional to the bins.
The Matplotlib Tutorials are worth investing time in.