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

如何解决Celluloid库椭圆轨迹动画在Jupyter Notebook中运行报错的问题

解决Celluloid椭圆动画在Jupyter Notebook中的运行问题

我帮你排查了这个问题,主要是Jupyter Notebook和Sublime Text在Matplotlib动画渲染逻辑上的差异,再加上代码里的几个小细节没适配Jupyter的环境,导致报错。下面是具体的问题分析和修正方案:

核心问题点

  • Matplotlib后端不兼容:Jupyter默认用的inline后端只能静态显示图片,不支持Celluloid需要的交互式动画渲染。
  • 图像数据类型错误:你用np.ones()创建的img是float类型,但后续设置的RGB值是0-255的整数,超出了float数组的0-1正常范围,会导致渲染异常。
  • 动画显示方式不对:Jupyter里直接用plt.show()无法正确加载Celluloid生成的动画,需要用IPython的HTML展示方法。

修正后的完整代码

# 切换Jupyter的Matplotlib后端,支持动画
%matplotlib notebook
import math
import numpy as np
import matplotlib.pyplot as plt
from celluloid import Camera
import copy
from IPython.display import HTML

# 改为uint8类型,初始化白色背景(255,255,255)
img = np.ones((90,60,3), dtype=np.uint8) * 255
fig = plt.figure(figsize=(10,8), dpi=100, facecolor='w')
camera = Camera(fig)

quarterCircleOne = []
quarterCircleTwoHalfOne = []
quarterCircleTwoHalfTwo = []
quarterCircleThree = []
quarterCircleFourHalfOne = []
quarterCircleFourHalfTwo = []

xc = 45
yc = 30
rx = 25
ry = 15

def GenerateElipse(xc,yc,rx,ry):
    # 修正:uint8数组赋值要符合0-255范围
    img[xc, yc] = (255,0,0)
    img[xc+1, yc] = (255,0,0)
    img[xc-1, yc] = (255,0,0)
    img[xc, yc+1] = (255,0,0)
    img[xc, yc-1] = (255,0,0)
    xk = 0
    yk = ry
    pk = ry**2 - rx**2 * ry + 1/4 * rx**2
    while ry**2 * xk < rx**2 * yk:
        if pk>0:
            xk = xk+1
            yk = yk-1
            pk = pk + 2 * ry**2 * xk + ry**2 - 2 * rx**2 * yk
        else:
            xk = xk+1
            pk = pk + 2 * ry**2 * xk + ry**2
        img[xc+xk, yc+yk] = (0,0,0)
        img[xc+xk, yc-yk] = (0,0,0)
        img[xc-xk, yc+yk] = (0,0,0)
        img[xc-xk, yc-yk] = (0,0,0)
        quarterCircleOne.append([xc-xk, yc-yk])
        quarterCircleTwoHalfTwo.append([xc-xk, yc+yk])
        quarterCircleThree.append([xc+xk, yc+yk])
        quarterCircleFourHalfOne.append([xc+xk, yc-yk])
    pk = ry**2 * (xk - 1/2)**2 + rx**2 * (yk - 1)**2 - rx**2 * ry**2
    while yk>0:
        if pk>0:
            yk = yk-1
            pk = pk - 2 * rx**2 * yk + rx**2
        else:
            xk = xk+1
            yk = yk-1
            pk = pk - 2 * rx**2 * yk + 2 * ry**2 * xk + rx**2
        img[xc+xk, yc+yk] = (0,0,0)
        img[xc+xk, yc-yk] = (0,0,0)
        img[xc-xk, yc+yk] = (0,0,0)
        img[xc-xk, yc-yk] = (0,0,0)
        quarterCircleOne.append([xc-xk, yc-yk])
        quarterCircleTwoHalfOne.append([xc-xk, yc+yk])
        quarterCircleThree.append([xc+xk, yc+yk])
        quarterCircleFourHalfTwo.append([xc+xk, yc-yk])

GenerateElipse(45, 30, 25, 15)

def DrawElipse(speed, img):
    sortedQuarterCircleOne = sorted(quarterCircleOne, key=lambda x: x[1])
    sortedQuarterCircleTwoHalfOne = sorted(quarterCircleTwoHalfOne, key=lambda x: x[1])
    sortedQuarterCircleTwoHalfTwo = sorted(quarterCircleTwoHalfTwo, key=lambda x: x[0])
    sortedQuarterCircleThree = sorted(quarterCircleThree, key=lambda x: x[1], reverse=True)
    sortedQuarterCircleFourHalfTwo = sorted(quarterCircleFourHalfTwo, key=lambda x: x[1], reverse=True)
    sortedQuarterCircleFourHalfOne = sorted(quarterCircleFourHalfOne, key=lambda x: x[0], reverse=True)
    circle = [sortedQuarterCircleOne, sortedQuarterCircleTwoHalfOne, sortedQuarterCircleTwoHalfTwo, sortedQuarterCircleThree, sortedQuarterCircleFourHalfTwo, sortedQuarterCircleFourHalfOne]
    i = 0
    for x in range(0, 6):
        for coordinates in circle[x]:
            freshImage = copy.deepcopy(img)
            freshImage[coordinates[0], coordinates[1]] = (0,0,0)
            freshImage[coordinates[0], coordinates[1]+1] = (255,0,0)
            freshImage[coordinates[0], coordinates[1]-1] = (255,0,0)
            freshImage[coordinates[0]+1, coordinates[1]-1] = (0,0,255)
            freshImage[coordinates[0]+1, coordinates[1]+1] = (0,0,255)
            freshImage[coordinates[0]+1, coordinates[1]] = (255,0,0)
            freshImage[coordinates[0]-1, coordinates[1]-1] = (0,0,255)
            freshImage[coordinates[0]-1, coordinates[1]+1] = (0,0,255)
            freshImage[coordinates[0]-1, coordinates[1]] = (255,0,0)
            if i % speed == 0:
                # 添加vmin和vmax确保颜色正确映射
                plt.imshow(freshImage, vmin=0, vmax=255)
                camera.snap()
            i = i + 1

DrawElipse(1, img)
animation = camera.animate()

# Jupyter中用HTML展示动画,替代plt.show()
HTML(animation.to_html5_video())

关键修改说明

  1. 后端切换:开头添加%matplotlib notebook(Jupyter Notebook)或%matplotlib widget(Jupyter Lab),让Matplotlib使用支持动画的交互式后端。
  2. 图像类型修正:将img定义为uint8类型并初始化为255(白色),匹配后续设置的0-255 RGB值范围,避免渲染时的数值异常。
  3. 动画展示方式:用IPython.display.HTML将动画转为HTML5视频格式,这是Jupyter中展示Celluloid动画的标准方式,替代原生的plt.show()。
  4. imshow参数优化:添加vmin=0, vmax=255确保Matplotlib正确解析RGB数值,避免颜色失真。

如果运行时提示缺少依赖(比如ffmpeg),可以通过pip install ffmpeg-python安装,这是生成HTML5视频需要的工具。

内容的提问来源于stack exchange,提问作者Nadīna Tarnovska

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 04:32:46