You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

plt.fill无法覆盖已有绘图及多图保留前置绘图问题求助

解决Matplotlib绘图遮挡与迭代图像生成问题

问题描述

我需要迭代生成多张图像,仅保留30度视角范围内的内容,其余区域用遮挡层覆盖。当前代码存在两个问题:

  • plt.fill绘制的遮挡层无法覆盖图中的蓝色和黑色线条
  • 前置绘制的蓝色线条未出现在所有输出图像中

原代码

import matplotlib.pyplot as plt
import numpy as np 

# number of interior walls 
intwallnum = 3 

# room 
x= np.linspace(1, 22, 100)
y = np.linspace(1, 20, 100)

#plt.plot(x, y, 'w')

#interior walls case 1 
x1 = 8
x2 = 13  

y1 = 5
y2 = 10
y3 = 18

numpoints = 50 

w1 = np.linspace(x1, x2, numpoints)

xlist = [x1, x2]
ylist = [y1, y2, y3]

y1list = np.zeros(numpoints)
y2list = np.zeros(numpoints)
y3list = np.zeros(numpoints)

for i in np.arange(numpoints):
  y1list[i] = y1
  y2list[i] = y2
  y3list[i] = y3

plt.plot(w1, y1list, 'k', linewidth = 3)
plt.plot(w1, y2list, 'k', linewidth = 3)
plt.plot(w1, y3list, 'k', linewidth = 3)

#lines of view
cam1 = [0, 20]
cam2 = [22, 0]

# adjusted to apply with this prob specifically 
def eq(xpoint, ypoint, cam):
  m = (cam[1] - ypoint)/(cam[0] - xpoint)
  b = cam[1] - m*cam[0] 
  y = m*np.linspace(0,22,22) + b 
  return y

def eq2(xpoint, ypoint, cam):
  m = (cam[1] - ypoint)/(cam[0] - xpoint)
  b = cam[1] - m*cam[0] 
  y = m*np.linspace(0,22,22) + b 
  return [m, b]

fill_listx = []
fill_listy = []

fill_listx1 = []
fill_listy1 = []

#https://www.geeksforgeeks.org/remove-elements-larger-than-a-specific-value-from-a-list-in-python/
for a in np.arange(len(xlist)*len(ylist)):   
  for j in np.arange(len(ylist)):
    for i in np.arange(len(xlist)):
      
      #plt.plot(np.linspace(0, 22, 22), eq(xlist[i], ylist[j], cam1), 'r', linewidth=1.)
      plt.plot(np.linspace(0, 22, 22), eq(xlist[i], ylist[j], cam2), 'b', linewidth=1.)
     
      if eq2(xlist[i], ylist[j], cam2)[1] >= 20:
        ptx = (20 - eq2(xlist[i], ylist[j], cam2)[1])/(eq2(xlist[i], ylist[j], cam2)[0])
      else:
        ptx = 0
      if eq2(xlist[i], ylist[j], cam2)[1] >= 20:
        pty = 20 
      else:
        pty = eq2(xlist[i], ylist[j], cam2)[1]     
      fill_listx = np.append(fill_listx, ptx)
      fill_listy = np.append(fill_listy, pty)

#camera 1 
      if eq2(xlist[i], ylist[j], cam1)[0]*(22)+eq2(xlist[i], ylist[j], cam1)[1] < 0:
        ptx = ( - eq2(xlist[i], ylist[j], cam1)[1])/(eq2(xlist[i], ylist[j], cam1)[0])
      else:
        ptx = 22
      if eq2(xlist[i], ylist[j], cam1)[0]*(22)+eq2(xlist[i], ylist[j], cam1)[1] >= 0:
        pty = (eq2(xlist[i], ylist[j], cam1)[0]*22+eq2(xlist[i], ylist[j], cam1)[1])
      else:
        pty = 0 
      fill_listx1 = np.append(fill_listx1, ptx)
      fill_listy1 = np.append(fill_listy1, pty)

for i in np.arange(intwallnum):
  y = ylist[i]
  
  if fill_listy[2*i+1] == fill_listx[2*i] or fill_listx[2*i] == fill_listx[2*i+1]: 
    filly = [fill_listy[2*i], fill_listy[2*i+1], ylist[i], ylist[i]] 
    fillx = [fill_listx[2*i], fill_listx[2*i+1], xlist[1], xlist[0]]
  else: 
    filly = [fill_listy[2*i],20, fill_listy[2*i+1], ylist[i], ylist[i]] 
    fillx = [fill_listx[2*i],0, fill_listx[2*i+1], xlist[1], xlist[0]]
  plt.fill(fillx, filly, facecolor='w',  alpha=1)

