การเพิ่มบรรทัดตามอำเภอใจให้กับพล็อต 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

สิ่งนี้จะไม่ลากเส้น แต่เป็นเพียงส่วนเท่านั้น คำถามว่าจะลากเส้นอย่างไรให้โยนสองจุดที่กำหนดยังไม่มีคำตอบ
Alexey

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
พารามิเตอร์ min / max ของ axhline และ axvline คือค่าสเกลาร์ระหว่าง 0 ถึง 1 ที่พล็อตเส้นโดยอ้างอิงกับขอบของพล็อต แม้ว่าจะเป็นเครื่องมือที่ดี แต่ก็อาจไม่ใช่วิธีแก้ปัญหาที่ดีที่สุดสำหรับคำชี้แจงปัญหาของผู้เขียนในการวาดเส้นคำอธิบายประกอบ
binarysubstrate

3
เหมาะอย่างยิ่งสำหรับการต้องการเพิ่มบรรทัดคำอธิบายประกอบในพื้นหลังที่ครอบคลุมทั้งกราฟ ถ้าฉันใช้วิธีแก้ปัญหาที่เลือกไว้ด้านบนเพื่อวาดเส้นแนวตั้งที่ x = 1 ฉันต้องระบุ min และ max y จากนั้นพล็อตจะปรับขนาดโดยอัตโนมัติด้วยบัฟเฟอร์ดังนั้นเส้นจะไม่ยืดทั่วทั้งพล็อตและ เป็นเรื่องยุ่งยาก สิ่งนี้สวยงามกว่าและไม่ปรับขนาดพล็อต
Bonnie

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-'
Austin Richardson

ขอบคุณที่มีประโยชน์มาก
Alex

6

ตอนนี้ Matplolib อนุญาต 'บรรทัดคำอธิบายประกอบ' ตามที่ OP กำลังมองหา annotate()ฟังก์ชั่นช่วยให้หลายรูปแบบของเส้นทางการเชื่อมต่อและหัวขาดและ tailess ลูกศรคือเส้นที่เรียบง่ายเป็นหนึ่งในนั้น

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

ในเอกสารระบุว่าคุณสามารถวาดได้เฉพาะลูกศรที่มีสตริงว่างเป็นอาร์กิวเมนต์แรก

จากตัวอย่างของ 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()

ตัวอย่างภาพอินไลน์

เช่นเดียวกับแนวทางในคำตอบของ 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ซึ่งในกรณีที่ค่าสำหรับผมเส้น TH values[i % M]คือ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.