Menambahkan baris sembarang ke plot matplotlib di notebook ipython

119

Saya agak baru mengenal python / matplotlib dan menggunakannya melalui notebook ipython. Saya mencoba menambahkan beberapa baris anotasi ke grafik yang ada dan saya tidak tahu cara merender garis pada grafik. Jadi, misalnya, jika saya memplot yang berikut ini:

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")

Saya mendapatkan grafik berikut:

plot pencar yang indah

Jadi bagaimana cara menambahkan garis vertikal dari (70.100) hingga (70.250)? Bagaimana dengan garis diagonal dari (70.100) sampai (90.200)?

Saya telah mencoba beberapa hal yang tidak Line2D()menghasilkan apa-apa selain kebingungan di pihak saya. Di Rsaya hanya akan menggunakan fungsi segment () yang akan menambahkan segmen garis. Apakah ada padanannya matplotlib?

JD Long
sumber

Jawaban:

185

Anda dapat langsung memplot garis yang Anda inginkan dengan memberi makan plotperintah dengan data yang sesuai (batas segmen):

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

(tentu saja Anda dapat memilih warna, lebar garis, gaya garis, dll.)

Dari contoh Anda:

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()

grafik baru

gcalmettes.dll
sumber
jawaban yang bagus dengan ilustrasi yang sangat bagus dan lengkap! banyak terima kasih!
JD Long
2
Koreksi kecil, kode di atas harus dibaca x = np.arange(1, 101).
WP McNeill
Ini tidak akan menarik garis, tetapi hanya satu segmen. Pertanyaan bagaimana menggambar garis melempar dua poin tetap tidak terjawab.
Alexey
6
@Rmano Anda dapat menghindari segmen untuk dipertimbangkan dalam legenda dengan menambahkan argumen label yang dimulai dengan "_". Contoh:plt.plot([70, 70], [100, 250], 'k-', lw=2, label="_not in legend")
gcalmettes
1
Fakta yang 90digunakan baik sebagai x2dan dan y1menyebabkan banyak ambiguitas. Untuk siapa pun yang melihat ini, catatan yang [70, 90]tidak mengacu pada satu titik di lokasi x1,y1. Untuk referensi, berikut adalah arti dari nilainya:[x1: 70, x2: 90], [y1: 90, y2: 200]
pookie
61

Belum terlambat untuk para pendatang baru .

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

Ini mengambil kisaran y juga, menggunakan ymin dan ymax.

penyelamat
sumber
1
Parameter min / max dari axhline dan axvline adalah nilai skalar antara 0 dan 1 yang memplot garis mengacu pada tepi plot. Meskipun alat yang bagus, ini mungkin bukan solusi terbaik untuk pernyataan masalah penulis dalam menggambar garis anotasi.
binarysubstrate
3
Ini sempurna untuk ingin menambahkan garis anotasi di latar belakang yang mencakup keseluruhan grafik. Jika saya menggunakan solusi yang dipilih di atas untuk menggambar garis vertikal pada x = 1, saya harus menentukan min dan max y, dan kemudian plot berubah ukuran secara otomatis dengan buffer, sehingga garis tidak membentang di seluruh plot, dan itu merepotkan. Ini lebih elegan dan tidak mengubah ukuran plot.
Bonnie
40

Menggunakan 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)

Tanda tangan panggilan dasar adalah:

vlines(x, ymin, ymax)
hlines(y, xmin, xmax)
Austin Richardson
sumber
2
itu luar biasa. Saya belum melihat vline()atau hline()fungsinya. Bagaimana dengan garis diagonal? Saya mengedit pertanyaan untuk menambahkan bit diagonal sekarang setelah Anda menunjukkan kepada saya garis h & v.
JD Long
Coba buat yang DataFrameberisi koordinat x, y dan gambarkan denganstyle='k-'
Austin Richards
Terima kasih, itu sangat berguna
Alex
6

Matplolib sekarang mengizinkan 'baris anotasi' seperti yang dicari OP. The annotate()Fungsi memungkinkan beberapa bentuk menghubungkan jalur dan tanpa kepala dan tailess panah, yaitu, garis sederhana, adalah salah satunya.

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

Dalam dokumentasi dikatakan bahwa Anda hanya dapat menggambar panah dengan string kosong sebagai argumen pertama.

Dari contoh OP:

%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()

Contoh gambar sebaris

Seperti pada pendekatan dalam jawaban gcalmettes, Anda dapat memilih warna, lebar garis, gaya garis, dll.

Berikut adalah perubahan pada bagian kode yang akan membuat salah satu dari dua baris contoh menjadi merah, lebih lebar, dan tidak 100% buram.

# 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."), 
              )

Anda juga dapat menambahkan kurva ke garis penghubung dengan menyesuaikan connectionstyle.

Wayne
sumber
1
Inilah yang akhirnya saya butuhkan. Saya ingin menggambar garis keluar dari batas plot, yang .plot()tidak bisa dilakukan.
Nick S
5

Daripada menyalahgunakan plotatau annotate, yang tidak efisien untuk banyak baris, Anda dapat menggunakan 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()

Gambar dengan dua garis diplot melalui LineCollection

Dibutuhkan daftar baris [l1, l2, ...], dimana setiap baris adalah urutan N koordinat ( N bisa lebih dari dua).

Kata kunci pemformatan standar tersedia, menerima nilai tunggal, dalam hal ini nilai berlaku untuk setiap baris, atau urutan M values , dalam hal ini nilai untuk baris ke- i adalah values[i % M].

Qualia
sumber