.. -*- coding: utf-8 -*-
.. _slicing-trajectories:

====================
Slicing trajectories
====================

MDAnalysis trajectories can be indexed to return a :class:`~MDAnalysis.coordinates.base.Timestep`, or sliced to give a :class:`~MDAnalysis.coordinates.base.FrameIterator`.

.. ipython:: python
    :okwarning:

    import MDAnalysis as mda
    from MDAnalysis.tests.datafiles import PSF, DCD

    u = mda.Universe(PSF, DCD)
    u.trajectory[4]


Indexing a trajectory shifts the :class:`~MDAnalysis.core.universe.Universe` to point towards that particular frame, updating dynamic data such as ``Universe.atoms.positions``.

.. note::

    The trajectory frame is not read from the MD data. It is the internal index assigned by MDAnalysis.

.. ipython:: python

    u.trajectory.frame

*Creating* a :class:`~MDAnalysis.coordinates.base.FrameIterator` by slicing a trajectory does not shift the :class:`~MDAnalysis.core.universe.Universe` to a new frame, but *iterating* over the sliced trajectory will rewind the trajectory back to the first frame.

.. ipython::: python

    fiter = u.trajectory[10::2]
    u.trajectory.frame

.. ipython:: python

    fiter = u.trajectory[10::10]
    frames = [ts.frame for ts in fiter]
    print(frames, u.trajectory.frame)

You can also create a sliced trajectory with boolean indexing and fancy indexing. Boolean indexing allows you to select only frames that meet a certain condition, by passing a :class:`~numpy.ndarray` with the same length as the original trajectory. Only frames that have a boolean value of ``True`` will be in the resulting :class:`~MDAnalysis.coordinates.base.FrameIterator`. For example, to select only the frames of the trajectory with an RMSD under 2 angstrom:

.. ipython:: python

    from MDAnalysis.analysis import rms

    protein = u.select_atoms('protein')
    rmsd = rms.RMSD(protein, protein).run()
    bools = rmsd.results.rmsd.T[-1] < 2
    print(bools)

.. ipython:: python
    :okwarning:

    fiter = u.trajectory[bools]
    print([ts.frame for ts in fiter])

You can also use fancy indexing to control the order of specific frames.

.. ipython:: python

    indices = [10, 2, 3, 9, 4, 55, 2]
    print([ts.frame for ts in u.trajectory[indices]])

You can even slice a :class:`~MDAnalysis.coordinates.base.FrameIterator` to create a new :class:`~MDAnalysis.coordinates.base.FrameIterator`.

.. ipython:: python

    print([ts.frame for ts in fiter[::3]])