Skip to content

Commit

Permalink
0.0.4 release
Browse files Browse the repository at this point in the history
  • Loading branch information
s-m-e committed Dec 14, 2020
2 parents 412004d + 54d8388 commit 511fa18
Show file tree
Hide file tree
Showing 26 changed files with 923 additions and 52 deletions.
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changes

## 0.0.4 (2020-12-14)

- FIX: Center offset in `DrawgingBoard` cares about subpixels.
- FIX: `bewegung` would fail to work at all without `numpy` present.
- DOCS: Completed vector chapters on algebra and camera as well as cross-references to classes and methods.

## 0.0.3 (2020-12-06)

- FEATURE: `DrawingBoard.make_svg` can generate SVG object handles from raw binary data.
Expand Down
2 changes: 2 additions & 0 deletions docs/about.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ There are various libraries in the overall Python ecosystem which target tasks r
- `manim`_: The ``manim`` package provides excellent functionality for generating explanatory math videos. It can handle LaTeX expressions and animate all sorts of mathematical expressions and transformations. Similar to ``bewegung``, it also integrates its own ``cairo``-based drawing system and encodes videos with ``ffmpeg``. In direct comparison to ``bewegung``, ``manim`` serves a completely different but also very interesting use-case.
- `mayavi`_: The ``mayavi`` library has `excellent integrated features`_ for generating interactive, near-real-time 3D visualizations. It is fairly easy to use and provides graphics acceleration. It lacks built-in capabilities for generating videos.
- `vispy`_: The ``vispy`` package is the undisputed crown jewel of real-time visualization of large quantities of data with Python. Its great performance comes at a price, however: The user has to write `OpenGL shaders`_ in C++, which is anything but trivial. ``vispy`` does not have built-in features for video export.
- `glumpy`_: Very similar to ``vispy``, with even lower-level access to APIs and internal facilities. ``glumpy`` can export videos via ``ffmpeg`` and borrows code from ``MoviePy`` for this task.
- `ffmpeg-python`_: The ``ffmpeg-python`` package is an object-oriented Python wrapper around the ``ffmpeg`` command line tool. It is an extremely powerful tool on its own, making the otherwise complicated and error-prone specification of ``ffmpeg`` options relatively easy. ``bewegung`` offers its own thin wrapper around ``ffmpeg``, which can be substituted by ``ffmpeg-python`` if desired.
- `PyAV`_: Python bindings to the libraries underneath ``ffmpeg``. In a nutshell even far more complicated to use than the ``ffmpeg`` command line version.
- `blender`_: A list of Python tools for animations would not be complete without ``Blender``. Although ``Blender`` is a GUI application, it is fully programmable & controllable through Python. ``Blender``'s features far exceed those of ``bewegung``. It can be argued that ``Blender`` serves different use-cases, primarily 3D modeling, lighting and video editing, while it can certainly also do what ``bewegung`` does - just different and slightly more complicated.
Expand All @@ -45,6 +46,7 @@ There are various libraries in the overall Python ecosystem which target tasks r
.. _mayavi: https://docs.enthought.com/mayavi/mayavi/index.html
.. _excellent integrated features: https://docs.enthought.com/mayavi/mayavi/mlab_animating.html
.. _vispy: https://vispy.org/
.. _glumpy: https://github.com/glumpy/glumpy
.. _OpenGL shaders: https://www.khronos.org/opengl/wiki/Shader
.. _ffmpeg-python: https://github.com/kkroening/ffmpeg-python
.. _PyAV: https://github.com/PyAV-Org/PyAV
Expand Down
6 changes: 5 additions & 1 deletion docs/algebra.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
Linear Algebra
==============

``bewegung`` offers a bunch of convenience classes for tasks related to linear algebra. They are neither very performant nor feature-complete.
``bewegung`` offers a bunch of convenience classes for tasks related to linear algebra.

.. note::

The classes provided here are neither very performant nor feature-complete.

.. toctree::
:maxdepth: 2
Expand Down
2 changes: 1 addition & 1 deletion docs/anatomy.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Compositing: Anatomy of a Video
===============================

