From 134be057fb745047d3f8a414c43d50f504a6eaa9 Mon Sep 17 00:00:00 2001 From: Alec Helbling Date: Thu, 2 Feb 2023 21:59:31 -0500 Subject: [PATCH] Made mcmc example. Added ability to view matplotlib plots. --- manim_ml/decision_tree/decision_tree.py | 6 +- .../decision_tree/decision_tree_surface.py | 15 +-- manim_ml/decision_tree/helpers.py | 4 +- manim_ml/diffusion/mcmc.py | 96 ++++++++++++------ .../neural_network/layers/convolutional_2d.py | 1 + manim_ml/neural_network/layers/embedding.py | 1 + .../neural_network/layers/feed_forward.py | 1 + .../layers/feed_forward_to_feed_forward.py | 1 + manim_ml/neural_network/layers/image.py | 18 +++- .../neural_network/layers/max_pooling_2d.py | 2 + .../max_pooling_2d_to_convolutional_2d.py | 2 +- .../neural_network/layers/parent_layers.py | 6 +- manim_ml/neural_network/layers/triplet.py | 1 + manim_ml/neural_network/layers/vector.py | 1 + manim_ml/neural_network/neural_network.py | 34 +++++-- manim_ml/utils/mobjects/image.py | 10 +- manim_ml/utils/mobjects/plotting.py | 28 +++++ setup.py | 4 +- .../plotting/matplotlib_to_image_mobject.npz | Bin 0 -> 70164 bytes tests/test_flow.py | 6 -- tests/test_mcmc.py | 95 ++++++++++++++--- tests/test_plotting.py | 71 +++++++++++++ 22 files changed, 322 insertions(+), 81 deletions(-) create mode 100644 manim_ml/utils/mobjects/plotting.py create mode 100644 tests/control_data/plotting/matplotlib_to_image_mobject.npz delete mode 100644 tests/test_flow.py create mode 100644 tests/test_plotting.py diff --git a/manim_ml/decision_tree/decision_tree.py b/manim_ml/decision_tree/decision_tree.py index 8c3e7ba..a4904ed 100644 --- a/manim_ml/decision_tree/decision_tree.py +++ b/manim_ml/decision_tree/decision_tree.py @@ -6,12 +6,11 @@ TODO reimplement the decision 2D decision tree surface drawing. """ from manim import * -from manim_ml.decision_tree.classification_areas import ( +from manim_ml.decision_tree.decision_tree_surface import ( compute_decision_areas, merge_overlapping_polygons, ) import manim_ml.decision_tree.helpers as helpers -from manim_ml.one_to_one_sync import OneToOneSync import numpy as np from PIL import Image @@ -329,6 +328,7 @@ class DecisionTreeDiagram(Group): # If it is not a leaf then remove the placeholder leaf node # then show the split node # If it is a leaf then just show the leaf node + pass pass @override_animation(Create) @@ -345,7 +345,7 @@ class DecisionTreeDiagram(Group): expand_tree_animation = self.make_expand_tree_animation(node_expand_order) return expand_tree_animation -class DecisionTreeContainer(OneToOneSync): +class DecisionTreeContainer(): """Connects the DecisionTreeDiagram to the DecisionTreeEmbedding""" def __init__(self, sklearn_tree, points, classes): diff --git a/manim_ml/decision_tree/decision_tree_surface.py b/manim_ml/decision_tree/decision_tree_surface.py index 8ac3c1e..0015086 100644 --- a/manim_ml/decision_tree/decision_tree_surface.py +++ b/manim_ml/decision_tree/decision_tree_surface.py @@ -3,7 +3,6 @@ import numpy as np from collections import deque from sklearn.tree import _tree as ctree - class AABB: """Axis-aligned bounding box""" @@ -20,7 +19,6 @@ class AABB: return left, right - def tree_bounds(tree, n_features=None): """Compute final decision rule for each node in tree""" if n_features is None: @@ -36,8 +34,13 @@ def tree_bounds(tree, n_features=None): queue.extend([l, r]) return aabbs - -def compute_decision_areas(tree_classifier, maxrange, x=0, y=1, n_features=None): +def compute_decision_areas( + tree_classifier, + maxrange, + x=0, + y=1, + n_features=None +): """Extract decision areas. tree_classifier: Instance of a sklearn.tree.DecisionTreeClassifier @@ -73,7 +76,6 @@ def compute_decision_areas(tree_classifier, maxrange, x=0, y=1, n_features=None) rectangles[:, [1, 3]] = np.minimum(rectangles[:, [1, 3]], maxrange[1::2]) return rectangles - def plot_areas(rectangles): for rect in rectangles: color = ["b", "r"][int(rect[4])] @@ -87,7 +89,6 @@ def plot_areas(rectangles): ) plt.gca().add_artist(rp) - def merge_overlapping_polygons(all_polygons, colors=[BLUE, GREEN, ORANGE]): # get all polygons of each color polygon_dict = { @@ -161,7 +162,6 @@ def merge_overlapping_polygons(all_polygons, colors=[BLUE, GREEN, ORANGE]): return_polygons.append(polygon) return return_polygons - class IrisDatasetPlot(VGroup): def __init__(self, iris): points = iris.data[:, 0:2] @@ -359,3 +359,4 @@ class DecisionTreeSurface(VGroup): # 1. Make a line split animation # 2. Create the relevant classification areas # and transform the old ones to them + pass diff --git a/manim_ml/decision_tree/helpers.py b/manim_ml/decision_tree/helpers.py index 50a7ed8..2ee94ec 100644 --- a/manim_ml/decision_tree/helpers.py +++ b/manim_ml/decision_tree/helpers.py @@ -66,8 +66,8 @@ def compute_bfs_traversal(tree): while len(queue) > 0: current_index = queue.pop(0) traversal_order.append(current_index) - left_child_index = self.tree.children_left[node_index] - right_child_index = self.tree.children_right[node_index] + left_child_index = tree.children_left[node_index] + right_child_index = tree.children_right[node_index] is_leaf_node = left_child_index == right_child_index if not is_leaf_node: queue.append(left_child_index) diff --git a/manim_ml/diffusion/mcmc.py b/manim_ml/diffusion/mcmc.py index f2429a7..929874e 100644 --- a/manim_ml/diffusion/mcmc.py +++ b/manim_ml/diffusion/mcmc.py @@ -9,8 +9,9 @@ from tqdm import tqdm from manim_ml.utils.mobjects.probability import GaussianDistribution +######################## MCMC Algorithms ######################### -def gaussian_proposal(x, sigma=0.2): +def gaussian_proposal(x, sigma=1.0): """ Gaussian proposal distribution. @@ -86,7 +87,6 @@ class MultidimensionalGaussianPosterior: else: return -1e6 - def metropolis_hastings_sampler( log_prob_fn=MultidimensionalGaussianPosterior(), prop_fn=gaussian_proposal, @@ -154,6 +154,7 @@ def metropolis_hastings_sampler( return chain, np.array([]), proposals +#################### MCMC Visualization Tools ###################### class MCMCAxes(Group): """Container object for visualizing MCMC on a 2D axis""" @@ -161,11 +162,15 @@ class MCMCAxes(Group): def __init__( self, dot_color=BLUE, - dot_radius=0.05, + dot_radius=0.02, accept_line_color=GREEN, reject_line_color=RED, - line_color=WHITE, - line_stroke_width=1, + line_color=BLUE, + line_stroke_width=3, + x_range=[-3, 3], + y_range=[-3, 3], + x_length=5, + y_length=5 ): super().__init__() self.dot_color = dot_color @@ -176,10 +181,10 @@ class MCMCAxes(Group): self.line_stroke_width = line_stroke_width # Make the axes self.axes = Axes( - x_range=[-3, 3], - y_range=[-3, 3], - x_length=12, - y_length=12, + x_range=x_range, + y_range=y_range, + x_length=x_length, + y_length=y_length, x_axis_config={"stroke_opacity": 0.0}, y_axis_config={"stroke_opacity": 0.0}, tips=False, @@ -214,7 +219,12 @@ class MCMCAxes(Group): return create_guassian def make_transition_animation( - self, start_point, end_point, candidate_point, run_time=0.1 + self, + start_point, + end_point, + candidate_point, + show_dots=True, + run_time=0.1 ) -> AnimationGroup: """Makes an transition animation for a single point on a Markov Chain @@ -224,6 +234,8 @@ class MCMCAxes(Group): Start point of the transition end_point : Dot End point of the transition + show_dots: boolean, optional + Whether or not to show the dots Returns ------- @@ -237,21 +249,33 @@ class MCMCAxes(Group): # point_is_rejected = not candidate_location == end_location point_is_rejected = False if point_is_rejected: - return AnimationGroup() + return AnimationGroup(), Dot().set_opacity(0.0) else: create_end_point = Create(end_point) - create_line = Create( - Line( - start_point, - end_point, - color=self.line_color, - stroke_width=self.line_stroke_width, - ) - ) - return AnimationGroup( - create_end_point, create_line, lag_ratio=1.0, run_time=run_time + line = Line( + start_point, + end_point, + color=self.line_color, + stroke_width=self.line_stroke_width, + buff=-0.1 ) + create_line = Create(line) + + if show_dots: + return AnimationGroup( + create_end_point, + create_line, + lag_ratio=1.0, + run_time=run_time + ), line + else: + return AnimationGroup( + create_line, + lag_ratio=1.0, + run_time=run_time + ), line + def show_ground_truth_gaussian(self, distribution): """ """ mean = distribution.mu @@ -265,6 +289,7 @@ class MCMCAxes(Group): self, log_prob_fn=MultidimensionalGaussianPosterior(), prop_fn=gaussian_proposal, + show_dots=False, sampling_kwargs={}, ): """ @@ -281,6 +306,8 @@ class MCMCAxes(Group): Function to compute proposal location, by default gaussian_proposal initial_location : list, optional initial location for the markov chain, by default None + show_dots : bool, optional + whether or not to show the dots on the screen, by default False iterations : int, optional number of iterations of the markov chain, by default 100 @@ -293,8 +320,8 @@ class MCMCAxes(Group): mcmc_samples, warm_up_samples, candidate_samples = metropolis_hastings_sampler( log_prob_fn=log_prob_fn, prop_fn=prop_fn, **sampling_kwargs ) - print(f"MCMC samples: {mcmc_samples}") - print(f"Candidate samples: {candidate_samples}") + # print(f"MCMC samples: {mcmc_samples}") + # print(f"Candidate samples: {candidate_samples}") # Make the animation for visualizing the chain animations = [] # Place the initial point @@ -308,30 +335,41 @@ class MCMCAxes(Group): animations.append(create_initial_point) # Show the initial point's proposal distribution # NOTE: visualize the warm up and the iterations + lines = [] num_iterations = len(mcmc_samples) + len(warm_up_samples) for iteration in tqdm(range(1, num_iterations)): next_sample = mcmc_samples[iteration] - print(f"Next sample: {next_sample}") + # print(f"Next sample: {next_sample}") candidate_sample = candidate_samples[iteration - 1] # Make the next point next_point = Dot( - self.axes.coords_to_point(next_sample[0], next_sample[1]), + self.axes.coords_to_point( + next_sample[0], + next_sample[1] + ), color=self.dot_color, radius=self.dot_radius, ) candidate_point = Dot( - self.axes.coords_to_point(candidate_sample[0], candidate_sample[1]), + self.axes.coords_to_point( + candidate_sample[0], + candidate_sample[1] + ), color=self.dot_color, radius=self.dot_radius, ) # Make a transition animation - transition_animation = self.make_transition_animation( + transition_animation, line = self.make_transition_animation( current_point, next_point, candidate_point ) + lines.append(line) animations.append(transition_animation) # Setup for next iteration current_point = next_point # Make the final animation group - animation_group = AnimationGroup(*animations, lag_ratio=1.0) + animation_group = AnimationGroup( + *animations, + lag_ratio=1.0 + ) - return animation_group + return animation_group, VGroup(*lines) diff --git a/manim_ml/neural_network/layers/convolutional_2d.py b/manim_ml/neural_network/layers/convolutional_2d.py index 5b51e81..b95c740 100644 --- a/manim_ml/neural_network/layers/convolutional_2d.py +++ b/manim_ml/neural_network/layers/convolutional_2d.py @@ -174,6 +174,7 @@ class Convolutional2DLayer(VGroupNeuralNetworkLayer, ThreeDLayer): ) self.construct_activation_function() + super().construct_layer(input_layer, output_layer, **kwargs) def construct_activation_function(self): """Construct the activation function""" diff --git a/manim_ml/neural_network/layers/embedding.py b/manim_ml/neural_network/layers/embedding.py index 14f4be4..6e07fe5 100644 --- a/manim_ml/neural_network/layers/embedding.py +++ b/manim_ml/neural_network/layers/embedding.py @@ -50,6 +50,7 @@ class EmbeddingLayer(VGroupNeuralNetworkLayer): self.latent_distribution = GaussianDistribution( self.axes, mean=self.mean, cov=self.covariance ) # Use defaults + super().construct_layer(input_layer, output_layer, **kwargs) def add_gaussian_distribution(self, gaussian_distribution): """Adds given GaussianDistribution to the list""" diff --git a/manim_ml/neural_network/layers/feed_forward.py b/manim_ml/neural_network/layers/feed_forward.py index 262046a..af3f01e 100644 --- a/manim_ml/neural_network/layers/feed_forward.py +++ b/manim_ml/neural_network/layers/feed_forward.py @@ -76,6 +76,7 @@ class FeedForwardLayer(VGroupNeuralNetworkLayer): self.add(self.surrounding_rectangle, self.node_group) self.construct_activation_function() + super().construct_layer(input_layer, output_layer, **kwargs) def construct_activation_function(self): """Construct the activation function""" diff --git a/manim_ml/neural_network/layers/feed_forward_to_feed_forward.py b/manim_ml/neural_network/layers/feed_forward_to_feed_forward.py index d55ae78..f94d585 100644 --- a/manim_ml/neural_network/layers/feed_forward_to_feed_forward.py +++ b/manim_ml/neural_network/layers/feed_forward_to_feed_forward.py @@ -39,6 +39,7 @@ class FeedForwardToFeedForward(ConnectiveLayer): ): self.edges = self.construct_edges() self.add(self.edges) + super().construct_layer(input_layer, output_layer, **kwargs) def construct_edges(self): # Go through each node in the two layers and make a connecting line diff --git a/manim_ml/neural_network/layers/image.py b/manim_ml/neural_network/layers/image.py index 2d70e7e..e0e828b 100644 --- a/manim_ml/neural_network/layers/image.py +++ b/manim_ml/neural_network/layers/image.py @@ -1,21 +1,27 @@ from manim import * import numpy as np +from PIL import Image + from manim_ml.utils.mobjects.image import GrayscaleImageMobject from manim_ml.neural_network.layers.parent_layers import NeuralNetworkLayer -from PIL import Image - class ImageLayer(NeuralNetworkLayer): """Single Image Layer for Neural Network""" - def __init__(self, numpy_image, height=1.5, show_image_on_create=True, **kwargs): + def __init__( + self, + numpy_image, + height=1.5, + show_image_on_create=True, + **kwargs + ): super().__init__(**kwargs) self.image_height = height self.numpy_image = numpy_image self.show_image_on_create = show_image_on_create - def construct_layer(self, input_layer, output_layer): + def construct_layer(self, input_layer, output_layer, **kwargs): """Construct layer method Parameters @@ -29,7 +35,8 @@ class ImageLayer(NeuralNetworkLayer): # Assumed Grayscale self.num_channels = 1 self.image_mobject = GrayscaleImageMobject( - self.numpy_image, height=self.image_height + self.numpy_image, + height=self.image_height ) elif len(np.shape(self.numpy_image)) == 3: # Assumed RGB @@ -38,6 +45,7 @@ class ImageLayer(NeuralNetworkLayer): self.image_height ) self.add(self.image_mobject) + super().construct_layer(input_layer, output_layer, **kwargs) @classmethod def from_path(cls, image_path, grayscale=True, **kwargs): diff --git a/manim_ml/neural_network/layers/max_pooling_2d.py b/manim_ml/neural_network/layers/max_pooling_2d.py index 50e8409..5e5f3ea 100644 --- a/manim_ml/neural_network/layers/max_pooling_2d.py +++ b/manim_ml/neural_network/layers/max_pooling_2d.py @@ -67,6 +67,8 @@ class MaxPooling2DLayer(VGroupNeuralNetworkLayer, ThreeDLayer): input_layer.feature_map_size[0] / self.kernel_size, input_layer.feature_map_size[1] / self.kernel_size, ) + super().construct_layer(input_layer, output_layer, **kwargs) + def _make_output_feature_maps(self, num_input_feature_maps, input_feature_map_size): """Makes a set of output feature maps""" diff --git a/manim_ml/neural_network/layers/max_pooling_2d_to_convolutional_2d.py b/manim_ml/neural_network/layers/max_pooling_2d_to_convolutional_2d.py index dd6ce7b..43ba7dc 100644 --- a/manim_ml/neural_network/layers/max_pooling_2d_to_convolutional_2d.py +++ b/manim_ml/neural_network/layers/max_pooling_2d_to_convolutional_2d.py @@ -51,4 +51,4 @@ class MaxPooling2DToConvolutional2D(Convolutional2DToConvolutional2D): output_layer : NeuralNetworkLayer output layer """ - pass + super().construct_layer(input_layer, output_layer, **kwargs) diff --git a/manim_ml/neural_network/layers/parent_layers.py b/manim_ml/neural_network/layers/parent_layers.py index 711baff..0346cc5 100644 --- a/manim_ml/neural_network/layers/parent_layers.py +++ b/manim_ml/neural_network/layers/parent_layers.py @@ -1,7 +1,6 @@ from manim import * from abc import ABC, abstractmethod - class NeuralNetworkLayer(ABC, Group): """Abstract Neural Network Layer class""" @@ -28,7 +27,8 @@ class NeuralNetworkLayer(ABC, Group): output_layer : NeuralNetworkLayer following layer """ - pass + if "debug_mode" in kwargs and kwargs["debug_mode"]: + self.add(SurroundingRectangle(self)) @abstractmethod def make_forward_pass_animation(self, layer_args={}, **kwargs): @@ -41,7 +41,6 @@ class NeuralNetworkLayer(ABC, Group): def __repr__(self): return f"{type(self).__name__}" - class VGroupNeuralNetworkLayer(NeuralNetworkLayer): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -55,7 +54,6 @@ class VGroupNeuralNetworkLayer(NeuralNetworkLayer): def _create_override(self): return super()._create_override() - class ThreeDLayer(ABC): """Abstract class for 3D layers""" diff --git a/manim_ml/neural_network/layers/triplet.py b/manim_ml/neural_network/layers/triplet.py index 12062e6..789da38 100644 --- a/manim_ml/neural_network/layers/triplet.py +++ b/manim_ml/neural_network/layers/triplet.py @@ -35,6 +35,7 @@ class TripletLayer(NeuralNetworkLayer): # Make the assets self.assets = self.make_assets() self.add(self.assets) + super().construct_layer(input_layer, output_layer, **kwargs) @classmethod def from_paths( diff --git a/manim_ml/neural_network/layers/vector.py b/manim_ml/neural_network/layers/vector.py index 0d536c6..ca41b84 100644 --- a/manim_ml/neural_network/layers/vector.py +++ b/manim_ml/neural_network/layers/vector.py @@ -18,6 +18,7 @@ class VectorLayer(VGroupNeuralNetworkLayer): output_layer: "NeuralNetworkLayer", **kwargs, ): + super().construct_layer(input_layer, output_layer, **kwargs) # Make the vector self.vector_label = self.make_vector() self.add(self.vector_label) diff --git a/manim_ml/neural_network/neural_network.py b/manim_ml/neural_network/neural_network.py index 895f60a..2b6b833 100644 --- a/manim_ml/neural_network/neural_network.py +++ b/manim_ml/neural_network/neural_network.py @@ -38,6 +38,7 @@ class NeuralNetwork(Group): title=" ", layout="linear", layout_direction="left_to_right", + debug_mode=False ): super(Group, self).__init__() self.input_layers_dict = self.make_input_layers_dict(input_layers) @@ -51,6 +52,7 @@ class NeuralNetwork(Group): self.created = False self.layout = layout self.layout_direction = layout_direction + self.debug_mode = debug_mode # TODO take layer_node_count [0, (1, 2), 0] # and make it have explicit distinct subspaces # Construct all of the layers @@ -124,9 +126,17 @@ class NeuralNetwork(Group): if layer_index > 0: prev_layer = self.input_layers[layer_index - 1] # Run the construct layer method for each - current_layer.construct_layer(prev_layer, next_layer) + current_layer.construct_layer( + prev_layer, + next_layer, + debug_mode=self.debug_mode + ) - def _place_layers(self, layout="linear", layout_direction="top_to_bottom"): + def _place_layers( + self, + layout="linear", + layout_direction="top_to_bottom" + ): """Creates the neural network""" # TODO implement more sophisticated custom layouts # Default: Linear layout @@ -224,10 +234,16 @@ class NeuralNetwork(Group): return animation_group def make_forward_pass_animation( - self, run_time=None, passing_flash=True, layer_args={}, **kwargs + self, + run_time=None, + passing_flash=True, + layer_args={}, + per_layer_animations=False, + **kwargs ): """Generates an animation for feed forward propagation""" all_animations = [] + per_layer_animations = {} per_layer_runtime = ( run_time / len(self.all_layers) if not run_time is None else None ) @@ -275,13 +291,19 @@ class NeuralNetwork(Group): break layer_forward_pass = AnimationGroup( - layer_forward_pass, connection_input_pass, lag_ratio=0.0 + layer_forward_pass, + connection_input_pass, + lag_ratio=0.0 ) all_animations.append(layer_forward_pass) + # Add the animation to per layer animation + per_layer_animations[layer] = layer_forward_pass # Make the animation group animation_group = Succession(*all_animations, lag_ratio=1.0) - - return animation_group + if per_layer_animations: + return per_layer_animations + else: + return animation_group @override_animation(Create) def _create_override(self, **kwargs): diff --git a/manim_ml/utils/mobjects/image.py b/manim_ml/utils/mobjects/image.py index e9c942f..b6ac47a 100644 --- a/manim_ml/utils/mobjects/image.py +++ b/manim_ml/utils/mobjects/image.py @@ -2,7 +2,6 @@ from manim import * import numpy as np from PIL import Image - class GrayscaleImageMobject(Group): """Mobject for creating images in Manim from numpy arrays""" @@ -15,9 +14,14 @@ class GrayscaleImageMobject(Group): # Convert grayscale to rgb version of grayscale input_image = np.repeat(input_image, 3, axis=0) input_image = np.rollaxis(input_image, 0, start=3) - self.image_mobject = ImageMobject(input_image, image_mode="RBG") + self.image_mobject = ImageMobject( + input_image, + image_mode="RBG", + ) self.add(self.image_mobject) - self.image_mobject.set_resampling_algorithm(RESAMPLING_ALGORITHMS["nearest"]) + self.image_mobject.set_resampling_algorithm( + RESAMPLING_ALGORITHMS["nearest"] + ) self.image_mobject.scale_to_fit_height(height) @classmethod diff --git a/manim_ml/utils/mobjects/plotting.py b/manim_ml/utils/mobjects/plotting.py new file mode 100644 index 0000000..296091b --- /dev/null +++ b/manim_ml/utils/mobjects/plotting.py @@ -0,0 +1,28 @@ +from manim import * +import numpy as np +import matplotlib +import matplotlib.pyplot as plt +from PIL import Image +import io + +def convert_matplotlib_figure_to_image_mobject(fig, dpi=200): + """Takes a matplotlib figure and makes an image mobject from it + + Parameters + ---------- + fig : matplotlib figure + matplotlib figure + """ + fig.tight_layout(pad=0) + plt.axis('off') + fig.canvas.draw() + # Save data into a buffer + image_buffer = io.BytesIO() + plt.savefig(image_buffer, format='png', dpi=dpi) + # Reopen in PIL and convert to numpy + image = Image.open(image_buffer) + image = np.array(image) + # Convert it to an image mobject + image_mobject = ImageMobject(image, image_mode="RGB") + + return image_mobject \ No newline at end of file diff --git a/setup.py b/setup.py index e42ac64..97a8afa 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name="manim_ml", - version="0.0.16", - description=(" Machine Learning Animations in python using Manim."), + version="0.0.17", + description=("Machine Learning Animations in python using Manim."), packages=find_packages(), ) diff --git a/tests/control_data/plotting/matplotlib_to_image_mobject.npz b/tests/control_data/plotting/matplotlib_to_image_mobject.npz new file mode 100644 index 0000000000000000000000000000000000000000..80f6c792ad454c7cb1b4c83fae4aa8f412866c85 GIT binary patch literal 70164 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 Qi82DA4Uj$r)W^U80FSkY*8l(j literal 0 HcmV?d00001 diff --git a/tests/test_flow.py b/tests/test_flow.py deleted file mode 100644 index ef76f0c..0000000 --- a/tests/test_flow.py +++ /dev/null @@ -1,6 +0,0 @@ -from manim_ml.flow.flow import * - - -class TestScene(Scene): - def construct(self): - self.add(Rectangle()) diff --git a/tests/test_mcmc.py b/tests/test_mcmc.py index 745c42d..fad0ac3 100644 --- a/tests/test_mcmc.py +++ b/tests/test_mcmc.py @@ -4,30 +4,99 @@ from manim_ml.diffusion.mcmc import ( MultidimensionalGaussianPosterior, metropolis_hastings_sampler, ) +from manim_ml.utils.mobjects.plotting import convert_matplotlib_figure_to_image_mobject + +import numpy as np +import matplotlib.pyplot as plt +import seaborn as sns +import matplotlib +plt.style.use('dark_background') # Make the specific scene config.pixel_height = 1200 config.pixel_width = 1200 -config.frame_height = 12.0 -config.frame_width = 12.0 - +config.frame_height = 10.0 +config.frame_width = 10.0 def test_metropolis_hastings_sampler(iterations=100): samples, _, candidates = metropolis_hastings_sampler(iterations=iterations) assert samples.shape == (iterations, 2) +def plot_hexbin_gaussian_on_image_mobject( + sample_func, + xlim=(-4, 4), + ylim=(-4, 4) +): + # Fixing random state for reproducibility + np.random.seed(19680801) + n = 100_000 + samples = [] + for i in range(n): + samples.append(sample_func()) + samples = np.array(samples) + + x = samples[:, 0] + y = samples[:, 1] + + fig, ax0 = plt.subplots(1, figsize=(5, 5)) + + hb = ax0.hexbin(x, y, gridsize=50, cmap='gist_heat') + + ax0.set(xlim=xlim, ylim=ylim) + + return convert_matplotlib_figure_to_image_mobject(fig) class MCMCTest(Scene): - def construct(self): - axes = MCMCAxes() - self.play(Create(axes)) - gaussian_posterior = MultidimensionalGaussianPosterior( - mu=np.array([0.0, 0.0]), var=np.array([4.0, 2.0]) + + def construct( + self, + mu=np.array([0.0, 0.0]), + var=np.array([[1.0, 1.0]]) + ): + + def gaussian_sample_func(): + vals = np.random.multivariate_normal( + mu, + np.eye(2) * var, + 1 + )[0] + + return vals + + image_mobject = plot_hexbin_gaussian_on_image_mobject( + gaussian_sample_func ) - show_gaussian_animation = axes.show_ground_truth_gaussian(gaussian_posterior) - self.play(show_gaussian_animation) - chain_sampling_animation = axes.visualize_metropolis_hastings_chain_sampling( - log_prob_fn=gaussian_posterior, sampling_kwargs={"iterations": 1000} + self.add(image_mobject) + self.play(FadeOut(image_mobject)) + + axes = MCMCAxes( + x_range=[-4, 4], + y_range=[-4, 4], + ) + self.play( + Create(axes) ) - self.play(chain_sampling_animation) + gaussian_posterior = MultidimensionalGaussianPosterior( + mu=np.array([0.0, 0.0]), + var=np.array([1.0, 1.0]) + ) + + chain_sampling_animation, lines = axes.visualize_metropolis_hastings_chain_sampling( + log_prob_fn=gaussian_posterior, + sampling_kwargs={"iterations": 500}, + ) + + self.play( + chain_sampling_animation, + run_time=3.5 + ) + self.play( + FadeOut(lines) + ) + self.wait(1) + self.play( + FadeIn(image_mobject) + ) + + diff --git a/tests/test_plotting.py b/tests/test_plotting.py new file mode 100644 index 0000000..f328564 --- /dev/null +++ b/tests/test_plotting.py @@ -0,0 +1,71 @@ + +from manim import * + +import matplotlib.pyplot as plt +import seaborn as sns +import matplotlib +plt.style.use('dark_background') + +from manim_ml.utils.mobjects.plotting import convert_matplotlib_figure_to_image_mobject +from manim_ml.utils.testing.frames_comparison import frames_comparison + +__module_test__ = "plotting" + +@frames_comparison +def test_matplotlib_to_image_mobject(scene): + # libraries & dataset + df = sns.load_dataset('iris') + # Custom the color, add shade and bandwidth + matplotlib.use('Agg') + plt.figure(figsize=(10,10), dpi=100) + displot = sns.displot( + x=df.sepal_width, + y=df.sepal_length, + cmap="Reds", + kind="kde", + ) + plt.axis('off') + fig = displot.fig + image_mobject = convert_matplotlib_figure_to_image_mobject(fig) + # Display the image mobject + scene.add(image_mobject) + +class TestMatplotlibToImageMobject(Scene): + + def construct(self): + # Make a matplotlib plot + # libraries & dataset + df = sns.load_dataset('iris') + # Custom the color, add shade and bandwidth + matplotlib.use('Agg') + plt.figure(figsize=(10,10), dpi=100) + displot = sns.displot( + x=df.sepal_width, + y=df.sepal_length, + cmap="Reds", + kind="kde", + ) + plt.axis('off') + fig = displot.fig + image_mobject = convert_matplotlib_figure_to_image_mobject(fig) + # Display the image mobject + self.add(image_mobject) + + +class HexabinScene(Scene): + + def construct(self): + # Fixing random state for reproducibility + np.random.seed(19680801) + n = 100_000 + x = np.random.standard_normal(n) + y = x + 1.0 * np.random.standard_normal(n) + xlim = -4, 4 + ylim = -4, 4 + + fig, ax0 = plt.subplots(1, figsize=(5, 5)) + + hb = ax0.hexbin(x, y, gridsize=50, cmap='inferno') + ax0.set(xlim=xlim, ylim=ylim) + + self.add(convert_matplotlib_figure_to_image_mobject(fig))