ManimCommunity / manim

A community-maintained Python framework for creating mathematical animations.
https://www.manim.community
MIT License
19.96k stars 1.48k forks source link

Surprising `Axes.__init__` default values #2479

Open stnbu opened 2 years ago

stnbu commented 2 years ago

Description of bug / unexpected behavior

When using Axes, knowing that the defaults for x_length and y_length are based upon the values of config.frame_width and config.frame_height, I set the latter two to a square: 15x15

The resulting Axes class had as its defaults values based upon the config.frame_* defaults, meaning that despite setting these in my code, the parse-time defaults of 14.2 and 8.0 were used.

This is only a "bug" in the sense that the behavior is confusing. I could well be abusing the config system by setting these values in my scripts...

I believe a better behavior would be to test for None-ness inside of init so the "current" (from the script's timeline point of view) values of config.frame_ are used to calculate the defaults.

Expected behavior

I expected the resulting Axes.*_length values to be 13x13 (15-2).

How to reproduce the issue

Code for reproducing the problem I changed the `round` calls in the `Axes.__init__` to be `dround` and created a wrapper function that prints the values of `config.frame_*` and added print statements inside of `__init__` to print the values of `self.*_length`. Here are the changes. Note that this is daf23c9d1031b12d9c119b8f6b7e60727d7f9242 / aka 0.14.0 ```diff $ git diff manim/mobject/coordinate_systems.py diff --git a/manim/mobject/coordinate_systems.py b/manim/mobject/coordinate_systems.py index 0a402f26..7083c877 100644 --- a/manim/mobject/coordinate_systems.py +++ b/manim/mobject/coordinate_systems.py @@ -12,6 +12,11 @@ __all__ = [ "ComplexPlane", ] +def dround(value): + print("Value of config.frame_height when Axes.__init__ parsed: %s" % config.frame_height) + print("Value of config.frame_width when Axes.__init__ parsed: %s" % config.frame_width) + return round(value) + import fractions as fr import numbers from typing import Any, Callable, Dict, Iterable, List, Optional, Sequence, Tuple, Union @@ -1752,8 +1757,8 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL): self, x_range: Sequence[float] | None = None, y_range: Sequence[float] | None = None, - x_length: float | None = round(config.frame_width) - 2, - y_length: float | None = round(config.frame_height) - 2, + x_length: float | None = dround(config.frame_width) - 2, + y_length: float | None = dround(config.frame_height) - 2, axis_config: dict | None = None, x_axis_config: dict | None = None, y_axis_config: dict | None = None, @@ -1763,6 +1768,9 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL): VGroup.__init__(self, **kwargs) CoordinateSystem.__init__(self, x_range, y_range, x_length, y_length) + print("Value of self.y_length when I actually *call* Axes.__init__: %s" % self.y_length) + print("Value of self.x_length when I actually *call* Axes.__init__: %s" % self.x_length) + self.axis_config = { "include_tip": tips, ``` I then ran the following script ```py print("About to import manim...") from manim import * print("...manim has been imported") config.frame_height = 15 config.frame_width = 15 print("Value of config.frame_height when I use my script: %s" % config.frame_height) print("Value of config.frame_width when I use my script: %s" % config.frame_width) axes = Axes() print("") print("Value of axes.y_length when I actually *call* Axes.__init__: %s" % axes.y_length) print("Value of axes.x_length when I actually *call* Axes.__init__: %s" % axes.x_length) ``` Which prints the following: ``` About to import manim... Value of config.frame_height when Axes.__init__ parsed: 8.0 Value of config.frame_width when Axes.__init__ parsed: 14.222222222222221 Value of config.frame_height when Axes.__init__ parsed: 8.0 Value of config.frame_width when Axes.__init__ parsed: 14.222222222222221 Manim Community v0.14.0 ...manim has been imported Value of config.frame_height when I use my script: 15 Value of config.frame_width when I use my script: 15 Value of self.y_length when I actually *call* Axes.__init__: 6 Value of self.x_length when I actually *call* Axes.__init__: 12 Value of axes.y_length when I actually *call* Axes.__init__: 6 Value of axes.x_length when I actually *call* Axes.__init__: 12 ``` (Not sure why only importing causes two passes...) If I make these changes: ```diff diff --git a/manim/mobject/coordinate_systems.py b/manim/mobject/coordinate_systems.py index 0a402f26..66e2d2fb 100644 --- a/manim/mobject/coordinate_systems.py +++ b/manim/mobject/coordinate_systems.py @@ -1752,14 +1752,17 @@ class Axes(VGroup, CoordinateSystem, metaclass=ConvertToOpenGL): self, x_range: Sequence[float] | None = None, y_range: Sequence[float] | None = None, - x_length: float | None = round(config.frame_width) - 2, - y_length: float | None = round(config.frame_height) - 2, + x_length: float | None = None, + y_length: float | None = None, axis_config: dict | None = None, x_axis_config: dict | None = None, y_axis_config: dict | None = None, tips: bool = True, **kwargs, ): + x_length = round(config.frame_width) - 2 if x_length is None else x_length + y_length = round(config.frame_width) - 2 if y_length is None else y_length + VGroup.__init__(self, **kwargs) CoordinateSystem.__init__(self, x_range, y_range, x_length, y_length) ``` ...then the above script prints... ``` About to import manim... Manim Community v0.14.0 ...manim has been imported Value of config.frame_height when I use my script: 15 Value of config.frame_width when I use my script: 15 Value of axes.y_length when I actually *call* Axes.__init__: 13 Value of axes.x_length when I actually *call* Axes.__init__: 13 ```

Additional media files

Images/GIFs

Logs

Terminal output ``` PASTE HERE OR PROVIDE LINK TO https://pastebin.com/ OR SIMILAR ```

System specifications

System Details - OS (with version, e.g Windows 10 v2004 or macOS 10.15 (Catalina)): OSX Big Sur 11.6.2 (20G314) - RAM: - Python version (`python/py/python3 --version`): 3.9.9 - Installed modules (provide output from `pip list`): ``` Package Version Editable project location ------------------------------------------------- ------------- --------------------------- aiohttp 3.8.1 aiosignal 1.2.0 alabaster 0.7.12 apipkg 1.5 appdirs 1.4.4 appnope 0.1.2 asttokens 2.0.5 async-timeout 4.0.1 asynctest 0.13.0 attrs 21.2.0 Babel 2.9.1 backcall 0.2.0 base58 2.1.1 bitarray 1.2.2 black 21.11b1 butterfly 3.2.5 cached-property 1.5.2 cachetools 4.2.4 certifi 2021.10.8 cffi 1.14.6 chardet 4.0.0 charset-normalizer 2.0.9 click 8.0.3 click-default-group 1.2.2 cloup 0.7.1 colorama 0.4.4 colour 0.1.5 commonmark 0.9.1 cryptography 3.4.7 Cython 0.29.26 cytoolz 0.11.2 dataclassy 0.11.1 decorator 5.0.9 docutils 0.17.1 eip712 0.1.0 eth-abi 2.1.1 eth-account 0.5.6 eth-bloom 1.0.4 eth-brownie 1.17.2 /Users/mburr/git/brownie eth-event 1.2.3 eth-hash 0.3.2 eth-keyfile 0.5.1 eth-keys 0.3.3 eth-rlp 0.2.1 eth-tester 0.6.0b4 eth-typing 2.2.2 eth-utils 1.10.0 execnet 1.9.0 frozenlist 1.2.0 gitdb 4.0.9 GitPython 3.1.26 glcontext 2.3.4 google-api-core 2.3.2 google-auth 2.3.3 google-cloud-texttospeech 2.9.0 googleapis-common-protos 1.54.0 grpcio 1.43.0 grpcio-status 1.43.0 hexbytes 0.2.2 hypothesis 6.27.3 idna 3.3 imagesize 1.3.0 importlib-metadata 4.8.2 inflection 0.5.0 iniconfig 1.1.1 ipdb 0.13.9 ipfshttpclient 0.8.0a2 ipython 7.24.0 ipython-genutils 0.2.0 isosurfaces 0.1.0 jedi 0.18.0 Jinja2 3.0.3 jsonschema 3.2.0 lazy-object-proxy 1.6.0 lru-dict 1.1.7 manim 0.14.0 ManimPango 0.4.0.post0 mapbox-earcut 0.12.11 MarkupSafe 2.0.1 MathChurch 0.0.11 /Users/mburr/git/MathChurch matplotlib-inline 0.1.2 mnemonic 0.20 moderngl 5.6.4 moderngl-window 2.4.1 mpmath 1.2.1 multiaddr 0.0.9 multidict 5.2.0 multipledispatch 0.6.0 mutagen 1.45.1 mypy-extensions 0.4.3 mythx-models 1.9.1 netaddr 0.8.0 networkx 2.6.3 numpy 1.22.0 packaging 21.3 parsimonious 0.8.1 parso 0.8.2 pathspec 0.9.0 pexpect 4.8.0 pickleshare 0.7.5 Pillow 9.0.0 pip 21.3.1 platformdirs 2.4.0 pluggy 1.0.0 prompt-toolkit 3.0.23 proto-plus 1.19.8 protobuf 3.19.1 psutil 5.8.0 ptyprocess 0.7.0 pudb 2021.1 py 1.11.0 py-ecc 4.1.0 py-evm 0.5.0a1 py-geth 3.7.0 py-solc-ast 1.2.9 py-solc-x 1.1.1 pyasn1 0.4.8 pyasn1-modules 0.2.8 pycairo 1.20.1 pycoin 0.91.20210515 pycparser 2.20 pycrypto 2.6.1 pycryptodome 3.12.0 pydub 0.25.1 pyethash 0.1.27 pyglet 1.5.21 Pygments 2.10.0 pygments-lexer-solidity 0.7.0 PyJWT 1.7.1 pyobjc 8.1 pyobjc-core 8.1 pyobjc-framework-Accessibility 8.1 pyobjc-framework-Accounts 8.1 pyobjc-framework-AddressBook 8.1 pyobjc-framework-AdServices 8.1 pyobjc-framework-AdSupport 8.1 pyobjc-framework-AppleScriptKit 8.1 pyobjc-framework-AppleScriptObjC 8.1 pyobjc-framework-ApplicationServices 8.1 pyobjc-framework-AppTrackingTransparency 8.1 pyobjc-framework-AudioVideoBridging 8.1 pyobjc-framework-AuthenticationServices 8.1 pyobjc-framework-AutomaticAssessmentConfiguration 8.1 pyobjc-framework-Automator 8.1 pyobjc-framework-AVFoundation 8.1 pyobjc-framework-AVKit 8.1 pyobjc-framework-BusinessChat 8.1 pyobjc-framework-CalendarStore 8.1 pyobjc-framework-CallKit 8.1 pyobjc-framework-CFNetwork 8.1 pyobjc-framework-ClassKit 8.1 pyobjc-framework-CloudKit 8.1 pyobjc-framework-Cocoa 8.1 pyobjc-framework-Collaboration 8.1 pyobjc-framework-ColorSync 8.1 pyobjc-framework-Contacts 8.1 pyobjc-framework-ContactsUI 8.1 pyobjc-framework-CoreAudio 8.1 pyobjc-framework-CoreAudioKit 8.1 pyobjc-framework-CoreBluetooth 8.1 pyobjc-framework-CoreData 8.1 pyobjc-framework-CoreHaptics 8.1 pyobjc-framework-CoreLocation 8.1 pyobjc-framework-CoreMedia 8.1 pyobjc-framework-CoreMediaIO 8.1 pyobjc-framework-CoreMIDI 8.1 pyobjc-framework-CoreML 8.1 pyobjc-framework-CoreMotion 8.1 pyobjc-framework-CoreServices 8.1 pyobjc-framework-CoreSpotlight 8.1 pyobjc-framework-CoreText 8.1 pyobjc-framework-CoreWLAN 8.1 pyobjc-framework-CryptoTokenKit 8.1 pyobjc-framework-DeviceCheck 8.1 pyobjc-framework-DictionaryServices 8.1 pyobjc-framework-DiscRecording 8.1 pyobjc-framework-DiscRecordingUI 8.1 pyobjc-framework-DiskArbitration 8.1 pyobjc-framework-DVDPlayback 8.1 pyobjc-framework-EventKit 8.1 pyobjc-framework-ExceptionHandling 8.1 pyobjc-framework-ExecutionPolicy 8.1 pyobjc-framework-ExternalAccessory 8.1 pyobjc-framework-FileProvider 8.1 pyobjc-framework-FileProviderUI 8.1 pyobjc-framework-FinderSync 8.1 pyobjc-framework-FSEvents 8.1 pyobjc-framework-GameCenter 8.1 pyobjc-framework-GameController 8.1 pyobjc-framework-GameKit 8.1 pyobjc-framework-GameplayKit 8.1 pyobjc-framework-ImageCaptureCore 8.1 pyobjc-framework-IMServicePlugIn 8.1 pyobjc-framework-InputMethodKit 8.1 pyobjc-framework-InstallerPlugins 8.1 pyobjc-framework-InstantMessage 8.1 pyobjc-framework-Intents 8.1 pyobjc-framework-IOSurface 8.1 pyobjc-framework-iTunesLibrary 8.1 pyobjc-framework-KernelManagement 8.1 pyobjc-framework-LatentSemanticMapping 8.1 pyobjc-framework-LaunchServices 8.1 pyobjc-framework-libdispatch 8.1 pyobjc-framework-LinkPresentation 8.1 pyobjc-framework-LocalAuthentication 8.1 pyobjc-framework-MapKit 8.1 pyobjc-framework-MediaAccessibility 8.1 pyobjc-framework-MediaLibrary 8.1 pyobjc-framework-MediaPlayer 8.1 pyobjc-framework-MediaToolbox 8.1 pyobjc-framework-Metal 8.1 pyobjc-framework-MetalKit 8.1 pyobjc-framework-MetalPerformanceShaders 8.1 pyobjc-framework-MetalPerformanceShadersGraph 8.1 pyobjc-framework-MLCompute 8.1 pyobjc-framework-ModelIO 8.1 pyobjc-framework-MultipeerConnectivity 8.1 pyobjc-framework-NaturalLanguage 8.1 pyobjc-framework-NetFS 8.1 pyobjc-framework-Network 8.1 pyobjc-framework-NetworkExtension 8.1 pyobjc-framework-NotificationCenter 8.1 pyobjc-framework-OpenDirectory 8.1 pyobjc-framework-OSAKit 8.1 pyobjc-framework-OSLog 8.1 pyobjc-framework-PassKit 8.1 pyobjc-framework-PencilKit 8.1 pyobjc-framework-Photos 8.1 pyobjc-framework-PhotosUI 8.1 pyobjc-framework-PreferencePanes 8.1 pyobjc-framework-PushKit 8.1 pyobjc-framework-Quartz 8.1 pyobjc-framework-QuickLookThumbnailing 8.1 pyobjc-framework-ReplayKit 8.1 pyobjc-framework-SafariServices 8.1 pyobjc-framework-SceneKit 8.1 pyobjc-framework-ScreenSaver 8.1 pyobjc-framework-ScreenTime 8.1 pyobjc-framework-ScriptingBridge 8.1 pyobjc-framework-SearchKit 8.1 pyobjc-framework-Security 8.1 pyobjc-framework-SecurityFoundation 8.1 pyobjc-framework-SecurityInterface 8.1 pyobjc-framework-ServiceManagement 8.1 pyobjc-framework-Social 8.1 pyobjc-framework-SoundAnalysis 8.1 pyobjc-framework-Speech 8.1 pyobjc-framework-SpriteKit 8.1 pyobjc-framework-StoreKit 8.1 pyobjc-framework-SyncServices 8.1 pyobjc-framework-SystemConfiguration 8.1 pyobjc-framework-SystemExtensions 8.1 pyobjc-framework-UniformTypeIdentifiers 8.1 pyobjc-framework-UserNotifications 8.1 pyobjc-framework-UserNotificationsUI 8.1 pyobjc-framework-VideoSubscriberAccount 8.1 pyobjc-framework-VideoToolbox 8.1 pyobjc-framework-Virtualization 8.1 pyobjc-framework-Vision 8.1 pyobjc-framework-WebKit 8.1 pyOpenSSL 20.0.1 pyparsing 3.0.6 PyQt5 5.15.6 PyQt5-Qt5 5.15.2 PyQt5-sip 12.9.0 pyrr 0.10.3 pyrsistent 0.18.0 pysha3 1.0.2 pytest 6.2.5 pytest-forked 1.3.0 pytest-xdist 1.34.0 python-dateutil 2.8.1 python-dotenv 0.16.0 pythx 1.6.1 pyttsx3 2.91 /Users/mburr/git/pyttsx3 pytz 2021.3 PyYAML 5.4.1 regex 2021.11.10 requests 2.26.0 rich 10.16.2 rlp 2.0.1 rsa 4.8 scipy 1.7.3 screeninfo 0.6.7 secp256k1 0.14.0 semantic-version 2.8.5 setuptools 56.0.0 six 1.16.0 skia-pathops 0.7.2 smmap 5.0.0 snowballstemmer 2.2.0 sortedcontainers 2.4.0 Sphinx 4.3.1 sphinx-rtd-theme 1.0.0 sphinxcontrib-applehelp 1.0.2 sphinxcontrib-devhelp 1.0.2 sphinxcontrib-htmlhelp 2.0.0 sphinxcontrib-jsmath 1.0.1 sphinxcontrib-qthelp 1.0.3 sphinxcontrib-serializinghtml 1.1.5 srt 3.5.0 svgwrite 1.4.1 sympy 1.9 toml 0.10.2 tomli 1.2.2 toolz 0.11.2 tornado 6.1 tqdm 4.62.3 traitlets 5.0.5 trie 2.0.0a5 typed-ast 1.5.1 typing-extensions 3.10.0.2 urllib3 1.26.7 urwid 2.1.2 varint 1.0.2 vvm 0.1.0 vyper 0.3.1 watchdog 2.1.6 wcwidth 0.2.5 web3 5.25.0 /Users/mburr/git/web3.py websockets 9.1 wheel 0.37.0 wrapt 1.13.3 yarl 1.7.2 zipp 3.6.0 ```
LaTeX details + LaTeX distribution (e.g. TeX Live 2020): + Installed LaTeX packages:
FFMPEG Output of `ffmpeg -version`: ``` PASTE HERE ```

Additional comments

hydrobeam commented 2 years ago

Thanks for describing the issue!

Changing config.frame_width is a valid thing to do, so this is definitely a bug with Axes. I'll implement your suggested fix and adjust the other places where config.ATTR is used in a similar manner 👍.