I have a 3D graph, and I would like to annotate them with the co-ordinates. However, the annotations gets overlapped. I would like them to not overlap.
My problem is -
Annotations get overlapped
In the legends, I don't understand why there are two symbols of triangles and circles. Shouldn't it be just one?
Just for information, my data set is limited to the following points only. So even if any other parameters are hard-coded, it is okay with me.
Here is my code.
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d import proj3d
import matplotlib.pyplot as plt
import pylab
xData1=[ 24500., 2980., 2980., 13740.]
xData2=[ 8360., 8360., 24500., 5670., 2980., 2980., 11050., 13740.]
yData1=[ 179., 244., 242., 181.]
yData2=[ 132., 149., 116., 163., 247., 228., 116., 116.]
zData1=[ 1., 44., 86., 44.]
zData2=[ 86., 22., 1., 86., 43., 86., 86., 22.]
fig = plt.figure()
ax = fig.gca(projection='3d')
ax.plot(xData1, yData1, zData1, '^', c='r', label='cfg1')
ax.plot(xData2, yData2, zData2, 'o', c='b', label='cfg2')
for i in range(len(xData1)):
text='['+str(int(xData1[i]))+','+str(int(yData1[i]))+','+str(int(zData1[i]))+']'
x2, y2, _ = proj3d.proj_transform(xData1[i],yData1[i],zData1[i], ax.get_proj())
label = pylab.annotate(text,
xycoords='data',
xy = (x2, y2), xytext = (60, 20),
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
for i in range(len(xData2)):
text='['+str(int(xData2[i]))+','+str(int(yData2[i]))+','+str(int(zData2[i]))+']'
x2, y2, _ = proj3d.proj_transform(xData2[i],yData2[i],zData2[i], ax.get_proj())
label = pylab.annotate(text,
xycoords='data',
xy = (x2, y2), xytext = (20, 20),
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
ax.set_xlabel('X-Data')
ax.set_ylabel('Y-Data')
ax.set_zlabel('Z-Data')
ax.legend(ncol=3)
plt.show()
Both questions are relatively easy answers. I'll start with the second one first: There are two symbols in your legend because you didn't specify the number when you defined the legend and the default value is two. To correct, simply change:
ax.legend(ncol=3, numpoints=1)
where numpoints changes the number of points within the legend - now it's set to 1.
The answer to your first question involves manipulating the placement of the text annotations, more specifically the xytext, which gives the coordinates for the text. Replacing your second for-loop with the below should get rid of your overlapping text and give you a good example of how to change the location of the annotation boxes for any other unsightly location-issues:
for i in range(len(xData2)):
text='['+str(int(xData2[i]))+','+str(int(yData2[i]))+','+str(int(zData2[i]))+']'
x2, y2, _ = proj3d.proj_transform(xData2[i],yData2[i],zData2[i], ax.get_proj())
if i==4:
label = pylab.annotate(text,
xycoords='data',
xy = (x2, y2), xytext = (0, -50),
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
elif i==6:
label = pylab.annotate(text,
xycoords='data',
xy = (x2, y2), xytext = (-40, 0),
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
else:
label = pylab.annotate(text,
xycoords='data',
xy = (x2, y2), xytext = (-20, 10),
textcoords = 'offset points', ha = 'right', va = 'bottom',
bbox = dict(boxstyle = 'round,pad=0.5', fc = 'yellow', alpha = 0.5),
arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
Related
I have typed a class for the matplotlib chart markers, everything works fine if I add markers to specific axes. But I want to add markers to all axes at once. Then I don't know how to get the Y value for the axis other than the one I clicked on.
class MplMarkers():
def __init__(self, fig, enable=None):
self.mpl_fig = fig
self.mpl_markers = []
self.mpl_markers_event = []
self.mpl_bbox_props = dict(boxstyle="round,pad=0.5", fc="w", ec="k", lw=1)
if enable:
self.enable()
def add(self, event):
if event.inaxes:
# add marker for current ax ######################
if event.button is MouseButton.RIGHT and event.key is None:
an = event.inaxes.annotate(bbox=self.mpl_bbox_props, text=' X={}\n Y={:4f}'.format(matplotlib.dates.num2date(event.xdata, tz=None).strftime("%H:%M:%S.%f"), event.ydata), xy=(event.xdata,0.98),
color='black', fontsize=8, alpha=0.5, xycoords=('data', 'axes fraction'), annotation_clip=False, verticalalignment='top', horizontalalignment='left' , rotation = 0)
vl = event.inaxes.axvline(x=event.xdata, linewidth=1.0, alpha=0.5, color='b', label='M-' + str(event.xdata))
self.mpl_markers.append({'x': event.xdata, 'y':event.ydata, 'an_cid':an, 'vl_cid':vl})
event.inaxes.figure.canvas.draw_idle()
# add marker for all ax ######################
if event.button is MouseButton.RIGHT and event.key == 'shift':
if len(self.mpl_fig.axes) > 1:
for a in self.mpl_fig.axes:
an = a.annotate(bbox=self.mpl_bbox_props, text=' X={}\n Y={:4f}'.format(matplotlib.dates.num2date(event.xdata, tz=None).strftime("%H:%M:%S.%f"), event.ydata), xy=(event.xdata,0.98),
color='black', fontsize=8, alpha=0.5, xycoords=('data', 'axes fraction'), annotation_clip=False, verticalalignment='top', horizontalalignment='left' , rotation = 0)
vl = a.axvline(x=event.xdata, linewidth=1.0, alpha=0.5, color='b', label='M-' + str(event.xdata))
self.mpl_markers.append({'x': event.xdata, 'y':event.ydata, 'an_cid':an, 'vl_cid':vl})
a.figure.canvas.draw_idle()
def remove(self, event):
if event.inaxes:
# remove all markers ##################
if event.button is MouseButton.RIGHT and event.key == 'control':
for m in self.mpl_markers:
m['an_cid'].remove()
m['vl_cid'].remove()
del m
self.mpl_markers=[]
for a in self.mpl_fig.axes:
a.figure.canvas.draw_idle()
def enable(self):
self.mpl_markers_event.append(self.mpl_fig.canvas.mpl_connect('button_press_event', self.add))
self.mpl_markers_event.append(self.mpl_fig.canvas.mpl_connect('button_press_event', self.remove))
def disable(self):
if self.mpl_markers_event:
for me in self.mpl_markers_event:
self.mpl_fig.canvas.mpl_disconnect(me)
How can I get the Y value for the rest of the axes?
In the code part - "# add marker for all ax ######################"
In this form, I get the Y value of the clicked axis on all axes
screenshot
I'm getting the error only when I set Blit=True in my code below, it works when I set Blit=False. Unfortunately, I need to have Blit=True because it makes the animation much smoother (at least that's what I suppose). What's wrong here? I saw other threads with the same error message, but it wasn't specifially for stuff including matplotlib.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
fig, ax = plt.subplots()
ax.axis('off')
circle_red1 = plt.Circle((1, 1), 1, color='red')
circle_red2 = plt.Circle((0, 0), 1, color='red')
circle_red3 = plt.Circle((0, 1), 1, color='red')
circle_red4 = plt.Circle((1,0), 1, color='red')
ax.add_artist(circle_red1)
ax.add_artist(circle_red2)
ax.add_artist(circle_red3)
ax.add_artist(circle_red4)
circle_white = plt.Circle((0.5, 0.5), 0.1, color='white')
ax.add_artist(circle_white)
fig.set_size_inches(5, 5)
def update(i, fig, ax):
while i <= 50:
circle_white = plt.Circle((0.5, 0.5), i/100, color='white')
ax.add_artist(circle_white)
return fig, ax, i
while 50 < i <= 100:
circle_red1 = plt.Circle((1, 1), i/1000, color='red')
circle_red2 = plt.Circle((0, 0), i/1000, color='red')
circle_red3 = plt.Circle((0, 1), i/1000, color='red')
circle_red4 = plt.Circle((1, 0), i/1000, color='red')
ax.add_artist(circle_red1)
ax.add_artist(circle_red2)
ax.add_artist(circle_red3)
ax.add_artist(circle_red4)
return fig, ax, i
anim = FuncAnimation(fig, update, frames=np.arange(0, 100, 1), interval=10, blit=True, repeat=False, fargs=(fig, ax))
plt.show()
If blit is True your update function must return an iterable of all artists that were modified or created, see documentation:
def update(i, fig, ax):
while i <= 50:
circle_white = plt.Circle((0.5, 0.5), i/100, color='white')
ax.add_artist(circle_white)
return [circle_white]
while 50 < i <= 100:
circle_red1 = plt.Circle((1, 1), i/1000, color='red')
circle_red2 = plt.Circle((0, 0), i/1000, color='red')
circle_red3 = plt.Circle((0, 1), i/1000, color='red')
circle_red4 = plt.Circle((1, 0), i/1000, color='red')
ax.add_artist(circle_red1)
ax.add_artist(circle_red2)
ax.add_artist(circle_red3)
ax.add_artist(circle_red4)
return [circle_red1, circle_red2, circle_red3, circle_red4]
I plotted a figure using matplotlib:
And now I would like the edges of the figure to display the coordinates, without manually looking them up and using paint like in this figure:
This is my code:
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
# setup Lambert Conformal basemap.
plt.figure(figsize=(20,10))
map = Basemap(width=400000,height=300500,projection='lcc',
resolution='h',lat_0=52.25,lon_0=4.5)#lat_1=50,lat_2=45
# draw coastlines.
# draw a boundary around the map, fill the background.
# this background will end up being the ocean color, since
# the continents will be drawn on top.
map.drawmapboundary(fill_color='turquoise')
# fill continents, set lake color same as ocean color.
map.fillcontinents(color='white',lake_color='turquoise')
map.drawcountries(linestyle='--')
map.drawmapscale(lon=6.5, lat=51.25, lon0=0, lat0=52, length=50)
lonA =np.loadtxt('AllStranding250Lon.txt',delimiter=',') ## [4.540377,4.173571,3.041619]
latA =np.loadtxt('AllStranding250Lat.txt',delimiter=',') # [52.395394,52.035414,51.286338]
AA=np.loadtxt('AllStranding250Numbers.txt',delimiter=',')
n=len(lonA)
m=len(latA)
print('m=', m)
print('n=',n)
SizeA=np.zeros(n)#number counted
q=len(SizeA)
print('q=',q)
x,y = map(lonA[0:7], latA[0:7])
z,a = map(lonA[7:9], latA[7:9])
for i in range (0,n):
if 250<=AA[i] <1000:
SizeA[i]=15
elif 1000 <= AA[i] < 5000:
SizeA[i]=25
elif 5000 <= AA[i] < 10000:
SizeA[i]=45
elif 10000<= AA[i]<50000:
SizeA[i]=65
elif 50000<= AA[i]<100000:
SizeA[i]=100
else:
SizeA[i]=200
map.scatter(x, y, s=SizeA, c='steelblue', marker='o', label = 'Aurelia aurita',zorder=2, edgecolors='k')
map.scatter(z, a, s=SizeA[7:9], c='coral', marker='v', label = 'Chrysaora hysoscella', zorder=2)
l2 = plt.scatter([],[], s=15,color='white', edgecolors='k')
l3 = plt.scatter([],[], s=25,color='white',edgecolors='k')
l4 = plt.scatter([],[], s=45,color='white', edgecolors='k')
l5 = plt.scatter([],[], s=65,color='white', edgecolors='k')
l6 = plt.scatter([],[], s=80,color='white', edgecolors='k')
l7 = plt.scatter([],[], s=200,color='white', edgecolors='k')
l8 = plt.scatter([],[], s=80,color='steelblue', edgecolors='k')
l9 = plt.scatter([],[], s=80,color='coral', marker = 'v', edgecolors='None')
labels = [ "250-1000", "1000-5 000", "5 000-10 000","10 000-50 000","50 000-100 000", "100 000<", 'Aurelia aurita','Chrysaora hysoscella']
plt.legend([ l2, l3, l4,l5,l6,l7,l8,l9], labels, frameon=True,
fontsize=12, handlelength=2, loc = 'upper left', borderpad = 1,
handletextpad=1,title ="Stranded medusa", scatterpoints = 1)#loc='upper center'
plt.savefig('AllStranding.png')
plt.show()
I tried to use the line:
map.drawmeridians([],labels=[left,right,top,bottom])
But then it says it doesn't know 'right', and I don't want to draw the meridians in the first place, I just want 2 numbers at each corner.
Thanks in advance!
Here is a solution, with only relevant code.
from mpl_toolkits.basemap import Basemap
import numpy as np
import matplotlib.pyplot as plt
#import matplotlib.patches as mpatches
plt.figure(figsize=(20,10))
ax = plt.gca()
width, height = 400000, 300500 # for Basemap()
sx, sy = width/20., height/20. # shifts for annotation placement
bmap = Basemap(width=width, height=height, projection='lcc', \
resolution='i', lat_0=52.25, lon_0=4.5)
# the limits (corner points) of the map
x1, x2, y1, y2 = bmap.xmin, bmap.xmax, bmap.ymin, bmap.ymax #meters
# corner points (x, y) in meters of the projection
ll = (x1, y1)
ur = (x2, y2)
ul = (x1, y2)
lr = (x2, y1)
# All (lon, lat) of corner points, degrees
LL = bmap(*ll, inverse=True)
UR = bmap(*ur, inverse=True)
UL = bmap(*ul, inverse=True)
LR = bmap(*lr, inverse=True)
bmap.drawmapboundary(fill_color='turquoise')
bmap.drawcoastlines(linewidth=0.7)
# fill continents, set lake color same as ocean color.
bmap.fillcontinents(color='#eceffd', lake_color='turquoise')
bmap.drawcountries(linestyle='--')
# set properties for use with annotation
anno = [{'text': "{:6.3f}".format(LL[1]), 'xy': np.array(ll), 'shift': [-sx, 0], 'va': 'center', 'ha': 'center'}, \
{'text': "{:6.3f}".format(UR[1]), 'xy': np.array(ur), 'shift': [+sx, 0], 'va': 'center', 'ha': 'center'}, \
{'text': "{:6.3f}".format(UL[1]), 'xy': np.array(ul), 'shift': [-sx, 0], 'va': 'center', 'ha': 'center'}, \
{'text': "{:6.3f}".format(LR[1]), 'xy': np.array(lr), 'shift': [+sx, 0], 'va': 'center', 'ha': 'center'}, \
{'text': "{:6.3f}".format(LL[0]), 'xy': np.array(ll), 'shift': [0, -sy], 'va': 'bottom', 'ha': 'center'}, \
{'text': "{:6.3f}".format(UR[0]), 'xy': np.array(ur), 'shift': [0, sy], 'va': 'top', 'ha': 'center'}, \
{'text': "{:6.3f}".format(UL[0]), 'xy': np.array(ul), 'shift': [0, sy], 'va': 'top', 'ha': 'center'}, \
{'text': "{:6.3f}".format(LR[0]), 'xy': np.array(lr), 'shift': [0, -sy], 'va': 'bottom', 'ha': 'center'}]
deg_sign= u'\N{DEGREE SIGN}'
# plot texts at all 4 corners of map
for ea in anno:
txt = ax.annotate(ea['text']+deg_sign, xy=ea['xy'], xytext=ea['xy']+ea['shift'], \
textcoords='data', \
arrowprops = dict(arrowstyle="-", lw=.5), \
size=10, ha=ea['ha'], va=ea['va'])
#plt.savefig('AllStranding.png')
plt.show()
I have a plot where I want to interactively adjust the position of a patch and use the interactive update to be used in recalculating a variable.
I have plotted and image and added a closed contour (represented using PathPatch)
Here is an example image. example image with contour where information is calculated from the pixels enclosed by the contour. The pixel mask needs to be updated so that plots on right can also be updated.
Currently I plot everything and then use an event to move the contour, I tried using transforms and this worked to move the contour but when I tried using the transform to update the binary mask needed to recalculate the plots on the right side, the transformation it returns is incorrect. On top of this the transforms caused the contour to move when zooming in and out from the interactive window.
I need to figure out how to shift the contour and re-plot it and then extract the shift and apply to extracting a new mask of enclosed points to update the calculation.
import matplotlib.pyplot as plt
import matplotlib as mpl
import matplotlib.path as mplpath
import matplotlib.patches as patches
from matplotlib.widgets import Button, Slider
# GENERATE SOME DATA TO PLOT
# event functions
def press(event):
print('press', event.key)
sys.stdout.flush()
if (event.key == 'left'):
shift[0] -= 1.0
elif (event.key == 'right'):
shift[0] += 1.0
elif (event.key == 'up'):
shift[1] += 1
elif (event.key == "down"):
shift[1] -= 1.0
# this is where I don't know how to properly transform and update[!
fig.canvas.draw()
class Recalculate(object):
def update(self, event):
x_update = [x_ for x_ in x_pts]
y_update = [y_ for y_ in y_pts]
verts_test = np.column_stack((x_update, y_update))
new_contour = mplpath.Path(verts_test, closed=True)
# create mask
new_grid = getMask(im_vol_resize, new_contour)
# calculate the flow
q_sum = []
for i in range(N): #assume size doesn't change
q_mask_sum = np.sum(test_q[:,:,i]*new_grid.astype(image_dtype))
q_sum.append(q_mask_sum*np.prod(spacing[0:2])/(100.0*scale**2)) # cm^3
print("total flow {0} cm^3/beat".format(np.trapz( q_sum, dx = np.mean(mean_diff)/1000)))
q_sum_roll = np.roll(q_sum, -16)
#q_interp = interpolate.CubicSpline(new_time, q_sum_roll, bc_type='periodic')
q_interp = interpolate.InterpolatedUnivariateSpline(new_time, q_sum_roll, k=3, ext=0)
q_test = q_interp(t_interp)
#plotting update
grid_handle.set_data(new_grid)
#print(new_time)
scat_data = np.stack((new_time, q_sum), axis=1)
#ax2.relim() # make sure all the data fits
#ax2.autoscale()
#print(scat_data.shape)
scatter_handle.set_offsets(scat_data)
interp_handle[-1].set_ydata(q_test)
ax3.relim() # make sure all the data fits
ax3.autoscale()
ax2.set_xlim(ax3.get_xlim())
ax2.set_ylim(ax3.get_ylim())
fig.canvas.draw()
def update_cine(val):
ind = int(slider.val)
s = [slice(ind, ind + 1) if i == 2 else slice(None)
for i in range(3)]
for sd in xyz_keys:
im = cubes[sd][s].squeeze()
cine_ax_dict[sd].set_data(im)
ax6.set_title("time: {0}".format(new_time[ind]))
ax2.scatter(new_time, q_sum, c='b', label='flowRate')
ax2.scatter(new_time[ind], q_sum[ind], c='r', label='time={0}'.format(new_time[ind]))
fig.canvas.draw()
#figures
gs = plt.GridSpec(6, 6, wspace=0.2, hspace=0.2)
fig = plt.figure(figsize=(17, 9))
fig.canvas.mpl_connect('key_press_event', press)
ax = fig.add_subplot(gs[3:,0:3])
#xl = ax.set_xlabel('easy come, easy go')
#ax.set_title('Press a key')
patch = patches.PathPatch(contour, facecolor=(1.0,165./255.0,0,0.25), lw=1 )#, alpha=0.5)
patch_handle = ax.add_patch(patch)
#plt.plot(x_pts, y_pts)
x_bounds = [round((bounds[0]-4)*scale), round((bounds[1]+4)*scale)]
y_bounds = [round((bounds[2]-4)*scale), round((bounds[3]+4)*scale)]
ax.set_xlim(x_bounds)
ax.set_ylim(y_bounds)
ax.imshow(im_vol_resize, interpolation='bilinear', cmap="gray", alpha=1.0)
ax5 = fig.add_subplot(gs[0:3,0:3])
patch2 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))#, alpha=0.5)
ax5.imshow(im_vol_resize, interpolation='bilinear', cmap="gray", alpha=1.0)
patch_handle2 = ax5.add_patch(patch2)
#new_contour = patch_.get_path()
ax5.set_xlim(x_bounds)
ax5.set_ylim(y_bounds)
# show ROI mask
grid_handle = ax.imshow(grid, interpolation='None', cmap="gray", alpha=0.1)
#print(dir(grid_handle))
ax2 = fig.add_subplot(gs[0:3, 4:])
scatter_handle = ax2.scatter(new_time, q_sum, c='b', label='flowRate')
ax2.scatter(new_time[0], q_sum[0], c='r', label='cine time')
#print(dir(scatter_handle))
#ax2.scatter(dict_time["y"], q_sum, label='flowRatey')
#ax2.scatter(dict_time["z"], q_sum, label='flowRatez')
#ax2.plot(dict_time["x"], q_sum)
#ax2.set_xlabel(r'$t$', fontsize=20)
ax2.set_title('terminal ICA Waveform', fontsize=20)
ax2.set_ylabel(r'Q, $Q(t)$ $cm^3/min$', fontsize=20)
ax2.xaxis.set_ticks_position('none')
ax2.xaxis.set_ticklabels([])
ax2.legend(loc='center left', bbox_to_anchor=(1, 0.9))
ax3 = fig.add_subplot(gs[3:, 4:])
ax3.set_xlabel(r'time $t$ $milliseconds$', fontsize=20)
ax3.set_ylabel(r'Flowrate $cm^3/min$', fontsize=20)
ax3.set_xlim(ax2.get_xlim())
ax3.set_ylim(ax2.get_ylim())
interp_handle = ax3.plot(t_interp, q_test, c='b', linestyle='-', label='interp')
#print(dir(interp_handle[0]))
ax3.legend(loc='center left', bbox_to_anchor=(1, 0.9))
cine_ax_dict = {}
ax6 = fig.add_subplot(gs[0:2,2:4])
ax6.set_title("time: {0}".format(new_time[0]))
cine_ax_dict["x"] = ax6.imshow(cubes['x'][:,:,0], interpolation='bilinear', cmap="viridis", alpha=1.0)
patch6 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))
ax6.add_patch(patch6)
ax6.set_xlim(x_bounds)
ax6.set_ylim(y_bounds)
ax7 = fig.add_subplot(gs[2:4,2:4])
cine_ax_dict["y"] = ax7.imshow(cubes['y'][:,:,0], interpolation='bilinear', cmap="viridis", alpha=1.0)
patch7 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))
ax7.add_patch(patch7)
ax7.set_xlim(x_bounds)
ax7.set_ylim(y_bounds)
ax8 = fig.add_subplot(gs[4:,2:4])
cine_ax_dict["z"] = ax8.imshow(cubes['z'][:,:,0], interpolation='bilinear', cmap="viridis", alpha=1.0)
patch8 = patches.PathPatch(contour, facecolor='none', linewidth=0.8, edgecolor=(1.0,165./255.0,0,0.50))
ax8.add_patch(patch8)
ax8.set_xlim(x_bounds)
ax8.set_ylim(y_bounds)
# define slider
axcolor = 'lightslategray'
ax_c = fig.add_axes([0.25, 0.05, 0.60, 0.03], aspect="auto", facecolor=axcolor)
slider = Slider(ax_c, 'Axis %i index' % 2, 0, cubes["x"].shape[2] - 1,
valinit=0, valfmt='%i')
The event.canvas.draw() seems to take a long time in below code, how can I just draw the annotation instead of the whole canvas?
import random
import matplotlib.pyplot as plt
def on_move(event):
if event.inaxes is not None:
x = event.xdata
y = event.ydata
annotation.xy = (x, y)
annotation.set_text("Test")
event.canvas.draw()
fig = plt.figure()
ax = plt.gca()
ax.plot(random.sample(xrange(100000), 50000), random.sample(xrange(100000), 50000), 'bo')
ax.plot(random.sample(xrange(100000), 50000), random.sample(xrange(100000), 50000), 'go')
annotation = ax.annotate(
'',
xy=(0,0),
xycoords='data',
ha = 'right',
xytext = (-20, 20),
textcoords = 'offset points',
va = 'bottom',
bbox = dict(boxstyle='round,pad=0.5', fc='yellow', alpha=0.75),
arrowprops = dict(
arrowstyle='->',
connectionstyle='arc3,rad=0',
relpos=(1., 0.))
)
fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()