Hello All and Merry Christmas,
Could someone please explain me how the following sample of code works (http://matplotlib.sourceforge.net/examples/animation/random_data.html) ?
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
timeline = [1,2,3,4,5,6,7,8,9,10] ;
metric = [10,20,30,40,50,60,70,80,90,100] ;
fig = plt.figure()
window = fig.add_subplot(111)
line, = window.plot(np.random.rand(10))
def update(data):
line.set_ydata(data)
return line,
def data_gen():
while True:
yield np.random.rand(10)
ani = animation.FuncAnimation(fig, update, data_gen, interval=5*1000)
plt.show()
In particular, I would like to use lists ("metric") in order to update the list.
Th problem is that FuncAnimation is using generators if I am not mistaken, but, how can I make it work ?
Thank you.
You can feed FuncAnimation with any iterable not just a generator.
From docs:
class matplotlib.animation.FuncAnimation(fig, func, frames=None,
init_func=None, fargs=None, save_count=None, **kwargs)
Makes an animation by repeatedly calling a function func, passing in
(optional) arguments in fargs. frames can be a generator, an iterable,
or a number of frames. init_func is a function used to draw a clear
frame. If not given, the results of drawing from the first item in the
frames sequence will be used.
Thus the equivalen code with lists could be:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
start = [1, 0.18, 0.63, 0.29, 0.03, 0.24, 0.86, 0.07, 0.58, 0]
metric =[[0.03, 0.86, 0.65, 0.34, 0.34, 0.02, 0.22, 0.74, 0.66, 0.65],
[0.43, 0.18, 0.63, 0.29, 0.03, 0.24, 0.86, 0.07, 0.58, 0.55],
[0.66, 0.75, 0.01, 0.94, 0.72, 0.77, 0.20, 0.66, 0.81, 0.52]
]
fig = plt.figure()
window = fig.add_subplot(111)
line, = window.plot(start)
def update(data):
line.set_ydata(data)
return line,
ani = animation.FuncAnimation(fig, update, metric, interval=2*1000)
plt.show()
Related
I have a Seaborn displot with a hued variable:
For each hued variable, I want to extract the mode of the density estimate and then plot each hue variable versus its mode, like so:
How do I do this?
You can use scipy.stats.gaussian_kde to create the density estimation function. And then call that function on an array of x-values to calculate its maximum.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
df = pd.DataFrame({'x': np.random.normal(0.001, 1, 1300).cumsum() + 30,
'hue': np.repeat(np.arange(0.08, 0.20001, 0.01), 100).round(2)})
g = sns.displot(df, x='x', hue='hue', palette='turbo', kind='kde', fill=True, height=6, aspect=1.5)
plt.show()
from scipy.stats import gaussian_kde
from matplotlib.cm import ScalarMappable
fig, ax = plt.subplots(figsize=(10, 6))
hues = df['hue'].unique()
num_hues = len(hues)
colors = sns.color_palette('turbo', num_hues)
xmin, xmax = df['x'].min(), df['x'].max()
xs = np.linspace(xmin, xmax, 500)
for hue, color in zip(hues, colors):
data = df[df['hue'] == hue]['x'].values
kde = gaussian_kde(data)
mode_index = np.argmax(kde(xs))
mode_x = xs[mode_index]
sns.scatterplot(x=[hue], y=[mode_x], color=color, s=50, ax=ax)
cmap = sns.color_palette('turbo', as_cmap=True)
norm = plt.Normalize(hues.min(), hues.max())
plt.colorbar(ScalarMappable(cmap=cmap, norm=norm), ax=ax, ticks=hues)
plt.show()
Here is another approach, extracting the kde curves. It uses the legend of the kde plot to get the correspondence between the curves and the hue values. sns.kdeplot is the axes-level function used by sns.displot(kind='kde'). fill=False creates lines instead of filled polygons for the curves, for which the values are easier to extract. (ax1.fill_between can fill the curves during a second pass). The x and y axes of the second plot are switched to align the x-axes of both plots.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
df = pd.DataFrame({'x': np.random.normal(0.007, 0.1, 1300).cumsum() + 30,
'hue': np.repeat(np.arange(0.08, 0.20001, 0.01), 100).round(2)})
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(12, 10), sharex=True)
sns.kdeplot(data=df, x='x', hue='hue', palette='turbo', fill=False, ax=ax1)
hues = [float(txt.get_text()) for txt in ax1.legend_.get_texts()]
ax2.set_yticks(hues)
ax2.set_ylabel('hue')
for hue, line in zip(hues, ax1.lines[::-1]):
color = line.get_color()
x = line.get_xdata()
y = line.get_ydata()
ax1.fill_between(x, y, color=color, alpha=0.3)
mode_ind = np.argmax(y)
mode_x = x[mode_ind]
sns.scatterplot(x=[mode_x], y=hue, color=color, s=50, ax=ax2)
sns.despine()
plt.tight_layout()
plt.show()
I´m trying to plot a chart and I have some problems to solve, sorry but I´m new in program language.
First one:
How to plot only one chart? I got that example from the internet and when a plot there is two figure for each code and two of them is blank.
The second one:
Is it possible to plot only a positive error bar?
Third one:
Is it possible to plot these two charts side by side in one figure?
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
Treat1 =pd.DataFrame({'Treatment': 1, 'weight': np.random.randint(low=1, high=100, size=40)})
Treat2 =pd.DataFrame({'Treatment': 2, 'weight': np.random.randint(low=1, high=100, size=40)})
df = pd.concat([Treat1, Treat2])
Treat3 =pd.DataFrame({'Treatment': 1, 'weight': np.random.randint(low=100, high=300, size=40)})
Treat4 =pd.DataFrame({'Treatment': 2, 'weight': np.random.randint(low=100, high=300, size=40)})
df2 = pd.concat([Treat3, Treat4])
sns.set(style="ticks")
fig, ax = plt.subplots()
color_map = dict(pos="indianred", neg="steelblue")
g = sns.catplot(x= "Treatment", y="weight", hue="Treatment", capsize=.07, ci ="sd",
data=df, kind="bar", palette = 'coolwarm', edgecolor="white")
plt.text(-0.22,99, "B")
plt.text(1.18,99, "A")
plt.ylabel('weight, kg')
plt.xticks([-0.2, 1.2], ['Group 1', 'Group 2'])
plt.ylim(0, 100)
color_map = dict(pos="indianred", neg="steelblue")
g = sns.catplot(x= "Treatment", y="weight", hue="Treatment", capsize=.07, ci ="sd",
data=df2, kind="bar", palette = 'coolwarm', edgecolor="white")
plt.text(-0.22,300, "B")
plt.text(1.18,300, "A")
plt.ylabel('weight, kg')
plt.xticks([-0.2, 1.2], ['Group 1', 'Group 2'])
plt.ylim(0, 300)
Thank you so much!
A seaborn catplot is a figure level plot, which creates and occupies a new figure. To have such a plot as a subplot, sns.barplot can be called directly. Supplying an ax tells into which subplot the barplot should go.
The barplot gets a legend, which in this case is superfluous, but it can be removed.
To only have the upper error bar visible, the rectangles of the bars can be plot on top of them. A zorder larger than the zorder of the lines of the errorbar (2) takes care of this.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
Treat1 = pd.DataFrame({'Treatment': 1, 'weight': np.random.randint(low=1, high=100, size=40)})
Treat2 = pd.DataFrame({'Treatment': 2, 'weight': np.random.randint(low=1, high=100, size=40)})
df1 = pd.concat([Treat1, Treat2])
Treat3 = pd.DataFrame({'Treatment': 1, 'weight': np.random.randint(low=100, high=300, size=40)})
Treat4 = pd.DataFrame({'Treatment': 2, 'weight': np.random.randint(low=100, high=300, size=40)})
df2 = pd.concat([Treat3, Treat4])
sns.set(style="ticks")
fig, axs = plt.subplots(ncols=2, figsize=(10, 4))
for ax, df, height in zip(axs, [df1, df2], [100, 300]):
color_map = {1: "indianred", 2: "steelblue"}
g = sns.barplot(x="Treatment", y="weight", hue="Treatment", capsize=.07, ci="sd",
data=df, palette=color_map, edgecolor="white", ax=ax)
g.legend_.remove()
for bar in g.patches:
bar.set_zorder(3)
ax.text(-0.2, height * 0.95, "B", ha='center')
ax.text(1.2, height * 0.95, "A", ha='center')
ax.set_ylabel('weight, kg')
ax.set_xticks([-0.2, 1.2])
ax.set_xticklabels(['Group 1', 'Group 2'])
ax.set_ylim(0, height)
plt.tight_layout()
plt.show()
PS: Note that the code can be simplified somewhat if you don't use hue=. This also puts the bars in a more logical position.
fig, axs = plt.subplots(ncols=2, figsize=(10, 4))
for ax, df, height in zip(axs, [df1, df2], [100, 300]):
color_map = {1: "indianred", 2: "steelblue"}
g = sns.barplot(x="Treatment", y="weight", capsize=.07, ci="sd",
data=df, palette=color_map, edgecolor="white", ax=ax)
for bar in g.patches:
bar.set_zorder(3)
ax.text(0, height * 0.97, "B", ha='center', va='top')
ax.text(1, height * 0.97, "A", ha='center', va='top')
ax.set_ylabel('weight, kg')
ax.set_ylim(0, height)
ax.set_xticklabels(['Group 1', 'Group 2'])
plt.tight_layout()
plt.show()
I am trying use PYMC3 to implement an example where the data comes from a mixture of multinomials. The goal is to infer the underlying state_prob vector (see below). The code runs, but the Metropolis sampler gets stuck at the initial state_prior vector. Also, for some reason I have not been able to get NUTS to work.
import numpy as np
import pandas as pd
from pymc3 import Model, Multinomial, Dirichlet
import pymc3
import theano.tensor as tt
from theano import function, printing
N = 10
state_prior = np.array([.3, .3, .3])
state_prob = np.array([0.3, 0.1, 0.6]) #need to infer this
state_emission_tran = np.array([[0.3, 0.2, 0.5],
[0.1, 0.5, 0.4],
[0.0, 0.05, 0.95]])
state_data = np.random.multinomial(1, state_prob, size=N)
emission_prob_given_state = np.matmul(state_data, state_emission_tran)
def rand_mult(row_p):
return np.random.multinomial(1, row_p)
emission_data = np.apply_along_axis(rand_mult, 1, emission_prob_given_state)
# done with creating data
with Model() as simple_dag:
state = Dirichlet('state', state_prior*100, shape=3)
emission_dist = [pymc3.Multinomial.dist(p=state_emission_tran[i], n=1, shape=3) for i in range(3)]
emission_mix = pymc3.Mixture('emission_mix', w = state, comp_dists = emission_dist, observed=emission_data)
with simple_dag:
step = pymc3.Metropolis(vars=[state])
trace = pymc3.sample(10000, cores=2, chains=2, tune=500, step=step, progressbar=True)
Try this one:
import numpy as np
import pandas as pd
from pymc3 import Model, Multinomial, Dirichlet
import pymc3
import theano.tensor as tt
from theano import function, printing
N = 10
state_prior = np.array([.3, .3, .3])
state_prob = np.array([0.3, 0.1, 0.6]) #need to infer this
state_emission_tran = np.array([[0.3, 0.2, 0.5],
[0.1, 0.5, 0.4],
[0.0, 0.05, 0.95]])
state_data = np.random.multinomial(1, state_prob, size=N)
emission_prob_given_state = np.matmul(state_data, state_emission_tran)
def rand_mult(row_p):
return np.random.multinomial(1, row_p)
emission_data = np.apply_along_axis(rand_mult, 1, emission_prob_given_state)
# done with creating data
with Model() as simple_dag:
state = Dirichlet('state', state_prior*100, shape=3)
emission_dist = [pymc3.Multinomial.dist(p=state_emission_tran[i], n=1, shape=3) for i in range(3)]
emission_mix = pymc3.Mixture('emission_mix', w = state, comp_dists = emission_dist, observed=emission_data)
with simple_dag:
trace = pymc3.sample(3000, tune=1000)
I am using pymc3 version 3.5 in Linux and it works fine.
I'm trying to create a plot in Python where the data that is being plotted gets updated as my simulation progresses. In MATLAB, I could do this with the following code:
t = linspace(0, 1, 100);
figure
for i = 1:100
x = cos(2*pi*i*t);
plot(x)
drawnow
end
I'm trying to use matplotlib's FuncAnimation function in the animation module to do this inside a class. It calls a function plot_voltage which recalculates voltage after each timestep in my simulation. I have it set up as follows:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def __init__(self):
ani = animation.FuncAnimation(plt.figure(2), self.plot_voltage)
plt.draw()
def plot_voltage(self, *args):
voltages = np.zeros(100)
voltages[:] = np.nan
# some code to calculate voltage
ax1 = plt.figure(2).gca()
ax1.clear()
ax1.plot(np.arange(0, len(voltages), 1), voltages, 'ko-')`
When my simulation runs, the figures show up but just freeze. The code runs without error, however. Could someone please let me know what I am missing?
Here is a translation of the matlab code into matplotlib using FuncAnimation:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
t = np.linspace(0, 1, 100)
fig = plt.figure()
line, = plt.plot([],[])
def update(i):
x = np.cos(2*np.pi*i*t)
line.set_data(t,x)
ani = animation.FuncAnimation(fig, update,
frames=np.linspace(1,100,100), interval=100)
plt.xlim(0,1)
plt.ylim(-1,1)
plt.show()
I'm new to python, matplotlib, and animation.
I've not been able to find a clear, detailed description of
animation.FuncAnimation(, , , , , , ......), so I've been trying to modifiy examples I've found. What are all the allowed parameters for FuncAnimation in English?
I want to produce a graph of dots shown one at a time with a time about 1 second between appearances.
Here's my current code that just produces a continuous curve after a delay:
def init():
line1.set_data([],[],'og')
return line1,
def animate(x):
x = np.linspace(0, 650, num=20, endpoint = True) #start at 0, stop at 650, number of values
y1 = (v0_y/v0_x)*x - (g/2)*(x/v0_x)**2
line1.set_data(x, y1)
time.sleep(1)
return line1,
anim = animation.FuncAnimation(fig, animate, init_func=init, frames=100, interval=3000, blit=True)
All suggestions appreciated!
You can check the documentation of FuncAnimation here, and this is an example code that does what you want:
from matplotlib import pyplot as plt
from matplotlib import animation
import numpy as np
xs = np.linspace(0, 650, num=20, endpoint = True)
ys = np.random.rand(20)
fig = plt.figure()
line1, = plt.plot([],[],'og')
plt.gca().set_xlim(0,650)
def init():
return line1,
def animate(i):
line1.set_data(xs[:i], ys[:i])
return line1,
anim = animation.FuncAnimation(fig, animate, init_func=init, interval=1000, blit=True)
plt.show()
Output window: