def animate_event_annotation(self): """Save H: ill, and E: test positive to the upper right """ if (self.is_show_only): self.mtex_event_h.scale(1.0 / self.scale_eq_f) self.txt_event_h.scale(0.8 / self.scale_txt_f) self.mtex_event_e.scale(1.0 / self.scale_eq_f) self.txt_event_e.scale(0.8 / self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_h, LEFT + DOWN, ORIGIN + 0.0 * RIGHT + 3.0 * UP) print(self.mtex_event_h.get_center()) self.txt_event_h.next_to(self.mtex_event_h) print(self.txt_event_h.get_center()) myutil.critical_point_move_to(self.mtex_event_e, LEFT + DOWN, ORIGIN + 2.5 * RIGHT + 3.0 * UP) print(self.mtex_event_e.get_center()) self.txt_event_e.next_to(self.mtex_event_e) print(self.txt_event_e.get_center()) return self.play(ApplyMethod(self.txt_event_h.scale, 1.0 / self.scale_eq_f), ApplyMethod(self.txt_event_h.scale, 0.8 / self.scale_txt_f), ApplyMethod(self.txt_event_e.scale, 1.0 / self.scale_eq_f), ApplyMethod(self.txt_event_e.scale, 0.8 / self.scale_txt_f)) self.play( ApplyMethod(self.mtex_event_h.move_to, ORIGIN + 0.2 * RIGHT + 3.2 * UP), ApplyMethod(self.txt_event_h.move_to, ORIGIN + 1.3 * RIGHT + 3.2 * UP), ApplyMethod(self.mtex_event_e.move_to, ORIGIN + 2.7 * RIGHT + 3.17 * UP), ApplyMethod(self.txt_event_e.move_to, ORIGIN + 4.0 * RIGHT + 3.17 * UP)) self.wait(self.time_wait)
def show_bayes(self): """ベイズの定理 """ # E: 検査+, H: 病気 self.mtex_event_h.scale(1.0 / self.scale_eq_f) self.txt_event_h.scale(0.8 / self.scale_txt_f) self.mtex_event_e.scale(1.0 / self.scale_eq_f) self.txt_event_e.scale(0.8 / self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_h, LEFT + DOWN, ORIGIN + 0.0 * RIGHT + 3.0 * UP) self.txt_event_h.next_to(self.mtex_event_h) myutil.critical_point_move_to(self.mtex_event_e, LEFT + DOWN, ORIGIN + 2.5 * RIGHT + 3.0 * UP) self.txt_event_e.next_to(self.mtex_event_e) if (self.is_show_only): self.add(self.mtex_bayes_full) self.add(self.mtex_event_e, self.txt_event_e) self.add(self.mtex_event_h, self.txt_event_h) return self.play(FadeIn(self.mtex_bayes_full), FadeIn(self.mtex_event_e), FadeIn(self.txt_event_e), FadeIn(self.mtex_event_h), FadeIn(self.txt_event_h)) self.wait(self.time_wait)
def create_title(self): """ """ self.txt_assumption = Text(r"前提:" ).scale(self.scale_title_f) self.txt_no_perfect = Text(r"完璧な検査はない").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_assumption, LEFT + DOWN, ORIGIN + -6 * RIGHT + 2.8 * UP) self.txt_no_perfect.next_to(self.txt_assumption) self.txt_handle_non_perfect = Text(r"不確実を扱う道具の話").scale(self.scale_txt_f) myutil.critical_point_move_to(self.txt_handle_non_perfect, LEFT + DOWN, ORIGIN + -5.5 * RIGHT + 2.0 * UP) self.txt_not_pre = Text(r"記号" ). scale(self.scale_txt_f) self.mtex_not_1 = MathTex(r"\lnot"). scale(1.0).set_color(self.col_n) self.txt_not_ja = Text(r": 〜ではない").scale(self.scale_txt_f) # It seems Text and MathTex don't share the positioning. Use other Text myutil.critical_point_move_to(self.txt_not_pre, LEFT + DOWN, ORIGIN + +0.2 * RIGHT + 3.0 * UP) self.mtex_not_1.next_to(self.txt_not_pre) self.txt_not_ja.next_to(self.mtex_not_1) self.mtex_not_2 = MathTex(r"\lnot"). scale(self.scale_eq_f).set_color(self.col_n) self.txt_ill = Text(r"病気"). scale(self.scale_txt_f) self.txt_not_ill = Text(r": 病気ではない").scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_not_2, LEFT + DOWN, ORIGIN + + 0.24 * RIGHT + 2.5 * UP) self.txt_ill.next_to(self.mtex_not_2) self.txt_not_ill.next_to(self.txt_ill)
def animate_probablity(self): """part 3 animate P()'s meaning """ # probability notation: reposition myutil.critical_point_move_to(self.tex_prob_eq[1], LEFT + DOWN, ORIGIN + -6.0 * RIGHT + -2.0 * UP) myutil.critical_point_move_to(self.tex_prob_eq[2], LEFT + DOWN, ORIGIN + -6.0 * RIGHT + -2.0 * UP) for i in range(0, len(self.txt_prob_exp)): self.txt_prob_exp[i].next_to(self.tex_prob_eq[i], buff=0.2) # working memory (Transform(a, b): a = b, a is written eq_work = copy.deepcopy(self.tex_prob_eq[0]) # P() self.play(FadeIn(eq_work)) self.wait(self.time_wait) # P() : 〜の確率 self.play(FadeIn(self.txt_prob_exp[0])) self.wait(self.time_wait) # P(A) self.play(Transform(eq_work, self.tex_prob_eq[1]), FadeOut(self.txt_prob_exp[0])) self.wait(self.time_wait) # P(A): A の確率 self.play(FadeIn(self.txt_prob_exp[1])) self.wait(self.time_wait) # P(H|E) self.play(Transform(eq_work, self.tex_prob_eq[2]), FadeOut(self.txt_prob_exp[1])) self.wait(self.time_wait) # P(H|E): E の時,H となる確率 self.play(FadeIn(self.txt_prob_exp[2])) self.wait(self.time_wait)
def animate_bayes_simple_to_full(self): """Transit Bayes simple forma to full form """ if (self.is_show_only): self.remove(self.mtex_bayes_simple) self.add(self.mtex_bayes_full) self.wait(1) return # replace with working copy. move P(E) to down # Note: self.remove(self.mtex_bayes_simple) does not work, seems objects are implicitly copied. # self.remove(self.mtex_bayes_simple[0], # self.mtex_bayes_simple[1], # self.mtex_bayes_simple[2], # self.mtex_bayes_simple[3], # self.mtex_bayes_simple[4], # self.mtex_bayes_simple[5], # ) eq_simple_dest = copy.deepcopy(self.mtex_bayes_simple) # self.add(eq_simple_dest) # destination: P(E) = P(H)P(E|H) + P(\lnot H)P(E|\lnot H) tex_e_full = MathTex( r"P(E)", # [0] e [0,2] r"=", # [1] r"P(H)", # [2] h [2,2] r"P(E|H)", # [3] e [3,2] h [3,4] r"+", # [4] r"P(\lnot H)", # [5] h [5,3] n [5, 2] r"P(E|\lnot H)" # [6] e [6,2] h [6,5] n [6, 4] ).scale(self.scale_eq_f) h_indices = [[2, 2], [3, 4], [5, 3], [6, 5]] for [i, j] in h_indices: tex_e_full[i][j].set_color(self.col_h) e_indices = [[0, 2], [3, 2], [6, 2]] for [i, j] in e_indices: tex_e_full[i][j].set_color(self.col_e) n_indices = [[5, 2], [6, 4]] for [i, j] in n_indices: tex_e_full[i][j].set_color(self.col_n) # push original position pushd_src_pos = eq_simple_dest[5].get_center() # get the dest position (based on critical point) # Note 1: 'RIGHT + DOWN' of the 0-th element! not 'LEFT + DOWN' # Thus re-adjuetment whole by LEFT + DOWN # Note 2: myutil.critical_point_move_to(tex[0], ...) creates # object copy of tex[0], derefernce by tex failed. car_tex_e_full = copy.deepcopy(tex_e_full[0]) myutil.critical_point_move_to(car_tex_e_full, RIGHT + DOWN, self.pos_line_3) pos_ld_car_tex_e_full = car_tex_e_full.get_critical_point(LEFT + DOWN) myutil.critical_point_move_to(tex_e_full, LEFT + DOWN, pos_ld_car_tex_e_full) pushd_dst_pos = tex_e_full[0].get_center() # move to the src tex_e_full[0].move_to(pushd_src_pos) # denominator P(E) moves to explanation self.play(ApplyMethod(tex_e_full[0].move_to, pushd_dst_pos)) self.wait(self.time_wait) # Explain P(E) '= ' self.play(FadeIn(tex_e_full[1])) self.wait(self.time_wait) # Explain P(E) = 'P(H)' self.play(FadeIn(tex_e_full[2])) self.wait(self.time_wait) # Explain P(E) = P(H) 'P(\lnot H)' self.play(FadeIn(tex_e_full[5])) self.wait(self.time_wait) # Explain P(E) = P(H)'P(E|H)' P(\lnot H) self.play(FadeIn(tex_e_full[3])) self.wait(self.time_wait) # Explain P(E) = P(H)P(E|H) P(\lnot H)'P(E|\lnot H)' self.play(FadeIn(tex_e_full[6])) self.wait(self.time_wait) # Explain P(E) = P(H)P(E|H) '+' P(\lnot H)P(E|\lnot H) self.play(FadeIn(tex_e_full[4])) self.wait(self.time_wait) # update to eq to full, keep denominator empty self.add(self.mtex_bayes_full[0], self.mtex_bayes_full[1]) self.remove(eq_simple_dest[0], eq_simple_dest[1], eq_simple_dest[2], eq_simple_dest[3]) # these seems implicitly copied self.remove(self.mtex_bayes_simple[0], self.mtex_bayes_simple[1], self.mtex_bayes_simple[2], self.mtex_bayes_simple[3], self.mtex_bayes_simple[4]) # P(H)P(E|H) in eq to move, transform the fraction bar pos_src_p_h = self.mtex_bayes_simple[2].get_center() pos_src_p_e_b_h = self.mtex_bayes_simple[3].get_center() pos_dst_p_h = self.mtex_bayes_full[2].get_center() pos_dst_p_e_b_h = self.mtex_bayes_full[3].get_center() self.mtex_bayes_full[2].move_to(pos_src_p_h) self.mtex_bayes_full[3].move_to(pos_src_p_e_b_h) self.play( ApplyMethod(self.mtex_bayes_full[2].move_to, pos_dst_p_h), ApplyMethod(self.mtex_bayes_full[3].move_to, pos_dst_p_e_b_h), Transform(eq_simple_dest[4], self.mtex_bayes_full[4])) self.wait(self.time_wait) # move the right hand side of P(E) = P(H)P{E|H) + P(\lnot H)P{E|\lnot H) # self.play(FadeOut(self.mtex_bayes_simple[5])) self.remove(self.mtex_bayes_simple[5]) # This seems implicitly copied self.play(FadeOut(eq_simple_dest[5])) self.wait(self.time_wait) # partal zip? self.play( FadeOut(tex_e_full[0]), FadeOut(tex_e_full[1]), ApplyMethod(tex_e_full[2].move_to, self.mtex_bayes_full[5].get_center()), ApplyMethod(tex_e_full[3].move_to, self.mtex_bayes_full[6].get_center()), ApplyMethod(tex_e_full[4].move_to, self.mtex_bayes_full[7].get_center()), ApplyMethod(tex_e_full[5].move_to, self.mtex_bayes_full[8].get_center()), ApplyMethod(tex_e_full[6].move_to, self.mtex_bayes_full[9].get_center())) self.wait(self.time_wait) # replace work equation to shared full beyes equation self.remove(tex_e_full) self.add(self.mtex_bayes_full) self.wait(self.time_wait)
def create_bayes_eq(self): """ """ self.txt_title_bayes = Text(r"ベイズの定理").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) # simple Bayes form (3b1b form, cond later) # indices for h,e color self.mtex_bayes_simple = MathTex( r"P(H|E)", # [0] e [0,4] h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(E)}", # [5] e [5,2] r"}", # [6] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_simple, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4]] for [i, j] in self.h_indices: self.mtex_bayes_simple[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [5, 2]] for [i, j] in self.e_indices: self.mtex_bayes_simple[i][j].set_color(self.col_e) # full Bayes form # indices for h,e color (MathTex removes white space)) self.mtex_bayes_full = MathTex( r"P(H|E)", # [0] e [0,4], h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(H)", # [5] h [5,2] r"P(E|H)}", # [6] e [6,2], h [6,4] r"+", # [7] r"{P(\lnot H)", # [8] h [8,3], n [8,2] r"P(E |\lnot H)}}", # [9] e [9,2], h [9,5], n [9,4] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_full, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4], [5, 2], [6, 4], [8, 3], [9, 5]] for [i, j] in self.h_indices: self.mtex_bayes_full[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [6, 2], [9, 2]] for [i, j] in self.e_indices: self.mtex_bayes_full[i][j].set_color(self.col_e) self.n_indices = [[8, 2], [9, 4]] for [i, j] in self.n_indices: self.mtex_bayes_full[i][j].set_color(self.col_n) # --- Event examples # event example H var_buff = 0.2 self.mtex_event_h = MathTex(r"H").scale(self.scale_eq_f).set_color( self.col_h) self.txt_event_h = Text(r": 病気").scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_h, RIGHT + DOWN, ORIGIN + -4.0 * RIGHT + 0.2 * UP) self.txt_event_h.next_to(self.mtex_event_h, buff=var_buff) # event example E self.mtex_event_e = MathTex(r"E").scale(self.scale_eq_f).set_color( self.col_e) self.txt_event_e = Text(r": 検査+", t2c={ r"[3:4]": self.col_positive }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_e, RIGHT + DOWN, ORIGIN + -4.0 * RIGHT + -0.6 * UP) self.txt_event_e.next_to(self.mtex_event_e, buff=var_buff) # event example H|E self.pos_line_3 = ORIGIN + -4.0 * RIGHT + -1.5 * UP self.pos_line_4 = ORIGIN + -4.0 * RIGHT + -2.3 * UP self.mtex_event_h_b_e = MathTex(r"H", r"|", r"E").scale(self.scale_eq_f) self.mtex_event_h_b_e[0].set_color(self.col_h) self.mtex_event_h_b_e[2].set_color(self.col_e) self.txt_event_h_b_e = Text(r": E (検査+) の時に H (病気)", t2c={ r"[1:2]": self.col_e, r"[5:6]": self.col_positive, r"[10:11]": self.col_h, }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_h_b_e, RIGHT + DOWN, self.pos_line_3) self.txt_event_h_b_e.next_to(self.mtex_event_h_b_e, buff=var_buff) # event example P(H|E) self.mtex_event_prob_h_b_e = MathTex(r"P(", r"H", r"|", r"E", r")").scale(self.scale_eq_f) self.mtex_event_prob_h_b_e[1].set_color(self.col_h) self.mtex_event_prob_h_b_e[3].set_color(self.col_e) self.txt_event_prob_h_b_e = Text(r": E (検査+) の時に H (病気) の確率", t2c={ r"[1:2]": self.col_e, r"[5:6]": self.col_positive, r"[10:11]": self.col_h }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_prob_h_b_e, RIGHT + DOWN, self.pos_line_4) self.txt_event_prob_h_b_e.next_to(self.mtex_event_prob_h_b_e, buff=var_buff) # event example 5 P(H) self.mtex_event_prob_h = MathTex(r"P(", r"H", r")").scale(self.scale_eq_f) self.mtex_event_prob_h[1].set_color(self.col_h) self.txt_event_prob_h = Text(r": H (病気) の確率", t2c={ r"[1:2]": self.col_h }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_prob_h, RIGHT + DOWN, self.pos_line_3) self.txt_event_prob_h.next_to(self.mtex_event_prob_h, buff=var_buff) # event example 6 P(E|H) self.mtex_event_prob_e_b_h = MathTex(r"P(", r"E", r"|", r"H", r")").scale(self.scale_eq_f) self.mtex_event_prob_e_b_h[1].set_color(self.col_e) self.mtex_event_prob_e_b_h[3].set_color(self.col_h) self.txt_event_prob_e_b_h = Text(r": H (病気) の時に,E (検査+) の確率", t2c={ r"[1:2]": self.col_h, r"[10:11]": self.col_e, r"[14:15]": self.col_positive, }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_prob_e_b_h, RIGHT + DOWN, self.pos_line_3) self.txt_event_prob_e_b_h.next_to(self.mtex_event_prob_e_b_h, buff=var_buff) # event example 7 P(E) self.mtex_event_prob_e = MathTex(r"P(", r"E", r")").scale(self.scale_eq_f) self.mtex_event_prob_e[1].set_color(self.col_e) self.txt_event_prob_e = Text(r": E (検査+) の確率", t2c={ r"[1:2]": self.col_e, r"[5:6]": self.col_positive, }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_prob_e, RIGHT + DOWN, self.pos_line_3) self.txt_event_prob_e.next_to(self.mtex_event_prob_e, buff=var_buff)
def create_bayes_eq(self): """create all mobjects """ self.txt_title_bayes = Text(r"具体例 2").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) # full Bayes form # indices for h,e color (MathTex removes white space)) self.mtex_bayes_full = MathTex(r"P(H|E)", # [0] e [0,4], h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(H)", # [5] h [5,2] r"P(E|H)}", # [6] e [6,2], h [6,4] r"+", # [7] r"{P(\lnot H)", # [8] h [8,3], n [8,2] r"P(E |\lnot H)}}", # [9] e [9,2], h [9,5], n [9,4] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_full, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4], [5, 2], [6, 4], [8, 3], [9, 5]] for [i,j] in self.h_indices: self.mtex_bayes_full[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [6, 2], [9, 2]] for [i,j] in self.e_indices: self.mtex_bayes_full[i][j].set_color(self.col_e) self.n_indices = [[8, 2], [9, 4]] for [i,j] in self.n_indices: self.mtex_bayes_full[i][j].set_color(self.col_n) # --- Event examples # event example H self.mtex_event_h = MathTex(r"H"). scale(self.scale_event_eq_f).set_color( self.col_h).move_to(0.2 * RIGHT + 3.4 * UP) self.txt_event_h = Text(r": 病気").scale(self.scale_event_txt_f).move_to(1.3 * RIGHT + 3.4 * UP) # event example E self.mtex_event_e = MathTex(r"E").scale(self.scale_event_eq_f).set_color( self.col_e).move_to(2.7 * RIGHT + 3.37 * UP) self.txt_event_e = Text(r": 検査+", t2c={r"[3:4]": self.col_positive}).scale( self.scale_event_txt_f).move_to(4.0 * RIGHT + 3.37 * UP) # --- another example (counter intuitive, but more realistic # 病気の確率 0.1%: P(H) = 0.001 self.text_p_h = [Text(r"病気の確率").scale(self.scale_txt_f), MathTex(r"0.1 \%"). scale(self.scale_eq_f),] self.mtex_p_h = MathTex(r"P(H)", r"=", r"0.001").scale(self.scale_eq_f) self.mtex_p_h[0][2].set_color(self.col_h) # ¬病気の可能性 0.1%: P(¬H) = 0.999 self.text_p_not_h = [Text(r"¬病気の確率", t2c={"[0:1]": self.col_n}).scale(self.scale_txt_f), MathTex(r"99.9 \%"). scale(self.scale_eq_f),] self.mtex_p_not_h = MathTex(r"P(\lnot H)", r"=", r"0.999").scale(self.scale_eq_f) self.mtex_p_not_h[0][2].set_color(self.col_n) self.mtex_p_not_h[0][3].set_color(self.col_h) # 病気の時に検査+ 100%: P(E|H) = 1.0 self.text_p_e_h = [Text(r"病気の時,検査+", t2c={"[7:8]": self.col_positive}).scale(self.scale_txt_f), MathTex(r"100 \%"). scale(self.scale_eq_f),] self.mtex_p_e_h = MathTex(r"P(E|H)", r"=", r"1.0"). scale(self.scale_eq_f) self.mtex_p_e_h[0][2].set_color(self.col_e) self.mtex_p_e_h[0][4].set_color(self.col_h) # ¬病気の時に検査+ 1%: P(E|¬H) = 0.01 self.text_p_e_not_h = [Text(r"¬病気の時,検査+", t2c={"[0:1]": self.col_n, "[8:9]": self.col_positive}).scale(self.scale_txt_f), MathTex(r" 1 \%"). scale(self.scale_eq_f)] self.mtex_p_e_not_h = MathTex(r"P(E|\lnot H)", r"=", r"0.01").scale(self.scale_eq_f) self.mtex_p_e_not_h[0][2].set_color(self.col_e) self.mtex_p_e_not_h[0][4].set_color(self.col_n) self.mtex_p_e_not_h[0][5].set_color(self.col_h) # text up shift and text right shift text_up = [ 0.0, -0.8, -1.6, -2.4] text_ri = [-5.5, +0.3] text_align = [LEFT, RIGHT] for i in range(0, 2): myutil.critical_point_move_to(self.text_p_h[i], text_align[i], text_ri[i] * RIGHT + text_up[0] * UP) myutil.critical_point_move_to(self.text_p_not_h[i], text_align[i], text_ri[i] * RIGHT + text_up[1] * UP) myutil.critical_point_move_to(self.text_p_e_h[i], text_align[i], text_ri[i] * RIGHT + text_up[2] * UP) myutil.critical_point_move_to(self.text_p_e_not_h[i], text_align[i], text_ri[i] * RIGHT + text_up[3] * UP) mtex_ri = [+3.0, +3.4, +4.2] text_align = [RIGHT, LEFT, LEFT] for i in range(0, 3): myutil.critical_point_move_to(self.mtex_p_h[i], text_align[i], ORIGIN + mtex_ri[i] * RIGHT + text_up[0] * UP) myutil.critical_point_move_to(self.mtex_p_not_h[i], text_align[i], ORIGIN + mtex_ri[i] * RIGHT + text_up[1] * UP) myutil.critical_point_move_to(self.mtex_p_e_h[i], text_align[i], ORIGIN + mtex_ri[i] * RIGHT + text_up[2] * UP) myutil.critical_point_move_to(self.mtex_p_e_not_h[i], text_align[i], ORIGIN + mtex_ri[i] * RIGHT + text_up[3] * UP)
def create_table(self): # horizontal lines tab_width = self.get_tab_width() self.line_tab_hline = [] for hidx in range(0, len(self.height_tcol)): anchor_pos = self.get_tab_cell_anchor_pos(0, hidx) self.line_tab_hline.append( Line(anchor_pos, anchor_pos + tab_width * RIGHT, color=self.color_tab_line, stroke_width=self.stroke_width_tab_line)) # append the last hline hsize = len(self.height_tcol) print("hsize: {0}".format(hsize)) last_h_anchor_pos = self.get_tab_cell_anchor_pos(0, hsize - 1) + self.height_tcol[hsize - 1] * DOWN self.line_tab_hline.append( Line(last_h_anchor_pos, last_h_anchor_pos + tab_width * RIGHT, color=self.color_tab_line, stroke_width=self.stroke_width_tab_line)) # (0,2) vline is one level shorter tab_height = self.get_tab_height() self.line_tab_vline = [] self.line_tab_vline.append( Line(self.get_tab_cell_anchor_pos(0, 0), self.get_tab_cell_anchor_pos(0, 0) + tab_height * DOWN, color=self.color_tab_line, stroke_width=self.stroke_width_tab_line)) self.line_tab_vline.append( Line(self.get_tab_cell_anchor_pos(1, 0), self.get_tab_cell_anchor_pos(1, 0) + tab_height * DOWN, color=self.color_tab_line, stroke_width=self.stroke_width_tab_line)) # [2] vline is one level (self.height_tcol[0]) shorter self.line_tab_vline.append( Line(self.get_tab_cell_anchor_pos(2, 1), self.get_tab_cell_anchor_pos(2, 1) + (tab_height - self.height_tcol[0]) * DOWN, color=self.color_tab_line, stroke_width=self.stroke_width_tab_line)) # append the last vline vsize = len(self.width_trow) last_v_anchor_pos = self.get_tab_cell_anchor_pos(vsize - 1, 0) + self.width_trow[vsize - 1] * RIGHT self.line_tab_vline.append( Line(last_v_anchor_pos, last_v_anchor_pos + tab_height * DOWN, color=self.color_tab_line, stroke_width=self.stroke_width_tab_line)) debug_show_all_cell_position = False if (debug_show_all_cell_position): # Show cell positions anchor_txt = [] for x in range(0, len(self.width_trow)): for y in range(0, len(self.height_tcol)): anchor_txt.append(Text("({0},{1})".format(x, y)).move_to( myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, x, y, ORIGIN, show=True))) self.add(*anchor_txt) # text column title scale_col_title_txt = 1.0 self.txt_tab_column_title = [ Text(r"検査結果").scale(scale_col_title_txt), Text(r"実際" ).scale(scale_col_title_txt) ] myutil.critical_point_move_to(self.txt_tab_column_title[0], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 0, 0, ORIGIN, show=False)) table_row_2_adjust = (self.width_trow[2] / 2) myutil.critical_point_move_to(self.txt_tab_column_title[1], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 1, 0, ORIGIN, show=False) + table_row_2_adjust * RIGHT) # test row title (+,-) scale_row_title_txt = 1.2 self.txt_tab_test_title = [ Text(r"+", font="sans-serif", color=self.color_positive).scale(scale_row_title_txt), Text(r"−", font="sans-serif", color=self.color_negative).scale(scale_row_title_txt) ] # '+' is localted at (0,2) myutil.critical_point_move_to(self.txt_tab_test_title[0], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 0, 2, ORIGIN, show=False)) # '-' is localted at (0,3) myutil.critical_point_move_to(self.txt_tab_test_title[1], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 0, 3, ORIGIN, show=False)) # ill, not ill title scale_row_title_txt = 1.0 not_ill = VGroup() tex_not = MathTex(r"\lnot").scale(scale_row_title_txt).set_color(self.col_n) txt_ill = Text(r"病気" ). scale(scale_row_title_txt).next_to(tex_not) not_ill.add(tex_not, txt_ill) self.txt_tab_ill_title = [ Text(r"病気"). scale(scale_col_title_txt), not_ill, ] myutil.critical_point_move_to(self.txt_tab_ill_title[0], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 1, 1, ORIGIN, show=False)) myutil.critical_point_move_to(self.txt_tab_ill_title[1], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 2, 1, ORIGIN, show=False)) # table contents self.txt_tab_true_pn = [ Text(r"真+", font="sans-serif", t2c = {"+": self.color_positive}), # t2w = {"+": BOLD} doesn't work Text(r"真−", font="sans-serif", t2c = {"−": self.color_negative}), # t2w = {"−": ULTRABOLD} doesn't work ] myutil.critical_point_move_to(self.txt_tab_true_pn[0], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 1, 2, ORIGIN, show=False)) myutil.critical_point_move_to(self.txt_tab_true_pn[1], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 2, 3, ORIGIN, show=False)) self.txt_tab_false_pn = [ Text(r"偽+", font="sans-serif", t2c = {"+": self.color_positive}), Text(r"偽−", font="sans-serif", t2c = {"−": self.color_negative}), ] myutil.critical_point_move_to(self.txt_tab_false_pn[0], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 2, 2, ORIGIN, show=False)) myutil.critical_point_move_to(self.txt_tab_false_pn[1], ORIGIN, myutil.get_tab_cell_critical_pos(self.pos_tab_origin, self.width_trow, self.height_tcol, 1, 3, ORIGIN, show=False))
def create_bayes_eq(self): """ """ self.txt_title_bayes = Text(r"何故ベイズの定理?").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) # full Bayes form # indices for h,e color (MathTex removes white space)) self.mtex_bayes_full = MathTex( r"P(H|E)", # [0] e [0,4], h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(H)", # [5] h [5,2] r"P(E|H)}", # [6] e [6,2], h [6,4] r"+", # [7] r"{P(\lnot H)", # [8] h [8,3] n [8,2] r"P(E |\lnot H)}}", # [9] e [9,2], h [9,5] n [9,4] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_full, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4], [5, 2], [6, 4], [8, 3], [9, 5]] for [i, j] in self.h_indices: self.mtex_bayes_full[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [6, 2], [9, 2]] for [i, j] in self.e_indices: self.mtex_bayes_full[i][j].set_color(self.col_e) self.n_indices = [[8, 2], [9, 4]] for [i, j] in self.n_indices: self.mtex_bayes_full[i][j].set_color(self.col_n) # --- Event examples # event example H var_buff = 0.2 self.mtex_event_h = MathTex(r"H").scale(self.scale_eq_f).set_color( self.col_h) self.txt_event_h = Text(r": 病気").scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_h, RIGHT + DOWN, ORIGIN + -4.0 * RIGHT + 0.2 * UP) self.txt_event_h.next_to(self.mtex_event_h, buff=var_buff) # event example E self.mtex_event_e = MathTex(r"E").scale(self.scale_eq_f).set_color( self.col_e) self.txt_event_e = Text(r": 検査+", t2c={ r"[3:4]": self.col_positive }).scale(self.scale_txt_f) myutil.critical_point_move_to(self.mtex_event_e, RIGHT + DOWN, ORIGIN + -4.0 * RIGHT + -0.6 * UP) self.txt_event_e.next_to(self.mtex_event_e, buff=var_buff) # P(H|E): 検査+ の時に実際に病気である確率。(不明,知りたいこと) self.mtex_event_prob_h_b_e = MathTex(r"P(", r"H", r"|", r"E", r")").scale(self.scale_eq_f) self.mtex_event_prob_h_b_e[1].set_color(self.col_h) self.mtex_event_prob_h_b_e[3].set_color(self.col_e) self.txt_event_prob_h_b_e = [ Text(r": 検査+の時に実際に病気の確率", t2c={ r"[3:4]": self.col_positive, }).scale(self.scale_txt_f), Text(r": 「知りたいこと」", ).scale(self.scale_txt_f), Text(r"(未知)", ).scale(self.scale_txt_f).set_color(RED), ] myutil.critical_point_move_to(self.mtex_event_prob_h_b_e, RIGHT + DOWN, -3.0 * RIGHT + 0.5 * UP) self.txt_event_prob_h_b_e[0].next_to(self.mtex_event_prob_h_b_e, buff=var_buff) self.txt_event_prob_h_b_e[1].next_to(self.mtex_event_prob_h_b_e, buff=var_buff) myutil.critical_point_move_to(self.txt_event_prob_h_b_e[2], LEFT + DOWN, 3.5 * RIGHT + 0.5 * UP) # P(H): 実際に病気である確率。(難しい。推定可能,検査で改善可能) self.mtex_event_prob_h = MathTex(r"P(", r"H", r")").scale(self.scale_eq_f) self.mtex_event_prob_h[1].set_color(self.col_h) self.txt_event_prob_h = [ Text(r": 実際に病気の確率", ).scale(self.scale_txt_f), Text(r": 推定,改善可能", ).scale(self.scale_txt_f), Text(r"(既知)", ).scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.mtex_event_prob_h, RIGHT + DOWN, -3.0 * RIGHT + -0.4 * UP) self.txt_event_prob_h[0].next_to(self.mtex_event_prob_h, buff=var_buff) self.txt_event_prob_h[1].next_to(self.mtex_event_prob_h, buff=var_buff) myutil.critical_point_move_to(self.txt_event_prob_h[2], LEFT + DOWN, 3.5 * RIGHT + -0.4 * UP) # P(\lnot H): 実際に病気でない確率。H の補集合,P(H) がわかればわかる self.mtex_event_prob_not_h = MathTex(r"P(", r"\lnot", r"H", r")").scale(self.scale_eq_f) self.mtex_event_prob_not_h[1].set_color(self.col_n) self.mtex_event_prob_not_h[2].set_color(self.col_h) self.txt_event_prob_not_h = [ Text(r": 実際に病気でない確率", ).scale(self.scale_txt_f), Text(r": H の補集合", ).scale(self.scale_txt_f), Text(r"(既知)", ).scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.mtex_event_prob_not_h, RIGHT + DOWN, -3.0 * RIGHT + -1.3 * UP) self.txt_event_prob_not_h[0].next_to(self.mtex_event_prob_not_h, buff=var_buff) self.txt_event_prob_not_h[1].next_to(self.mtex_event_prob_not_h, buff=var_buff) myutil.critical_point_move_to(self.txt_event_prob_not_h[2], LEFT + DOWN, 3.5 * RIGHT + -1.3 * UP) # P(E|H): 実際に病気の時に検査+ の確率: 検査キットの性能, (測定可能,既知) self.mtex_event_prob_e_b_h = MathTex(r"P(", r"E", r"|", r"H", r")").scale(self.scale_eq_f) self.mtex_event_prob_e_b_h[1].set_color(self.col_e) self.mtex_event_prob_e_b_h[3].set_color(self.col_h) self.txt_event_prob_e_b_h = [ Text(r": 実際に病気の時に,検査+の確率", t2c={ r"[12:13]": self.col_positive, }).scale(self.scale_txt_f), Text(r": 検査の性能: 感度", ).scale(self.scale_txt_f), Text(r"(既知)", ).scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.mtex_event_prob_e_b_h, RIGHT + DOWN, -3.0 * RIGHT + -2.2 * UP) self.txt_event_prob_e_b_h[0].next_to(self.mtex_event_prob_e_b_h, buff=var_buff) self.txt_event_prob_e_b_h[1].next_to(self.mtex_event_prob_e_b_h, buff=var_buff) myutil.critical_point_move_to(self.txt_event_prob_e_b_h[2], LEFT + DOWN, 3.5 * RIGHT + -2.2 * UP) # P(E|\lnot H): 実際に病気でない時に検査+ の確率: 検査キットの性能 (測定可能,既知) self.mtex_event_prob_e_b_not_h = MathTex(r"P(", r"E", r"|", r"\lnot", r"H", r")").scale(self.scale_eq_f) self.mtex_event_prob_e_b_not_h[1].set_color(self.col_e) self.mtex_event_prob_e_b_not_h[3].set_color(self.col_n) self.mtex_event_prob_e_b_not_h[4].set_color(self.col_h) self.txt_event_prob_e_b_not_h = [ Text(r": 実際に病気でない時に,検査+の確率", t2c={ r"[14:15]": self.col_positive, }).scale(self.scale_txt_f), Text(r": 検査の性能: 1 - 特異度", ).scale(self.scale_txt_f), Text(r"(既知)", ).scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.mtex_event_prob_e_b_not_h, RIGHT + DOWN, -3.0 * RIGHT + -3.1 * UP) self.txt_event_prob_e_b_not_h[0].next_to( self.mtex_event_prob_e_b_not_h, buff=var_buff) self.txt_event_prob_e_b_not_h[1].next_to( self.mtex_event_prob_e_b_not_h, buff=var_buff) myutil.critical_point_move_to(self.txt_event_prob_e_b_not_h[2], LEFT + DOWN, 3.5 * RIGHT + -3.1 * UP)
def create_bayes_eq(self): """create all mobjects """ self.txt_title_bayes = Text(r"再検査の効果").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) # full Bayes form # indices for h,e color (MathTex removes white space)) self.mtex_bayes_full = MathTex( r"P(H|E)", # [0] e [0,4], h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(H)", # [5] h [5,2] r"P(E|H)}", # [6] e [6,2], h [6,4] r"+", # [7] r"{P(\lnot H)", # [8] h [8,3], n [8,2] r"P(E |\lnot H)}}", # [9] e [9,2], h [9,5], n [9,4] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_full, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4], [5, 2], [6, 4], [8, 3], [9, 5]] for [i, j] in self.h_indices: self.mtex_bayes_full[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [6, 2], [9, 2]] for [i, j] in self.e_indices: self.mtex_bayes_full[i][j].set_color(self.col_e) self.n_indices = [[8, 2], [9, 4]] for [i, j] in self.n_indices: self.mtex_bayes_full[i][j].set_color(self.col_n) # 11 people example values self.p_h_nom = MathTex(r"P(H)", r"=", r"0.09").scale( self.scale_eq_f).move_to(-2.0 * RIGHT + +0.5 * UP) self.p_h_nom[0][2].set_color(self.col_h) self.p_h_den = copy.deepcopy(self.p_h_nom) # P(E|H) nominator term, denominator self.p_e_h_nom = MathTex(r"P(E|H)", r"=", r"1.0").scale( self.scale_eq_f).move_to(+2.5 * RIGHT + +0.5 * UP) self.p_e_h_nom[0][2].set_color(self.col_e) self.p_e_h_nom[0][4].set_color(self.col_h) self.p_e_h_den = copy.deepcopy(self.p_e_h_nom) # P(\lnot H) self.p_not_h_den = MathTex(r"P(\lnot H)", r"=", r"0.91").scale( self.scale_eq_f).move_to(-2.2 * RIGHT + -0.5 * UP) self.p_not_h_den[0][2].set_color(self.col_n) self.p_not_h_den[0][3].set_color(self.col_h) # P(E|\lnot H) self.p_e_not_h_den = MathTex(r"P(E|\lnot H)", r"=", r"0.01").scale( self.scale_eq_f).move_to(+2.5 * RIGHT + -0.5 * UP) self.p_e_not_h_den[0][2].set_color(self.col_e) self.p_e_not_h_den[0][4].set_color(self.col_n) self.p_e_not_h_den[0][5].set_color(self.col_h) # # simple from the figure # self.p_h_e_simple = MathTex(r"P(H|E)", r"=", r"{1", r"\over", r"11}", r"\approx", r"0.09").\ # scale(self.scale_eq_f).move_to(0.0 * RIGHT + +2.0 * UP) # self.p_h_e_simple[0][2].set_color(self.col_h) # self.p_h_e_simple[0][4].set_color(self.col_e) # --- Event examples # event example H self.mtex_event_h = MathTex(r"H").scale( self.scale_event_eq_f).set_color(self.col_h).move_to(0.2 * RIGHT + 3.2 * UP) self.txt_event_h = Text(r": 病気").scale( self.scale_event_txt_f).move_to(1.3 * RIGHT + 3.2 * UP) # event example E self.mtex_event_e = MathTex(r"E").scale( self.scale_event_eq_f).set_color(self.col_e).move_to(2.7 * RIGHT + 3.17 * UP) self.txt_event_e = Text(r": 検査+", t2c={ r"[3:4]": self.col_positive }).scale(self.scale_event_txt_f).move_to(4.0 * RIGHT + 3.17 * UP) # 11 people position self.nb_people = self.nb_true_positive + self.nb_false_positive # create 11 people self.svg_people = [] for i in range(0, self.nb_people): pos = self.people_pos_left + i * self.people_delta_dist person = SVGMobject("svg/person_silhouette", fill_opacity=1.0).scale(self.person_size).\ move_to(pos).set_color(self.col_false_positive) self.svg_people.append(person) # true positive color self.svg_people[0].set_color(self.col_positive) # move true positive label self.label_true_positive = myutil.LabeledRectangle(Text( r"真+", t2c={ "[0:1]": WHITE, "[1:2]": WHITE }).scale(self.scale_label_txt), tip_direction=DOWN, color=RED, fill_color=RED, fill_opacity=1.0) myutil.critical_point_move_to(self.label_true_positive, DOWN, self.people_pos_left).\ shift(self.person_size * self.label_shift_up * UP) self.label_false_positives = [] for i in range(0, self.nb_false_positive): fpos_dst = self.people_pos_left + ( i + self.nb_true_positive) * self.people_delta_dist label_fpos = myutil.LabeledRectangle( Text( r"偽+".format(i), # i is for debug t2c={ "[0:1]": BLACK, "[1:2]": RED, "[2:]": BLACK }).scale(self.scale_label_txt), tip_direction=DOWN, color=WHITE, fill_color=WHITE, fill_opacity=1.0) self.label_false_positives.append(label_fpos) # move false positive label myutil.critical_point_move_to(self.label_false_positives[i], DOWN, fpos_dst).\ shift(self.person_size * self.label_shift_up * UP) if (i % 2 == 0): self.label_false_positives[i].shift(self.label_shift_up * UP) self.rhs = MathTex(r"\approx", r"0.91").scale( self.scale_eq_f).move_to(-2.4 * RIGHT + 2.0 * UP) self.text_repeat = Text(r"独立した再検査によって精度向上").scale( self.scale_txt_f).move_to(-1.0 * RIGHT + 1.0 * UP)
def create_title(self): """ """ scale_f = 0.7 self.txt_title_ja = Text(r"病気の検査とベイズの定理").scale(self.scale_title_f) self.txt_title_en = Text( r"Medical Diagnosis and Bayes' Theorem").scale(self.scale_txt_f) self.txt_ref_video = [ Text(r"参考ビデオ(英語)").scale(self.scale_txt_f), Text(r"* 3Blue1Brown: Bayes theorem").scale(self.scale_txt_f), Text(r"* Numberphile: Are you REALLY sick?").scale( self.scale_txt_f), Text(r"* Veritasium: The Bayesian Trap").scale(self.scale_txt_f) ] self.txt_footnote_en = Text( r"The video narration is in Japanese with English subtitles." ).scale(self.scale_txt_f * 0.85) myutil.critical_point_move_to(self.txt_title_ja, LEFT + DOWN, ORIGIN + -6 * RIGHT + 2.8 * UP) myutil.critical_point_move_to(self.txt_title_en, LEFT + DOWN, ORIGIN + -6 * RIGHT + 1.8 * UP) myutil.critical_point_move_to(self.txt_ref_video[0], LEFT + DOWN, ORIGIN + -6 * RIGHT + 0.5 * UP) myutil.critical_point_move_to(self.txt_ref_video[1], LEFT + DOWN, ORIGIN + -5.5 * RIGHT + -0.5 * UP) myutil.critical_point_move_to(self.txt_ref_video[2], LEFT + DOWN, ORIGIN + -5.5 * RIGHT + -1.4 * UP) myutil.critical_point_move_to(self.txt_ref_video[3], LEFT + DOWN, ORIGIN + -5.5 * RIGHT + -2.3 * UP) myutil.critical_point_move_to(self.txt_footnote_en, LEFT + DOWN, ORIGIN + -6.5 * RIGHT + -3.2 * UP)
def create_bayes_eq(self): """ """ self.txt_title_bayes = Text(r"ベイズの定理").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) self.txt_how_to_read = Text(r"式の「読み方」").scale(self.scale_txt_f) myutil.critical_point_move_to(self.txt_how_to_read, LEFT + DOWN, ORIGIN + -1.0 * RIGHT + 3.0 * UP) # simple Bayes form # indices for h,e color self.mtex_bayes_simple = MathTex(r"P(H|E)", # e [0,4] h [0,2] r"={", # r"{P(H)", # h [2,2] r"P(E|H)}", # e [3,2], h [3,4] r"\over", # r"{P(E)}", # e [5,2] r"}", # ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_simple, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.1 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4]] for [i,j] in self.h_indices: self.mtex_bayes_simple[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [5, 2]] for [i,j] in self.e_indices: self.mtex_bayes_simple[i][j].set_color(self.col_e) # events notation self.tex_events_eq = MathTex(r"E", r",", r"H", r", A, B:").scale(self.scale_eq_f) self.tex_events_eq[0].set_color(self.col_e) self.tex_events_eq[2].set_color(self.col_h) self.txt_events_exp = [ Text(r"事象 (Event): ").scale(self.scale_txt_f), Text(r"病気, "). scale(self.scale_txt_f), Text(r"検査+", t2c={r"+": self.col_positive},).scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.tex_events_eq, LEFT + DOWN, ORIGIN + -6.0 * RIGHT + 0.0 * UP) myutil.critical_point_move_to(self.txt_events_exp[0], LEFT + DOWN, ORIGIN + -2.6 * RIGHT + 0.0 * UP) for i in range(1, len(self.txt_events_exp)): self.txt_events_exp[i].next_to(self.txt_events_exp[i-1], buff=0.2) # conditional notation self.tex_cond_eq = MathTex(r"H", r"|", r"E").scale(self.scale_eq_f) self.tex_cond_eq[0].set_color(self.col_h) self.tex_cond_eq[2].set_color(self.col_e) myutil.critical_point_move_to(self.tex_cond_eq, LEFT + DOWN, ORIGIN + -6.0 * RIGHT + -1.0 * UP) self.txt_cond_exp_1 = [ Text(r": Evidence (証拠)").scale(self.scale_txt_f).set_color(self.col_e), Text(r"の時,"). scale(self.scale_txt_f), Text(r"Hypothesis (仮説)").scale(self.scale_txt_f).set_color(self.col_h), ] myutil.critical_point_move_to(self.txt_cond_exp_1[0], LEFT + DOWN, ORIGIN + -4.6 * RIGHT + -1.0 * UP) for i in range(1, len(self.txt_cond_exp_1)): self.txt_cond_exp_1[i].next_to(self.txt_cond_exp_1[i-1], buff=0.2) # baseline adjustment of Evidence self.txt_cond_exp_1[0].shift(0.05 * UP) # Hypothesis given the Evidence self.txt_cond_exp_2 = [ Text(r"Hypothesis"). scale(self.scale_txt_f).set_color(self.col_h), Text(r"given"). scale(self.scale_txt_f), Text(r"the Evidence").scale(self.scale_txt_f).set_color(self.col_e), ] myutil.critical_point_move_to(self.txt_cond_exp_2[0], LEFT + DOWN, ORIGIN + -4.2 * RIGHT + -2.0 * UP) for i in range(1, len(self.txt_cond_exp_2)): self.txt_cond_exp_2[i].next_to(self.txt_cond_exp_2[i-1], buff=0.2) # baseline adjustment of the Evidence self.txt_cond_exp_2[2].shift(0.05 * UP) # animation destination, destination of "Hypothesis of the Evidence" self.tex_cond_eq_2 = MathTex(r"H", r"|", r"E").scale(self.scale_eq_f) self.tex_cond_eq_2[0].set_color(self.col_h) self.tex_cond_eq_2[2].set_color(self.col_e) myutil.critical_point_move_to(self.tex_cond_eq_2, LEFT + DOWN, ORIGIN + -4.2 * RIGHT + -2.0 * UP) # probability notation self.tex_prob_eq = [ MathTex(r"P()"). scale(self.scale_eq_f), MathTex(r"P(A)"). scale(self.scale_eq_f), MathTex(r"P(", r"H", r"|", r"E", r")").scale(self.scale_eq_f), ] self.tex_prob_eq[2][1].set_color(self.col_h) self.tex_prob_eq[2][3].set_color(self.col_e) self.txt_prob_exp = [ Text(r": 〜の確率 (Probability)").scale(self.scale_txt_f), Text(r": A の確率"). scale(self.scale_txt_f), Text(r": E の時に H になる確率", t2c={"[1:2]": self.col_e, "[5:6]": self.col_h} ). scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.tex_prob_eq[0], LEFT + DOWN, ORIGIN + -6.0 * RIGHT + -2.0 * UP) myutil.critical_point_move_to(self.tex_prob_eq[1], LEFT + DOWN, ORIGIN + 2.0 * RIGHT + -2.0 * UP) myutil.critical_point_move_to(self.tex_prob_eq[2], LEFT + DOWN, ORIGIN + -6.0 * RIGHT + -3.0 * UP) for i in range(0, len(self.txt_prob_exp)): self.txt_prob_exp[i].next_to(self.tex_prob_eq[i])
def animate_positive_only(self): """Get positive only """ people_negative_xy_idx = [] for iy in range(0, self.nb_people_y): for ix in range(0, self.nb_people_x): if ([ix, iy] in self.true_positive_pcoords): # skip true positive continue if ([ix, iy] in self.false_positive_pcoords): # skip false positive continue people_negative_xy_idx.append([ix, iy]) people_negative = [] for pcoord in people_negative_xy_idx: people_negative.append( self.svg_people[self.get_person_1d_idx(pcoord)]) person_size = 0.9 nb_person = 11 nb_true_positive = 1 people_pos_left = -5.5 * RIGHT + -2.5 * UP people_delta_dist = 1.1 * RIGHT label_shift_up = 1.0 if (self.is_show_only): # remove people negative self.remove(*people_negative) # move true positive tpos_idx = self.get_person_1d_idx(self.true_positive_pcoords[0]) tpos_dst = people_pos_left self.svg_people[tpos_idx].scale( person_size * (1.0 / self.size_person_1000)).move_to(tpos_dst) # move true positive label myutil.critical_point_move_to(self.label_true_positive, DOWN, tpos_dst).\ shift(person_size * label_shift_up * UP) for i in range(0, len(self.false_positive_pcoords)): fpos_idx = self.get_person_1d_idx( self.false_positive_pcoords[i]) # move false positive fpos_dst = people_pos_left + ( i + nb_true_positive) * people_delta_dist self.svg_people[fpos_idx].scale( person_size * (1.0 / self.size_person_1000)).move_to(fpos_dst) # move false positive label myutil.critical_point_move_to(self.label_false_positive[i], DOWN, fpos_dst).\ shift(person_size * label_shift_up * UP) if (i % 2 == 0): self.label_false_positive[i].shift(label_shift_up * UP) return # remove people negative self.play(*[FadeOut(mobj) for mobj in people_negative]) # move true positive tpos_idx = self.get_person_1d_idx(self.true_positive_pcoords[0]) tpos_dst = people_pos_left # make true positive front self.remove(self.svg_people[tpos_idx], self.label_true_positive) self.add(self.svg_people[tpos_idx], self.label_true_positive) # move true positive label (create a dummy and use for the destination position calculation) tpos_label_dst_tmp = copy.deepcopy(self.label_true_positive) myutil.critical_point_move_to(tpos_label_dst_tmp, DOWN, tpos_dst).shift(person_size * label_shift_up * UP) # create a dummy dstination copy tpos_person_dst_tmp = copy.deepcopy(self.svg_people[tpos_idx]) tpos_person_dst_tmp.scale( person_size * (1.0 / self.size_person_1000)).move_to(tpos_dst) self.play( Transform(self.svg_people[tpos_idx], tpos_person_dst_tmp), ApplyMethod(self.label_true_positive.move_to, tpos_label_dst_tmp.get_center())) self.wait(self.time_wait) # Same as the true positive people and labels fpos_trans = [] label_move = [] for i in range(0, len(self.false_positive_pcoords)): fpos_idx = self.get_person_1d_idx(self.false_positive_pcoords[i]) fpos_dst = people_pos_left + (i + nb_true_positive) * people_delta_dist ptmp = copy.deepcopy(self.svg_people[fpos_idx]) ptmp.scale(person_size * (1.0 / self.size_person_1000)).move_to(fpos_dst) fpos_trans.append(Transform(self.svg_people[fpos_idx], ptmp)) ltmp = copy.deepcopy(self.label_false_positive[i]) myutil.critical_point_move_to(ltmp, DOWN, fpos_dst).shift( person_size * label_shift_up * UP) if (i % 2 == 0): ltmp.shift(label_shift_up * UP) label_move.append( ApplyMethod(self.label_false_positive[i].move_to, ltmp.get_center())) self.play(*fpos_trans, *label_move) self.wait(self.time_wait)
def create_bayes_eq(self): """create all mobjects """ self.txt_title_bayes = Text(r"具体例 2").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) # full Bayes form # indices for h,e color (MathTex removes white space)) self.mtex_bayes_full = MathTex( r"P(H|E)", # [0] e [0,4], h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(H)", # [5] h [5,2] r"P(E|H)}", # [6] e [6,2], h [6,4] r"+", # [7] r"{P(\lnot H)", # [8] h [8,3], n [8,2] r"P(E |\lnot H)}}", # [9] e [9,2], h [9,5], n [9,4] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_full, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4], [5, 2], [6, 4], [8, 3], [9, 5]] for [i, j] in self.h_indices: self.mtex_bayes_full[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [6, 2], [9, 2]] for [i, j] in self.e_indices: self.mtex_bayes_full[i][j].set_color(self.col_e) self.n_indices = [[8, 2], [9, 4]] for [i, j] in self.n_indices: self.mtex_bayes_full[i][j].set_color(self.col_n) # 1000 people example values self.p_h_nom = MathTex(r"0.001").scale(self.scale_eq_f).move_to( self.mtex_bayes_full[2].get_center()) self.p_h_den = MathTex(r"0.001").scale(self.scale_eq_f).move_to( self.mtex_bayes_full[5].get_center()) # P(E|H) nominator term, denominator self.p_e_h_nom = MathTex(r"1.0").scale(self.scale_eq_f).move_to( self.mtex_bayes_full[3].get_center()) self.p_e_h_den = MathTex(r"1.0").scale(self.scale_eq_f).move_to( self.mtex_bayes_full[6].get_center()) # P(\lnot H) self.p_not_h_den = MathTex(r"0.999").scale(self.scale_eq_f).move_to( self.mtex_bayes_full[8].get_center()) # P(E|\lnot H) self.p_e_not_h_den = MathTex(r"0.01").scale(self.scale_eq_f).move_to( self.mtex_bayes_full[9].get_center()) # simple from the figure self.p_h_e_simple = MathTex(r"P(H|E)", r"=", r"{1", r"\over", r"11}", r"\approx", r"0.09").\ scale(self.scale_eq_f).move_to(-3.0 * RIGHT + +2.0 * UP) self.p_h_e_simple[0][2].set_color(self.col_h) self.p_h_e_simple[0][4].set_color(self.col_e) self.mtex_exp = MathTex(r"P(H)", r"\ll", r"P(E|\lnot H)").\ scale(self.scale_eq_f).move_to(2.0 * RIGHT + +2.0 * UP) self.mtex_exp[0][2].set_color(self.col_h) self.mtex_exp[2][2].set_color(self.col_e) self.mtex_exp[2][4].set_color(self.col_n) self.mtex_exp[2][5].set_color(self.col_h) self.text_exp = Text(r"1% 間違える方法で 0.1% を見つける難しさ").scale(self.scale_txt_f).\ move_to(0.0 * RIGHT + +1.1 * UP) # --- Event examples # event example H self.mtex_event_h = MathTex(r"H").scale( self.scale_event_eq_f).set_color(self.col_h).move_to(0.2 * RIGHT + 3.2 * UP) self.txt_event_h = Text(r": 病気").scale( self.scale_event_txt_f).move_to(1.3 * RIGHT + 3.2 * UP) # event example E self.mtex_event_e = MathTex(r"E").scale( self.scale_event_eq_f).set_color(self.col_e).move_to(2.7 * RIGHT + 3.17 * UP) self.txt_event_e = Text(r": 検査+", t2c={ r"[3:4]": self.col_positive }).scale(self.scale_event_txt_f).move_to(4.0 * RIGHT + 3.17 * UP) # show 1000 people self.people_dx = (self.pos_people_max[0] - self.pos_people_min[0]) / (self.nb_people_x - 1) self.people_dy = (self.pos_people_max[1] - self.pos_people_min[1]) / (self.nb_people_y - 1) self.svg_people = [] for iy in range(0, self.nb_people_y): for ix in range(0, self.nb_people_x): pos = self.get_person_position([ix, iy]) person = SVGMobject("svg/person_silhouette", fill_opacity=1.0).scale(self.size_person_1000).\ move_to(pos).set_color(self.color_people) self.svg_people.append(person) # true positive label pos = self.get_person_position(self.true_positive_pcoords[0]) self.label_true_positive = myutil.LabeledRectangle(Text( r"真+", t2c={ "[0:1]": WHITE, "[1:2]": WHITE }).scale(self.scale_label_txt), tip_direction=DOWN, color=RED, fill_color=RED, fill_opacity=1.0) myutil.critical_point_move_to(self.label_true_positive, DOWN, pos).shift(self.size_person_1000 * 0.8 * UP) # false positive label idx = 0 self.label_false_positive = [] for pcoord in self.false_positive_pcoords: lr = myutil.LabeledRectangle(Text(r"偽+".format(idx), t2c={ "[0:1]": BLACK, "[1:2]": RED, "[2:]": BLACK }).scale(self.scale_label_txt), tip_direction=DOWN, color=WHITE, fill_color=WHITE, fill_opacity=1.0) pos = self.get_person_position(pcoord) myutil.critical_point_move_to(lr, DOWN, pos).shift( self.size_person_1000 * 0.8 * UP) self.label_false_positive.append(lr) idx += 1
def create_text(self): """ """ self.txt_want_to_know = Text(r"検査が不完全な時に知りたいこと").scale( self.scale_title_f) myutil.critical_point_move_to(self.txt_want_to_know, LEFT + DOWN, ORIGIN + -6.0 * RIGHT + 2.5 * UP) self.txt_test_positive = [ Text(r"1.検査結果").scale(self.scale_txt_f), Text(r"+", color=self.col_positive).scale(self.scale_txt_f), Text(r"の時").scale(self.scale_txt_f), Text(r",実際に病気").scale(self.scale_txt_f), Text(r"の可能性").scale(self.scale_txt_f), ] self.txt_test_negative = [ Text(r"2.検査結果").scale(self.scale_txt_f), Text(r"−", color=self.col_negative).scale(self.scale_txt_f), Text(r"の時").scale(self.scale_txt_f), Text(r",実際に¬病気", t2c={ "[4:5]": self.col_n }).scale(self.scale_txt_f), Text(r"の可能性").scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.txt_test_positive[0], LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.5 * UP) myutil.critical_point_move_to(self.txt_test_negative[0], LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 0.5 * UP) for i in range(1, len(self.txt_test_positive)): self.txt_test_positive[i].next_to(self.txt_test_positive[i - 1], buff=0.1) self.txt_test_negative[i].next_to(self.txt_test_negative[i - 1], buff=0.1) # Underlines pos_when_beg = [ self.txt_test_positive[2].get_critical_point(LEFT + DOWN) + self.line_down_offset * DOWN, # の時 0 self.txt_test_negative[2].get_critical_point(LEFT + DOWN) + self.line_down_offset * DOWN, # の時 1 self.txt_test_positive[4].get_critical_point(LEFT + DOWN) + self.line_down_offset * DOWN, # の可能性 0 self.txt_test_negative[4].get_critical_point(LEFT + DOWN) + self.line_down_offset * DOWN, # の可能性 1 ] pos_when_end = [ self.txt_test_positive[2].get_critical_point(RIGHT + DOWN) + self.line_down_offset * DOWN, # の時 0 self.txt_test_negative[2].get_critical_point(RIGHT + DOWN) + self.line_down_offset * DOWN, # の時 1 self.txt_test_positive[4].get_critical_point(RIGHT + DOWN) + self.line_down_offset * DOWN, # の可能性 0 self.txt_test_negative[4].get_critical_point(RIGHT + DOWN) + self.line_down_offset * DOWN, # の可能性 1 ] self.line_cond = [ Line(pos_when_beg[0], pos_when_end[0], color=self.line_color_when, stroke_width=self.line_stroke_when), Line(pos_when_beg[1], pos_when_end[1], color=self.line_color_when, stroke_width=self.line_stroke_when) ] self.line_possibility = [ Line(pos_when_beg[2], pos_when_end[2], color=self.line_color_cond, stroke_width=self.line_stroke_when), Line(pos_when_beg[3], pos_when_end[3], color=self.line_color_cond, stroke_width=self.line_stroke_when) ] # ベイズの定理 (Bayes theorem) self.txt_bayes_1 = Text(r"ベイズの定理 (Bayes theorem)").scale( self.scale_txt_f) myutil.critical_point_move_to(self.txt_bayes_1, LEFT + DOWN, ORIGIN + -6.0 * RIGHT + -1.0 * UP) # E の時,H の可能性 self.txt_bayes_2 = [ Text(r"E ").scale(self.scale_txt_f), Text(r"の時").scale(self.scale_txt_f), Text(r",H ").scale(self.scale_txt_f), Text(r"の可能性").scale(self.scale_txt_f), Text(r"→").scale(self.scale_txt_f), Text(r"E ", color=YELLOW).scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.txt_bayes_2[0], LEFT + DOWN, ORIGIN + -5.0 * RIGHT + -2.0 * UP) for i in range(1, len(self.txt_bayes_2)): self.txt_bayes_2[i].next_to(self.txt_bayes_2[i - 1], buff=0.1) # repeat E の時,H の可能性 self.txt_bayes_3 = [ Text(r"E ").scale(self.scale_txt_f), Text(r"の時").scale(self.scale_txt_f), Text(r",H ").scale(self.scale_txt_f), Text(r"の可能性").scale(self.scale_txt_f), ] myutil.critical_point_move_to(self.txt_bayes_3[0], LEFT + DOWN, ORIGIN + -5.0 * RIGHT + -3.0 * UP) for i in range(1, len(self.txt_bayes_3)): self.txt_bayes_3[i].next_to(self.txt_bayes_3[i - 1], buff=0.1) self.txt_e_changes_h = Text(r"証拠により可能性が変化")
def create_bayes_eq(self): """create all mobjects """ self.txt_title_bayes = Text(r"具体例 1").scale(self.scale_title_f) myutil.critical_point_move_to(self.txt_title_bayes, LEFT + DOWN, ORIGIN + -6.3 * RIGHT + 3.0 * UP) # full Bayes form # indices for h,e color (MathTex removes white space)) self.mtex_bayes_full = MathTex( r"P(H|E)", # [0] e [0,4], h [0,2] r"={", # [1] r"{P(H)", # [2] h [2,2] r"P(E|H)}", # [3] e [3,2], h [3,4] r"\over", # [4] r"{P(H)", # [5] h [5,2] r"P(E|H)}", # [6] e [6,2], h [6,4] r"+", # [7] r"{P(\lnot H)", # [8] h [8,3], n [8,2] r"P(E |\lnot H)}}", # [9] e [9,2], h [9,5], n [9,4] ).scale(self.scale_eq_f) myutil.critical_point_move_to(self.mtex_bayes_full, LEFT + DOWN, ORIGIN + -5.0 * RIGHT + 1.4 * UP) self.h_indices = [[0, 2], [2, 2], [3, 4], [5, 2], [6, 4], [8, 2], [8, 3], [9, 4], [9, 5]] for [i, j] in self.h_indices: self.mtex_bayes_full[i][j].set_color(self.col_h) self.e_indices = [[0, 4], [3, 2], [6, 2], [9, 2]] for [i, j] in self.e_indices: self.mtex_bayes_full[i][j].set_color(self.col_e) self.n_indices = [[8, 2], [9, 4]] for [i, j] in self.n_indices: self.mtex_bayes_full[i][j].set_color(self.col_n) # --- Event examples # event example H self.mtex_event_h = MathTex(r"H"). scale(self.scale_event_eq_f).set_color(self.col_h).\ move_to(0.2 * RIGHT + 3.4 * UP) self.txt_event_h = Text(r": 病気").scale(self.scale_event_txt_f).\ move_to(1.3 * RIGHT + 3.4 * UP) # event example E self.mtex_event_e = MathTex(r"E").scale(self.scale_event_eq_f).set_color(self.col_e).\ move_to(2.7 * RIGHT + 3.37 * UP) self.txt_event_e = Text(r": 検査+", t2c={r"[3:4]": self.col_positive}).\ scale(self.scale_event_txt_f).move_to(4.0 * RIGHT + 3.37 * UP) # show ten people person_size = 0.9 nb_person = 10 nb_sick = 4 nb_false_positive = 2 nb_total_positive = nb_sick + nb_false_positive people_pos_left = -4.5 * RIGHT + -2.5 * UP people_delta_dist = 1.0 * RIGHT self.svg_people = [] for i in range(0, nb_person): pos = people_pos_left + i * people_delta_dist person = SVGMobject("svg/person_silhouette").scale( person_size).move_to(pos).set_color(self.color_people) self.svg_people.append(person) # 4 real sick people sign_scale = 1.0 sick_sign = Text(r"病").scale(sign_scale).set_color(self.col_ill_sign) self.sick_signs = [] for i in range(0, nb_sick): self.sick_signs.append(copy.deepcopy(sick_sign)) for i in range(0, nb_sick): pos = people_pos_left + ( i) * people_delta_dist + -0.3 * RIGHT + -0.15 * UP myutil.critical_point_move_to(self.sick_signs[i], LEFT + DOWN, pos) # 6 test positive test_p_sign = Text(r"+").scale(sign_scale).set_color(self.col_positive) self.test_positive_signs = [] for i in range(0, nb_total_positive): self.test_positive_signs.append(copy.deepcopy(test_p_sign)) for i in range(0, nb_total_positive): pos = people_pos_left + ( i) * people_delta_dist + -0.25 * RIGHT + +1.0 * UP myutil.critical_point_move_to(self.test_positive_signs[i], LEFT + DOWN, pos) # lines for brance anotation br_up_off = 1.6 * UP br_beg_off = 0.5 * LEFT br_end_off = 0.5 * RIGHT pos_sick_begin = self.svg_people[0].get_center( ) + br_up_off + br_beg_off pos_sick_end = self.svg_people[nb_sick - 1].get_center() + br_up_off + br_end_off pos_no_sick_begin = self.svg_people[nb_sick].get_center( ) + br_up_off + br_beg_off pos_no_sick_end = self.svg_people[ nb_person - 1].get_center() + br_up_off + br_end_off pos_false_pos_begin = self.svg_people[nb_sick].get_center( ) + br_up_off + br_beg_off pos_false_pos_end = self.svg_people[ nb_total_positive - 1].get_center() + br_up_off + br_end_off self.line_annot["sick"] = Line(pos_sick_begin, pos_sick_end) self.line_annot["no_sick"] = Line(pos_no_sick_begin, pos_no_sick_end).set_color(YELLOW) self.line_annot["true_positive"] = Line(pos_sick_begin, pos_sick_end).set_color(RED) self.line_annot["false_positive"] = Line( pos_false_pos_begin, pos_false_pos_end).set_color(BLUE) self.line_annot["total_positive"] = Line( pos_sick_begin, pos_false_pos_end).set_color(GREEN) for key in self.line_annot: self.brace_annot[key] = Brace(self.line_annot[key], UP) self.mtex_annot["sick"] = self.brace_annot["sick"].get_tex(r"H") self.mtex_annot["sick"].set_color(self.col_h) self.mtex_annot["no_sick"] = self.brace_annot["no_sick"].get_tex( r"\lnot", r"H") self.mtex_annot["no_sick"][0].set_color(self.col_n) self.mtex_annot["no_sick"][1].set_color(self.col_h) self.mtex_annot["true_positive"] = self.brace_annot[ "true_positive"].get_tex(r"E", r"|", r"H") self.mtex_annot["true_positive"][0].set_color(self.col_e) self.mtex_annot["true_positive"][2].set_color(self.col_h) self.mtex_annot["false_positive"] = self.brace_annot[ "false_positive"].get_tex(r"E", r"|", r"\lnot", r" H") self.mtex_annot["false_positive"][0].set_color(self.col_e) self.mtex_annot["false_positive"][2].set_color(self.col_n) self.mtex_annot["false_positive"][3].set_color(self.col_h) self.mtex_annot["total_positive"] = self.brace_annot[ "total_positive"].get_tex(r"E") self.mtex_annot["total_positive"].set_color(self.col_e) self.text_annot["sick"] = Text(r"病気").scale(self.scale_txt_f) self.text_annot["no_sick"] = Text(r"¬病気", t2c={ "[0:1]": self.col_n }).scale(self.scale_txt_f) self.text_annot["true_positive"] = Text(r"病気の時,検査+", t2c={ "[7:8]": self.col_positive }).scale(self.scale_txt_f) self.text_annot["false_positive"] = Text(r"¬病気の時,検査+", t2c={ "[0:1]": self.col_n, "[8:9]": self.col_positive }).scale(self.scale_txt_f) self.text_annot["total_positive"] = Text(r"検査+", t2c={ "[2:3]": self.col_positive }).scale(self.scale_txt_f) # copy the math tex position to text for key in self.annot_key: self.text_annot[key].move_to(self.mtex_annot[key].get_center())