Python 如何在没有溢出的情况下通过散点图绘制直线

Python 如何在没有溢出的情况下通过散点图绘制直线,python,matplotlib,Python,Matplotlib,因此,我目前正在绘制一个散点图,其中包含matplotlib中的许多x和ys: plt.scatter(x, y) 我想在这个散点图上画一条线,穿过整个图(即击中两个“边界”),我知道梯度和截距-m和方程y=mx+c中的c 我曾考虑过获取绘图的4个点(计算最小和最大散射x和ys),并从中计算直线的最小和最大坐标,然后绘图,但这似乎非常复杂。有没有更好的方法来做到这一点,记住这条线甚至可能不在“绘图”中 散点图示例: 如图中所示,四个边界坐标为: 左下角:-1,-2 左上角:-1,2 右下

因此,我目前正在绘制一个散点图,其中包含matplotlib中的许多
x
y
s:

plt.scatter(x, y)
我想在这个散点图上画一条线,穿过整个图(即击中两个“边界”),我知道梯度和截距-
m
和方程
y=mx+c
中的
c

我曾考虑过获取绘图的4个点(计算最小和最大散射
x
y
s),并从中计算直线的最小和最大坐标,然后绘图,但这似乎非常复杂。有没有更好的方法来做到这一点,记住这条线甚至可能不在“绘图”中


散点图示例:

如图中所示,四个边界坐标为:

  • 左下角:
    -1,-2
  • 左上角:
    -1,2
  • 右下角:
    6,-2
  • 右上角
    6,2
我现在有一条线,我需要绘制,不能超过这些边界,但如果它进入绘图,必须接触两个边界点

所以当x=-1时,我可以检查y等于什么,然后检查该值是否在-1和6之间,如果是,那么直线必须穿过左边界,绘制它,依此类推


理想情况下,我会创建一条从-infinity到infinity的直线,然后裁剪它以适合绘图。

您可以尝试:

import matplotlib.pyplot as plt
import numpy as np

m=3
c=-2
x1Data= np.random.normal(scale=2, loc=.4, size=25)
y1Data= np.random.normal(scale=3, loc=1.2, size=25)
x2Data= np.random.normal(scale=1, loc=3.4, size=25)
y2Data= np.random.normal(scale=.65, loc=-.2, size=25)

fig = plt.figure()
ax = fig.add_subplot( 1, 1, 1 )
ax.scatter(x1Data, y1Data)
ax.scatter(x2Data, y2Data)
ylim = ax.get_ylim()
xlim = ax.get_xlim()
ax.plot( xlim, [ m * x + c for x in xlim ], 'r:' )
ax.set_ylim( ylim )
ax.set_xlim( xlim )
plt.show()
其中:


这里的想法是在绘图中画一条等式
y=m*x+y0
。这可以通过将最初在轴坐标中给出的水平线转换为数据坐标、根据直线方程应用仿射2D转换并转换回屏幕坐标来实现

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

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

虽然这个解决方案乍一看有点复杂,但人们不需要完全理解它。只需将
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()

我不完全明白你的意思。您是否可以创建一个图像,并可能包括所需输出的图像?是的。对不起,我会上车的it@DavidG你现在明白了吗?如果你知道这条线的方程式,你不能为
x
指定宽点吗,那就得到相应的
y
。然后使用
plt.plot()
进行绘图,并将轴限制设置为“裁剪”直线?…这就是想法..检查。get_ylim和set_ylim不应
xlim=ax.get_ylim()
be
xlim=ax.get_xlim()
?另外,请注意,如果在
ax.plot
命令中设置
scalex=False,scaley=False
,则不需要重新设置x和ylimits@tom关于第一条评论:是的,我改变了。。。(解释为什么图像在数据中实际上是正方形,…ups)关于第二条注释:
ax.set\u autoscale\u on(False)
之前,绘图会很好…相当大的一把锤子…很好,人们可以美化我的快速和肮脏版本,使其成为类似于您的
axaline
的函数,包括
**kwargs
等。平移效果可能不太重要。但我的方法最终可能失败的地方是在之后绘制第三个数据集在这种情况下,你的解决方案可能会派上用场。@mikuszefski理论上是的,但实际上不是,因为它没有像目前那样工作。变换的反转似乎有问题,需要在所有其他元素之后绘制这条线(这当然是不需要的).仍在研究中。是的..刚刚尝试了这个,但不幸的是没有,既没有pan也没有其他数据…期待有效的解决方案…我还可以提到你的斜率
m
似乎是
0.5
,而不是
2
…和截距。。。?