Related
Until this morning I was able to display labels information when hovering the dots on a scatter plot.
Now, if I run the following code it does not display any error but the interactivity is not working and it looks like mplconnect or mlpcursors are completely ignored.
I've tried the same code under windows and Fedora.
Not understanding what's going on.
from matplotlib.pyplot import figure, show
import numpy as npy
from numpy.random import rand
x, y, c, s = rand(4, 100)
def onpick3(event):
ind = event.ind
print('onpick3 scatter:', ind, npy.take(x, ind), npy.take(y, ind))
fig = figure()
ax1 = fig.add_subplot(111)
col = ax1.scatter(x, y, 100*s, c, picker=True)
#fig.savefig('pscoll.eps')
fig.canvas.mpl_connect('pick_event', onpick3)
show()
Or
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)
x = np.random.rand(15)
y = np.random.rand(15)
names = np.array(list("ABCDEFGHIJKLMNO"))
c = np.random.randint(1,5,size=15)
norm = plt.Normalize(1,4)
cmap = plt.cm.RdYlGn
fig,ax = plt.subplots()
sc = plt.scatter(x,y,c=c, s=100, cmap=cmap, norm=norm)
annot = ax.annotate("", xy=(0,0), xytext=(20,20),textcoords="offset points",
bbox=dict(boxstyle="round", fc="w"),
arrowprops=dict(arrowstyle="->"))
annot.set_visible(False)
def update_annot(ind):
pos = sc.get_offsets()[ind["ind"][0]]
annot.xy = pos
text = "{}, {}".format(" ".join(list(map(str,ind["ind"]))),
" ".join([names[n] for n in ind["ind"]]))
annot.set_text(text)
annot.get_bbox_patch().set_facecolor(cmap(norm(c[ind["ind"][0]])))
annot.get_bbox_patch().set_alpha(0.4)
def hover(event):
vis = annot.get_visible()
if event.inaxes == ax:
cont, ind = sc.contains(event)
if cont:
update_annot(ind)
annot.set_visible(True)
fig.canvas.draw_idle()
else:
if vis:
annot.set_visible(False)
fig.canvas.draw_idle()
fig.canvas.mpl_connect("motion_notify_event", hover)
plt.show()
This is not my code, I've copied and pasted it from a website but the behavior is the same.
Plotly express solves the problem
import plotly.express as px
alpha = data[data['Ticker']==focus].V1
gamma = data[data['Ticker']==focus].V2
fig = px.scatter(data, x='V1', y='V2', color=Colors.Market_Cap, hover_data=["Ticker"] )
fig.add_shape(type="circle",
xref="x", yref="y",
x0=int(alpha-3), y0=int(gamma-3), x1=int(alpha+3), y1=int(gamma+3),
line_color="LightSeaGreen",
)
fig.show()
I have a figure where 2 axhlines move with mouse movement. I want to put a slider at the bottom where it will change the range of y-axis values covered by these axhlines.
enter image description here
I tried the following code. Problem is that the value of the slider changes but the mouse event object does not update.
Thanks
%matplotlib notebook
import pandas as pd
import numpy as np
import scipy.stats as stats
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
from matplotlib.widgets import Slider
np.random.seed(12345)
df = pd.DataFrame([np.random.normal(32000,200000,3650),
np.random.normal(43000,100000,3650),
np.random.normal(43500,140000,3650),
np.random.normal(48000,70000,3650)],
index=[1992,1993,1994,1995])
df=df.T
data=df.describe().T
data['error']=df.sem()
data['error_range']=df.sem()*1.96
fig, ax = plt.subplots()
def plot_bar(x,y,error,title,alpha_level=0.7):
ax.bar(x,y, yerr=error,
align='center', alpha=alpha_level,
error_kw=dict(ecolor='black', elinewidth=1, capsize=5, capthick=1))
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_title(title)
ax.xaxis.set_major_locator(ticker.FixedLocator(data.index))
ax.yaxis.set_major_formatter(ticker.StrMethodFormatter('{x:,.0f}'))
ax.set_ylim([-5000,55000])
ax.set_xlim([1990.5,1995.5])
ax.spines['bottom'].set_position(('data',0))
ax.spines['left'].set_position(('data',1991.4))
plt.tight_layout()
return (ax, ax.get_children()[1:5])
ax, barlist=plot_bar(x=data.index,y=data['mean'],error=data['error_range'],title='Even Harder Option', alpha_level=0.6)
fig.subplots_adjust(bottom=0.1)
axcolor = 'lightgoldenrodyellow'
range_slider = plt.axes([0.2, 0.05, 0.65, 0.03], facecolor=axcolor)
slider = Slider(range_slider, 'Range', 0, 55000, valinit=10000, valstep=100)
def update(val):
slider.val = slider.val
slider.on_changed(update)
class Cursor(object):
_df=None
_bl=None
def __init__(self, ax,data_F, bars, slider):
#global slider
self._df=data_F
self._bl=bars
self.ax = ax
self.lx1 = ax.axhline(color='b')
self.lx2 = ax.axhline(color='b')
self.text1 = ax.text(1990.55, y, '%d' %45,bbox=dict(fc='white',ec='k'), fontsize='x-small')
self.text2 = ax.text(1990.55, y, '%d' %45,bbox=dict(fc='white',ec='k'), fontsize='x-small')
self._sl = slider.val
def mouse_move(self, event):
if not event.inaxes:
return
x, y = event.xdata, event.ydata
r = self._sl
y1 , y2 = y+r/2 , y-r/2
#self.lx1.set_ydata(y)
self.lx1.set_ydata(y+r/2)
self.lx2.set_ydata(y-r/2)
for i in range(4):
#shade = cmap(norm((data['mean'.values[i]-event.ydata)/df_std.values[i]))
prob1=stats.norm.cdf(y1,self._df['mean'].values[i],self._df['error'].values[i])
prob2=stats.norm.cdf(y2,self._df['mean'].values[i],self._df['error'].values[i])
shade = cmap(prob1-prob2)
self._bl[i].set_color(shade)
self.text1.set_text('%d' %y1)
self.text1.set_position((1990.55, y1))
self.text2.set_text('%d' %y2)
self.text2.set_position((1990.55, y2))
plt.draw()
cursor = Cursor(ax, data,barlist, slider)
#plt.connect('range_change', cursor.update)
plt.connect('motion_notify_event', cursor.mouse_move)
In the following Python code, I am trying to make an animation of a 2 rotating vectors around the origin. I am using matplotlib 3.2.1 and Python 3.8.2 on Ubuntu 20.04.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
r = 2.0
def circle(phi):
return np.array([r*np.cos(phi), r*np.sin(phi)])
fig, ax = plt.subplots(figsize=(10,6))
ax.axis([-3.5*r,3.5*r,-2.5*r,2.5*r])
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# set equal aspect
ax.set_aspect("equal")
point, = ax.plot(0, r, marker="o")
traj = plt.Circle((0,0), r, fill=False, color='black')
ax.add_artist(traj) # draw the circular trajectory
def update(phi):
x, y = circle(phi)
point.set_data([x], [y])
er_vec = np.array([0.5*x, 0.5*y])
eθ_vec = np.array([-0.5*y, 0.5*x])
er_arr = plt.arrow(x, y, dx=er_vec[0], dy=er_vec[1], head_width=0.1, head_length=0.2, color='gray')
eθ_arr = plt.arrow(x, y, dx=eθ_vec[0], dy=eθ_vec[1], head_width=0.1, head_length=0.2, color='grey')
annot_er = plt.text(1.7*x, 1.7*y, r'$\mathbf{e}_r$', fontsize=11)
annot_eθ = plt.text(1.1*(x-0.5*y), 1.1*(y+0.5*x), r'$\mathbf{e}_\theta$', fontsize=11)
ax.add_artist(er_arr)
ax.add_artist(eθ_arr)
ax.add_artist(annot_er)
ax.add_artist(annot_eθ)
return point, er_arr, eθ_arr, annot_er, annot_eθ
anim = FuncAnimation(fig, update, interval=10, blit=True, repeat=False, frames=np.linspace(0, 2.0*np.pi, 360, endpoint=False))
plt.show()
The code above runs smoothly and without any issues.
This is a screenshot of the animation:
However, when I try to save the animation to an mp4 video:
anim.save('anim-issue.mp4', writer='ffmpeg')
the animation in the video appears with traces which, something like this screenshot:
Could someone help me fix that issue with the video animation?
I appreciate your help.
Edit 1: According to this answer this is due to blit=True. But that doesn't solve the issue here, since the arrows have no set_position method.
Edit 2: I found another related question with the same issue I described above but I don't know how to adapt my code to make it work as expected in both cases (plt.show, anim.save).
Updating the position of an arrow would be quite tricky.
The easiest solution is indeed to create new arrows at each frame, but you have to make sure you remove the previous arrows first
full code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
r = 2.0
def circle(phi):
return np.array([r*np.cos(phi), r*np.sin(phi)])
fig, ax = plt.subplots(figsize=(10,6))
ax.axis([-3.5*r,3.5*r,-2.5*r,2.5*r])
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# set equal aspect
ax.set_aspect("equal")
point, = ax.plot(0, r, marker="o")
traj = plt.Circle((0,0), r, fill=False, color='black')
ax.add_artist(traj) # draw the circular trajectory
er_arr = None
eθ_arr = None
annot_er = None
annot_eθ = None
def init():
global er_arr, eθ_arr, annot_er, annot_eθ
x,y = 0,0
er_vec = np.array([0.5*x, 0.5*y])
eθ_vec = np.array([-0.5*y, 0.5*x])
er_arr = plt.arrow(x, y, dx=er_vec[0], dy=er_vec[1], head_width=0.1, head_length=0.2, color='gray')
eθ_arr = plt.arrow(x, y, dx=eθ_vec[0], dy=eθ_vec[1], head_width=0.1, head_length=0.2, color='grey')
annot_er = plt.text(1.7*x, 1.7*y, r'$\mathbf{e}_r$', fontsize=11)
annot_eθ = plt.text(1.1*(x-0.5*y), 1.1*(y+0.5*x), r'$\mathbf{e}_\theta$', fontsize=11)
return er_arr, eθ_arr, annot_er, annot_eθ
def update(phi):
global er_arr, eθ_arr, annot_er, annot_eθ
x, y = circle(phi)
point.set_data([x], [y])
er_vec = np.array([0.5*x, 0.5*y])
eθ_vec = np.array([-0.5*y, 0.5*x])
#remove previous artists
er_arr.remove()
eθ_arr.remove()
er_arr = plt.arrow(x, y, dx=er_vec[0], dy=er_vec[1], head_width=0.1, head_length=0.2, color='gray')
eθ_arr = plt.arrow(x, y, dx=eθ_vec[0], dy=eθ_vec[1], head_width=0.1, head_length=0.2, color='grey')
annot_er.set_position((1.7*x, 1.7*y))
annot_eθ.set_position((1.1*(x-0.5*y), 1.1*(y+0.5*x)))
return point, er_arr, eθ_arr, annot_er, annot_eθ
anim = FuncAnimation(fig, update, init_func=init, interval=10, blit=True, repeat=False, frames=np.linspace(0, 2.0*np.pi, 360, endpoint=False))
plt.show()
I want to show this matplotlib real-time graph in tkinter GUI
Real-time Graph
import tkinter as tk
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
root= tk.Tk()
style.use('fivethirtyeight')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
graph = open('data.txt','r').read()
lines = graph.split('\n')
xs = []
ys = []
zs = []
for line in lines:
if len(line) > 1:
x, y, z = line.split(',')
xs.append(float(x))
ys.append(float(y))
zs.append(float(z))
ax1.clear()
ax1.plot(xs, ys, zs)
anim = animation.FuncAnimation(fig, animate, interval=1000)
app = (fig, root)
root.mainloop()
I tried the code above, but the GUI isn't show anything. What can I do to show that real-time graph?
Sorry, my bad. I updated my code in this line:
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
With this line:
fig = plt.figure(figsize=(5,4), dpi=100)
ax1 = fig.add_subplot(111)
line2 = FigureCanvasTkAgg(fig, root)
line2.get_tk_widget().pack(side=tk.LEFT, fill=tk.BOTH)
I got my answer now.
I want to click on my graph and add a point to it. I am using event handling, but the append command is not working.
My Code:
from matplotlib import pyplot as plt
class LineBuilder:
def __init__(self, line):
self.line = line
self.xs = line.get_xdata()
self.ys = line.get_ydata()
self.cid = line.figure.canvas.mpl_connect('button_press_event', self.click)
def click(self, event):
if event.inaxes != self.line.axes:
return
self.xs.append(event.xdata)
self.ys.append(event.ydata)
self.line.set_data(self.xs, self.ys)
self.line.figure.canvas.draw()
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click to add a point')
line, = ax.plot([], [], 'o') # empty point
linebuilder = LineBuilder(line)
plt.show()
My Error:
numpy.ndarray' object has no attribute 'append