#camera 1   
for i in np.arange(intwallnum):
  y = ylist[i]

  if fill_listy1[2*i+1] == fill_listx1[2*i] or fill_listx1[2*i] == fill_listx1[2*i+1]: 
    filly1 = [fill_listy1[2*i], fill_listy1[2*i+1], ylist[i], ylist[i]] 
    fillx1 = [fill_listx1[2*i], fill_listx1[2*i+1], xlist[1], xlist[0]]
  else: 
    filly1 = [fill_listy1[2*i],0, fill_listy1[2*i+1], ylist[i], ylist[i]] 
    fillx1 = [fill_listx1[2*i],22, fill_listx1[2*i+1], xlist[1], xlist[0]]
  
  plt.fill(fillx1, filly1, facecolor='g', alpha=.75)

theta_deg = 15 
for i in np.arange(1, 90/theta_deg):
  angle = i*theta_deg
  x30 = np.linspace(0, 22, 22)
  y30 = -np.tan(angle*np.pi/180)*x30 + np.tan(angle*np.pi/180)*22

  y2 = -np.tan((angle+30)*np.pi/180)*x30 + np.tan((angle+30)*np.pi/180)*22


  if np.tan(angle*np.pi/180)*22 > 20: #y-intercept
    fillx = [22, 0, 0, (20 - np.tan(angle*np.pi/180)*22)/-np.tan(angle*np.pi/180)]
    filly = [0, 0, 22, 20]
    plt.fill(fillx, filly, facecolor='y', alpha=1)
    plt.plot(x30, y30, 'g','--')
  else: # Too lazy to code exception: line intesects (0, 20)
    fillx = [0, 22, 22, 0]
    filly = [20, 20, 0, np.tan(angle*np.pi/180)*22]
    plt.fill(fillx, filly, facecolor='y', alpha=1)
    plt.plot(x30, y30, 'g','--')

  #ax.set_facecolor("k")

  plt.xlim(0,22)  
  plt.ylim(0,20)
  plt.figure(figsize=(20, 22))

  plt.show()

问题原因分析

  1. 遮挡层无法覆盖线条:Matplotlib绘图元素按代码执行顺序叠加,先绘制的元素在底层,后绘制的在顶层。原代码先画黑色墙壁和蓝色视线,再绘制遮挡层,导致遮挡层在底层,无法覆盖上方的线条。
  2. 蓝色线条缺失:原代码中蓝色视线和墙壁仅在循环外绘制一次,后续迭代生成新图像时未重新绘制这些元素,因此只有第一张图有蓝色线条,后续图缺失。

修改后的代码

import matplotlib.pyplot as plt
import numpy as np 

# 室内墙壁数量
intwallnum = 3 

# 房间边界参数
x1_wall = 8
x2_wall = 13  
y_walls = [5, 10, 18]
numpoints = 50 
w1 = np.linspace(x1_wall, x2_wall, numpoints)

# 视线相机位置
cam1 = [0, 20]
cam2 = [22, 0]

# 计算视线方程
def eq(xpoint, ypoint, cam):
    m = (cam[1] - ypoint)/(cam[0] - xpoint)
    b = cam[1] - m*cam[0] 
    x_vals = np.linspace(0,22,22)
    y_vals = m * x_vals + b 
    return x_vals, y_vals

def eq2(xpoint, ypoint, cam):
    m = (cam[1] - ypoint)/(cam[0] - xpoint)
    b = cam[1] - m*cam[0] 
    return [m, b]

# 预计算遮挡区域的点(无需每次循环重复计算)
fill_listx = []
fill_listy = []
fill_listx1 = []
fill_listy1 = []

xlist = [x1_wall, x2_wall]
ylist = y_walls

for j in np.arange(len(ylist)):
    for i in np.arange(len(xlist)):
        # 计算cam2的遮挡点
        m, b = eq2(xlist[i], ylist[j], cam2)
        if b >= 20:
            ptx = (20 - b)/m
            pty = 20 
        else:
            ptx = 0
            pty = b     
        fill_listx.append(ptx)
        fill_listy.append(pty)

        # 计算cam1的遮挡点
        m1, b1 = eq2(xlist[i], ylist[j], cam1)
        if m1*22 + b1 < 0:
            ptx1 = (-b1)/m1
            pty1 = 0 
        else:
            ptx1 = 22
            pty1 = m1*22 + b1 
        fill_listx1.append(ptx1)
        fill_listy1.append(pty1)

