Änderungen von Dokument Animation Reaktionsgeschwindigkeit
Zuletzt geändert von Holger Engels am 2026/10/26 19:37
Von Version 4.1
bearbeitet von Holger Engels
am 2026/10/10 21:25
am 2026/10/10 21:25
Änderungskommentar:
Neuen Anhang ReaktionskinetikAnimation.mp4 hochladen
Auf Version 5.1
bearbeitet von Holger Engels
am 2026/10/10 21:26
am 2026/10/10 21:26
Änderungskommentar:
Löschung des Anhangs reaktionskinetik.py
Zusammenfassung
-
Anhänge (0 geändert, 0 hinzugefügt, 1 gelöscht)
Details
- reaktionskinetik.py
-
- Author
-
... ... @@ -1,1 +1,0 @@ 1 -xwiki:XWiki.holgerengels - Größe
-
... ... @@ -1,1 +1,0 @@ 1 -17.9 KB - Inhalt
-
... ... @@ -1,438 +1,0 @@ 1 -from manim import * 2 -import numpy as np 3 -from styles import * 4 - 5 -# ============================================================================= 6 -# 1. MATHEMATISCHES & CHEMISCHES MODELL 7 -# ============================================================================= 8 -# Eduktkonzentration: c(t) = c_0 * exp(-k * t) 9 -# c_0 = 1.0 mol/l 10 -# k = 0.00078 s^-1 11 -# t in [0, 4000] Sekunden 12 - 13 -C_0 = 1.0 14 -K_RATE = 0.00078 15 - 16 -def get_conc(t): 17 - """Konzentration des Edukts zum Zeitpunkt t in mol/l.""" 18 - return C_0 * np.exp(-K_RATE * t) 19 - 20 -def get_reaction_rate(t): 21 - """Betrag der momentanen Reaktionsgeschwindigkeit v(t) = |dc/dt| in mol/(l*s).""" 22 - return K_RATE * C_0 * np.exp(-K_RATE * t) 23 - 24 -def get_solution_color(c_val): 25 - """ 26 - Farbverlauf der Reaktionslösung im Erlenmeyerkolben: 27 - Tiefes Kristallviolett bei c=1.0 mol/l 28 - -> Hellviolett / Rosa bei c=0.5 mol/l 29 - -> Fast farblos / transparent-wässrig bei c->0. 30 - """ 31 - alpha = float(np.clip(c_val / 1.0, 0.0, 1.0)) 32 - c_start = ManimColor("#6A1B9A") # Tiefes Violett 33 - c_mid = ManimColor("#BA68C8") # Helles Rosa-Violett 34 - c_end = ManimColor("#E1BEE7") # Blasses, wässriges Violett 35 - 36 - if alpha > 0.4: 37 - return interpolate_color(c_mid, c_start, (alpha - 0.4) / 0.6) 38 - else: 39 - return interpolate_color(c_end, c_mid, alpha / 0.4) 40 - 41 -def get_solution_opacity(c_val): 42 - alpha = float(np.clip(c_val / 1.0, 0.0, 1.0)) 43 - return 0.20 + 0.70 * alpha 44 - 45 -# Farbcodierung analog zum Arbeitsblatt 46 -COLOR_DURCHSCHNITT = COLOR_INFLOW # #00E5FF (Cyan / Blau für Sekante / mittlere Änderungsrate) 47 -COLOR_MOMENTAN = COLOR_OUTFLOW # #FF5252 (Korallrot für Tangente / momentane Änderungsrate) 48 -COLOR_ANFANG = COLOR_EQUILIBRIUM # #26A69A (Grün für Anfangsgeschwindigkeit) 49 - 50 - 51 -def create_erlenmeyer(width=2.4, height=3.0): 52 - """ 53 - Erstellt einen detailreichen Erlenmeyerkolben mit Glaswand, 54 - Skalenstrichen und dynamischer Flüssigkeitsfüllung. 55 - """ 56 - neck_w = 0.60 57 - neck_h = 0.90 58 - base_w = width 59 - body_h = height - neck_h 60 - rim_w = 0.76 61 - rim_h = 0.10 62 - 63 - # Eckpunkte des Glaskörpers (konischer Rumpf) 64 - p_bl = np.array([-base_w/2, -body_h/2, 0]) 65 - p_br = np.array([ base_w/2, -body_h/2, 0]) 66 - p_tr = np.array([ neck_w/2, body_h/2, 0]) 67 - p_tl = np.array([-neck_w/2, body_h/2, 0]) 68 - 69 - body = Polygon( 70 - p_bl, p_br, p_tr, p_tl, 71 - stroke_color=WHITE, stroke_width=2.4, 72 - fill_color="#101422", fill_opacity=0.4 73 - ) 74 - 75 - neck = Rectangle( 76 - width=neck_w, height=neck_h, 77 - stroke_color=WHITE, stroke_width=2.4, 78 - fill_color="#101422", fill_opacity=0.4 79 - ).next_to(body, UP, buff=0) 80 - 81 - rim = RoundedRectangle( 82 - corner_radius=0.04, width=rim_w, height=rim_h, 83 - stroke_color=WHITE, stroke_width=1.8, 84 - fill_color="#1E2438", fill_opacity=0.9 85 - ).next_to(neck, UP, buff=0) 86 - 87 - # Skalenstriche auf dem Glas 88 - marks = VGroup() 89 - for dy in [-0.5, -0.15, 0.2]: 90 - m_line = Line([-neck_w*0.8, dy, 0], [-neck_w*0.4, dy, 0], stroke_color=GREY_A, stroke_width=1.4) 91 - marks.add(m_line) 92 - 93 - glass = VGroup(body, neck, rim, marks) 94 - 95 - # Flüssigkeits-Trapez (Füllstand ca. 72% der Rumpfhöhe) 96 - fill_ratio = 0.72 97 - y_liquid_top = -body_h/2 + body_h * fill_ratio 98 - top_w = base_w - (base_w - neck_w) * fill_ratio 99 - 100 - l_bl = np.array([-base_w/2 + 0.05, -body_h/2 + 0.05, 0]) 101 - l_br = np.array([ base_w/2 - 0.05, -body_h/2 + 0.05, 0]) 102 - l_tr = np.array([ top_w/2 - 0.03, y_liquid_top, 0]) 103 - l_tl = np.array([-top_w/2 + 0.03, y_liquid_top, 0]) 104 - 105 - liquid = Polygon( 106 - l_bl, l_br, l_tr, l_tl, 107 - stroke_width=0, fill_color=ManimColor("#6A1B9A"), fill_opacity=0.85 108 - ) 109 - 110 - meniscus = Line(l_tl, l_tr, stroke_color="#CE93D8", stroke_width=2.0) 111 - 112 - return VGroup(liquid, meniscus, glass), liquid, meniscus 113 - 114 - 115 -class ReaktionskinetikAnimation(Scene): 116 - def construct(self): 117 - self.camera.background_color = COLOR_BG 118 - 119 - # ------------------------------------------------------------- 120 - # 1. Schritt: Initialisierung 121 - # ------------------------------------------------------------- 122 - self.next_section("01_Initialisierung") 123 - 124 - formula_header = MathTex( 125 - r"\text{Reaktionsgeschwindigkeit: } v = \frac{|\Delta c|}{\Delta t}", 126 - font_size=FONT_SIZE_FORMULA, color=COLOR_STEP_LINE 127 - ).to_edge(UP, buff=0.15) 128 - 129 - self.play(Write(formula_header), run_time=0.8) 130 - 131 - # Erlenmeyerkolben links 132 - flask_group, liquid_poly, meniscus_line = create_erlenmeyer(width=2.4, height=3.0) 133 - flask_group.move_to([-4.6, -0.3, 0]) 134 - 135 - flask_title = Tex(r"\textbf{Reaktionsansatz}", font_size=16, color=WHITE).next_to(flask_group, UP, buff=0.18) 136 - c_label = Tex(r"$c(\text{Edukt}) = $", font_size=15, color=COLOR_TEXT_MUTED) 137 - c_num = DecimalNumber(1.0, num_decimal_places=2, unit=r"\,\text{mol/l}", font_size=15, color=WHITE) 138 - c_readout = VGroup(c_label, c_num).arrange(RIGHT, buff=0.06).next_to(flask_group, DOWN, buff=0.22) 139 - 140 - erlenmeyer_full = VGroup(flask_group, flask_title, c_readout) 141 - 142 - # Koordinatensystem rechts 143 - axes = Axes( 144 - x_range=[0, 4200, 500], 145 - y_range=[0, 1.25, 0.2], 146 - x_length=6.4, 147 - y_length=4.4, 148 - axis_config=AXIS_COMMON_CONFIG, 149 - x_axis_config=get_x_axis_config([500, 1000, 1500, 2000, 2500, 3000, 3500, 4000], font_size=14), 150 - y_axis_config=get_y_axis_config([0.2, 0.4, 0.6, 0.8, 1.0, 1.2], font_size=14) 151 - ).move_to([1.8, -0.35, 0]) 152 - 153 - y_label = Tex(r"Konzentration $c$ [$\text{mol}\cdot\text{l}^{-1}$]", font_size=15, color=COLOR_TEXT_PRIMARY).next_to( 154 - axes.y_axis.get_top(), UP, buff=0.10 155 - ).shift(RIGHT * 1.0) 156 - x_label = Tex(r"Zeit $t$ [$\text{s}$]", font_size=16, color=COLOR_TEXT_MUTED).next_to( 157 - axes.x_axis.get_end(), RIGHT, buff=0.15 158 - ) 159 - 160 - axes_group = VGroup(axes, x_label, y_label) 161 - 162 - self.play( 163 - FadeIn(erlenmeyer_full), 164 - Create(axes), Write(x_label), Write(y_label), 165 - run_time=1.2 166 - ) 167 - self.wait(0.4) 168 - 169 - # ------------------------------------------------------------- 170 - # 2. Schritt: Reaktion und Punkte .. am Ende erscheint die Näherungskurve 171 - # ------------------------------------------------------------- 172 - self.next_section("02_Reaktion_und_Messpunkte") 173 - 174 - np.random.seed(42) 175 - sample_times = np.arange(0, 4001, 250) 176 - noisy_concs = np.clip(get_conc(sample_times) + np.random.normal(0, 0.018, len(sample_times)), 0.02, 1.05) 177 - noisy_concs[0] = 1.00 178 - 179 - t_tracker = ValueTracker(0.0) 180 - 181 - # Updater für Flüssigkeitsfarbe & Konzentration 182 - liquid_poly.add_updater(lambda m: m.set_color(get_solution_color(get_conc(t_tracker.get_value()))).set_opacity(get_solution_opacity(get_conc(t_tracker.get_value())))) 183 - c_num.add_updater(lambda m: m.set_value(get_conc(t_tracker.get_value()))) 184 - 185 - # Punktwolke der Messwerte mit Rauschen 186 - noisy_dots = VGroup() 187 - for t_s, c_s in zip(sample_times, noisy_concs): 188 - dot = Dot(axes.c2p(t_s, c_s), radius=0.065, color="#81D4FA") 189 - dot.set_opacity(0.0) 190 - noisy_dots.add(dot) 191 - 192 - # Updater für synchrone Messpunkterfassung exakt zum jeweiligen Reaktionszeitpunkt t_s 193 - def update_noisy_dots(group): 194 - curr_t = t_tracker.get_value() 195 - for dot, t_s in zip(group, sample_times): 196 - if curr_t < t_s: 197 - dot.set_opacity(0.0) 198 - else: 199 - dt = curr_t - t_s 200 - flash_window = 140.0 201 - if dt < flash_window: 202 - frac = dt / flash_window 203 - dot.set_opacity(1.0) 204 - dot.set_color(interpolate_color(WHITE, ManimColor("#81D4FA"), frac)) 205 - else: 206 - dot.set_opacity(1.0) 207 - dot.set_color(ManimColor("#81D4FA")) 208 - 209 - noisy_dots.add_updater(update_noisy_dots) 210 - self.add(noisy_dots) 211 - 212 - # Reaktion läuft ab: Entfärbung der Flüssigkeit und Erscheinen der Punkte erfolgen synchron (erhöhte Geschwindigkeit) 213 - self.play( 214 - t_tracker.animate.set_value(4000.0), 215 - run_time=3.2, 216 - rate_func=linear 217 - ) 218 - self.wait(0.3) 219 - noisy_dots.clear_updaters() 220 - for dot in noisy_dots: 221 - dot.set_opacity(1.0) 222 - dot.set_color(ManimColor("#81D4FA")) 223 - 224 - # Am Ende dieses Schritts: Näherungskurve erscheint durch die Punkte! 225 - full_curve = axes.plot(lambda t: get_conc(t), x_range=[0, 4000], color=COLOR_STEP_LINE, stroke_width=3.4) 226 - curve_label = Tex(r"\textbf{Ausgleichskurve} $c(t)$", font_size=14, color=COLOR_STEP_LINE).next_to( 227 - axes.c2p(500, get_conc(500)), UR, buff=0.10 228 - ) 229 - 230 - self.play(Create(full_curve), FadeIn(curve_label), run_time=1.5) 231 - self.wait(0.6) 232 - 233 - # ------------------------------------------------------------- 234 - # 3. Schritt: Zoom und Punkte verschwinden 235 - # ------------------------------------------------------------- 236 - self.next_section("03_Zoom_und_Ausgleichskurve") 237 - 238 - liquid_poly.clear_updaters() 239 - c_num.clear_updaters() 240 - 241 - diagram_all = VGroup(axes, x_label, y_label, full_curve) 242 - target_center = np.array([-2.45, -0.30, 0.0]) 243 - zoom_scale = 1.12 244 - 245 - self.play( 246 - FadeOut(erlenmeyer_full, shift=LEFT * 1.5), 247 - FadeOut(noisy_dots, scale=0.8), 248 - FadeOut(curve_label), 249 - diagram_all.animate.move_to(target_center).scale(zoom_scale), 250 - run_time=1.8 251 - ) 252 - self.wait(0.6) 253 - 254 - # ------------------------------------------------------------- 255 - # 4. Schritt: Mittlere Änderungsrate (Sekante 1000 - 2000 s) 256 - # ------------------------------------------------------------- 257 - self.next_section("04_Mittlere_Aenderungsrate") 258 - 259 - t1, t2 = 1000.0, 2000.0 260 - c1, c2 = get_conc(t1), get_conc(t2) 261 - pt1 = axes.c2p(t1, c1) 262 - pt2 = axes.c2p(t2, c2) 263 - 264 - # 1. Zeitpunkte auf der x-Achse & von unten nach oben animierte Projektionslinien 265 - p_axis_1 = axes.c2p(t1, 0) 266 - p_axis_2 = axes.c2p(t2, 0) 267 - 268 - dot_axis1 = Dot(p_axis_1, radius=0.05, color=COLOR_DURCHSCHNITT) 269 - dot_axis2 = Dot(p_axis_2, radius=0.05, color=COLOR_DURCHSCHNITT) 270 - proj_line_1 = DashedLine(p_axis_1, pt1, color=COLOR_DURCHSCHNITT, stroke_width=2.0, dash_length=0.07) 271 - proj_line_2 = DashedLine(p_axis_2, pt2, color=COLOR_DURCHSCHNITT, stroke_width=2.0, dash_length=0.07) 272 - 273 - self.play(FadeIn(dot_axis1), FadeIn(dot_axis2), run_time=0.3) 274 - self.play( 275 - Create(proj_line_1), Create(proj_line_2), 276 - run_time=1.0 277 - ) 278 - self.wait(0.2) 279 - 280 - # 2. Punkte auf der Kurve erscheinen 281 - dot1 = create_data_point(pt1, is_milestone=True, color=COLOR_DURCHSCHNITT) 282 - dot2 = create_data_point(pt2, is_milestone=True, color=COLOR_DURCHSCHNITT) 283 - 284 - self.play( 285 - FadeIn(dot1, scale=1.5), 286 - FadeIn(dot2, scale=1.5), 287 - run_time=0.6 288 - ) 289 - self.wait(0.2) 290 - 291 - # 3. Delta y (|Delta c|) und Delta x (Delta t) - FONT_SIZE_DELTA aus styles.py für optimale Lesbarkeit 292 - pt_corner = axes.c2p(t2, c1) 293 - tri_sec_dc = Line(pt_corner, pt2, color=COLOR_DURCHSCHNITT, stroke_width=2.2) 294 - dc_sec_lbl = MathTex(r"|\Delta c| \approx 0{,}25\,\frac{\text{mol}}{\text{l}}", font_size=FONT_SIZE_DELTA, color=COLOR_DURCHSCHNITT).next_to(tri_sec_dc, RIGHT, buff=0.10) 295 - 296 - tri_sec_dt = Line(pt1, pt_corner, color=COLOR_DURCHSCHNITT, stroke_width=2.2) 297 - dt_sec_lbl = MathTex(r"\Delta t = 1000\,\text{s}", font_size=FONT_SIZE_DELTA, color=COLOR_DURCHSCHNITT).next_to(tri_sec_dt, UP, buff=0.10) 298 - 299 - self.play(Create(tri_sec_dc), Write(dc_sec_lbl), run_time=0.7) 300 - self.play(Create(tri_sec_dt), Write(dt_sec_lbl), run_time=0.7) 301 - self.wait(0.2) 302 - 303 - # 4. Sekante und Info-Badge (am rechten Rand) 304 - sec_dir = normalize(pt2 - pt1) 305 - sec_start = pt1 - sec_dir * 0.7 306 - sec_end = pt2 + sec_dir * 0.7 307 - secant_line = Line(sec_start, sec_end, color=COLOR_DURCHSCHNITT, stroke_width=3.2) 308 - 309 - badge_sec = create_info_badge( 310 - r"\textbf{Sekante} $\mathbf{\hat{=}}$ \textbf{Mittlere Rate}", 311 - r"$\bar{v} = \frac{|\Delta c|}{\Delta t} \approx 2{,}5 \times 10^{-4}\,\frac{\text{mol}}{\text{l}\cdot\text{s}}$", 312 - border_color=COLOR_DURCHSCHNITT, width=4.7, height=1.18, 313 - font_size_title=22, font_size_body=21 314 - ).move_to([4.45, 1.70, 0]) 315 - 316 - self.play( 317 - Create(secant_line), 318 - FadeIn(badge_sec, shift=LEFT * 0.2), 319 - proj_line_1.animate.set_stroke(opacity=0.35), 320 - proj_line_2.animate.set_stroke(opacity=0.35), 321 - run_time=1.0 322 - ) 323 - self.wait(1.5) 324 - 325 - # ------------------------------------------------------------- 326 - # 5. Schritt: Momentane Änderungsrate (Tangente t = 3000 s, nebeneinander zur Sekante) 327 - # ------------------------------------------------------------- 328 - self.next_section("05_Momentane_Aenderungsrate") 329 - 330 - tm = 3000.0 331 - cm = get_conc(tm) 332 - pt_m = axes.c2p(tm, cm) 333 - 334 - # 1. Erst der senkrechte Strich (von der Zeitachse nach oben zur Kurve) 335 - p_axis_m = axes.c2p(tm, 0) 336 - dot_axis_m = Dot(p_axis_m, radius=0.05, color=COLOR_MOMENTAN) 337 - proj_line_m = DashedLine(p_axis_m, pt_m, color=COLOR_MOMENTAN, stroke_width=2.0, dash_length=0.07) 338 - 339 - self.play(FadeIn(dot_axis_m), run_time=0.3) 340 - self.play(Create(proj_line_m), run_time=0.9) 341 - self.wait(0.2) 342 - 343 - # 2. Dann der Punkt auf der Kurve 344 - dot_m = create_data_point(pt_m, is_milestone=True, color=COLOR_MOMENTAN) 345 - self.play(FadeIn(dot_m, scale=1.5), run_time=0.5) 346 - self.wait(0.2) 347 - 348 - # 3. Schließlich die Tangente mit einem Steigungsdreieck (oberhalb, Breite 1000 s) 349 - t_tan_start, t_tan_end = 2400.0, 3600.0 350 - slope_m = -K_RATE * cm 351 - c_tan_start = cm + slope_m * (t_tan_start - tm) 352 - c_tan_end = cm + slope_m * (t_tan_end - tm) 353 - 354 - pt_tan_s = axes.c2p(t_tan_start, c_tan_start) 355 - pt_tan_e = axes.c2p(t_tan_end, c_tan_end) 356 - tan_m_line = Line(pt_tan_s, pt_tan_e, color=COLOR_MOMENTAN, stroke_width=3.2) 357 - 358 - # Steigungsdreieck an der Tangente (oberhalb der Tangente von 2500 bis 3500 s, Breite 1000) 359 - t_tri1 = 2500.0 360 - t_tri2 = 3500.0 361 - c_tri1 = cm + slope_m * (t_tri1 - tm) 362 - c_tri2 = cm + slope_m * (t_tri2 - tm) 363 - 364 - p_tri_start = axes.c2p(t_tri1, c_tri1) 365 - p_tri_corner = axes.c2p(t_tri2, c_tri1) 366 - p_tri_end = axes.c2p(t_tri2, c_tri2) 367 - 368 - tri_tan_dt = Line(p_tri_start, p_tri_corner, color=COLOR_MOMENTAN, stroke_width=2.2) 369 - tri_tan_dc = Line(p_tri_corner, p_tri_end, color=COLOR_MOMENTAN, stroke_width=2.2) 370 - 371 - dt_tan_lbl = MathTex(r"\Delta t = 1000\,\text{s}", font_size=FONT_SIZE_DELTA, color=COLOR_MOMENTAN).next_to(tri_tan_dt, UP, buff=0.08) 372 - dc_tan_lbl = MathTex(r"|\Delta c| \approx 0{,}075\,\frac{\text{mol}}{\text{l}}", font_size=FONT_SIZE_DELTA, color=COLOR_MOMENTAN).next_to(tri_tan_dc, RIGHT, buff=0.10) 373 - 374 - # Info-Badge rechts unter dem 1. Badge (ohne v im Titel, vergrößerte Schrift) 375 - badge_tan = create_info_badge( 376 - r"\textbf{Tangente} $\mathbf{\hat{=}}$ \textbf{Momentane Rate}", 377 - r"$v = \frac{|\Delta c|}{\Delta t} \approx 7{,}5 \times 10^{-5}\,\frac{\text{mol}}{\text{l}\cdot\text{s}}$", 378 - border_color=COLOR_MOMENTAN, width=4.7, height=1.18, 379 - font_size_title=22, font_size_body=21 380 - ).move_to([4.45, 0.35, 0]) 381 - 382 - self.play(Create(tan_m_line), run_time=1.0) 383 - self.play( 384 - Create(tri_tan_dt), Write(dt_tan_lbl), 385 - Create(tri_tan_dc), Write(dc_tan_lbl), 386 - run_time=1.0 387 - ) 388 - self.play( 389 - FadeIn(badge_tan, shift=LEFT * 0.2), 390 - proj_line_m.animate.set_stroke(opacity=0.35), 391 - run_time=0.8 392 - ) 393 - self.wait(1.5) 394 - 395 - # ------------------------------------------------------------- 396 - # 6. Schritt: Startgeschwindigkeit (Tangente t = 0 s, oberhalb, Breite 1000 s) 397 - # ------------------------------------------------------------- 398 - self.next_section("06_Startgeschwindigkeit") 399 - 400 - p0 = axes.c2p(0, 1.0) 401 - p0_end = axes.c2p(1282, 0.0) 402 - 403 - tan_0 = Line(p0, p0_end, color=COLOR_ANFANG, stroke_width=3.2) 404 - dot_0 = create_data_point(p0, is_milestone=True, color=COLOR_ANFANG) 405 - 406 - # Steigungsdreieck oberhalb mit Breite 1000 s (von t = 0 bis t = 1000 s) 407 - t0_start = 0.0 408 - t0_end = 1000.0 409 - c0_start = 1.0 410 - c0_end = 1.0 - K_RATE * 1000.0 # 0.22 mol/l 411 - 412 - p_0_start = axes.c2p(t0_start, c0_start) 413 - p_0_corner = axes.c2p(t0_end, c0_start) 414 - p_0_tan_pt = axes.c2p(t0_end, c0_end) 415 - 416 - tri_0_dt = Line(p_0_start, p_0_corner, color=COLOR_ANFANG, stroke_width=2.2) 417 - tri_0_dc = Line(p_0_corner, p_0_tan_pt, color=COLOR_ANFANG, stroke_width=2.2) 418 - 419 - dt_0_lbl = MathTex(r"\Delta t = 1000\,\text{s}", font_size=FONT_SIZE_DELTA, color=COLOR_ANFANG).next_to(tri_0_dt, UP, buff=0.08) 420 - dc_0_lbl = MathTex(r"|\Delta c| = 0{,}78\,\frac{\text{mol}}{\text{l}}", font_size=FONT_SIZE_DELTA, color=COLOR_ANFANG).next_to(tri_0_dc, RIGHT, buff=0.10) 421 - 422 - # Info-Badge rechts unter dem 2. Badge 423 - badge_0 = create_info_badge( 424 - r"\textbf{Tangente} $\mathbf{\hat{=}}$ \textbf{Startgeschwindigkeit}", 425 - r"$v_0 = \frac{|\Delta c|}{\Delta t} \approx 7{,}8 \times 10^{-4}\,\frac{\text{mol}}{\text{l}\cdot\text{s}}$", 426 - border_color=COLOR_ANFANG, width=4.7, height=1.18, 427 - font_size_title=22, font_size_body=21 428 - ).move_to([4.45, -1.00, 0]) 429 - 430 - self.play( 431 - FadeIn(dot_0), Create(tan_0), 432 - Create(tri_0_dt), Write(dt_0_lbl), 433 - Create(tri_0_dc), Write(dc_0_lbl), 434 - FadeIn(badge_0, shift=LEFT * 0.2), 435 - run_time=1.8 436 - ) 437 - self.wait(2.5) 438 -