Thêm một dòng tùy ý vào một biểu đồ matplotlib trong sổ ghi chép ipython


119

Tôi khá mới đối với cả python / matplotlib và sử dụng nó thông qua sổ ghi chép ipython. Tôi đang cố gắng thêm một số dòng chú thích vào biểu đồ hiện có và tôi không thể tìm ra cách hiển thị các dòng trên biểu đồ. Vì vậy, ví dụ, nếu tôi vẽ biểu đồ sau:

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

Tôi nhận được đồ thị sau:

âm mưu phân tán đẹp

Vậy làm cách nào để thêm một đường thẳng đứng từ (70,100) đến (70,250)? Còn đường chéo từ (70,100) đến (90,200) thì sao?

Tôi đã thử một vài điều mà không có Line2D()kết quả gì ngoài sự nhầm lẫn về phía tôi. Trong Rtôi chỉ cần sử dụng hàm segment () để thêm các đoạn thẳng. Có tương đương trong matplotlibkhông?

Câu trả lời:


185

Bạn có thể vẽ trực tiếp các đường bạn muốn bằng cách cung cấp plotlệnh với dữ liệu tương ứng (ranh giới của các đoạn):

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

(tất nhiên bạn có thể chọn màu, độ rộng dòng, kiểu dòng, v.v.)

Từ ví dụ của bạn:

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

biểu đồ mới


câu trả lời tuyệt vời với hình ảnh minh họa xuất sắc và đầy đủ! rất rất cảm ơn!
JD Dài

2
Chỉnh sửa nhỏ, đoạn mã trên nên đọc x = np.arange(1, 101).
WP McNeill

Thao tác này sẽ không vẽ một đường thẳng, mà chỉ một phân đoạn. Câu hỏi làm thế nào để vẽ một đường ném hai điểm nhất định vẫn chưa được trả lời.
Alexey

6
@Rmano, bạn có thể tránh các phân đoạn được tính đến trong chú giải bằng cách thêm đối số nhãn bắt đầu bằng "_". Ví dụ:plt.plot([70, 70], [100, 250], 'k-', lw=2, label="_not in legend")
gcalmettes

1
Thực tế 90là được sử dụng cả x2và và y1dẫn đến rất nhiều sự mơ hồ. Đối với bất kỳ ai đang xem điều này, hãy lưu ý rằng [70, 90]không đề cập đến một điểm duy nhất tại vị trí x1,y1. Để tham khảo, đây là ý nghĩa của các giá trị:[x1: 70, x2: 90], [y1: 90, y2: 200]
Pookie

61

Không phải là quá muộn cho những người mới .

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

Nó cũng sử dụng phạm vi của y, sử dụng ymin và ymax.


1
Các tham số tối thiểu / tối đa của axhline và axvline là các giá trị vô hướng từ 0 đến 1 vẽ các đường tham chiếu đến cạnh của biểu đồ. Mặc dù là một công cụ tốt, nó có lẽ không phải là giải pháp tốt nhất cho vấn đề của tác giả về việc vẽ các dòng chú thích.
binarysubstrate

3
Điều này là hoàn hảo khi bạn muốn thêm một dòng chú thích trong nền kéo dài toàn bộ biểu đồ. Nếu tôi sử dụng giải pháp đã chọn ở trên để vẽ một đường thẳng đứng tại x = 1, tôi phải chỉ định y tối thiểu và tối đa, sau đó ô tự động thay đổi kích thước bằng bộ đệm, do đó, đường thẳng không kéo dài trên toàn bộ ô và đó là một rắc rối. Điều này thanh lịch hơn và không thay đổi kích thước cốt truyện.
Bonnie

40

Sử dụng 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)

Các chữ ký cuộc gọi cơ bản là:

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

2
thật xuất sắc. Tôi đã không nhìn thấy vline()hoặc các hline()chức năng. Còn đường chéo thì sao? Tôi đã chỉnh sửa câu hỏi để thêm bit đường chéo bây giờ bạn đã chỉ cho tôi các dòng h & v.
JD Long

Hãy thử làm một DataFramechứa x, y tọa độ và hình vẽ chúng bằngstyle='k-'
Austin Richardson

Cảm ơn bạn, điều đó rất hữu ích
Alex

6

Matplolib hiện cho phép 'dòng chú thích' như OP đang tìm kiếm. Các annotate()chức năng cho phép nhiều hình thức các đường dẫn kết nối và không đầu và tailess mũi tên, ví dụ, một dòng đơn giản, là một trong số họ.

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

Trong tài liệu, nó nói rằng bạn chỉ có thể vẽ một mũi tên với một chuỗi rỗng làm đối số đầu tiên.

Từ ví dụ của 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()

Hình ảnh nội tuyến mẫu

Cũng giống như cách tiếp cận trong câu trả lời của gcalmettes, bạn có thể chọn màu sắc, độ rộng dòng, kiểu dòng, v.v.

Đây là một thay đổi đối với một phần của mã sẽ làm cho một trong hai dòng ví dụ có màu đỏ, rộng hơn và không mờ 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."), 
              )

Bạn cũng có thể thêm đường cong vào đường kết nối bằng cách điều chỉnh connectionstyle.


1
Đây là những gì cuối cùng tôi cần. Tôi muốn vẽ một đường ra bên ngoài biên giới của âm mưu, điều này .plot()không thể làm được.
Nick S

5

Thay vì lạm dụng plothoặc annotate, sẽ không hiệu quả cho nhiều dòng, bạn có thể sử dụng 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()

Hình có hai đường được vẽ qua LineCollection

Nó có một danh sách các dòng [l1, l2, ...], trong đó mỗi dòng là một chuỗi N tọa độ ( N có thể nhiều hơn hai).

Các từ khóa định dạng chuẩn có sẵn, chấp nhận một giá trị duy nhất, trong trường hợp đó giá trị áp dụng cho mọi dòng hoặc một chuỗi M values , trong trường hợp đó giá trị cho dòng thứ ivalues[i % M].

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.