行星轨道动画问题:多窗口、图片不显示及Hover功能失效求助
行星轨道动画开发问题及解决方案
问题描述
- 输入年份后弹出多个图表窗口,仅需保留一个动画窗口;
- 行星轨道显示正常,但行星图片无法在对应轨道位置显示(已验证图片路径并通过PIL调整尺寸);
- 自定义hover交互函数未触发。
修正后的完整代码
import numpy as np import matplotlib.pyplot as plt import matplotlib.animation as animation from astropy.time import Time from astropy.coordinates import solar_system_ephemeris, get_body_barycentric from astropy.coordinates import CartesianRepresentation from astropy import units as u from PIL import Image import mplcursors def compute_positions_and_orbits(year): positions = {} orbits = {} start_time = Time(f'{year}-01-01', scale='utc') end_time = start_time + 365 * u.day # 模拟一年的数据 with solar_system_ephemeris.set('builtin'): planets = ['mercury', 'venus', 'earth', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune'] for planet_name in planets: times = Time(np.linspace(start_time.jd, end_time.jd, 1000), format='jd') planet = get_body_barycentric(planet_name, times) coords = planet.represent_as(CartesianRepresentation).xyz.value positions[planet_name] = coords orbits[planet_name] = coords return positions, orbits def update(frame, current_year, positions, orbits, planet_images, planet_sizes): ax = plt.gca() ax.clear() ax.set_xlabel('X (AU)') ax.set_ylabel('Y (AU)') ax.set_title(f'Planetary Orbits and Positions in {current_year}') ax.set_facecolor('black') # 存储行星图片的艺术家对象,用于hover识别 planet_artists = {} for planet_name, orbit in orbits.items(): x_orbit, y_orbit, _ = orbit x_pos, y_pos, _ = positions[planet_name] # 绘制轨道 ax.plot(x_orbit, y_orbit, color='white', alpha=0.3) # 绘制行星图片 img = planet_images[planet_name] size = planet_sizes[planet_name] extent = (x_pos[frame] - size, x_pos[frame] + size, y_pos[frame] - size, y_pos[frame] + size) artist = ax.imshow(img, extent=extent, alpha=0.8, origin='lower') planet_artists[artist] = planet_name # 设置坐标轴比例和范围 ax.set_aspect('equal') ax.set_xlim(-50, 50) ax.set_ylim(-50, 50) return planet_artists.values() def display_zoomed_image(planet_name, planet_image): print(f"Hovering over planet: {planet_name}") fig, ax = plt.subplots(figsize=(4,4)) ax.imshow(planet_image, origin='lower') ax.set_title(planet_name) ax.axis('off') plt.show() def animate(year): positions, orbits = compute_positions_and_orbits(year) num_frames = len(next(iter(positions.values()))[0]) # 提前加载并调整行星图片,避免每次update重复加载 planet_image_paths = { 'mercury': r"C:\Users\Dell\Desktop\planet imgs\mercury.jpeg", 'venus': r"C:\Users\Dell\Desktop\planet imgs\venus.jpeg", 'earth': r"C:\Users\Dell\Desktop\planet imgs\earth.jpeg", 'mars': r"C:\Users\Dell\Desktop\planet imgs\mars.jpeg", 'jupiter': r"C:\Users\Dell\Desktop\planet imgs\jupiter.png", # 修正拼写错误 'saturn': r"C:\Users\Dell\Desktop\planet imgs\saturn.png", 'uranus': r"C:\Users\Dell\Desktop\planet imgs\uranus.jpeg", 'neptune': r"C:\Users\Dell\Desktop\planet imgs\neptune.jpg" } # 根据行星实际大小设置显示尺寸(AU单位) planet_sizes = { 'mercury': 0.2, 'venus': 0.3, 'earth': 0.3, 'mars': 0.25, 'jupiter': 1.0, 'saturn': 0.8, 'uranus': 0.5, 'neptune': 0.5 } planet_images = {} for name, path in planet_image_paths.items(): img = Image.open(path) # 调整为正方形,避免拉伸 img = img.resize((200, 200)) planet_images[name] = img fig = plt.figure(figsize=(10, 10)) ax = fig.add_subplot(111) # 初始化动画 ani = animation.FuncAnimation(fig, update, frames=num_frames, fargs=(year, positions, orbits, planet_images, planet_sizes), interval=50, repeat=False) # 设置hover交互,只初始化一次 def on_hover(event): # 检查hover的对象是否是行星图片 if hasattr(event.target, '_extent'): # 匹配对应的行星名称 for artist, name in planet_images.items(): if event.target == artist: display_zoomed_image(name, planet_images[name]) break mplcursors.cursor(ax, hover=True).connect("add", on_hover) plt.show() def main(): while True: year_input = input("Enter a year between 1900 and 2040: ") try: year = int(year_input) if 1900 <= year <= 2040: animate(year) break else: print("Invalid year. Please enter a year between 1900 and 2040.") except ValueError: print("Invalid input. Please enter a valid year.") if __name__ == "__main__": main()
问题修复细节
1. 多窗口弹出问题
- 原因:
update函数中每次调用plt.show(),与FuncAnimation自身的窗口渲染重复触发;原代码中未使用的第三方模块(transformers、tensorflow、spacy)会造成不必要的资源加载。 - 修复:删除
update函数内的plt.show(),仅保留animate函数末尾的一次调用;移除未使用的冗余模块。
2. 行星图片不显示问题
- 原因:
plt.imshow默认origin='upper',与轨道坐标系(Y轴向上)不匹配;- 原代码在
update中重复加载图片,性能低下且易引发渲染异常; - 木星图片路径拼写错误(
jupyter.png应为jupiter.png); - 图片尺寸与显示范围不匹配,导致图片超出可视区域。
- 修复:
- 提前加载所有行星图片并调整为统一正方形尺寸;
imshow添加origin='lower'参数,匹配轨道坐标系;- 修正木星路径拼写错误;
- 为不同行星设置对应显示尺寸(AU单位),确保图片在轨道位置可见。
3. Hover交互未触发问题
- 原因:
- 原代码在
update中每次重新创建mplcursors.cursor,plt.cla()会清除所有交互事件; on_hover函数未正确识别hover的行星对象,硬编码为Earth。
- 原代码在
- 修复:
- 将cursor初始化和事件连接移到
animate函数中,仅执行一次; - 修改
on_hover函数,通过event.target识别行星图片对象,匹配对应的行星名称; - 调整
display_zoomed_image函数,直接使用提前加载的PIL图片对象。
- 将cursor初始化和事件连接移到
内容的提问来源于stack exchange,提问作者Shades05
相关产品推荐
相关产品推荐

