-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Introduce seed in random_color
method to produce colors deterministically
#4265
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 6 commits
bec30bb
09e32f7
8e18ed7
15d49dc
c92a1c7
96a1196
ec0e871
fc2c24d
d1af775
95c1a9f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -1508,9 +1508,94 @@ | |||||||
ManimColor | ||||||||
A random :class:`ManimColor`. | ||||||||
""" | ||||||||
return RandomColorGenerator().next() | ||||||||
|
||||||||
|
||||||||
class RandomColorGenerator: | ||||||||
""" | ||||||||
A generator for producing random colors from a given list of Manim colors, | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
optionally in a reproducible sequence using a seed value. | ||||||||
|
||||||||
When initialized with a specific seed, this class produces a deterministic | ||||||||
sequence of `ManimColor` instances. If no seed is provided, the selection is | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
non-deterministic using Python’s global random state. | ||||||||
|
||||||||
Parameters | ||||||||
---------- | ||||||||
seed : int | None, optional | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. type annoations are taken from the actual type hints, no need to add them twice
Suggested change
|
||||||||
A seed value to initialize the internal random number generator. | ||||||||
If None (default), colors are chosen using the global random state. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
sample_colors : list[ManimColor], optional | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
A custom list of Manim colors to sample from. Defaults to the full Manim color palette. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Examples | ||||||||
-------- | ||||||||
Without a seed (non-deterministic): | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The actual formatting for the example blocks need to be slightly adapted to make the documentation render correctly. I'll push a commit to take care of it. 👍 |
||||||||
>>> from manim import RandomColorGenerator, ManimColor, RED, GREEN, BLUE | ||||||||
>>> rnd = RandomColorGenerator() | ||||||||
>>> isinstance(rnd.next(), ManimColor) | ||||||||
True | ||||||||
|
||||||||
With a seed (deterministic sequence): | ||||||||
>>> rnd = RandomColorGenerator(42) | ||||||||
>>> rnd.next() | ||||||||
ManimColor('#ECE7E2') | ||||||||
>>> rnd.next() | ||||||||
ManimColor('#BBBBBB') | ||||||||
>>> rnd.next() | ||||||||
ManimColor('#BBBBBB') | ||||||||
|
||||||||
Re-initializing with the same seed gives the same sequence: | ||||||||
>>> rnd2 = RandomColorGenerator(42) | ||||||||
>>> rnd2.next() | ||||||||
ManimColor('#ECE7E2') | ||||||||
>>> rnd2.next() | ||||||||
ManimColor('#BBBBBB') | ||||||||
>>> rnd2.next() | ||||||||
ManimColor('#BBBBBB') | ||||||||
|
||||||||
Using a custom color list: | ||||||||
>>> custom_palette = [RED, GREEN, BLUE] | ||||||||
>>> rnd_custom = RandomColorGenerator(1, sample_colors=custom_palette) | ||||||||
>>> rnd_custom.next() in custom_palette | ||||||||
True | ||||||||
>>> rnd_custom.next() in custom_palette | ||||||||
True | ||||||||
|
||||||||
Without a seed and custom palette (non-deterministic): | ||||||||
>>> rnd_nodet = RandomColorGenerator(sample_colors=[RED]) | ||||||||
>>> rnd_nodet.next() | ||||||||
ManimColor('#FC6255') | ||||||||
""" | ||||||||
|
||||||||
import manim.utils.color.manim_colors as manim_colors | ||||||||
|
||||||||
return random.choice(manim_colors._all_manim_colors) | ||||||||
def __init__( | ||||||||
self, | ||||||||
seed: int | None = None, | ||||||||
sample_colors: list[ManimColor] = manim_colors._all_manim_colors, | ||||||||
|
||||||||
) -> None: | ||||||||
self.choice = random.choice if seed is None else random.Random(seed).choice | ||||||||
self.colors = sample_colors | ||||||||
|
||||||||
|
||||||||
def next(self) -> ManimColor: | ||||||||
""" | ||||||||
Returns the next color from the configured color list. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
Returns | ||||||||
------- | ||||||||
ManimColor | ||||||||
A randomly selected color from the specified color list. | ||||||||
|
||||||||
Examples | ||||||||
-------- | ||||||||
>>> from manim import RandomColorGenerator, RED | ||||||||
>>> rnd = RandomColorGenerator(sample_colors=[RED]) | ||||||||
>>> rnd.next() | ||||||||
ManimColor('#FC6255') | ||||||||
""" | ||||||||
return self.choice(self.colors) | ||||||||
|
||||||||
|
||||||||
def get_shaded_rgb( | ||||||||
|
@@ -1566,6 +1651,7 @@ | |||||||
"average_color", | ||||||||
"random_bright_color", | ||||||||
"random_color", | ||||||||
"RandomColorGenerator", | ||||||||
"get_shaded_rgb", | ||||||||
"HSV", | ||||||||
"RGBA", | ||||||||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@behackl
While thinking about the warning that you mentioned.
Do you think it would make sense to use a singleton object here instead of initializing a new one each time?
In a scenario where
random_color
is called frequently across a project, repeatedly creating and discarding instances could be inefficient (though I'm not entirely sure how Python handles cleanup in this case).Would it be better to define a static version of the method, allowing us to directly call
next()
on the class rather than an instance?Open to your thoughts or suggestions. Happy to include this as part of the current PR or address it as a follow-up improvement.