ManimCommunity / ManimCommunity/manim
TracedPath stroke_opacity acting weird, with working version for comparison
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 40.9k
- Forks
- 3.1k
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 25
Description
## Description of bug / unexpected behavior
TracedPath stroke_opacity gradient has weird bug where the opacity gradient direction suddenly flips mid animation
## Expected behavior
Fading trail behind a moving Dot3D in a ThreeDScene, this trail should have a opacity gradient with a color gradient and disappear over time.
## How to reproduce the issue
```py
from manim import *
from manim import config
import pandas as pd
import numpy as np
from tqdm import tqdm
SCALE_FACTOR = 4 # Manifold scaling factor
ORBITS = 1.2 # Number of revolutions, can be float
TRAIL_LENGTH = config.frame_rate * 1.2 # Length of trail behind mercury
DESIRED_TOTAL_TIME = 12 # Desired length of animation, may not be this length
def prepare_data(file_name):
"""
Prepare Data Method
Scales data to fit on screen
:param file_name: The name of the CSV file containing the data.
:return: The processed dataframe.
"""
orbit_points = int(90023 / (5 / 0.2408467) * ORBITS) # 90023 points = 5 yrs -> 0.2408467 yrs = 1 rev, * # of revs
df = pd.read_csv(file_name, nrows=orbit_points, usecols=[1, 2, 3, 8], dtype=np.float64)
df.reset_index(drop=True, inplace=True)
max_value = df['RG'].values.max()
for col in ['X', 'Y', 'Z']:
df[col] = df[col] / max_value * SCALE_FACTOR
return df
class Orbit(ThreeDScene):
"""Class for visualizing the orbit of Mercury.
This class inherits from the ThreeDScene class
"""
def construct(self):
axes = ThreeDAxes(num_axis_pieces=20,
color=GREY,
axis_config={
'stroke_opacity': 0.8,
'stroke_width': 0.5,
'include_tip': False
})
self.camera.background_color = BLACK # Dark grey
df = prepare_data('horizons_half_hour.csv') # This processes Mercury's orbit data
# list of points, with each point of the form [x, y, z]
points = df[['X', 'Y', 'Z']].values
# Mercury representation
mercury = Dot3D(radius=SCALE_FACTOR * 0.01, color=GREY)
mercury.move_to(points[0])
index_tracker = ValueTracker(0) # Tracker for locus of mercury
mercury.add_updater(lambda m: m.move_to(
points[min(int(index_tracker.get_value()), len(points) - 1)]
))
# Sun representation (radius close to 4.375% of orbit)
sun = Dot3D(radius=.6 * SCALE_FACTOR * 0.04375, color=ORANGE)
traced_path = TracedPath(mercury.get_center,
stroke_color=[PURE_BLUE, PINK],
stroke_opacity=[0, 1],
dissipating_time=1,
stroke_width=SCALE_FACTOR / 1.5)
fading_path = VMobject(stroke_color=[DARK_BLUE, LIGHT_PINK], stroke_width=4)
fading_path.start_new_path(mercury.get_center())
def update_path(path_group):
new_line = Line(path_group[-1].get_end(), mercury.get_center())
start_color = PURE_BLUE
end_color = PINK
# calculate linear gradient function for opacity
max_opacity = 1
min_opacity = 0
opacity_step = (max_opacity - min_opacity) / len(path_group)
new_line.set_opacity(max_opacity)
new_line.set_color(end_color)
path_group.add(new_line)
if len(path_group) > TRAIL_LENGTH:
for line in path_group:
# If the opacity of a line is lower than threshold, remove it from path_group
if line.get_stroke_opacity() < 0.05:
path_group.remove(line)
for i, line in enumerate(path_group):
# update opacity for each line in the path group
new_opacity = min_opacity + i * opacity_step
line.set_stroke(opacity=new_opacity)
# update color of each line in the path group
ratio = i / len(path_group)
new_color = interpolate_color(start_color, end_color, ratio)
line.set_color(new_color)
fading_path.add_updater(update_path)
self.add(axes, mercury, sun, traced_path)
self.set_camera_orientation(phi=65 * DEGREES, theta=-120 * DEGREES)
# initialize trackers for camera orientation
phi: ValueTracker = self.camera.phi_tracker
theta: ValueTracker = self.camera.theta_tracker
step = 100
total_steps = (len(points) - 2) // step
run_time = DESIRED_TOTAL_TIME / total_steps
for _ in tqdm(range(0, int(total_steps))):
# animate orientation and increment
self.play(phi.animate.increment_value(-0.004),
theta.animate.increment_value(0.006),
ApplyMethod(index_tracker.increment_value, step),
rate_func=linear,
run_time=run_time
)
mercury.clear_updaters()
self.remove(phi, theta)
self.wait()
```
## Necessary Information
The real 'horizons_half_hour.csv' is 36 million rows long, so I have provided a shortened version
[shortened_data.csv](https://github.com/user-attachments/files/16200351/shortened_data.csv)
By running the code, as is right now, you will notice the traced path has weird behavior, the opacity gradient suddenly flips at random moments in the orbit.
By modifying the code to replace ```traced_path``` with ```fading_path``` in the ```self.add()``` line, you will see what the desired behavior is
By debugging you will find that it is not due to the color gradient, or dissipation time, but the stroke_opacity gradient passed by the list, as when this is removed everything behaves normally.
This functionality is not specifically mentioned in the documentation, however it is used in the example on the [TracedPath documentation page](https://docs.manim.community/en/stable/reference/manim.animation.changing.TracedPath.html#tracedpath) so I am unsure of many details regarding this feature.
## Screenshots:
BUG:
WORKING:
## System specifications
System Details
- OS (with version, e.g., Windows 10 v2004 or macOS 10.15 (Catalina)): macOS Sonoma 14.3
- RAM: 16GB
- Python version (`python/py/python3 --version`): 3.9.6
- Installed modules (provide output from `pip list`):
```
(.venv) (base) usr@mac project % pip list
Package Version
---------------------------- ------------------
absl-py 2.1.0
anyio 4.4.0
appnope 0.1.4
argon2-cffi 23.1.0
argon2-cffi-bindings 21.2.0
arrow 1.3.0
astropy 6.0.1
astropy-iers-data 0.2024.7.8.0.31.19
asttokens 2.4.1
astunparse 1.6.3
async-lru 2.0.4
attrs 23.2.0
Babel 2.15.0
beautifulsoup4 4.12.3
bleach 6.1.0
certifi 2024.6.2
cffi 1.16.0
charset-normalizer 3.3.2
click 8.1.7
cloup 3.0.5
colour 0.1.5
comm 0.2.2
contourpy 1.2.1
cycler 0.12.1
Cython 3.0.10
debugpy 1.8.2
decorator 5.1.1
defusedxml 0.7.1
exceptiongroup 1.2.1
executing 2.0.1
fastjsonschema 2.20.0
flatbuffers 24.3.25
fonttools 4.53.0
fqdn 1.5.1
gast 0.6.0
glcontext 2.5.0
google-pasta 0.2.0
grpcio 1.64.1
h11 0.14.0
h5py 3.11.0
httpcore 1.0.5
httpx 0.27.0
idna 3.7
importlib_metadata 8.0.0
importlib_resources 6.4.0
ipykernel 6.29.5
ipython 8.18.1
ipywidgets 8.1.3
isoduration 20.11.0
isosurfaces 0.1.2
jedi 0.19.1
Jinja2 3.1.4
json5 0.9.25
jsonpointer 3.0.0
jsonschema 4.22.0
jsonschema-specifications 2023.12.1
jupyter 1.0.0
jupyter_client 8.6.2
jupyter-console 6.6.3
jupyter_core 5.7.2
jupyter-events 0.10.0
jupyter-lsp 2.2.5
jupyter_server 2.14.1
jupyter_server_terminals 0.5.3
jupyterlab 4.2.3
jupyterlab_pygments 0.3.0
jupyterlab_server 2.27.2
jupyterlab_widgets 3.0.11
keras 3.4.1
kiwisolver 1.4.5
libclang 18.1.1
manim 0.18.1
manimgl 1.6.1
ManimPango 0.5.0
mapbox-earcut 1.0.1
Markdown 3.6
markdown-it-py 3.0.0
MarkupSafe 2.1.5
matplotlib 3.9.0
matplotlib-inline 0.1.7
mdurl 0.1.2
mistune 3.0.2
ml-dtypes 0.3.2
moderngl 5.10.0
moderngl-window 2.4.6
mpmath 1.3.0
multipledispatch 1.0.0
namex 0.0.8
nbclient 0.10.0
nbconvert 7.16.4
nbformat 5.10.4
nest-asyncio 1.6.0
networkx 3.2.1
nodejs 0.1.1
notebook 7.2.1
notebook_shim 0.2.4
npm 0.1.1
numpy 1.26.4
opt-einsum 3.3.0
optional-django 0.1.0
optree 0.11.0
overrides 7.7.0
packaging 24.1
pandas 2.2.2
pandocfilters 1.5.1
parso 0.8.4
pexpect 4.9.0
pillow 10.4.0
pip 24.1.1
platformdirs 4.2.2
prometheus_client 0.20.0
prompt_toolkit 3.0.47
protobuf 4.25.3
psutil 6.0.0
ptyprocess 0.7.0
pure-eval 0.2.2
pycairo 1.26.1
pycparser 2.22
pydub 0.25.1
pyerfa 2.0.1.4
pyglet 2.0.15
Pygments 2.18.0
pyobjc-core 10.3.1
pyobjc-framework-Cocoa 10.3.1
PyOpenGL 3.1.7
pyparsing 3.1.2
pyrr 0.10.3
python-dateutil 2.9.0.post0
python-json-logger 2.0.7
pytz 2024.1
PyYAML 6.0.1
pyzmq 26.0.3
qtconsole 5.5.2
QtPy 2.4.1
referencing 0.35.1
requests 2.32.3
rfc3339-validator 0.1.4
rfc3986-validator 0.1.1
rich 13.7.1
rpds-py 0.18.1
scipy 1.13.1
screeninfo 0.8.1
seaborn 0.13.2
Send2Trash 1.8.3
setuptools 68.2.0
six 1.16.0
skia-pathops 0.8.0.post1
sniffio 1.3.1
soupsieve 2.5
srt 3.5.3
stack-data 0.6.3
svgelements 1.9.6
sympy 1.12.1
tensorboard 2.16.2
tensorboard-data-server 0.7.2
tensorflow 2.16.2
tensorflow-io-gcs-filesystem 0.37.1
termcolor 2.4.0
terminado 0.18.1
tinycss2 1.3.0
tomli 2.0.1
tornado 6.4.1
tqdm 4.66.4
traitlets 5.14.3
types-python-dateutil 2.9.0.20240316
typing_extensions 4.12.2
tzdata 2024.1
uri-template 1.3.0
urllib3 2.2.2
validators 0.29.0
vg 2.0.0
watchdog 4.0.1
wcwidth 0.2.13
webcolors 24.6.0
webencodings 0.5.1
websocket-client 1.8.0
Werkzeug 3.0.3
wheel 0.41.2
widgetsnbextension 4.0.11
wrapt 1.16.0
zipp 3.19.2
```
LaTeX details
+ LaTeX distribution (e.g. TeX Live 2020): TeX Live 2024
+ Installed LaTeX packages: A lot and I don't think this is important so I save the space, if needed let me know
## Additional comments
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the issue with the provided shortened_data.csv and the TracedPath example, then inspect how TracedPath handles a list passed as stroke_opacity during animation and dissipation. Compare it with the working fading_path behavior. Done means the opacity gradient no longer reverses unexpectedly while the documented example still produces the intended fading trail.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- computer-graphics
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100