I have a weird problem with the following plotting code:
topfolder="test"
cfeature="READ_COUNT_RNR"
plotsensitives=[0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.7666666666666667, 0.7666666666666667, 0.6666666666666666, 0.6666666666666666, 0.23333333333333334, 0.23333333333333334, 0.23333333333333334, 0.23333333333333334, 0.16666666666666666, 0.16666666666666666]
plot1mspecificities=[0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7, 0.7, 0.2666666666666667, 0.2666666666666667, 0.23333333333333328, 0.23333333333333328, 0.16666666666666663, 0.16666666666666663]
seed=[57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0]
cutoff=[10.0, 10.0, 30.0, 30.0, 50.0, 50.0, 75.0, 75.0, 100.0, 100.0, 150.0, 150.0, 250.0, 250.0, 500.0, 500.0, 750.0, 750.0, 1000.0, 1000.0]
pangiaver=['test']*20
labels=["{0},{1},{2},{3},{4}".format(round(100*plotsensitives[pos],2),round(100*plot1mspecificities[pos],2),seed[pos],cutoff[pos],pangiaver[pos]) for pos in range(len(plot1mspecificities))]
annotations = [None for label in labels]
import matplotlib.pyplot as plt
import math
##defining size of markers:
markersize = 5
markersize_inches = markersize/72.
fig,ax = plt.subplots()
sc = plt.scatter(plot1mspecificities,plotsensitives)
plt.title('Receiver Operating Characteristic for the feature {0} in the {1} dataset'.format(cfeature,topfolder))
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
trans = ax.transData+fig.dpi_scale_trans.inverted()
##function for checking mouse coordinates and annotating
## need to define xdata,ydata
xdata,ydata=plotsensitives,plot1mspecificities
def on_move(event):
if event.inaxes:
x0, y0 = trans.transform((event.xdata, event.ydata))
#user coordinates=event.xdata, event.ydata, these are values seen by user, plot coordinates x0, y0, unseen coordinates used by plot
xfig, yfig = zip(*[trans.transform((x,y)) for x,y in zip(xdata,ydata)])
dists = [math.sqrt((x-x0)**2+(y-y0)**2) for x,y in zip(xfig, yfig)]
for n,(x,y,dist,label) in enumerate(zip(xdata,ydata,dists, labels)):
if dist < markersize_inches and annotations[n] is None:
annotations[n]=ax.annotate(
label,
[x,y], xycoords='data',
xytext = (10,10), textcoords='offset points',
ha='left', va='center',
bbox=dict(facecolor='white', edgecolor='black', boxstyle='round'),
zorder=10,
)
fig.canvas.draw()
elif dist > markersize_inches and annotations[n] is not None:
annotations[n].remove()
annotations[n] = None
fig.canvas.draw()
##connecting the event handler
cid = fig.canvas.mpl_connect('motion_notify_event', on_move)
plt.show()
the plot is designed to display labels when a mouse hovers over a point and this works, but for only some points. It is supposed to work over all points and I see no obvious way why it should only work for some points. It is run on python 3.5 on Ubuntu 16.04 using matplotlib installed with pip in the last month.
I think this code could be useful as a template to make interactive, in a certain way, plots that could be useful to a lot of people. If someone can figure out the issue, I will post the full fixed code below ,so that anyone can use it, and give the person who solves it full credit. I would really appreciate anything helpful.
Edit 1: As pointed out by @DyZ, a solution to having the labels display only the coordinate info is found here:Possible to make labels appear when hovering over a point in matplotlib?. However what if you want to add metadata?
below is my code after modifying the solution that was pointed out to me, how can you fix the code so that it prints the 5 different values associated wuith a datapoint?
import matplotlib.pyplot as plt
topfolder="test"
cfeature="READ_COUNT_RNR"
plotsensitives=[0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.7666666666666667, 0.7666666666666667, 0.6666666666666666, 0.6666666666666666, 0.23333333333333334, 0.23333333333333334, 0.23333333333333334, 0.23333333333333334, 0.16666666666666666, 0.16666666666666666]
plot1mspecificities=[0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7666666666666666, 0.7, 0.7, 0.2666666666666667, 0.2666666666666667, 0.23333333333333328, 0.23333333333333328, 0.16666666666666663, 0.16666666666666663]
seed=[57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0, 57.0, 75.0]
cutoff=[10.0, 10.0, 30.0, 30.0, 50.0, 50.0, 75.0, 75.0, 100.0, 100.0, 150.0, 150.0, 250.0, 250.0, 500.0, 500.0, 750.0, 750.0, 1000.0, 1000.0]
pangiaver=['test']*20
tempdata=[[round(100*entry,2) for entry in plot1mspecificities],[round(100*entry,2) for entry in plotsensitives],seed,cutoff,pangiaver]
transposeddata=list(map(list,zip(*tempdata)))
fig,ax = plt.subplots()
sc = plt.scatter(plot1mspecificities,plotsensitives, s=10) #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]]
alldatafrompoint=transposeddata[ind["ind"][0]]
annot.xy = alldatafrompoint
text=("{}, "*len(pos))[:-2].format(*alldatafrompoint)
annot.set_text(text)
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()
Edit 2: an alternative method mentioned in, Using matplotlib to label points on a scatter plot on mouse over with some label other than x,y coordinates, seems to have a decent solution, but can it be extended to alot of points, though in practice needing to look at 10000 points with pop up labels is not likely going to be needed.