【问题标题】:Matplotlib clearing old axis labels when re-plotting dataMatplotlib 在重新绘制数据时清除旧的轴标签
【发布时间】:2021-07-07 23:45:08
【问题描述】:

我有一个脚本,其中我有两个函数,makeplots() 以特定方式排列空白子图(取决于要绘制的子图的数量),drawplots() 稍后调用,绘制图(显然)。函数贴在下面。

脚本对给定数量的“目标”(可以从 1 到 9 的任意数量)进行一些数据分析,并为每个目标创建线性回归图。当有多个目标时,这很有效。但是当有单个目标时(即图中的单个“子图”),Y 轴标签会与轴本身重叠(当有多个目标时不会发生这种情况)。

理想情况下,每个子图都是正方形的,没有标签重叠,并且对于一个目标和多个目标的工作方式相同。但是当我尝试减小 y 轴标签的大小并将其移动一点时,实际轴对象似乎是在 之前的空白方形图上绘制的(其轴范围从 0到 1),旧的刻度线标签仍然可见。我想在调用drawplots() 时删除那些旧的刻度线。我尝试更改makeplots 中的subplot_kw={} 参数,以及从drawplots 中删除ax.set_aspect('auto'),均无济于事。请注意,最后还有各种行为的屏幕截图。

def makeplots(targets, active=actwindow):

    def rowcnt(y):
        rownumb = y//3 if (y%3 == 0) else y//3+1
        return rownumb

    def colcnt(x):
        if x <= 3: colnumb = x
        elif x == 4: colnumb = 2
        else: colnumb = 3
        return colnumb

    numsubs = len(targets)
    numrow, numcol = rowcnt(numsubs), colcnt(numsubs)

    if numsubs >= 1:
        if numsubs == 1:
            fig, axs = plt.subplots(num='LOD-95 Plots', nrows=1, ncols=1, figsize = [8,6], subplot_kw={'adjustable': 'box', 'aspect': 1})
            # changed 'box' to 'datalim'
        fig, axs = plt.subplots(num='LOD-95 Plots', nrows=numrow, ncols=numcol, figsize = [numcol*6,numrow*6], subplot_kw={'adjustable': 'box', 'aspect': 1})
        fig.text(0.02, 0.5, 'Probit score\n    $(\sigma + 5)$', va='center', rotation='vertical', size='16')
    else:
        raise ValueError(f'Error generating plots [call: makeplots({targets},{active}) - invalid numsubs value]')

    axs = np.ravel(axs)
    for i, ax in enumerate(axs):
        ax.set_title(f'Limit of Detection: {targets[i]}', size=11)
        ax.grid()
    return fig, axs

def drawplots(ax, dftables, color1, color2):
    y = dftables.probit
    y95 = 6.6448536269514722
    logreg = False
    regfun = lambda m, x, b : (m*x) + b
    regq = scipy.stats.linregress(dftables.qty,y)
    regl = scipy.stats.linregress(dftables.log_qty,y)
    if regq.rvalue**2 >= regl.rvalue**2:
        regression = regq
        x_label = 'input quantity'
        x = dftables.qty
    elif regq.rvalue**2 < regl.rvalue**2:
        regression = regl
        x_label = '$log_{10}$(input quantity)'
        x = dftables.log_qty
        logreg = True
    slope, intercept, r = regression.slope, regression.intercept, regression.rvalue
    r2 = r**2
    lod = (y95-intercept)/slope
    xr = [0, lod*1.2]
    yr = [intercept, regfun(slope, xr[1], intercept)]
    regeqn = "y = "+str(f"{slope:.2e}")+"x + "+str(f"{intercept:.3f}")

    if logreg:
        lodstr = f'log(LOD) = {lod:.2f}' if lod <= 100 else f'log(LOD) = {lod:.2e}'
    elif not logreg:
        lodstr = f'LOD = {lod:.2f}' if lod <= 100 else f'LOD = {lod:.2e}'
