Extended docs and a library of examples are available
at:

http://mmb.irbbarcelona.org/molywood

### What does `molywood` do?

Molywood is there to make cool molecular movies for you.

Specifically, `molywood` automatizes the most tedious steps in
generation of these movies, i.e. scripting in TCL, rendering, generating
overlays and combining frames, as well as merging frames into the final
movie.

We try to simplify the movie making syntax, as well as add extended
functionalities such as animating trajectory data with matplotlib,
adding insets or making multi-panel movies.

The basic idea behind the functionalities of `molywood` is best understood
through the examples hosted on ... Ambitious users are advised to
familiarize themselves with the documentation of individual keywords,
and explore the capabilities of the script through experimentation.

### Installation

The simplest way to install `molywood` is through `pip`:

`pip install molywood`

will install the script as a command-line tool, so that on most Unix-based
systems `molywood` can be run right away with an example input:

`molywood movie_script.txt`

If any dependencies are missing (e.g., on a remote cluster or workstation),
you can use `conda` to automatically install them and create a virtual
environment. After installation with `pip`, just run 

`molywood-gen-env`

in your command line to (a) automatically look for missing dependencies
and (b) directly download them from `conda` channels if there are any. Even when installing
VMD, you won't need root privileges - everything is managed through your
private `conda` package manager. When the virtual environment is set up,
type:

`source activate molywood`

(or `conda activate molywood`, depending on your `conda` setup). If the virtual
environment is not activated, `molywood` will try to activate it on-the-fly
whenever VMD cannot be found in the system path.

#### Manual installation of dependencies

Full functionality requires that `python3`, `VMD`, `imagemagick` and
`ffmpeg` be installed. The good news is that the actual rendering can be done externally,
e.g. on a remote workstation, once you set up the visualization state
locally. Using the draft mode with `render=f` (see below), you can also
preview your movie only with `python3` and `VMD`.

Alternatively, all dependencies can be installed separately:
+ It is recommended to use `python3` from the Anaconda distribution
as it contains `numpy` and `matplotlib` as a pre-installed package.
+ `VMD` can be obtained at `https://www.ks.uiuc.edu/Research/vmd/`.
+ `imagemagick` is installed by default on most Linux distributions;
run e.g. `convert` to make sure it is available on your machine.
+ `ffmpeg` can be installed e.g. from the Ubuntu repository by
typing `sudo apt-get install ffmpeg`.

### Usage

Sample movie scripts are available in the `examples` directory: try
them first to see how the library works.

`molywood` can be run from the console (e.g. in the `examples/simple_movie`
directory) as:

 `python ../../molywood/moly.py script.txt`

In general, to run `molywood` the following files are needed:

1. either (a) a visualization state generated by VMD, or (b) a structure
file; (a) is the preferred way - user may define the representations
as well as set the camera angle as desired, and then go to File > Save
Visualization State); in option (b), a default representation is used,
and a compatible trajectory file can be provided. Alternatively, one can
provide a four-character `pdb_code=...`, and the structure will be
automatically downloaded from the PDB database.
1. a 'movie script', i.e. a simple text file containing directives,
including a reference to the VMD visualization state (see examples and
the explanations below).

### List of available action keywords and parameters:

###### Instantaneous actions:

+ center_view (selection='...')
+ add_label (label='...' atom_index=... \[label_color=...
text_size=... alias=...\])
+ add_distance (selection1='...' selection2='...' \[label_color=...
text_size=... alias=...\])
+ remove_label (\[alias=... remove_all=t/**f**\])
+ remove_distance (\[alias=... remove_all=t/**f**\])
+ toggle_molecule (molecule_id=... \[top=t/f, freeze=t/f active=t/f drawn=t/f\])

##### Instantaneous or finite-time actions

+ fit_trajectory (selection='...' \[axis=x/y/z/"v_x v_y v_z" t=...s
invert=t/**f**\])
+ rotate (axis=x/y/z angle=... \[sigmoid=**t**/f/sls t=...s fraction=...\])
+ translate (vector=Tx,Ty,Tz \[sigmoid=**t**/f/sls t=...s fraction=...\])
+ zoom_in/zoom_out (scale=... \[sigmoid=**t**/f/sls t=...s fraction=...\])
+ animate (frames=init_frame:final_frame \[smooth=... t=...s\])
+ make_transparent/make_opaque (material=... \[sigmoid=**t**/f/sls
start=... limit=... t=...s fraction=...\])
+ highlight (selection=... \[color=**red** mode=u/d/n/**ud**
material=**Opaque**/Diffuse/Transparent/... isovalue=...
style=**newcartoon**/licorice/surf/quicksurf/vdw/tube/isosurface 
fade_in=**0.2** fade_out=**0.2** thickness=... alias=...  t=...\])

