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()
Related
I’m trying to come up with an approach to find and mark the orange and green curves (Edges of a static and moving metal object). the goal is to measure the distance\angles between the two objects in real time.
I have already made a script that crops out the top & bottom 50 pixels and searches for the first “drastic” drop in darkness from left and right size but the result is not rubust enought for changing lighting conditions, the result is the bottom two images. The eyes can simply see the curved border all the time but my algo fails when lighting changes.
Any suggestion for a better way to find those edges?
(tried blur+canny but it fails misserably)
Thanks
My current algo
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
import math
matplotlib.use('Agg')
capture = cv2.VideoCapture("rtsp://10.0.0.100:5555/vid0")
#capture = cv2.VideoCapture("src.ts")
scale_percent = 50
width = int(1088*scale_percent/100)
height = int(1080*scale_percent/100)
fig, ax = plt.subplots(figsize=(544/72, 540/72), dpi=72)
fig.tight_layout()
ax.set_xlim(0,width)
ax.set_ylim(-2,1)
lines = {}
lines["upper"] = ax.plot(np.arange(width), np.zeros((width,)), c='blue', lw=1, alpha=1, label='RGB')[0]
lines["lower"] = ax.plot(np.arange(width), np.zeros((width,)), c='blue', lw=1, alpha=1, label='RGB')[0]
lines["upperAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='black', lw=1, alpha=1, label='RGB')[0]
lines["upperAvgDelta"] = ax.plot(np.arange(width), np.zeros((width,)), c='red', lw=1, alpha=1, label='RGB')[0]
lines["uppermeanAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='orange', lw=1, alpha=1, label='RGB')[0]
lines["lowerAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='black', lw=1, alpha=1, label='RGB')[0]
lines["lowerAvgDelta"] = ax.plot(np.arange(width), np.zeros((width,)), c='red', lw=1, alpha=1, label='RGB')[0]
lines["lowermeanAvg"] = ax.plot(np.arange(width), np.zeros((width,)), c='orange', lw=1, alpha=1, label='RGB')[0]
def moving_average(a, n) :
ret = np.cumsum(a, dtype=float)
ret[n:] = ret[n:] - ret[:-n]
return ret[n - 1:] / n
def getCrossIndex(frame,sl,wh,sm,lineName,offset):
#crop ROI
band = frame[sl:sl+wh,:,0]
cv2.imshow(str(lineName),band)
#apply intial smooting to signal
roisum = band.sum(axis=0)/wh/255
roisum = [roisum[0]]*sm+list(moving_average(roisum,sm))[:-1]
#calculate cumulative avarage for light/dark segmentation
roiavg = list(np.cumsum(roisum)/np.arange(1,len(roisum)+1))
#get change amplitude
delta = np.subtract(roiavg, roisum)
#get meanAvg level of changes from light to dark
meanValue = max(delta[0:int(width)])/2
lines[lineName+"Avg"].set_ydata(list(np.asarray(roiavg)+offset))
lines[lineName+"AvgDelta"].set_ydata(list(np.asarray(delta)+offset))
lines[lineName+""].set_ydata(list(np.asarray(roisum)+offset))
lines[lineName+"meanAvg"].set_ydata(list(np.asarray([meanValue]*width)+offset))
i0 = 0
#find the first drastic change from light to dark
for i in range(len(delta)):
if delta[i] > meanValue:# and roisum[i]<roiavg[i]:
i0 = int(i-sm/2)
break
return i0
cv2.namedWindow('control')
def nothing(x):
pass
cv2.createTrackbar('wh','control',50,int(height/2),nothing)
cv2.createTrackbar('smooth','control',20,100,nothing)
cv2.createTrackbar('sliseoffset','control',0,100,nothing)
while True:
wh = max(cv2.getTrackbarPos('wh','control'),1)
smooth = max(cv2.getTrackbarPos('smooth','control'),1)
slizeoffset = max(cv2.getTrackbarPos('sliseoffset','control'),1)
slices = [{'index':slizeoffset,'name':'upper'},{'index':height-slizeoffset-wh,'name':'lower'}]
(grabbed, frame) = capture.read()
if not grabbed:
continue
frame = cv2.resize(frame, (width,height), interpolation = cv2.INTER_AREA)
coords = [{},{}]
i = 0
for _slice in slices:
offset = -1.5*slices.index(_slice)
i1 = width-getCrossIndex(cv2.flip(frame,1),_slice['index'],wh,smooth,_slice['name'],offset)
i0 = getCrossIndex(frame,_slice['index'],wh,smooth,_slice['name'],offset)
y = _slice['index']+wh/2
coords[i]['i0'] = i0
coords[i]['i1'] = i1
coords[i]['y'] = y
i = i+1
#calc angle and draw overlay
h = coords[1]['y']-coords[0]['y']
w = (coords[1]['i0']-coords[0]['i0'])
a = -math.atan(w/h)*180/3.14
if abs(a)<5:
cv2.putText(frame, "%.2f deg"%(a), (int((coords[1]['i0']+coords[0]['i0'])/2+10),int((coords[1]['y']+coords[0]['y'])/2)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255),1)
cv2.line(img=frame, pt1=(int(coords[0]['i0']), int(coords[0]['y'])), pt2=(int(coords[1]['i0']), int(coords[1]['y'])), thickness=2,color=(0, 255, 255))
for coord in coords:
i0 = coord['i0']
ii = coord['i1']
y = coord['y']
cv2.putText(frame, "%.2f mm"%((i1-i0)/50), (int(i1+10),int(y+5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255),1)
cv2.circle(frame,center =(int(i0), int(y)), radius=10,thickness=3,color=(255, 0, 0))
cv2.circle(frame,center =(int(i1), int(y)), radius=10,thickness=3,color=(255, 0, 0))
cv2.line(img=frame, pt1=(int(i0), int(y)), pt2=(int(i1), int(y)), thickness=2,color=(255, 255, 255))
else:
cv2.putText(frame, "Not Found", (int(width/2),int(height/2)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255),1)
fig.canvas.draw()
img = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='')
img = img.reshape(fig.canvas.get_width_height()[::-1] + (3,))
img = cv2.cvtColor(img,cv2.COLOR_RGB2BGR)
cv2.imshow('chart',img)
cv2.imshow('frame',frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
capture.release()
cv2.destroyAllWindows()
I was trying to animate arrow and used the script from the following answer. Plus my animation has scatter-points and text too.
This is the script that I am using:-
from my_func import Pitch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
## Pitch for plotting the football-pitch in the background
pitch = Pitch(line_color='grey', pitch_color='#121212', orientation='horizontal')
fig, ax = pitch.create_pitch()
x_start, y_start = (50, 35)
x_end, y_end = (90, 45)
x_1, y_1, x_2, y_2 = 50.55, 35.1375, 89.45, 44.8625
x = np.linspace(x_1, x_2, 20)
y = np.linspace(y_1, y_2, 20)
sc_1 = ax.scatter([], [], color="crimson", zorder=4, s=150, alpha=0.7, edgecolor="w")
sc_2 = ax.scatter([], [], color="crimson", zorder=4, s=150, alpha=0.7, edgecolor="w")
title = ax.text(50, 65, "", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5}, ha="center")
def animate(i):
if i == 1:
sc_1.set_offsets([x_start, y_start])
title.set_text("Start of Action 01")
if i == 2:
plt.pause(0.5)
title.set_text("Action 02")
## plot arrow
## haven't included ax.cla() as it was removing the pitch in the background
if i <= len(x):
patch = plt.Arrow(x_start, y_start, x[i] - x_start, y[i] - y_start)
ax.add_patch(patch)
## plot scatter point
if i > len(x):
plt.pause(0.2)
title.set_text("Action 03")
sc_2.set_offsets([x_end, y_end])
return sc_1, patch, sc_2, title,
ani = animation.FuncAnimation(
fig=fig, func=animate, interval=50, blit=True)
plt.show()
The result is showing a little bit of animation and then giving me the following error:
File "test.py", line 33, in animate
patch = plt.Arrow(x_start, y_start, x[i] - x_start, y[i] - y_start)
IndexError: index 20 is out of bounds for axis 0 with size 20
[1] 14116 abort (core dumped) python test.py
I am a begineer in matplotlib animations and don't know how to solve this error what should I change in my code to remove the error and generate the animated output.
The modifications are as follows: 1) plt.axes() is added to ax. 2) The return value of the animation function is set to ax. 3) The number of objects to be animated is 20, so frames=20 is used.
# from my_func import Pitch
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
## Pitch for plotting the football-pitch in the background
# pitch = Pitch(line_color='grey', pitch_color='#121212', orientation='horizontal')
# fig, ax = pitch.create_pitch()
fig,ax = plt.subplots()
x_start, y_start = 50, 35
x_end, y_end = 90, 45
x_1, y_1, x_2, y_2 = 50.55, 35.1375, 89.45, 44.8625
x = np.linspace(x_1, x_2, 20)
y = np.linspace(y_1, y_2, 20)
ax = plt.axes(xlim=(50, 90), ylim=(35, 45))
sc_1 = ax.scatter([], [], color="crimson", zorder=1, s=150, alpha=0.7, edgecolor="w")
sc_2 = ax.scatter([], [], color="crimson", zorder=1, s=150, alpha=0.7, edgecolor="w")
title = ax.text(50, 65, "", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5}, ha="center")
def animate(i):
if i == 1:
sc_1.set_offsets([x_start, y_start])
title.set_text("Start of Action 01")
if i == 2:
plt.pause(0.5)
title.set_text("Action 02")
## plot arrow
## haven't included ax.cla() as it was removing the pitch in the background
if i <= len(x):
ax.clear()
#patch = plt.Arrow(x_start, y_start, x[i] - x_start, y[i] - y_start)
#ax.add_patch(patch)
ax.arrow(x_start, y_start, x[i]-x_start, y[i]-y_start, head_width=1, head_length=1, fc='black', ec='black')
ax.set(xlim=(50,90), ylim=(35,45))
## plot scatter point
if i == len(x)-1:
plt.pause(0.2)
title.set_text("Action 03")
sc_2.set_offsets([x_end, y_end])
return sc_1, sc_2, title, ax
ani = animation.FuncAnimation(fig=fig, func=animate, frames=20, interval=200, repeat=False, blit=True)
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()
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'))