#        raise ValueError(f'Error raised calling drawplots()')


    ax.set_xlabel(x_label, fontweight='bold')
    ax.plot(xr, yr, color=color1, linestyle='--') # plot regression line
    ax.plot(lod, y95, marker='D', color=color2, markersize=7) # plot point for LoD
    ax.plot(xr, [y95,y95], color=color2, linestyle=':') # horizontal crosshair
    ax.plot([lod,lod],[0, 7.1], color=color2, linestyle=':') # vertical crosshair
    ax.scatter(x, y, s=81, color=color1, marker='.') # actual data points
    ax.annotate(f"{lodstr}", xy=(lod,0.1),
                xytext=(0.9*lod,0.5), fontsize=8, arrowprops = dict(facecolor='black', headlength=5, width=2, headwidth=5))
    ax.set_aspect('auto')
    ax.set_xlim(left=0)
    ax.set_ylim(bottom=0)
    ax.plot()
    if logreg: lod = 10 ** lod

    return r2, lod, regeqn, logreg

调用它们的上下文:

fig, axs = makeplots(targets)
wg.SetForegroundWindow(actwindow)

with open(outName, 'a+') as f:
    print(f"Lower Limit of Detection Analysis on {dt} at {tm}\n", file=f)
    for i, tars in enumerate(targets):
        data[tars] = stripThousands(data[tars])
#        logans = checkyn(f"Analyze {tars} using log10(concentration/quantity)? (y/n): ")
        for idx, val in enumerate(qtys):
            tables[i,idx,2] = hitrate(val,data,tars)
            tables[i,idx,3] = norm.ppf(tables[i,idx,2])+5

        printtables[tars] = pd.DataFrame(tables[i,:,:], columns=["qty","log_qty","probability","probit"])
        # construct dataframes from np.arrays and drop
        #     rows with infinite probit values:
        dftables[tars] = pd.DataFrame(tables[i,:,:], columns=["qty","log_qty","probability","probit"])
        dftables[tars].probit.replace([np.inf,-np.inf],np.nan, inplace=True)
        dftables[tars].dropna(inplace=True)


        r2, lod, eqn, logreg = drawplots(axs[i], dftables[tars], cbcolors[i], cbcolors[i+5])

【问题讨论】:

    标签: python pandas matplotlib


    【解决方案1】:

    您应该在每次迭代中使用 pyplot.cla() 清除坐标区。

    您发布了很多代码,因此我不能 100% 确定将其放置在您的代码中的最佳位置,但总体思路是在每个新绘图之前清除轴。

    这是一个没有cla()的最小演示:

    x = [[1,2,3], [3,2,1]]
    
    fig, ax = plt.subplots()
    for index, data in enumerate(x):
        ax.plot(data)
    

    还有cla():

    for index, data in enumerate(x):
        ax.cla()
        ax.plot(data)
    

    【讨论】:

    • 抱歉,这是一个非常长的脚本,所以我尽量减少它,同时仍然提供必要的信息。基本上,首先调用drawplots(targets)targets 只是作为要绘制的每个图形的 y 值的列标题的列表),并生成一个空白图形,其中包含正确配置的空白子图/轴。然后对每个数据集/“目标”列进行一些计算,并迭代调用 drawplots 以绘制每个图形。这是使布局正确的最简单方法,但初始图无关紧要。我会试试 cla()!
    • 嗯,没有骰子。问题是,在调用drawplots() 之前,我不知道x 限制是多少,所以在调用makeplots() 时,基本正方形图(两个轴从0 到1,每0.2 个单位带有刻度线)。 y 轴永远不会超过 8,所以我可以手动设置,但 x 轴的范围可以从 0 到 1.4 或从 0 到 100,000。我将 ax.cla() 卡在 ax.set_xlabel(x_label, fontweight='bold') 之前的 drawplots() def 中(drawplots() 中 Axes 对象的第一次操作),但该图看起来仍然与 OP 中三个绘图图像中的第二个相同/跨度>
    猜你喜欢
    • 2012-08-03
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    • 2016-02-14
    • 2022-01-18
    相关资源
    最近更新 更多