Додавання довільної лінії до графіку matplotlib у зошиті ipython


119

Я досить новачок як у python / matplotlib, так і використовую його через ноутбук ipython. Я намагаюся додати кілька рядків анотацій до наявного графіка, і я не можу зрозуміти, як відобразити рядки на графіку. Наприклад, якщо я побудую наступне:

import numpy as np
np.random.seed(5)
x = arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
p =  plot(x, y, "o")

Я отримую такий графік:

красивий розкид сюжету

То як би я додавав вертикальну лінію від (70,100) до (70,250)? Що з діагональною лінією від (70 100) до (90 200)?

Я спробував кілька речей, в Line2D()результаті чого з моєї сторони не було нічого, крім плутанини. В Rя б просто використовувати сегменти () функція , яка буде додавати відрізки. Чи є еквівалент в matplotlib?

Відповіді:


185

Ви можете прямо побудувати потрібні рядки, подаючи plotкоманду відповідними даними (межі сегментів):

plot([x1, x2], [y1, y2], color='k', linestyle='-', linewidth=2)

(звичайно, ви можете вибрати колір, ширину лінії, стиль лінії тощо)

З вашого прикладу:

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")


# draw vertical line from (70,100) to (70, 250)
plt.plot([70, 70], [100, 250], 'k-', lw=2)

# draw diagonal line from (70, 90) to (90, 200)
plt.plot([70, 90], [90, 200], 'k-')

plt.show()

нова діаграма


чудова відповідь з відмінними та повними ілюстраціями! багато спасибі!
JD Long

2
Незначне виправлення, код вище повинен читатися x = np.arange(1, 101).
WP McNeill

Це не буде проводити лінію, а лише відрізок. Питання, як намалювати лінію кидання двох заданих точок, залишається без відповіді.
Олексій

6
@Rmano ви можете уникнути сегментів, які слід враховувати в легенді, додавши аргумент мітки, починаючи з "_". Напр .:plt.plot([70, 70], [100, 250], 'k-', lw=2, label="_not in legend")
gcalmettes

1
Те, що 90використовується як x2і, так і y1призводить до багатозначності. Для всіх, хто переглядає це, зверніть увагу, що [70, 90]не посилається на одну точку в місці розташування x1,y1. Для довідки, ось значення значень:[x1: 70, x2: 90], [y1: 90, y2: 200]
pookie

61

Для новачків ще не пізно .

plt.axvline(x, color='r')

Він також приймає діапазон y, використовуючи ymin і ymax.


1
Мінімальні / максимальні параметри осі лінії та аксіатрини - це скалярні значення між 0 і 1, які накреслюють лінії по відношенню до краю ділянки. Хоча це гарний інструмент, це, мабуть, не найкраще рішення авторської постановки проблеми нанесення рядків анотацій.
binarysubstrate

3
Це ідеально підходить для того, щоб хотіти додати рядок анотацій на задньому плані, який охоплює весь графік. Якщо я використовую вибране рішення вище, щоб намалювати вертикальну лінію при x = 1, я повинен вказати min та max y, а потім графік автоматично змінюється за допомогою буфера, тому лінія не розтягується на всю ділянку, і ось клопоту. Це більш елегантно і не змінює розмір сюжету.
Бонні

40

Використання vlines:

import numpy as np
np.random.seed(5)
x = arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
p =  plot(x, y, "o")
vlines(70,100,250)

Основними підписами виклику є:

vlines(x, ymin, ymax)
hlines(y, xmin, xmax)

2
це чудово. Я не бачив vline()або hline()функцій. Що з діагональними лініями? Я редагував питання, щоб додати біт діагоналі тепер, коли ви показали мені рядки h & v.
JD Long

Спробуйте скласти DataFrameкоординати x, y та накреслити їх за допомогоюstyle='k-'
Остін Річардсон

Дякую, це дуже зручно
Алекс

6

Matplolib тепер дозволяє "рядки анотацій", як прагнула ОП. Ця annotate()функція дозволяє декілька форм з'єднувальних шляхів, і одна з них - безголова і безглузда стрілка, тобто проста лінія.

ax.annotate("",
            xy=(0.2, 0.2), xycoords='data',
            xytext=(0.8, 0.8), textcoords='data',
            arrowprops=dict(arrowstyle="-",
                      connectionstyle="arc3, rad=0"),
            )

У документації сказано, що ви можете намалювати лише стрілку з порожнім рядком як перший аргумент.

З прикладу ОП:

%matplotlib notebook
import numpy as np
import matplotlib.pyplot as plt

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")


# draw vertical line from (70,100) to (70, 250)
plt.annotate("",
              xy=(70, 100), xycoords='data',
              xytext=(70, 250), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              connectionstyle="arc3,rad=0."), 
              )

# draw diagonal line from (70, 90) to (90, 200)
plt.annotate("",
              xy=(70, 90), xycoords='data',
              xytext=(90, 200), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              connectionstyle="arc3,rad=0."), 
              )

plt.show()

Приклад вбудованого зображення

Так само, як у підході у відповіді gcalmettes, ви можете вибрати колір, ширину лінії, стиль лінії тощо.

Ось зміна частини коду, яка зробить одну з двох прикладних ліній червоною, ширшою та не на 100% непрозорою.

# draw vertical line from (70,100) to (70, 250)
plt.annotate("",
              xy=(70, 100), xycoords='data',
              xytext=(70, 250), textcoords='data',
              arrowprops=dict(arrowstyle="-",
                              edgecolor = "red",
                              linewidth=5,
                              alpha=0.65,
                              connectionstyle="arc3,rad=0."), 
              )

Ви також можете додати криву до з'єднувальної лінії, регулюючи connectionstyle.


1
Це те, що я закінчив потребувати. Я хотів провести лінію, що виходила за межі сюжету, що .plot()не може зробити.
Nick S

5

Замість того, щоб зловживати plotабо annotate, що буде неефективно для багатьох рядків, ви можете використовувати matplotlib.collections.LineCollection:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection

np.random.seed(5)
x = np.arange(1, 101)
y = 20 + 3 * x + np.random.normal(0, 60, 100)
plt.plot(x, y, "o")

# Takes list of lines, where each line is a sequence of coordinates
l1 = [(70, 100), (70, 250)]
l2 = [(70, 90), (90, 200)]
lc = LineCollection([l1, l2], color=["k","blue"], lw=2)

plt.gca().add_collection(lc)

plt.show()

Фігура з двома лініями, накресленими за допомогою LineCollection

Він займає список ліній [l1, l2, ...], де кожен рядок - це послідовність N координат ( N може бути більше двох).

Стандартні ключові слова форматування доступні, приймаючи або одне значення, і в цьому випадку значення застосовується до кожного рядка, або послідовність M values , у цьому випадку значення для i- го рядка values[i % M].

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.