Я использую matplotlib для построения графиков разброса. Каждая точка на диаграмме рассеивания связана с именованным объектом. Я хотел бы видеть имя объекта при наведении курсора на точку на графике рассеяния, связанную с этим объектом. В частности, было бы неплохо иметь возможность быстро видеть имена точек, которые являются выбросами. Самое близкое, что мне удалось найти при поиске здесь, - это команда annotate, но она, похоже, создает фиксированную метку на графике. К сожалению, с таким количеством точек диаграмма разброса была бы нечитабельной, если бы я пометил каждую точку. Кто-нибудь знает, как создавать метки, которые появляются только при наведении курсора в окрестности этой точки?
python
matplotlib
jdmcbr
источник
источник
Ответы:
Кажется, что ни один из других ответов здесь на самом деле не отвечает на вопрос. Итак, вот код, который использует разброс и показывает аннотацию при наведении курсора на точки разброса.
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()
Поскольку люди также хотят использовать это решение для линии
plot
вместо разброса, следующее будет тем же решениемplot
(которое работает немного по-другому).Показать фрагмент кода
import matplotlib.pyplot as plt import numpy as np; np.random.seed(1) x = np.sort(np.random.rand(15)) y = np.sort(np.random.rand(15)) names = np.array(list("ABCDEFGHIJKLMNO")) norm = plt.Normalize(1,4) cmap = plt.cm.RdYlGn fig,ax = plt.subplots() line, = plt.plot(x,y, marker="o") 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): x,y = line.get_data() annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]]) 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_alpha(0.4) def hover(event): vis = annot.get_visible() if event.inaxes == ax: cont, ind = line.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()
Если кто-то ищет решение для линий в двойных осях, см. Как сделать так, чтобы метки появлялись при наведении курсора на точку на нескольких осях?
Если кто-то ищет решение для гистограмм, обратитесь, например, к этому ответу .
источник
ind["ind"]
на самом деле это список индексов для всех точек под курсором. Это означает, что приведенный выше код фактически дает вам доступ ко всем точкам в данной позиции, а не только к самой верхней точке. Например, если у вас есть две точки перекрытия, текст можно читать,1 2, B C
или даже1 2 3, B C D
если у вас есть 3 точки перекрытия.0 8, A I
(см. Рисунок ).fig.canvas.draw_idle()
много раз (он даже меняет курсор на бездействующий). Я решил, что сохранил предыдущий индекс и проверил, еслиind["ind"][0] == prev_ind
. Затем обновляйте только в том случае, если вы перемещаетесь из одной точки в другую (обновляете текст), прекращаете наведение (сделайте аннотацию невидимой) или начнете зависать (сделайте аннотацию видимой). С этим изменением он стал более чистым и эффективным.%matplotlib notebook
в ноутбуке IPython / Jupyter.Это решение работает при наведении курсора на строку без необходимости щелкать по ней:
import matplotlib.pyplot as plt # Need to create as global variable so our callback(on_plot_hover) can access fig = plt.figure() plot = fig.add_subplot(111) # create some curves for i in range(4): # Giving unique ids to each data member plot.plot( [i*1,i*2,i*3,i*4], gid=i) def on_plot_hover(event): # Iterating over each data member plotted for curve in plot.get_lines(): # Searching which data member corresponds to current mouse position if curve.contains(event)[0]: print "over %s" % curve.get_gid() fig.canvas.mpl_connect('motion_notify_event', on_plot_hover) plt.show()
источник
matplotlib
...) - это работает сipython
/jupyter
notebooks? Это также работает, когда есть несколько подзаговоров? А что насчет гистограммы, а не линейного графика?Из http://matplotlib.sourceforge.net/examples/event_handling/pick_event_demo.html :
from matplotlib.pyplot import figure, show import numpy as npy from numpy.random import rand if 1: # picking on a scatter plot (matplotlib.collections.RegularPolyCollection) 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()
источник
print
заявлении также должны использоваться паренсы для совместимости с python 3Небольшое изменение примера, представленного в http://matplotlib.org/users/shell.html :
import numpy as np import matplotlib.pyplot as plt fig = plt.figure() ax = fig.add_subplot(111) ax.set_title('click on points') line, = ax.plot(np.random.rand(100), '-', picker=5) # 5 points tolerance def onpick(event): thisline = event.artist xdata = thisline.get_xdata() ydata = thisline.get_ydata() ind = event.ind print('onpick points:', *zip(xdata[ind], ydata[ind])) fig.canvas.mpl_connect('pick_event', onpick) plt.show()
Это строит прямолинейный график, как просил Сохаиб.
источник
Другие ответы не касались моей потребности в правильном отображении всплывающих подсказок в последней версии встроенного рисунка matplotlib Jupyter. Хотя это работает:
import matplotlib.pyplot as plt import numpy as np import mplcursors np.random.seed(42) fig, ax = plt.subplots() ax.scatter(*np.random.random((2, 26))) ax.set_title("Mouse over a point") crs = mplcursors.cursor(ax,hover=True) crs.connect("add", lambda sel: sel.annotation.set_text( 'Point {},{}'.format(sel.target[0], sel.target[1]))) plt.show()
При наведении курсора мыши на точку приводит к чему-то вроде следующего изображения:
источник
mpld3 решит это за меня. РЕДАКТИРОВАТЬ (КОД ДОБАВЛЕН):
import matplotlib.pyplot as plt import numpy as np import mpld3 fig, ax = plt.subplots(subplot_kw=dict(axisbg='#EEEEEE')) N = 100 scatter = ax.scatter(np.random.normal(size=N), np.random.normal(size=N), c=np.random.random(size=N), s=1000 * np.random.random(size=N), alpha=0.3, cmap=plt.cm.jet) ax.grid(color='white', linestyle='solid') ax.set_title("Scatter Plot (with tooltips!)", size=20) labels = ['point {0}'.format(i + 1) for i in range(N)] tooltip = mpld3.plugins.PointLabelTooltip(scatter, labels=labels) mpld3.plugins.connect(fig, tooltip) mpld3.show()
Вы можете проверить этот пример
источник
TypeError: array([1.]) is not JSON serializable
.mplcursors у меня работали. mplcursors предоставляет интерактивную аннотацию для matplotlib. Он в значительной степени вдохновлен mpldatacursor ( https://github.com/joferkington/mpldatacursor ) с значительно упрощенным API
import matplotlib.pyplot as plt import numpy as np import mplcursors data = np.outer(range(10), range(1, 5)) fig, ax = plt.subplots() lines = ax.plot(data) ax.set_title("Click somewhere on a line.\nRight-click to deselect.\n" "Annotations can be dragged.") mplcursors.cursor(lines) # or just mplcursors.cursor() plt.show()
источник
matplotlib
сделал каждую 10-ю строку одного цвета, такая боль.mplcursors
все же разбирается.Если вы используете блокнот jupyter, мое решение очень простое:
%pylab import matplotlib.pyplot as plt import mplcursors plt.plot(...) mplcursors.cursor(hover=True) plt.show()
Вы можете получить что-то вроде
источник
Я сделал многострочную систему аннотаций, чтобы добавить ее: https://stackoverflow.com/a/47166787/10302020 . для получения самой последней версии: https://github.com/AidenBurgess/MultiAnnotationLineGraph
Просто измените данные в нижнем разделе.
import matplotlib.pyplot as plt def update_annot(ind, line, annot, ydata): x, y = line.get_data() annot.xy = (x[ind["ind"][0]], y[ind["ind"][0]]) # Get x and y values, then format them to be displayed x_values = " ".join(list(map(str, ind["ind"]))) y_values = " ".join(str(ydata[n]) for n in ind["ind"]) text = "{}, {}".format(x_values, y_values) annot.set_text(text) annot.get_bbox_patch().set_alpha(0.4) def hover(event, line_info): line, annot, ydata = line_info vis = annot.get_visible() if event.inaxes == ax: # Draw annotations if cursor in right position cont, ind = line.contains(event) if cont: update_annot(ind, line, annot, ydata) annot.set_visible(True) fig.canvas.draw_idle() else: # Don't draw annotations if vis: annot.set_visible(False) fig.canvas.draw_idle() def plot_line(x, y): line, = plt.plot(x, y, marker="o") # Annotation style may be changed here 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) line_info = [line, annot, y] fig.canvas.mpl_connect("motion_notify_event", lambda event: hover(event, line_info)) # Your data values to plot x1 = range(21) y1 = range(0, 21) x2 = range(21) y2 = range(0, 42, 2) # Plot line graphs fig, ax = plt.subplots() plot_line(x1, y1) plot_line(x2, y2) plt.show()
источник