Technophile周刊(第26期)¶
视频¶
-
ax.c2p() that's the coordinate to point. This will convert the a given point that exists on that coordinate system to a point on the entire screen.
-
The Manim Experience - Creating animations with Python
A great video for learning how to code and debug. 摘个评论@serg472: If you want to become a programmer this video is exactly how it goes - you try to do something cool, it doesn't work in the unexpected ways, you start googling and trying random stuff, you get meaningless errors you have no idea what they try to tell you, after you fix what seems to be the last error 5 new errors appear you didn't suspect were there, but then at 3am it starts working and it's the best feeling ever that makes you look forward to doing it all over again tomorrow.// t = ValueTracker(10) // always_redraw()
-
一个讲Bayes Theorem的视频
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
from manim import * from threemds.utils import render_scenes class BayesTheorem(Scene): def construct(self): title = Tex("Bayes Theorem", color=BLUE).scale(1.3).to_edge(UL) self.play(Write(title)) self.wait() bt_tex = MathTex(r"P(A|B) = \frac{P(B|A) \times P(A)}{P(B)}").scale(1.3) self.play(Write(bt_tex)) self.wait() class BayesTheoremTex(MathTex): def __init__(self, a:str, b: str, **kwargs): tex_strings = [] p_a = r"P(\text{" + a + r"})" p_b = r"P(\text{" + b + "})" p_a_b = r"P(\text{" + a + r"}|\text{" + b + r"})" p_b_a = r"P(\text{" + b + r"}|\text{" + a + r"})" tex = p_a_b + r" = \frac{" + p_b_a + r" \times " + p_a + "}{" + p_b + "}" print(tex) super().__init__(tex, **kwargs) global i i = 2 def incr(j): global i if type(j) == str: i += len(j) else: i += j return i self.a1 = self[0][i:incr(a)] # capture A incr(1) self.b1 = self[0][i:incr(b)] # capture b self.a_given_b = self[0][0:i+1] incr(4) self.b2 = self[0][i:incr(b)] # capture b incr(1) self.a2 = self[0][i:incr(a)] # capture a self.b_given_a = self[0][i-len(a)-len(b)-3:i+1] incr(4) self.a3 = self[0][i:incr(a)] # capture a self.p_a = self[0][i-len(a)-2:i+1] incr(4) self.b3 = self[0][i:incr(b)] # capture b self.p_b = self[0][-len(b)-3:] VGroup(self.a1, self.a2, self.a3).set_color(RED) VGroup(self.b1, self.b2, self.b3).set_color(BLUE) class VideoGameHomicidalExample1(Scene): def construct(self): self.add(Tex("Bayes Theorem", color=BLUE).scale(1.3).to_edge(UL)) p_homicidal_gamer = MathTex(r"P(", r"\text{gamer}", r"|", r"\text{homicidal}", r")", "=", ".85").scale(1.3) p_homicidal_gamer[1].set_color(BLUE) p_homicidal_gamer[3].set_color(RED) self.play(Write(p_homicidal_gamer)) self.wait() p_gamer_homicidal = MathTex(r"P(", r"\text{homicidal}", r"|", r"\text{gamer}", r")", "=", r"\text{ ? }").scale(1.3) p_gamer_homicidal[1].set_color(RED) p_gamer_homicidal[3].set_color(BLUE) VGroup(p_homicidal_gamer.generate_target(), p_gamer_homicidal).arrange(DOWN, buff=.75) self.play(MoveToTarget(p_homicidal_gamer), Write(p_gamer_homicidal)) self.wait() class VideoGameHomicidalExample2(Scene): def construct(self): stats = VGroup( MathTex(r"P(", r"\text{gamer}", r"|", r"\text{homicidal}", r")", "=", ".85"), MathTex(r"P(", r"\text{Gamer}", ") = .19"), MathTex(r"P(", r"\text{Homicidal}", ") = .0001"), MathTex(r"P(", r"\text{homicidal}", r"|", r"\text{gamer}", r")", "=", r"\text{ ? }") ).scale(1.3).arrange(DOWN, buff=.75) VGroup(stats[0][3], stats[2][1], stats[3][1]).set_color(RED) VGroup(stats[0][1], stats[1][1], stats[3][3]).set_color(BLUE) for m in stats: self.play(Write(m), lag_ratio=2) self.wait() class VideoGameHomicidalExample3(Scene): def construct(self): self.add(Tex("Bayes Theorem", color=BLUE).scale(1.3).to_edge(UL)) bt1 = BayesTheoremTex("A", "B") self.play(Write(bt1)) self.wait() bt2 = BayesTheoremTex("Homicidal", "Gamer") self.play(ReplacementTransform(bt1, bt2)) self.wait() p_solve = MathTex(r" = \frac{.85 \times .0001 }{.19}") p_solve[0][5:10].set_color(RED) p_solve[0][12:15].set_color(BLUE) a_given_b = bt2.a_given_b.copy() self.add(a_given_b) VGroup(a_given_b.generate_target(), p_solve).arrange(RIGHT) self.play(FadeOut(bt2)) self.play(MoveToTarget(a_given_b), Write(p_solve)) self.wait() p_solved = MathTex("= .0004").next_to(p_solve, DOWN, buff=.75, aligned_edge=LEFT) self.play(Write(p_solved)) self.wait() self.play(Circumscribe(p_solved)) self.wait() class VennDiagramBayes(MovingCameraScene): def construct(self): # change line width behavior on camera zoom INITIAL_LINE_WIDTH_MULTIPLE = self.camera.cairo_line_width_multiple INITIAL_FRAME_WIDTH = config.frame_width def line_scale_down_updater(mobj): proportion = self.camera.frame.width / INITIAL_FRAME_WIDTH self.camera.cairo_line_width_multiple = INITIAL_LINE_WIDTH_MULTIPLE * proportion mobj = Mobject() mobj.add_updater(line_scale_down_updater) self.add(mobj) whole = Circle(radius=3.5,color=YELLOW) whole_txt = Tex("100K Population").move_to(whole) self.play(*[Write(m) for m in (whole, whole_txt)]) self.wait() gamers = Circle(radius=1.5, color=BLUE).move_to([0,-2,0]) gamers_txt = Tex("19K Gamers").scale(.75).move_to(gamers) self.play(*[Write(m) for m in (gamers, gamers_txt)]) self.wait() homicidals = Circle(radius=.01, color=RED) \ .move_to(gamers.get_top()) \ .shift(.005 * DOWN) \ .rotate(45*DEGREES, about_point=gamers.get_center()) homicidals_txt = Tex("10 Homicidals") \ .scale_to_fit_width(homicidals.width * .6) \ .move_to(homicidals) self.play(*[Write(m) for m in (homicidals, homicidals_txt)]) self.wait() self.wait() self.camera.frame.save_state() self.play( self.camera.frame.animate.set(height=homicidals.height * 1.2) \ .move_to(homicidals), run_time=3 ) self.wait() homicidals_txt.save_state() homicidals_play_games_txt = Tex(r"8.5 homicidals","are gamers").arrange(DOWN) \ .scale_to_fit_width(homicidals.width * .6) \ .move_to(homicidals) \ .rotate(45 * DEGREES) homicidals_dont_play_games_txt = Tex(r"1.5 homicidals","are not gamers").arrange(DOWN) \ .scale_to_fit_width(homicidals.width * .4) \ .move_to(homicidals.get_top()) \ .next_to(gamers.get_top(), UP, buff=.001) \ .rotate(45 * DEGREES, about_point=gamers.get_center()) self.play(Transform(homicidals_txt, VGroup(homicidals_play_games_txt, homicidals_dont_play_games_txt) ) ) self.wait() self.play(Restore(homicidals_txt)) self.wait() self.play(Restore(self.camera.frame), run_time=3) self.wait() self.play(Wiggle(gamers)) self.wait() self.play(Circumscribe(homicidals,color=RED)) self.wait() self.play( self.camera.frame.animate.set(height=homicidals.height * 1.2) \ .move_to(homicidals), run_time=3 ) intersect = Intersection(homicidals, gamers, color=PURPLE, fill_opacity=.6) diff1 = Difference(homicidals, gamers, color=RED, fill_opacity=.6) diff2 = Difference(gamers, homicidals, color=BLUE, fill_opacity=.6) homicidals_play_games_prop = Tex(r".85") \ .scale_to_fit_width(homicidals.width * .2) \ .move_to(homicidals) \ .rotate(45 * DEGREES) homicidals_dont_play_games_prop = Tex(r".15") \ .scale_to_fit_width(homicidals.width * .2) \ .move_to(homicidals.get_top()) \ .next_to(gamers.get_top(), UP, buff=.001) \ .rotate(45 * DEGREES, about_point=gamers.get_center()) self.play(*[Write(m) for m in (diff1,diff2,intersect)]) self.wait() self.play(Transform(homicidals_txt, VGroup(homicidals_play_games_prop, homicidals_dont_play_games_prop) ) ) self.wait() self.play( Restore(self.camera.frame), *[FadeOut(m) for m in (diff1,diff2,intersect)], run_time=3 ) self.wait() if __name__ == "__main__": render_scenes(q='k', scene_names=['VideoGameHomicidalExample2', 'VideoGameHomicidalExample1'])
-
Logistic Regression in 3 Minutes
一个讲Logistic Regression的视频
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
import math import pandas as pd from manim import * import os class DataPoint(Dot): def __init__(self, point: list | np.ndarray, x: float, y: float, color, **kwargs): super().__init__(point=point, radius=.15, color=color, **kwargs) self.x = x self.y = y def create_model(data: pd.DataFrame, initial_m: float, initial_b: float) -> tuple: m_tracker = ValueTracker(initial_m) b_tracker = ValueTracker(initial_b) ax = Axes( x_range=[-0.5, 10], y_range=[-0.2, 1.3], x_axis_config={"include_tip": False, "include_numbers": False}, y_axis_config={"include_tip": False, "include_numbers": True} ) # plot points false_points = [DataPoint(point=ax.c2p(p.x, p.y), x=p.x, y=p.y, color=RED) for p in data.itertuples() if p.y == 0.0] true_points = [DataPoint(point=ax.c2p(p.x, p.y), x=p.x, y=p.y, color=BLUE) for p in data.itertuples() if p.y == 1.0] points = [*true_points, *false_points] # plot function f = lambda x: 1.0 / (1.0 + math.exp(-(b_tracker.get_value() + m_tracker.get_value() * x))) plot = always_redraw(lambda: ax.plot(f, color=YELLOW)) # max line max_line = DashedLine(start=ax.c2p(0, 1), end=ax.c2p(10, 1), color=WHITE) # likelihood_lines likelihood_lines = [ always_redraw( lambda p=p: DashedLine( start=p.get_center(), end=ax.c2p(p.x, f(p.x)), color=p.get_color() ) ) for p in points ] return data, m_tracker, b_tracker, ax, points, true_points, false_points, plot, f, max_line, likelihood_lines class LogisticRegressionScene(Scene): def construct(self): # build the logistic regression model url = r"https://raw.githubusercontent.com/thomasnield/machine-learning-demo-data/master/classification/simple_logistic_regression.csv" data, m_tracker, b_tracker, ax, points, true_points, false_points, \ plot, f, max_line, likelihood_lines = create_model(data=pd.read_csv(url), initial_m=0.69267212, initial_b=-3.17576395 ) # draw and initialize the objects self.play(LaggedStartMap(Write, ax), Write(max_line), Write(MathTex("0") \ .scale(.8) \ .next_to(ax.c2p(0, 0), DL, buff=.2) ) ) self.wait() self.play(LaggedStartMap(Write, VGroup(*true_points))) self.play(LaggedStartMap(Write, VGroup(*false_points))) self.play(Write(plot)) self.wait() # draw axis labels x_label = ax.get_x_axis_label( Tex("Hours of Rain").scale(0.8), edge=DOWN, direction=DOWN, buff=0.5 ) y_label = ax.get_y_axis_label( Tex("Probability of Flood").scale(0.8).rotate(90 * DEGREES), edge=LEFT, direction=LEFT, buff=0.3, ) # label x and y axes self.play(Write(x_label)) self.wait() self.play(Write(y_label)) self.wait() self.play(Unwrite(x_label), Unwrite(y_label), run_time=1/3) self.wait() # label true and false data true_data_label = Tex("TRUE", color=BLUE).next_to(VGroup(*true_points), UP) false_data_label = Tex("FALSE", color=RED).next_to(VGroup(*false_points), UP) self.play(Write(true_data_label), Circumscribe(VGroup(*true_points))) self.wait() self.play(Write(false_data_label), Circumscribe(VGroup(*false_points))) self.wait() self.play(Unwrite(true_data_label), Unwrite(false_data_label), run_time=1 / 3) self.wait() # Project likelihood lines self.play(LaggedStartMap(Write, VGroup(*likelihood_lines))) self.wait() self.play(m_tracker.animate.increment_value(-.3), b_tracker.animate.increment_value(-.3)) self.play(m_tracker.animate.increment_value(.3), b_tracker.animate.increment_value(.3)) self.play(m_tracker.animate.increment_value(.3), b_tracker.animate.increment_value(.3)) self.play(m_tracker.animate.increment_value(-.3), b_tracker.animate.increment_value(-.3)) self.wait() # Highlight middle self.play( Circumscribe( VGroup(*[p for p in points if 2.3 < ax.p2c(p.get_center())[0] < 7.5]) ), run_time=3 ) # Remove likelihood lines self.play(*[Unwrite(mobj) for mobj in (*points, *likelihood_lines)]) self.wait() # trace the curve alpha_tracker = ValueTracker(.65) # the trace dot that follows the curve class TraceDot(Dot): def __init__(self, alpha: float): self.point = plot.point_from_proportion(alpha) super().__init__(point=self.point, color=YELLOW) self.x = ax.p2c(self.point)[0] self.y = ax.p2c(self.point)[1] trace_dot: TraceDot = always_redraw(lambda: TraceDot(alpha_tracker.get_value())) # Have a label chase the trace trace_label = always_redraw(lambda: MathTex(round(TraceDot(alpha_tracker.get_value()).y, 2)) \ .scale(.75) \ .next_to(trace_dot, UL) ) self.play(Write(trace_dot), Write(trace_label)) self.wait() self.play(alpha_tracker.animate.set_value(0.0), run_time=3) self.play(alpha_tracker.animate.set_value(1.0), run_time=3) self.play(alpha_tracker.animate.set_value(0.65), run_time=3) self.wait() # demonstrate a prediction self.play(alpha_tracker.animate.set_value(.65), run_time=1) self.wait() predict_line_vert = DashedLine(color=YELLOW, dash_length=.3, start=trace_dot.get_center(), end=ax.c2p(trace_dot.x, 0) ) predict_line_horz = DashedLine(color=YELLOW, dash_length=.3, start=trace_dot.get_center(), end=ax.c2p(0, trace_dot.y) ) self.play( Write(predict_line_vert), Write(predict_line_horz) ) predict_label_vert = MathTex( round(trace_dot.x, 2) ).scale(.8) \ .next_to(predict_line_vert, DOWN, buff=.25) predict_label_horz = MathTex( round(trace_dot.y, 2) ).scale(.8) \ .next_to(predict_line_horz, LEFT, buff=.25) self.play(Unwrite(trace_label)) self.play( Write(predict_label_vert), Write(predict_label_horz) ) self.wait() # demonstrate threshhold regions def generate_regions(threshold=0.5): false_region = Polygon(*[ax.c2p(x, y) for x, y in [(0, 0), (0, threshold), (10, threshold), (10, 0)]], color=RED, stroke_width=0, fill_opacity=.5) \ .next_to(Point(ax.c2p(0, 0)), aligned_edge=DL, buff=0) true_region = Polygon(*[ax.c2p(x, y) for x, y in [(0, threshold), (0, 1), (10, 1), (10, threshold)]], color=BLUE, stroke_width=0, fill_opacity=.5) \ .next_to(Point(ax.c2p(0, threshold)), aligned_edge=DL, buff=0) return true_region, false_region true_region, false_region = generate_regions() true_region.save_state() false_region.save_state() self.play( LaggedStartMap(FadeIn, true_region), LaggedStartMap(FadeIn, false_region) ) self.wait() self.wait() true_text = Text("TRUE", color=WHITE) \ .move_to(true_region, aligned_edge=RIGHT) \ .shift(LEFT) false_text = Text("FALSE", color=WHITE) \ .move_to(false_region, aligned_edge=RIGHT) \ .shift(LEFT) self.play(Write(true_text), Write(false_text)) self.wait() self.play(Wiggle(true_text), FocusOn(trace_dot)) self.wait() self.play(FadeOut(true_text), FadeOut(false_text)) self.wait() true_region1, false_region1 = generate_regions(.8) self.play( Transform(true_region, true_region1), Transform(false_region, false_region1) ) self.wait() false_text.move_to(false_region1, aligned_edge=RIGHT).shift(LEFT) self.play(FadeIn(false_text)) self.play(Wiggle(false_text), FocusOn(trace_dot)) self.play(FadeOut(false_text)) self.wait() self.play( Restore(true_region), Restore(false_region) ) self.wait() true_region2, false_region2 = generate_regions(.2) self.play( Transform(true_region, true_region2), Transform(false_region, false_region2) ) self.wait() self.play( Restore(true_region), Restore(false_region) ) if __name__ == "__main__": os.system( r"manim -qk -v WARNING -p --disable_caching -o NeuralNetworkScene.mp4 20220918_logistic_regression.py NeuralNetworkScene")
-
What is FMCW Radar and why is it useful?
一个讲FMCW Radar的视频,理论部分有点难懂,还是只关注manim的创作部分吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
import math from typing import Callable, List import cv2 import numpy as np from manim import * from scipy import signal, constants # config.background_color = BLACK BACKGROUND_COLOR = ManimColor.from_hex("#183340") config.background_color = BACKGROUND_COLOR # config.background_color = ManimColor.from_hex("#253f4b") # config.background_color = ManimColor.from_hex("#183340") TX_COLOR = BLUE RX_COLOR = RED """Helpers""" def pretty_num(n: float) -> str: nstr, dec = str(f"{n:.2f}").split(".") nstr_fmt = ",".join( [nstr[::-1][start : start + 3][::-1] for start in range(0, len(nstr), 3)][::-1] ) return f"{nstr_fmt}.{dec}" class WeatherRadarTower: def __init__(self, **kwargs): width_scale = 2 LINE_STYLE = dict( color=WHITE, stroke_width=DEFAULT_STROKE_WIDTH * width_scale * 2 ) # Defining the components of the radar tower leg = Line(ORIGIN, UP * 3, **LINE_STYLE) self.left_leg = leg.copy().shift(LEFT) self.right_leg = leg.copy().shift(RIGHT) self.middle_leg = leg.copy().shift(DOWN / 1.5) self.conn1_y_shift = DOWN / 2 self.conn1 = Line( self.middle_leg.get_center() + self.conn1_y_shift, self.right_leg.get_center() + self.conn1_y_shift, **LINE_STYLE, ) self.conn2 = Line( self.middle_leg.get_center() + self.conn1_y_shift, self.left_leg.get_center() + self.conn1_y_shift, **LINE_STYLE, ) self.conn3 = self.conn1.copy().shift(-self.conn1_y_shift * 2) self.conn4 = self.conn2.copy().shift(-self.conn1_y_shift * 2) self.radome = Circle(radius=1.08, **LINE_STYLE).next_to( self.middle_leg, direction=UP, buff=0, ) # Grouping all components self.vgroup = VGroup( self.left_leg, self.right_leg, self.middle_leg, self.conn1, self.conn2, self.conn3, self.conn4, self.radome, ).move_to(ORIGIN) def get_animation(self): return LaggedStart( AnimationGroup( Create(self.left_leg), Create(self.middle_leg), Create(self.right_leg), ), AnimationGroup( Create(self.conn1), Create(self.conn2), Create(self.conn3), Create(self.conn4), ), Create(self.radome), lag_ratio=0.75, ) class WeatherRadarScene(Scene): def construct(self): # Create the radar tower object radar_tower = WeatherRadarTower() # Add the radar tower to the scene self.add(radar_tower.vgroup) # Play the animation of building the radar tower self.play(radar_tower.get_animation()) # Hold the scene for a moment self.wait(2)