2025-08-30

# databar.py (仅列出与原文件不同或新增的部分)

from manimimport *

import pandasas pd

import math

font1 ="Bodoni MT"

font2 ="KaiTi"

MAX_BAR_LENGTH =12        # 你要求的“最大只能为12”

# 前面的读取 Excel、配置画布大小等保持不变

# ──────────────────────────────────────────────────────────────

excel_path ="data.xlsx"

df0 = pd.read_excel(excel_path)# 仅做尺寸计算

data_cols = df0.shape[1] -1

if data_cols <=10:

config.frame_width =16

    config.frame_height =10

else:

config.frame_width =16

    config.frame_height =10 + (data_cols -10)

config.pixel_width = config.frame_width *60 *1

config.pixel_height = config.frame_height *60 *1

class DataBar(ThreeDScene):

#  ───── 创建单根柱子─────

    #  现在返回(len_tracker, value_tracker)

    def make_bar(self, top_buff, init_len, init_val,

label_text="", bar_color=RED):

len_tracker  = ValueTracker(init_len)# 显示长度

        value_tracker = ValueTracker(init_val)# 真实数值

        # 1. 柱体

        bar = always_redraw(

lambda: Cube(side_length=1,

fill_color  = bar_color,

fill_opacity=1,

stroke_width=1,

stroke_color=WHITE

)

.scale([len_tracker.get_value(),0.4,0.4])# 只用长度tracker

            .to_edge(LEFT,buff=2)

.to_edge(UP,buff=top_buff)

)

# 2. 数字(用 value_tracker)

        number = always_redraw(

lambda: DecimalNumber(value_tracker.get_value(),

num_decimal_places=2,

color=WHITE,

font_size=28

                                  ).next_to(bar, RIGHT,buff=0.2)

)

# 3. 标签

        label = Text(label_text,color=WHITE,font_size=32,font=font2)

label.add_updater(lambda m: m.next_to(bar, LEFT,buff=0.2)

.align_to(bar, UP))

self.add(bar, number, label)

return len_tracker, value_tracker

#  ───── construct ─────

    def construct(self):

# 1) 背景(可选)

        bg = ImageMobject("image/bg.png")

bg.set_z_index(-10)

self.add(bg)

# 2) 读取真正用于动画的Excel

        df = pd.read_excel(excel_path)

date_list    = df.iloc[:,0].astype(str).tolist()

numeric_part = df.iloc[:,1:]

bar_names    = numeric_part.columns.tolist()

nums_sets    = [numeric_part[c].tolist()for cin bar_names]

n_bars  =len(bar_names)

n_frames =len(df)

palette = [RED, GOLD, GREEN, BLUE, PINK, PURPLE,

ORANGE, MAROON_B, TEAL, YELLOW]

palette = (palette * math.ceil(n_bars /len(palette)))[:n_bars]

# 0. 先算第 0 帧的缩放

        frame0_max =max(s[0]for sin nums_sets)

scale0    = MAX_BAR_LENGTH / frame0_maxif frame0_max !=0 else 1

        # 1. 创建柱子

        len_trs, val_trs = [], []

for iin range(n_bars):

top_buff  =1.5 +0.8 * i

len0      = nums_sets[i][0] * scale0

init_value = nums_sets[i][0]

lt, vt =self.make_bar(top_buff, len0, init_value,

label_text=bar_names[i],

bar_color=palette[i])

len_trs.append(lt)

val_trs.append(vt)

# 2. 右上角日期

        date_mobj = Text(date_list[0],color=YELLOW,

font_size=40,font=font1).to_edge(UR,buff=0.5)

self.add(date_mobj)

# 3. 逐帧播放

        for stepin range(1, n_frames):

frame_max =max(nums_sets[k][step]for kin range(n_bars))

scale    = MAX_BAR_LENGTH / frame_maxif frame_max !=0 else 1

            bar_len_anims = [

len_trs[k].animate.set_value(nums_sets[k][step] * scale)

for kin range(n_bars)

]

bar_val_anims = [

val_trs[k].animate.set_value(nums_sets[k][step])

for kin range(n_bars)

]

# 日期瞬时替换

            new_date = Text(date_list[step],color=YELLOW,

font_size=40,font=font1).to_edge(UR,buff=0.5)

date_mobj.become(new_date)

self.play(*(bar_len_anims + bar_val_anims),

run_time=2,rate_func=linear)

self.wait(0.5)

# manim -pql caogao.py DataBar

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容