Based on *layers* and *sequences*, ``bewegung`` offers a lot of infrastructure for compositing animations and videos. At its core, there is :ref:`time <time>`. It is primarily measured in frame numbers (the :attr:`bewegung.Time.index`), but can also be converted to seconds (:attr:`bewegung.Time.seconds`). Time is described using :class:`bewegung.Time` objects. A :ref:`video <video>` is fundamentally defined using the :class:`bewegung.Video` class. It offers decorators for :ref:`sequence classes <sequences>`, :ref:`prepare task methods <prepare_tasks>` and :ref:`layer task methods <layer_tasks>`. Prepare tasks and layer tasks are orders using indices, which are managed by :ref:`index pools <index_pool>`. :ref:`Effects <effects>` can be applied to individual layers. Animations can be rendered in their entirety (see :meth:`bewegung.Video.render`) while frames can also be rendered individually (see :meth:`bewegung.Video.render_frame`). The process of rendering videos is fully parallelized. ``bewegung`` supports different :ref:`encoders <encoders>`.
Based on *layers* and *sequences*, ``bewegung`` offers a lot of infrastructure for compositing animations and videos. At its core, there is :ref:`time <time>`. It is primarily measured in frame numbers (the :attr:`bewegung.Time.index`), but can also be converted to seconds (:attr:`bewegung.Time.seconds`). Time is described using :class:`bewegung.Time` objects. A :ref:`video <video>` is fundamentally defined using the :class:`bewegung.Video` class. It offers decorators for :ref:`sequence classes <sequences>`, :ref:`prepare task methods <prepare_tasks>` and :ref:`layer task methods <layer_tasks>`. Prepare tasks and layer tasks are ordered using indices, which are managed by :ref:`index pools <index_pool>`. :ref:`Effects <effects>` can be applied to individual layers. Animations can be rendered in their entirety (see :meth:`bewegung.Video.render`) while frames can also be rendered individually (see :meth:`bewegung.Video.render_frame`). The process of rendering videos is fully parallelized. ``bewegung`` supports different :ref:`encoders <encoders>`.

.. toctree::
:maxdepth: 2
Expand Down
4 changes: 3 additions & 1 deletion docs/camera.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
3D to 2D projections: A Camera
==============================

Foo bar.
``bewegung`` includes a `pin-hole camera`_ for simple 3D to 2D projections. In a nutshell, the a :class:`bewegung.Camera` object can convert a :class:`bewegung.Vector3D` object into a :class:`bewegung.Vector2Ddist` object given a location and direction in 3D space, i.e. the 3D vector is projected into a plane in 2D space. Because the "camera" is actually not a rendering system on its own, it simply adds meta information to the returned 2D vector: The absolute distance from the "pinhole" in 3D space to the vector in 3D space. This allows to (manually) implement various kinds of depth perception, e.g. backgrounds and foregrounds, in visualizations. The camera is a useful tool if e.g. multiple :ref:`drawing backends <drawing>` are combined within a single animation and some kind of common 3D visualization is required. A typical combination is :ref:`datashader <datashader>` for density distributions and :ref:`cairo <backendcairo>` for annotations on top, see :ref:`gallery <gallery>` for examples.

.. _pin-hole camera: https://en.wikipedia.org/wiki/Pinhole_camera

.. autoclass:: bewegung.Camera
:members:
18 changes: 9 additions & 9 deletions docs/canvas.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
Drawing: Canvas Types & Backends
================================

``bewegung`` offers a set of "backends" for drawing on canvases. A specific backend can be selected and configured through the ``Video.canvas`` method. Full access to the inventory of backends and all of their functionality is provided through the ``backends`` dictionary.
``bewegung`` offers a set of "backends" for drawing on canvases. A specific backend can be selected and configured through the :meth:`bewegung.Video.canvas` method. Full access to the inventory of backends and all of their functionality is provided through the ``backends`` dictionary.

Canvas Factories: ``Video.canvas``
----------------------------------

The ``Video.canvas`` method is typically used to configure a layer. It returns a "factory", i.e. a special function, which can be called to generate new pre-configured canvases of a certain type.
The :meth:`bewegung.Video.canvas` method is typically used to configure a layer. It returns a "factory", i.e. a special function, which can be called to generate new pre-configured canvases of a certain type.

.. code:: python
Expand All @@ -20,7 +20,7 @@ The ``Video.canvas`` method is typically used to configure a layer. It returns a
canvas_a = canvas_factory() # produce a new canvas
canvas_b = canvas_factory() # produce yet another new canvas
In the context of a layer's configuration, the use of ``Video.canvas`` looks as follows.
In the context of a layer's configuration, the use of :meth:`bewegung.Video.canvas` looks as follows.

.. note::

Expand All @@ -41,7 +41,7 @@ A new, pre-configured canvas of the requested type is fed into the layer method
def bar(self, canvas): # a new canvas is generated and passed once per frame
return canvas
Parameters of the ``Video.canvas`` method other than ``backend``, i.e. the name of the selected backend, are usually forwarded to the underlying library.
Parameters of the :meth:`bewegung.Video.canvas` method other than ``backend``, i.e. the name of the selected backend, are usually forwarded to the underlying library.

