Skip to content

Instantly share code, notes, and snippets.

@Aleksey-Danchin
Created January 26, 2024 11:42
Show Gist options
  • Save Aleksey-Danchin/9af1bd051d99ff1baa9ca7dbaa6b6033 to your computer and use it in GitHub Desktop.
Save Aleksey-Danchin/9af1bd051d99ff1baa9ca7dbaa6b6033 to your computer and use it in GitHub Desktop.
Hashtag cloud with clockwise transform
# Based on https://www.youtube.com/watch?v=u8zLAUroUq8&ab_channel=WildMathing
from manim import *
from numpy.random import uniform
# WORDS = (
# r"e^{i/pi}+1=0",
# r"3^2+4^2=5^2",
# r"V+F-E=2",
# r"\exists",
# r"\forall",
# r"\Rightarrow",
# r"\Leftarrow",
# r"\oint",
# r"\varnothing",
# r"\varepsilon",
# r"\pi",
# r"\zeta(-1)=-\frac{1}{12}",
# r"1729=1^3+12^3=9^3+10^3",
# r"\sin^x+\cos^2x=1",
# r"\frac{a+b}{2}\geqslant \sqrt{ab}",
# r"\pi (x) \sim \frac{x}{\log x}",
# )
WORDS = (
"React",
"Vue",
"Angular",
"Svelte",
"JavaScript",
"TypeScript",
"NodeJS",
"Redux",
"Zustand",
"GraphQL",
"Patterns",
"OOP",
"ConstCode"
)
STEPS = 5
def get_position(horizontal=(-6.5, 6.5), vertical=(-3, 3)):
x, y = uniform(*horizontal), uniform(*vertical)
return np.array((x, y, 0))
def fit_into_fram(word):
if word.get_left()[0] < -6.9:
word.to_edge(LEFT)
if word.get_right()[0] > 6.9:
word.to_edge(RIGHT)
if word.width > 1.5:
word.set(width = 1.5)
def get_intersections(words, limit = 1_000_000):
counter = 0
boxes= [SurroundingRectangle(w, buff=0.03) for w in words]
for n, box_1 in enumerate(boxes):
for box_2 in boxes[n+1:]:
counter += len(Intersection(box_1, box_2))
if counter >= limit:
return counter
return counter
def get_cloud(words):
words = shuffle_words(words)
while get_intersections(words, 1) > 0:
words = shuffle_words(words)
return words
def shuffle_words (words):
new_words = VGroup()
min_distance = 10000
min_distance_word = None
for word in words:
height = uniform(0.1, 1.2)
array = get_position()
x, y, z = list(array)
dist = (x**2 + y**2)**0.5
new_word = word.copy()
if min_distance > dist:
min_distance = dist
min_distance_word = new_word
new_word.move_to(array)
new_word.set(height=height)
new_word.set_opacity(0.2 + height)
fit_into_fram(new_word)
new_words += new_word
min_distance_word.set(height=1.5)
min_distance_word.set_opacity(1)
return new_words
class Cloud(Scene):
def construct(self):
words = VGroup(*[MathTex(w) for w in WORDS])
words = get_cloud(words)
fade_kwargs = {
'rate_func': rate_functions.ease_in_out_elastic,
'run_time': 3
}
fade = [GrowFromCenter(w, **fade_kwargs) for w in words]
self.play(AnimationGroup(*fade, lag_ratio=0.03))
self.wait()
for _ in range(STEPS):
transform = []
for w1, w2 in zip(words, get_cloud(words)):
anim = np.random.choice([
ClockwiseTransform,
CounterclockwiseTransform
])
transform.append(anim(w1, w2, run_time=1.5))
self.play(AnimationGroup(*transform, lag_ratio=0.01))
self.wait()
fade_out = [FadeOut(w, scale=0) for w in words]
self.play(*fade_out, lag_ratio=0.05)
self.wait(2)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment