from manim import * import elementy.elements as elements frame_width = config["frame_width"] frame_height = config["frame_height"] Elements = elements.get_elements() def narrator(a): for i in a: globals()[f't{str(i)}']=Text(a[i], font = "STZhongsong").to_edge(DOWN).scale(0.6) class Element(VGroup): def __init__( self, **kwargs ): super().__init__(**kwargs) square = RoundedRectangle(height=2, width=2, corner_radius=0.3, fill_opacity=0.8, fill_color=GRAY) self.add(square) self.square = square def add_content(self, current_content = None, next_content = None, is_number = True): if is_number: font_size = 15 else: font_size = 25 if current_content is not None: mob_current_content = Text(current_content, font_size=font_size).move_to(self) self.add(mob_current_content) self.current_content = mob_current_content if next_content is not None: mob_next_content = Text(next_content, font_size=font_size).move_to(self).flip(axis=[1,0,0]).set_opacity(0) self.add(mob_next_content) self.next_content = mob_next_content @property def flip(self): anim = AnimationGroup(self.square.animate.flip(axis=[1,0,0]).set_color(self.target_color), self.current_content.animate.flip(axis=[1,0,0]).set_opacity(0), self.next_content.animate.flip(axis=[1,0,0]).set_opacity(1)) return anim def get_target_color(self, value, min, max, color1, color2): target_value = (value-min)/(max-min) color = interpolate_color(color1, color2, target_value) self.target_color = color class ElementsPeriodicTable(VGroup): def __init__(self, **kwargs): super().__init__(**kwargs) row = 5 col = 18 elements = VGroup() for i in range(row): for j in range(col): elements.add(Element()) elements.arrange_in_grid(row, col, buff=0.5) elements.set_width(frame_width*0.95) del elements.submobjects[1:17] del elements.submobjects[4:14] del elements.submobjects[12:22] self.elements = elements self.add(elements) self.origin() def origin(self): n = 0 symbol = [] for element in self.elements: element.add_content(current_content=Elements[n].symbol, is_number=False) symbol.append(Elements[n].symbol) n += 1 self.symbol = symbol def to_property(self, property_list, color1, color2): max_value = max(property_list) min_value = min(property_list) self.get_full_graph() n = 0 for element in self.elements: value = property_list[n] element.add_content(next_content=str(round(value, 2))) element.get_target_color(value, min_value, max_value, color1, color2) n += 1 anim1 = LaggedStart(*[ele.flip for ele in self.elements], run_time=3) anim2 = Wait(3) anim = Succession(anim1, anim2) return anim @property def to_affinity(self): property_list = [Elements[i].electron_affinity for i in range(len(self.elements))] print(property_list) self.property_list = property_list self.graph_color = PURPLE return self.to_property(property_list, PURPLE_A, PURPLE_E) @property def to_ionization(self): property_list = [Elements[i].ionisation_energies[0] for i in range(len(self.elements))] self.property_list = property_list self.graph_color = BLUE return self.to_property(property_list, BLUE_A, BLUE_E) @property def to_radius(self): property_list = [Elements[i].radius_covalent for i in range(len(self.elements))] self.property_list = property_list self.graph_color = GREEN return self.to_property(property_list, GREEN_A, GREEN_E) def get_graph(self): property_list = self.property_list period = self.period symbol = self.symbol if period == 1: ele_index = [0, 2] elif period == 2: ele_index = [2, 10] elif period == 3: ele_index = [10, 18] elif period == 4: ele_index = [18, 36] elif period == 5: ele_index = [36, 54] period_property_list = property_list[ele_index[0]:ele_index[1]] period_symbol = symbol[ele_index[0]:ele_index[1]] max_value = max(period_property_list) min_value = min(period_property_list) plane = NumberPlane( x_range = (0, len(period_property_list)), y_range = (min_value, max_value), x_length = frame_width*0.8, y_length = frame_height*0.6, axis_config={"include_numbers": True} ) graph = plane.plot_line_graph( x_values = [i + 1 for i in range(len(self.elements))], y_values = period_property_list, line_color = self.graph_color ) graph.center() n = 0 graph_vg = VGroup(graph) for dot in graph["vertex_dots"]: text = Text(period_symbol[n], font_size=30).next_to(dot, UP) graph_vg.add(text) n += 1 self.graph = graph_vg def set_period(self, period): self.period = period self.get_graph() def get_full_graph(self): property_list = self.property_list symbol = self.symbol max_value = max(property_list) min_value = min(property_list) plane = NumberPlane( x_range = (0, len(property_list)), y_range = (min_value, max_value), x_length = frame_width*0.8, y_length = frame_height*0.6, axis_config={"include_numbers": True} ) graph = plane.plot_line_graph( x_values = [i + 1 for i in range(len(self.elements))], y_values = property_list, line_color = self.graph_color ) graph.center() # n = 0 # graph_vg = VGroup(graph) # for dot in graph["vertex_dots"]: # text = Text(symbol[n], font_size=15).next_to(dot, UP) # graph_vg.add(text) # n += 1 self.full_graph = graph return graph class AtomicOrbitalTemplate(TexTemplate): def __init__(self,**kwargs): super().__init__(**kwargs) self.add_to_preamble("\\usepackage{tikzorbital}") class AtomicOrbital(VGroup): def __init__( self, orbital_name: str, orbital_name_tex: str, **kwargs ): super().__init__(**kwargs) self.template = AtomicOrbitalTemplate() orbital = MathTex("\\begin{tikzpicture} \\orbital{%s} \\end{tikzpicture}" % orbital_name, tex_template = self.template, stroke_width=2, fill_color=BLUE, fill_opacity=0.6, **kwargs) name = MathTex(orbital_name_tex) name.next_to(orbital, DOWN) self.orbital = orbital self.name = name self.add(self.orbital) self.add(self.name) class AtomicElectronsArrangement(VGroup): def __init__(self, orbital_name, orbital_label, electrons_num, **kwargs): super().__init__(**kwargs) if orbital_name == 's': self.orbital_lines_buff = 2 self.orbital_num = 1 self.orbital_name_shift_distance = 0 orbital = AtomicOrbital('s', orbital_label) elif orbital_name == 'p': self.orbital_lines_buff = 6 self.orbital_num = 3 self.orbital_name_shift_distance = 0.3 orbital = AtomicOrbital('py', orbital_label) elif orbital_name == 'd': self.orbital_lines_buff = 6 self.orbital_num = 5 self.orbital_name_shift_distance = 0.8 orbital = AtomicOrbital('dyz', orbital_label) lines = VGroup(*[Line(LEFT/2, RIGHT/2) for i in range(self.orbital_num)]) lines.arrange(buff=0.5) orbital.next_to(lines[0], self.orbital_lines_buff*LEFT) orbital.name.shift(self.orbital_name_shift_distance*DOWN) self.orbital = orbital self.add(lines, orbital) self.center() dots = VGroup() if electrons_num > self.orbital_num: for i in range(self.orbital_num): dot = Dot(color=BLUE).move_to(lines[i]).shift(0.2*UP + 0.3*LEFT) arrow = MathTex(r'\uparrow').set_color(BLUE).scale(0.8).next_to(dot, 0.5*UP) dots.add(VGroup(dot ,arrow)) for i in range(electrons_num - self.orbital_num): dot = Dot(color=RED).move_to(lines[i]).shift(0.2*UP + 0.3*RIGHT) arrow = MathTex(r'\downarrow').set_color(RED).scale(0.8).next_to(dot, 0.5*UP) dots.add(VGroup(dot ,arrow)) else: for i in range(electrons_num): dot = Dot(color=BLUE).move_to(lines[i]).shift(0.2*UP + 0.3*LEFT) arrow = MathTex(r'\uparrow').set_color(BLUE).scale(0.8).next_to(dot, 0.5*UP) dots.add(VGroup(dot ,arrow)) dots.set_opacity(0) self.add(dots) self.dots = dots self.show_dots = self.anim_show_dots() def anim_show_dots(self): anim = Succession(*[ApplyMethod(dot.set_opacity, 1) for dot in self.dots]) # bug:使用 animate 会使物件 opacity 变为 1 的同时回到屏幕中心 return anim class AnimIonization(VGroup): def __init__(self, **kwargs): super().__init__(**kwargs) self.Be_B = self.mob_Be_B() self.N_O = self.mob_N_O() def mob_Be_B(self): text = VGroup(Text('Be', font_size=30), Text('B', font_size=30)).arrange(buff=5) text.shift(2*DOWN) Be_e = AtomicElectronsArrangement('s', '2s', 2).scale(0.8).next_to(text[0], 6*UP) B_e1 = AtomicElectronsArrangement('s', '2s', 2).scale(0.8) B_e2 = AtomicElectronsArrangement('p', '2p', 1).scale(0.8) B_e = VGroup(B_e1, B_e2).arrange(direction=UP, buff=1).next_to(text[1], 2*UP) self.show_Be_B_dots = Succession(Be_e.show_dots, B_e1.show_dots, B_e2.show_dots) mob_vg = VGroup(text, Be_e, B_e) return mob_vg def mob_N_O(self): text = VGroup(Text('N', font_size=30), Text('O', font_size=30)).arrange(buff=5) text.shift(DOWN) N_e = AtomicElectronsArrangement('p', '2p', 3).scale(0.6).next_to(text[0], 3*UP) O_e = AtomicElectronsArrangement('p', '2p', 4).scale(0.6).next_to(text[1], 3*UP) self.show_N_O_dots = Succession(N_e.show_dots, O_e.show_dots) mob_vg = VGroup(text, N_e, O_e) return mob_vg class AnimAtomRadius(VGroup): def __init__(self, **kwargs): super().__init__(**kwargs) self.two_atoms = self.mob_two_atoms() self.mob_atom() self.shrink = self.anim_shrink() self.grow = self.anim_grow() def anim_atom_wave(self, mob, radius=2): wave = Circle(radius=radius).set_color(color=[BLUE_B, BLUE_D]) anim = Broadcast(wave, focal_point=mob.get_center(), n_mobs=4, initial_opacity=0.8, run_time=4) return anim def mob_two_atoms(self): atom1 = Circle(radius=2, fill_opacity=0.8).set_color(color=[BLUE_A, BLUE_E]) atom2 = Circle(radius=2, fill_opacity=0.8).set_color(color=[BLUE_E, BLUE_A]).shift(3*RIGHT) line = DashedLine(0.75*LEFT, 0.75*RIGHT).shift(0.75*RIGHT) vertical_line = Line(3*UP, 3*DOWN, color=BLUE) atoms = VGroup(atom1, atom2).center() self.show_two_atoms = AnimationGroup(self.anim_atom_wave(atom1), self.anim_atom_wave(atom2)) lines = VGroup(line, vertical_line) self.show_lines_of_two_atom = Succession(DrawBorderThenFill(lines), FadeOut(lines)) return atoms def mob_atom(self): single_atom = Circle(radius=2, fill_opacity=0.8).set_color(color=[BLUE_A, BLUE_E]).set_z_index(-2) nucleus = Circle(radius=0.3, fill_opacity=0.8).set_color(color=[GREEN_A, GREEN_E]).set_z_index(2) atom = VGroup(single_atom, nucleus) single_atom.save_state() self.single_atom = single_atom self.nucleus = nucleus self.atom = atom def anim_shrink(self): dots_lines = VGroup() for i in range(4): dot = Dot().set_color(color=[RED, PURPLE]) distance = 0.3 + np.random.random() angle = np.random.random()*2*PI dot.shift([distance*np.cos(angle), distance*np.sin(angle), 0]) line = DashedLine(dot.get_center(), self.atom.get_center(), dashed_ratio=0.5).set_opacity(0.6) rotate_angle = angle_of_vector(dot.get_center()) arrow = MathTex(r'\leftarrow').scale(0.8).shift(line.get_length()/2*RIGHT).rotate(rotate_angle, about_point=ORIGIN) dot_line = VGroup(dot, line, arrow).add_updater(lambda z: z.rotate(0.04, about_point=ORIGIN)) dots_lines.add(dot_line) self.shrink_dots_lines = dots_lines anim = Succession(*[Succession(AnimationGroup(FadeIn(dot_line), ApplyMethod(self.single_atom.scale, 0.9)), Wait(2)) for dot_line in dots_lines]) return anim def anim_grow(self): dots = VGroup() dots_lines = VGroup() for i in range(4): dot = Dot().set_color(color=[RED, PURPLE]) distance = 0.5 + np.random.random()*1.5 angle = np.random.random()*2*PI dot.shift([distance*np.cos(angle), distance*np.sin(angle), 0]) dot.add_updater(lambda z: z.rotate(0.04, about_point=ORIGIN)) lines = VGroup() for pre_dot in dots: def generate_updater(line, dot1, dot2): def updater(line): line.become(DashedLine(dot1.get_center(), dot2.get_center(), dashed_ratio=0.5).set_opacity(0.6)) return updater single_line = DashedLine(dot.get_center(), pre_dot.get_center(), dashed_ratio=0.5).set_opacity(0.6) single_line.add_updater(generate_updater(single_line, dot, pre_dot)) lines.add(single_line) dot_line = VGroup(dot, lines) dots.add(dot) dots_lines.add(dot_line) self.grow_dots_lines = dots_lines anim = Succession(Restore(self.single_atom), *[Succession(AnimationGroup(FadeIn(dot_line, suspend_mobject_updating=False, run_time=0.01), ApplyMethod(self.single_atom.scale, 1.1)), Wait(2)) for dot_line in dots_lines]) return anim
标签:orbital,dots,color,self,元素,dot,property,周期表,性质 From: https://www.cnblogs.com/daxiangcai/p/17206874.html