.. warning::

Expand All @@ -60,7 +60,7 @@ All backends can be accessed via the ``backends`` dictionary, which represents t
>>> [backend for backend in backends.values()]
[<DrawingBoardBackend>, <PillowBackend>, <DatashaderBackend>, <CairoBackend>, <MatplotlibBackend>]
Backends are "lazy" objects. They only import the underlying library if actually used. For most intents and purposes, working with ``Video.canvas`` is sufficient. Further details about the common structure of backends are provided in the :ref:`sections on custom backends <custombackends>`.
Backends are "lazy" objects. They only import the underlying library if actually used. For most intents and purposes, working with :meth:`bewegung.Video.canvas` is sufficient. Further details about the common structure of backends are provided in the :ref:`sections on custom backends <custombackends>`.

.. _drawingboard:

Expand Down Expand Up @@ -265,7 +265,7 @@ Layer methods are expected to return ``datashader.transfer_functions.Image`` obj

.. warning::

If a ``datashader.transfer_functions.Image`` object is returned, ``bewegung`` will mirror the image along the x-axis, i.e. the y-axis will be flipped. This makes the output consistent with ``Pillow`` and ``pycairo``, were the y-axes is positive downwards. The flip can be avoided by manually converting the image to a Pillow Image object before returning, i.e. ``return img.as_pil()`` in the above example.
If a ``datashader.transfer_functions.Image`` object is returned, ``bewegung`` will mirror the image along the x-axis, i.e. the y-axis will be flipped. This makes the output consistent with ``Pillow`` and ``pycairo``, were the y-axis is positive downwards. The flip can be avoided by manually converting the image to a Pillow Image object before returning, i.e. ``return img.as_pil()`` in the above example.

