如何通过散点图绘制一条线而没有溢出

max*_*sme 2 python matplotlib

所以我目前正在matplotlib中绘制包含许多xys 的散点图:

plt.scatter(x, y)
Run Code Online (Sandbox Code Playgroud)

我想在此散点图上画一条线,该线穿过整个图(即命中两个“边界”),我知道梯度和截距m以及c等式中的y = mx +c

我已经考虑过要获取曲线图的4个点(计算最小和最大散点xys),然后从中计算直线的最小和最大坐标,然后进行绘制,但这似乎很复杂。有没有更好的方法可以做到这一点,请牢记线甚至可能不在“图”内?


散点图示例: 在此处输入图片说明

如图所示,四个边界坐标大致是:

  • 左下方: -1,-2
  • 左上方: -1,2
  • 右下: 6,-2
  • 右上 6,2

现在,我需要绘制一条线,该线不得超过这些边界,但是如果它进入该线,则必须接触两个边界点。

因此,我可以检查x = -1时y等于什么,然后检查该值是否在-1和6之间,以及是否该线必须越过左边界,因此将其绘制,依此类推,等等。


理想情况下,尽管我会创建一条从-infinity到infinity的线,然后对其进行裁剪以适合绘图。

Imp*_*est 6

这里的想法是在图中绘制一条方程式的线y=m*x+y0。这可以通过以下方式实现:将最初在轴坐标中给出的一条水平线转换为数据坐标,然后根据该线方程应用Affine2D转换并将其转换回屏幕坐标。

这样做的好处是,您根本不需要知道轴限制。您还可以自由缩放或平移情节;该线将始终保持在轴边界内。因此,它有效地实现了从-infinity到+ inifinty的行。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.transforms as mtransforms

def axaline(m,y0, ax=None, **kwargs):
    if not ax:
        ax = plt.gca()
    tr = mtransforms.BboxTransformTo(
            mtransforms.TransformedBbox(ax.viewLim, ax.transScale))  + \
         ax.transScale.inverted()
    aff = mtransforms.Affine2D.from_values(1,m,0,0,0,y0)
    trinv = ax.transData
    line = plt.Line2D([0,1],[0,0],transform=tr+aff+trinv, **kwargs)
    ax.add_line(line)

x = np.random.rand(20)*6-0.7
y = (np.random.rand(20)-.5)*4
c = (x > 3).astype(int)

fig, ax = plt.subplots()
ax.scatter(x,y, c=c, cmap="bwr")

# draw y=m*x+y0 into the plot
m = 0.4; y0 = -1
axaline(m,y0, ax=ax, color="limegreen", linewidth=5)

plt.show()
Run Code Online (Sandbox Code Playgroud)

在此处输入图片说明

虽然此解决方案乍看之下似乎有些复杂,但并不需要完全理解它。只需将axaline函数复制到您的代码中并按原样使用即可。


为了使自动更新在不执行转换的情况下工作,可以添加回调,每当绘图中发生某些更改时,回调都会重置转换。

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import transforms

class axaline():
    def __init__(self, m,y0, ax=None, **kwargs):
        if not ax: ax = plt.gca()
        self.ax = ax
        self.aff = transforms.Affine2D.from_values(1,m,0,0,0,y0)
        self.line = plt.Line2D([0,1],[0,0], **kwargs)
        self.update()
        self.ax.add_line(self.line)
        self.ax.callbacks.connect('xlim_changed', self.update)
        self.ax.callbacks.connect('ylim_changed', self.update)

    def update(self, evt=None):
        tr = ax.transAxes - ax.transData
        trinv = ax.transData
        self.line.set_transform(tr+self.aff+trinv)

x = np.random.rand(20)*6-0.7
y = (np.random.rand(20)-.5)*4
c = (x > 3).astype(int)

fig, ax = plt.subplots()
ax.scatter(x,y, c=c, cmap="bwr")

# draw y=m*x+y0 into the plot
m = 0.4; y0 = -1
al = axaline(m,y0, ax=ax, color="limegreen", linewidth=5)

plt.show()
Run Code Online (Sandbox Code Playgroud)

  • ...相当大锤...不错 (2认同)