###### Finite-time actions:

+ show_figure (t=...s \[figure=... datafile=...
dataframes=init_frame:final_frame\])
+ do_nothing (t=...s)
+ add_overlay (t=...s \[figure=... datafile=... origin=0,0 text=...
relative_size=**1** dataframes=init_frame:final_frame aspect_ratio=...
2D=t/**f** textsize=**1** sigmoid=t/**f** alpha=a_init\[:a_final\]
scene=... transparent_background=t/**f** textcolor=**black**
decimal_points=**3**\])
+ add_audio (audiofile=... \[from=**0** length=... volume=**1**\])


(Note that **only** finite-time actions can be combined using curly
brackets. Also, almost all finite-time actions (except for `rotate`)
require the t=...s keyword. Above, square brackets denote optional
parameters. Values in bold font indicate defaults when parameters
are optional.)

### List of available global keywords and parameters:

+ global (\[fps=**20**  draft=t/**f** keepframes=t/**f** name=**movie**
render=**t**/f\])
+ layout (\[rows=**1** columns=**1**\])
+ figure (\[files=figure1.png,figure2.png,...\])
+ scene_identifier (\[visualization=... structure=... trajectory=...
pdb_code=... position=**0,0** resolution=**1000,1000** after=...
ambient_occlusion=t/**f** max_transparent_surfaces=**1**\])

(instead of scene_identifier, you should put the actual identifier
of the scene in question, e.g., `scene_1` in the example below)

### Notes on global keywords:

+ `fps=...` sets the frame ratio, effectively translating `t=...s`
keywords in indivivual actions into actual frame numbers. A value of
20 will produce a smooth movie; setting it low (5-10) is, however,
convenient for early tests and experimentation as the movie preparation
becomes very fast.
+ The `draft` mode allows for a quick-and-dirty render on a local
machine, using the Snapshot renderer (esentially VMD screenshots)
instead of the more robust but costly Tachyon. It is recommended to
only run a `draft=f` job once a `draft=t` movie looks good. Note: minor
aspects (e.g. the appearence of transparent materials or text labels)
will differ between the two modes.
+ With `keepframes`, one can preserve most of the files generated
on-the-fly (.png frames and the .tcl script). This can be useful in
many cases, e.g. when designing complex overlays on top of already
rendered frames, or when introducing custom changes into the .tcl script.
+ The `render` option indicates that the run should render frames and
produce a movie. Turning it off allows the user to only "watch" the movie
within VMD (consecutive actions are performed but no images are rendered),
so that the disk drive is not overwhelmed, but composition and overlays
cannot be previewed this way (use `draft=t` instead).
+ `restart=t` can be used if a fraction of frames has already been
successfully rendered (sometimes taking a lot of time) and only the
remaining ones should be produced. In this case, the script should
automatically detect which actions have been rendered completely, and
only re-render missing ones.
+ `name` only affects the names of the .png frames and the final
.mp4 movie file. Can be useful to avoid overwriting existing files.
+ `ambient_occlusion=t` enables the Tachyon's Ambient Occlusion
rendering mode (with a predefined setting). This yields the most
visually appealing results, but will take significantly (at least order
of magnitude) longer, so it should only be applied as the final polish
to already well-tested setups. Not compatible with the draft mode.
+ `max_transparent_surfaces=...` sets the maximum number of transparencies
allowed by the renderer. When set to the default (`...=1`), only one object
on top will appear as transparent; when set to a large number, all
elements will maintain transparency, which tends to produce ugly results,
e.g., with semi-transparent Licorice or NewCartoon representations.

### Notes on input formatting:

+ A hash `#` marks the *beginning* of a scene input section, and should
be followed by a single-word scene identifier,  e.g. `# scene_1`
+ Single actions have to be specified on a single line, starting with
a keyword and followed by any number of whitespace-separated
 `parameter=value` pairs (note: no spaces encircling the `=` sign)
+ Multiple actions (e.g. rotation and zoom_in) can be performed
simultaneously if they are encircled in curly brackets and separated
with semicolons, e.g. `{rotate t=1s angle=50; zoom_in t=1s scale=2}`;
they can also be split over several lines for convenience. Note that here,
the second `t=1s` parameter specification will overwrite the first, so
that time might as well only be specified once
+ A line starting with a `$` sign specifies global keywords, e.g.
`$ global fps=20` (see available global keywords above)
+ true/false values can be specified as `true/false`, `yes/no` or in
shorthand notation (`t/f`, `y/n`)
+ Comments can be introduced with an exclamation mark, `!`

### Notes on extra graphics features

+ External figures (e.g. ending credits) can be featured in the movies.
The external graphics file has to be specified as a parameter in the
`show_figure` action (e.g. `show_figure t=4s figure=picture.png`).
+ Note that it is *the user* who is responsible for setting correct
resolutions for the individual scenes. By default, each scene is
rendered in a resolution of 1000x1000; if e.g. a source figure isn't
exactly rectangular, it will be scaled to
fit in the rectangle, but its aspect ratio (shape) will not be affected.
+ Multiple overlays (insets) can be added to each scene. The inset can
either be a static image (specified with the `figure` keyword in
`add_overlay`), or a dynamically generated matplotlib plot (by
specifying the `datafile` parameter in `add_overlay`). Currently 1D
line plots (generated with plt.plot) and 2D histograms (generated with
plt.hexbin) are supported; the former is default if a `datafile` is
supplied, and the latter can be requested with `2D=t`. The relative
coordinates of the origin (from `0,0` to denote bottom left to `1,1` to
denote upper right corner), inset size relative to the background figure,
and the aspect ratio (X to Y size) can all be specified independently to
position the inset/overlay as desired.
+ When generating figures with matplotlib, axis labels can be specified
directly in the datafile by adding a `# x label; y label` (spaces and
latex-compatible math notation are allowed). In addition, multiple
matplotlib-compatible `keyword=value` pairs can be enumerated after the
`!` character to modify plt.plot/plt.hexbin defaults, e.g.
`! bins='log' cmap='seismic'`, or plot properties, e.g.
`! xlim=-1,2 ylim=0,500` (no spaces around the `=` sign).
+ Invidivual scenes can be combined not only side-by-side (as using
`$ layout ...`), but also one after the other. To append `next_scene`
at the end of `previous_scene`, it is sufficient to set e.g.
`$ next_scene visualization=... after=previous_scene`. Note that to
avoid technical issues, it is advised to list the scenes in the input
in the actual order they need to be concatenated, especially when
concatenating more than two of them.

### Notes on individual actions

###### Instantaneous actions:

+ `center_view` is an instantaneous action that sets the geometric
center of `selection` (VMD-compatible) as the new camera center to
which zoom will converge; useful when zooming onto e.g. a reaction center
+ `add_label` instantaneously adds a text label anchored to an atom.
specified with `atom_index`, with the labeling text specified through
the `label` parameter; if desired, text size  and color can be
specified with `label_color` and `text_size`. If the label will be removed
later, consider giving it an `alias=...`.
+ `add_distance` instantaneously adds a distance label between
the centers of geometry of two VMD-compatible selections, specified
with `selection1` and `selection2`; as above, text size and color can
be specified with `label_color` and `text_size`, and an `alias=...` can
be set to remove the distance label later on.
+ `remove_label` instantaneously deletes a label specified through
`alias=...` identical to an `alias` previously specified in `add_label`;
alternatively, `all=t` removes all existing labels. Note that `alias=...`
and `all=t` should be mutually exclusive: one either deletes a specific
label or all of them.
+ `remove_distance` works identically to `remove_label`, but affects
labels added using `add_distance` instead of `add_label`.
+ `toggle_molecule` allows to dynamically change molecule properties in VMD:
`freeze`, `drawn` and `active` can be toggled on and off with `t` or `f`,
and the top molecule can be changed by setting `top=t`, all for the molecule
specified with `molecule_id=...`.

##### Instantaneous or finite-time actions

+ `rotate` rotates the scene by `angle` degrees about `axis` in time `t`.
`sigmoid=t` gives a smooth transition, while `sigmoid=f` gives a
constant-velocity one; optionally, `sigmoid=sls` performs a smooth-
linear-smooth transition (preferable for e.g. multiple full rotations);
when `t` is not specified, `rotate` will behave as an instantaneous
action.
+ `translate` moves the camera position by `vector`, specified by three
comma-separated values; the unit is screen size, so usually fractional
values should be used to achieve a modest change. Other parameters (`t`,
`sigmoid`) behave identically to `rotate`.
almost identically to `rotate`.
+ `zoom_in`/`zoom_out` scales the view by a factor of `scale`. Other
parameters (`t`, `sigmoid`) behave identically to `rotate`.
+ `animate` runs the trajectory from `init_frame` to `final_frame`,
adjusting the playback speed to the time specified with `t`;
`smooth=X` sets the smoothing of all VMD representations to X. When `t`
is not specified, `animate frame=Y` instantaneously goes to frame
number `Y`.
+ `highlight` creates a new representation to highlight a subset of
the system selected by specifying the `selection` parameter. Color can
be chosen with `color`, using either simple color names (black, red,
blue, orange, yellow, green and white), VMD-compatible ColorIDs (0-32)
or a coloring scheme keyword (name, type, element, structure etc.).
Similarly, `style` can be set to newcartoon, licorice, surf,
quicksurf, vdw or tube (non-case sensitive).
    + By default, highlight appears (fades in from transparency) and
    disappears smoothly over the course of the action. If you want your
    highlight to stay visible, use `mode=u` (up) to make it appear only.
    + To turn off a previously created highlight (possibly after several
    intervening actions), use `mode=d` (down) along with
    `alias=...` identical to a previously set `alias` of the highlight
    to be turned off; you only need to provide an alias to a highlight
    if you first turn it on and want to turn it off/modify later.
    + To modify the properties of a previously created highlight, use
    `mode=n` along with property modifiers such as `thickness=...`,
    `isovalue=...` or `alpha=...`. To change the property in a smooth
    manner, use the colon-based (`...=init_value:end_value`) range syntax.
    + Highlights can also be created or deleted instantaneously (e.g.
    at the beginning of a scene instead of adding a VMD representation)
    if the `t=...s` keyword is omitted *and* `mode=u/d` is specified.
    + With `style=isosurface`, volumetric data (e.g., CCP4 density maps
    or electron densities) can be shown, given that the mandatory 
    keyword `isovalue=...` is provided. When a range of values is given
    (e.g., `isovalue=0.01:0.2`), the isovalue will change continuously.
    Note: `molywood` does **not** normalize the isovalues, so that one 
    should use the same values as used in VMD.
    + The semi-transparent fade-in and fade-out of highlights can be
    controlled with the `fade_in=...` and `fade_out=...` keywords,
    which specify the fraction (from 0 to 1) of the action's duration
    spent at the transition. E.g., when `mode=ud` (default), `t=4s`, 
    `fade_in=0` and `fade_out=0.5`, the highlight will appear instantaneously,
    will be opaque for 2s and will disappear smoothly over the next 2s.
+ `fit_trajectory` uses RMSD-based fitting to instantaneously align a
trajectory to the reference (first) frame, using the `selection` to
calculate the optimal alignment; when `t` is specified, this alignment
will be gradual instead of abrupt. When `axis=x/y/z/"x_comp,y_comp,z_comp"`
is specified, the main principal axis of `selection` will be aligned
to the chosen/defined axis. If you want to choose an opposite orientation
than is done by default, simply add `invert=t`.
+ `make_transparent`/`make_opaque` change the opacity of a selected
`material` to make it fully transparent or fully opaque in time `t`.
`start` and `limit` optionally accept floating-point values from 0 to 1
to restrict the transition to this range (note that transparency=0 is
equivalent to opacity=1). `sigmoid` works like for `rotation`. When
`t` is not specified, the change in opacity is instantaneous, and
`start` and `limit` can be used interchangeably.

###### Finite-time actions:

+ `show_figure` just shows an image instead of a VMD render during time
`t`; the image is specified using `figure=fig_file_name`.
+ `do_nothing` renders the VMD scene for time `t` without doing
anything else.
+ `add_overlay` allows to add an inset to the scene, with the position
specified through `origin` (0,0  corresponds to the bottom left corner,
as in a regular Cartesian coordinate system), and size through
`relative_size` (1 means fit into the whole  scene, 0.1 means fit into
a rectangle 10% of the scene size).
    + The content of the overlay can be  an external figure (specified
    through `figure_index`), an on-the-fly  generated matplotlib line
    plot (based on a data file speficied with the `datafile` parameter)
    or plain text.
    + If `datafile=...` is specified, a dot will dynamically follow the
    values on the plot. By default, the script will try to use `frames`
    from the accompanying `animate` action to select datapoint indices
    from the `datafile`. To independently select datapoint indices for
    the 1D plot (e.g. when the `datafile` has much more entries than
    the trajectory used in `animate`, one can supply `datafile=...`
    with `dataframes=...` - it will take precendence over `animate`'s
    `frames`.
    + If the  data file starts with a single line formatted as
    `# x axis label; y axis label`, `x axis label` and `y axis label`
    will be used to label the corresponding axes of the plot.
    + If `text="sample text` is used, the text will be displayed at
    a position specified with `origin`.
    + Mulitple overlays can be added to a scene simultaneously; adding
    many `add_overlay` commands separated by semicolons and encircled
    in curly brackets works just as any other multiple action (see
    `Notes on input formatting` above).
    + By default `mode=ud`, in analogy to `highlight`; if `mode=u`,
    the overlay will remain in place until the end of the movie,
    unless `mode=d` is specified later with a matching `alias=...`
    entry (`alias=...` *only* needs to be specified in this specific case)
    + By specifying `alpha`, the overlay can be made semi-transparent;
    `alpha` can either be a float between 0 and 1 (e.g. `alpha=0.3`),
    or a range separated by a colon (e.g. `alpha=1:0`); in the latter
    case, transparency will change linearly from the first value
    (here non-transparent, alpha=1) to the other (here fully
    transparent, alpha=0).
+ `add_audio` allows to add a soundtrack to the movie, be it a piece of
music or a spoken comment. Like `add_overlay`, it has to be combined
with another action using the curly bracket `{...}` notation. By default,
a given recording starts at the beginning of the action, and can exceed
the action's duration, even until the end of the movie.
    + The audio file can be specified with the `audiofile=...` keyword;
    for now, only the .mp3 format is properly tested.
    + When `from=...` and `length=...` are specified, the input audio
    will be trimmed to start from the specified timestamp and have the 
    appropriate duration (both values are in seconds and can be floats).
    + Within a movie, many audio files can be added, although only one
    file per action is supported. If consecutive audio files overlap,
    the preceding one will be interrupted where the next one begins.
    + To adjust the volume of individual audio segments, add 
    `volume=...`, passing the new volume relative to the original
    (a value of `1` yields the original volume)

### Known issues

+ VMD labels are always rendered using the `Opaque` material, so that
making this material transparent (`make_transparent material=Opaque`)
will make the labels disappear as well; the straightforward solution is
to use a different material, or generate a copy.
(`VMD Main > Graphics > Materials > Create New`)
+ Also, the labels are rendered with a slightly different size and
appearance with the Snapshot (`draft=t`) and Tachyon (`draft=f`)
renderers.
+ `fit_trajectory` combined with `axis` can become slow if combined
with large `selection` (in terms of number of atoms) and `animation`
with large `smooth=...` values; it is suggested to only use backbones
for alignment to principal axes, as the repeated calculation of tensors
of inertia can be time-consuming in VMD.
+ With the default `ffmpeg` settings, choppy video playback has been
reported when VLC is being run on OSX; this is solely a video player
issue.
+ Due to how Tachyon renders transparencies, at times the default setting
`max_transparent_surfaces=1` might turn out troublesome when working with
many transparent representations overlaid on one another: if that is the
case, try increasing this value. The default is set to 1 as otherwise
representations like Licorice or NewCartoon look quite ugly when transparent.

### Featured movies

If you believe your `molywood`-generated movie should be featured in our gallery
to inspire other users, please email your example (input file, the rendered movie, 
and possibly other files, such as your structure/trajectory and the .vmd 
visualization state) to [this address](mailto:milafternoon@gmail.com). You may also
include a literature reference to highlight your work.