Backend: ``matplotlib``
-----------------------
Expand Down Expand Up @@ -318,7 +318,7 @@ Similar to ``matplotlib.pyplot.figure``, the function call ``v.canvas(backend =
- ``height``, height *in pixels*. Mapped to ``figsize`` if provided together with ``width``. Converted to inches based on the value of ``dpi``.
- ``tight_layout``, by default ``True``.
- ``facecolor``, a background color.
- ``background_color``, mapped to ``facecolor``. Accepts ``bewegung.Color`` objects.
- ``background_color``, mapped to ``facecolor``. Accepts :class:`bewegung.Color` objects.
- ``managed``, a boolean, by default ``True``. This value indicates whether the the ``matplotlib.figure.Figure`` object is "managed" by ``bewegung``. If ``True``, ``bewegung`` will close, i.e. destroy, a figure that is returned by a layer method.

Layer methods are expected to return ``matplotlib.figure.Figure`` objects.
Expand Down Expand Up @@ -389,7 +389,7 @@ The less a figure changes, the faster the above code becomes. Depending on the d
Defining & Registering Custom Backends
--------------------------------------

``bewegung`` allows to add new, custom backends. It is a two-step process. First, a backend class must be derived from ``bewegung.BackendBase``. Second, an instance / object of this class must be added to the ``bewegung.backends`` dictionary.
``bewegung`` allows to add new, custom backends. It is a two-step process. First, a backend class must be derived from :class:`bewegung.BackendBase`. Second, an instance / object of this class must be added to the ``bewegung.backends`` dictionary.

The ``BackendBase`` API
~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -483,7 +483,7 @@ The ``_prototype`` method should return a factory function without parameters. I
Cross-Backend Abstraction: Colors
---------------------------------

All backends work with variations of RGB, RGBA or RGBa color spaces. Some use pre-multiplied alpha values, some do not. Some accept RGB values as floats from 0.0 to 1.0, some accept RGB values as integers from 0 to 255, some expect hexadecimal notations as strings. The ``Color`` class tries to provide a common base for working with RGB(A) colors in different notations.
All backends work with variations of RGB, RGBA or RGBa color spaces. Some use pre-multiplied alpha values, some do not. Some accept RGB values as floats from 0.0 to 1.0, some accept RGB values as integers from 0 to 255, some expect hexadecimal notations as strings. The :class:`bewegung.Color` class tries to provide a common base for working with RGB(A) colors in different notations.

The ``Color`` API
~~~~~~~~~~~~~~~~~
Expand Down
12 changes: 12 additions & 0 deletions docs/gallery.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _gallery:

Gallery
=======

Expand Down Expand Up @@ -37,3 +39,13 @@ This video is inspired by (and essentially a remake of) `Asteroid Discovery From
.. _Orbital elements: https://en.wikipedia.org/wiki/Orbital_elements
.. _Minor Planet Center: https://www.minorplanetcenter.net/data
.. _poliastro: https://github.com/poliastro/poliastro

Density Wave Theory
-------------------

.. youtube:: arWvq_9_0ak

The `density wave theory`_ by Lin & Shu (1964) provides an explanation for stable arms of spiral galaxies. It is also an interesting and widely used theme for visualizations. The above example contains 10 million stars and highlights the secret location of `Magrathea`_.

.. _density wave theory: https://en.wikipedia.org/wiki/Density_wave_theory
.. _Magrathea: https://hitchhikers.fandom.com/wiki/Magrathea
2 changes: 1 addition & 1 deletion docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ The output looks as follows:

Compared to the initial minimal example, the above complex example contains two :ref:`sequences <sequences>` with one :ref:`layer <layer_tasks>` each. The :ref:`video <video>`, the layers and the sequences are a lot more configured. The video for instance is not defined based on its length in seconds. Instead, the number of frames is provided. Besides, the video is not using ``bewegung``'s default frame rate of 60 fps but 30 fps instead.

The "empty" layer in the "Background" sequence receives a background :ref:`color <colors>`, a dark gray tone. It is provided with an explicit z-index at the bottom of the stack of layers. The "SomeForeground" sequence begins 1 second into the video and ends one second before the end of the video. The "moving_red_ball" layer has a transparent background color so the "empty" layer from the "Background" sequence becomes visible. It is also provided with an explicit z-index - this time at the top of the stack of layers. In addition, the "moving_red_ball" layer is decorated with *video effects*, making it to fade in and out.
The "empty" layer in the "Background" sequence receives a background :ref:`color <colors>`, a dark gray tone. It is provided with an explicit z-index at the bottom of the stack of layers. The "SomeForeground" sequence begins one second into the video and ends one second before the end of the video. The "moving_red_ball" layer has a transparent background color so the "empty" layer from the "Background" sequence becomes visible. It is also provided with an explicit z-index - this time at the top of the stack of layers. In addition, the "moving_red_ball" layer is decorated with *video effects*, making it to fade in and out.

The video frames are *rendered in parallel*. The ``processes`` parameter of the :meth:`bewegung.Video.render` method defines the number of parallel rendering processes. It is set to the `number of logical cores`_ of the computer's CPU(s). ``bewegung`` evaluates every layer once per video frame and composes all layers to an image - the actual video frame. Because of the parallel nature of ``bewegung``, the *generation of frames may occur out-of-order*. However, the video frames are always forwarded to the video encoder in the right order.

Expand Down
4 changes: 2 additions & 2 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
bewegung - a versatile video renderer
=====================================

*/bəˈveːɡʊŋ/ (German, noun, feminine: `motion/movement/animation`_)*
*/bəˈveːɡʊŋ/* - German, noun, feminine: `motion / movement / animation`_

.. _motion/movement/animation: https://dict.leo.org/englisch-deutsch/bewegung
.. _motion / movement / animation: https://dict.leo.org/englisch-deutsch/bewegung

.. |docs_master| image:: https://readthedocs.org/projects/bewegung/badge/?version=latest&style=flat-square
:target: https://bewegung.readthedocs.io/en/latest/
Expand Down
4 changes: 2 additions & 2 deletions docs/layer_tasks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ Layer tasks are special, decorated methods within user-defined :ref:`sequence <s

Layers can be configured to use a certain :ref:`backend for drawing <drawing>`. ``DrawingBoard`` is the default backend, see :ref:`here <drawingboard>`. It does not matter what kind of object a layer method returns as long as it is recognized by one of the currently loaded backends. If the canvas was provided by ``bewegung``, a layer method usually does not need to return it - ``bewegung`` will keep a reference on it. There are exceptions however: The :ref:`datashader backend <datashader>` for instance requires the user to convert the canvas to an image before the user must in fact return the image from the layer method.

Layers may have an *offset* from the top-left corner of the video frame, where the y-axes is positive. The size, i.e. width and height, of a layer must be configured through its backend via the :meth:`bewegung.Video.canvas` method.
Layers may have an *offset* from the top-left corner of the video frame, where the y-axes is positive downwards. The size, i.e. width and height, of a layer must be configured through its backend via the :meth:`bewegung.Video.canvas` method.

Layers can be post-processed by an arbitrary number of :ref:`effects`. Effects are special decorator classes which are stacked on top of the layer decorator.
Layers can be post-processed by an arbitrary number of :ref:`effects`. Effects are special decorator classes which are stacked on top of the :meth:`bewegung.Video.layer` decorator method.

The ``Video.layer`` Decorator
-----------------------------
Expand Down
Loading

0 comments on commit 511fa18

Please sign in to comment.