# 迭代生成每张视角图像
theta_deg = 15 
for i in np.arange(1, int(90/theta_deg)):
    # 1. 新建画布
    plt.figure(figsize=(20, 22))
    
    # 2. 绘制基础元素:墙壁、蓝色视线
    # 绘制黑色墙壁
    for y in y_walls:
        y_list = np.full(numpoints, y)
        plt.plot(w1, y_list, 'k', linewidth=3)
    
    # 绘制蓝色视线
    for j in np.arange(len(ylist)):
        for i_x in np.arange(len(xlist)):
            x_vals, y_vals = eq(xlist[i_x], ylist[j], cam2)
            plt.plot(x_vals, y_vals, 'b', linewidth=1.)
    
    # 3. 绘制原有遮挡层(白色和绿色)
    # cam2的白色遮挡
    for idx in np.arange(intwallnum):
        y = ylist[idx]
        if fill_listy[2*idx+1] == fill_listx[2*idx] or fill_listx[2*idx] == fill_listx[2*idx+1]: 
            filly = [fill_listy[2*idx], fill_listy[2*idx+1], y, y] 
            fillx = [fill_listx[2*idx], fill_listx[2*idx+1], xlist[1], xlist[0]]
        else: 
            filly = [fill_listy[2*idx],20, fill_listy[2*idx+1], y, y] 
            fillx = [fill_listx[2*idx],0, fill_listx[2*idx+1], xlist[1], xlist[0]]
        plt.fill(fillx, filly, facecolor='w', alpha=1)
    
    # cam1的绿色遮挡
    for idx in np.arange(intwallnum):
        y = ylist[idx]
        if fill_listy1[2*idx+1] == fill_listx1[2*idx] or fill_listx1[2*idx] == fill_listx1[2*idx+1]: 
            filly1 = [fill_listy1[2*idx], fill_listy1[2*idx+1], y, y] 
            fillx1 = [fill_listx1[2*idx], fill_listx1[2*idx+1], xlist[1], xlist[0]]
        else: 
            filly1 = [fill_listy1[2*idx],0, fill_listy1[2*idx+1], y, y] 
            fillx1 = [fill_listx1[2*idx],22, fill_listx1[2*idx+1], xlist[1], xlist[0]]
        plt.fill(fillx1, filly1, facecolor='g', alpha=.75)
    
    # 4. 计算当前30度视角的边界,绘制黄色遮挡层(覆盖视角外区域)
    angle = i * theta_deg
    x30 = np.linspace(0, 22, 22)
    y30 = -np.tan(angle*np.pi/180)*x30 + np.tan(angle*np.pi/180)*22
    y30_upper = -np.tan((angle+30)*np.pi/180)*x30 + np.tan((angle+30)*np.pi/180)*22

    # 绘制视角边界线
    plt.plot(x30, y30, 'g', linestyle='--')
    plt.plot(x30, y30_upper, 'g', linestyle='--')
    
    # 绘制视角外的黄色遮挡层
    plt.fill_between(x30, 0, y30, facecolor='y', alpha=1)
    plt.fill_between(x30, y30_upper, 20, facecolor='y', alpha=1)
    
    # 设置坐标轴范围
    plt.xlim(0,22)  
    plt.ylim(0,20)
    
    # 显示当前图像
    plt.show()

关键改动说明

  1. 画布与元素绘制顺序:将新建画布的操作放到迭代循环最开始,每次迭代都创建新图;同时把墙壁、蓝色视线的绘制逻辑移到循环内部,确保每张图都包含这些基础元素。
  2. 遮挡层层级调整:所有基础元素绘制完成后,再绘制各类遮挡层(白色、绿色、黄色),保证遮挡层在元素上方,能够覆盖不需要显示的内容。
  3. 优化视角遮挡逻辑:改用fill_between更简洁地实现视角外区域的遮挡,避免原代码中手动构造多边形的复杂逻辑,同时确保遮挡区域完整覆盖视角外的线条。

内容的提问来源于stack exchange,提问作者user20678942

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 18:40:39