.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "examples/smooth.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. or to run this example in your browser via Binder .. rst-class:: sphx-glr-example-title .. _sphx_glr_examples_smooth.py: Smooth pose tracks ===================== Smooth pose tracks using the median and Savitzky-Golay filters. .. GENERATED FROM PYTHON SOURCE LINES 8-10 Imports ------- .. GENERATED FROM PYTHON SOURCE LINES 10-16 .. code-block:: Python from matplotlib import pyplot as plt from scipy.signal import welch from movement import sample_data .. GENERATED FROM PYTHON SOURCE LINES 17-23 Load a sample dataset --------------------- Let's load a sample dataset and print it to inspect its contents. Note that if you are running this notebook interactively, you can simply type the variable name (here ``ds_wasp``) in a cell to get an interactive display of the dataset's contents. .. GENERATED FROM PYTHON SOURCE LINES 23-27 .. code-block:: Python ds_wasp = sample_data.fetch_dataset("DLC_single-wasp.predictions.h5") print(ds_wasp) .. rst-class:: sphx-glr-script-out .. code-block:: none Size: 61kB Dimensions: (time: 1085, individuals: 1, keypoints: 2, space: 2) Coordinates: * time (time) float64 9kB 0.0 0.025 0.05 0.075 ... 27.05 27.07 27.1 * individuals (individuals) ` method of the ``move`` accessor, we apply a rolling window median filter over a 0.1-second window (4 frames) to the wasp dataset. As the ``window`` parameter is defined in *number of observations*, we can simply multiply the desired time window by the frame rate of the video. We will also create a copy of the dataset to avoid modifying the original data. .. GENERATED FROM PYTHON SOURCE LINES 121-126 .. code-block:: Python window = int(0.1 * ds_wasp.fps) ds_wasp_smooth = ds_wasp.copy() ds_wasp_smooth.update({"position": ds_wasp_smooth.move.median_filter(window)}) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 head: 0/1085 (0.0%) stinger: 0/1085 (0.0%) Missing points (marked as NaN) in output Individual: individual_0 head: 0/1085 (0.0%) stinger: 0/1085 (0.0%) .. raw:: html
<xarray.Dataset> Size: 61kB
    Dimensions:      (time: 1085, individuals: 1, keypoints: 2, space: 2)
    Coordinates:
      * time         (time) float64 9kB 0.0 0.025 0.05 0.075 ... 27.05 27.07 27.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U7 56B 'head' 'stinger'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float64 35kB 1.086e+03...
        confidence   (time, individuals, keypoints) float64 17kB 0.05305 ... 0.0
    Attributes:
        fps:              40.0
        time_unit:        seconds
        source_software:  DeepLabCut
        source_file:      /home/runner/.movement/data/poses/DLC_single-wasp.predi...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-wasp_frame-10...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 127-141 .. note:: The ``move`` accessor :meth:`median_filter()\ ` method is a convenience method that applies :func:`movement.filtering.median_filter` to the ``position`` data variable. The equivalent function call using the :mod:`movement.filtering` module would be: .. code-block:: python from movement.filtering import median_filter ds_wasp_smooth.update({"position": median_filter(position, window)}) .. GENERATED FROM PYTHON SOURCE LINES 143-146 We see from the printed report that the dataset has no missing values neither before nor after smoothing. Let's visualise the effects of the median filter in the time and frequency domains. .. GENERATED FROM PYTHON SOURCE LINES 146-151 .. code-block:: Python plot_raw_and_smooth_timeseries_and_psd( ds_wasp, ds_wasp_smooth, keypoint="stinger" ) .. image-sg:: /examples/images/sphx_glr_smooth_001.png :alt: Time Domain, Frequency Domain :srcset: /examples/images/sphx_glr_smooth_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 152-162 We see that the median filter has removed the "spikes" present around the 14 second mark in the raw data. However, it has not dealt the big shift occurring during the final second. In the frequency domain, we can see that the filter has reduced the power in the high-frequency components, without affecting the low frequency components. This illustrates what the median filter is good at: removing brief "spikes" (e.g. a keypoint abruptly jumping to a different location for a frame or two) and high-frequency "jitter" (often present due to pose estimation working on a per-frame basis). .. GENERATED FROM PYTHON SOURCE LINES 164-170 Choosing parameters for the median filter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ We can control the behaviour of the median filter via two parameters: ``window`` and ``min_periods``. To better understand the effect of these parameters, let's use a dataset that contains missing values. .. GENERATED FROM PYTHON SOURCE LINES 170-174 .. code-block:: Python ds_mouse = sample_data.fetch_dataset("SLEAP_single-mouse_EPM.analysis.h5") print(ds_mouse) .. rst-class:: sphx-glr-script-out .. code-block:: none Size: 1MB Dimensions: (time: 18485, individuals: 1, keypoints: 6, space: 2) Coordinates: * time (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1 * individuals (individuals)
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 189-200 The report informs us that the raw data contains NaN values, most of which occur at the ``snout`` and ``tail_end`` keypoints. After filtering, the number of NaNs has increased. This is because the default behaviour of the median filter is to propagate NaN values, i.e. if any value in the rolling window is NaN, the output will also be NaN. To modify this behaviour, you can set the value of the ``min_periods`` parameter to an integer value. This parameter determines the minimum number of non-NaN values required in the window for the output to be non-NaN. For example, setting ``min_periods=2`` means that two non-NaN values in the window are sufficient for the median to be calculated. Let's try this. .. GENERATED FROM PYTHON SOURCE LINES 200-205 .. code-block:: Python ds_mouse_smooth.update( {"position": ds_mouse.move.median_filter(window, min_periods=2)} ) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 snout: 4494/18485 (24.3%) left_ear: 513/18485 (2.8%) right_ear: 533/18485 (2.9%) centre: 490/18485 (2.7%) tail_base: 704/18485 (3.8%) tail_end: 2496/18485 (13.5%) Missing points (marked as NaN) in output Individual: individual_0 snout: 4455/18485 (24.1%) left_ear: 487/18485 (2.6%) right_ear: 507/18485 (2.7%) centre: 465/18485 (2.5%) tail_base: 673/18485 (3.6%) tail_end: 2428/18485 (13.1%) .. raw:: html
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 206-212 We see that this time the number of NaN values has decreased across all keypoints. Let's visualise the effects of the median filter in the time and frequency domains. Here we focus on the first 80 seconds for the ``snout`` keypoint. You can adjust the ``keypoint`` and ``time_range`` arguments to explore other parts of the data. .. GENERATED FROM PYTHON SOURCE LINES 212-217 .. code-block:: Python plot_raw_and_smooth_timeseries_and_psd( ds_mouse, ds_mouse_smooth, keypoint="snout", time_range=slice(0, 80) ) .. image-sg:: /examples/images/sphx_glr_smooth_002.png :alt: Time Domain, Frequency Domain :srcset: /examples/images/sphx_glr_smooth_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 218-222 The smoothing once again reduces the power of high-frequency components, but the resulting time series stays quite close to the raw data. What happens if we increase the ``window`` to 2 seconds (60 frames)? .. GENERATED FROM PYTHON SOURCE LINES 222-228 .. code-block:: Python window = int(2 * ds_mouse.fps) ds_mouse_smooth.update( {"position": ds_mouse.move.median_filter(window, min_periods=2)} ) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 snout: 4494/18485 (24.3%) left_ear: 513/18485 (2.8%) right_ear: 533/18485 (2.9%) centre: 490/18485 (2.7%) tail_base: 704/18485 (3.8%) tail_end: 2496/18485 (13.5%) Missing points (marked as NaN) in output Individual: individual_0 snout: 795/18485 (4.3%) left_ear: 80/18485 (0.4%) right_ear: 80/18485 (0.4%) centre: 80/18485 (0.4%) tail_base: 80/18485 (0.4%) tail_end: 239/18485 (1.3%) .. raw:: html
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 229-234 The number of NaN values has decreased even further. That's because the chance of finding at least 2 valid values within a 2-second window (i.e. 60 frames) is quite high. Let's plot the results for the same keypoint and time range as before. .. GENERATED FROM PYTHON SOURCE LINES 234-238 .. code-block:: Python plot_raw_and_smooth_timeseries_and_psd( ds_mouse, ds_mouse_smooth, keypoint="snout", time_range=slice(0, 80) ) .. image-sg:: /examples/images/sphx_glr_smooth_003.png :alt: Time Domain, Frequency Domain :srcset: /examples/images/sphx_glr_smooth_003.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 239-247 We see that the filtered time series is much smoother and it has even "bridged" over some small gaps. That said, it often deviates from the raw data, in ways that may not be desirable, depending on the application. Here, our choice of ``window`` may be too large. In general, you should choose a ``window`` that is small enough to preserve the original data structure, but large enough to remove "spikes" and high-frequency noise. Always inspect the results to ensure that the filter is not removing important features. .. GENERATED FROM PYTHON SOURCE LINES 249-269 Smoothing with a Savitzky-Golay filter -------------------------------------- Here we use the :meth:`savgol_filter()\ ` method of the ``move`` accessor, which is a convenience method that applies :func:`movement.filtering.savgol_filter` (a wrapper around :func:`scipy.signal.savgol_filter`), to the ``position`` data variable. The Savitzky-Golay filter is a polynomial smoothing filter that can be applied to time series data on a rolling window basis. A polynomial with a degree specified by ``polyorder`` is applied to each data segment defined by the size ``window``. The value of the polynomial at the midpoint of each ``window`` is then used as the output value. Let's try it on the mouse dataset, this time using a 0.2-second window (i.e. 6 frames) and the default ``polyorder=2`` for smoothing. As before, we first compute the corresponding number of observations to be used as the ``window`` size. .. GENERATED FROM PYTHON SOURCE LINES 269-273 .. code-block:: Python window = int(0.2 * ds_mouse.fps) ds_mouse_smooth.update({"position": ds_mouse.move.savgol_filter(window)}) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 snout: 4494/18485 (24.3%) left_ear: 513/18485 (2.8%) right_ear: 533/18485 (2.9%) centre: 490/18485 (2.7%) tail_base: 704/18485 (3.8%) tail_end: 2496/18485 (13.5%) Missing points (marked as NaN) in output Individual: individual_0 snout: 5810/18485 (31.4%) left_ear: 895/18485 (4.8%) right_ear: 905/18485 (4.9%) centre: 839/18485 (4.5%) tail_base: 1186/18485 (6.4%) tail_end: 3801/18485 (20.6%) .. raw:: html
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 274-280 We see that the number of NaN values has increased after filtering. This is for the same reason as with the median filter (in its default mode), i.e. if there is at least one NaN value in the window, the output will be NaN. Unlike the median filter, the Savitzky-Golay filter does not provide a ``min_periods`` parameter to control this behaviour. Let's visualise the effects in the time and frequency domains. .. GENERATED FROM PYTHON SOURCE LINES 280-284 .. code-block:: Python plot_raw_and_smooth_timeseries_and_psd( ds_mouse, ds_mouse_smooth, keypoint="snout", time_range=slice(0, 80) ) .. image-sg:: /examples/images/sphx_glr_smooth_004.png :alt: Time Domain, Frequency Domain :srcset: /examples/images/sphx_glr_smooth_004.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 285-287 Once again, the power of high-frequency components has been reduced, but more missing values have been introduced. .. GENERATED FROM PYTHON SOURCE LINES 289-290 Now let's apply the same Savitzky-Golay filter to the wasp dataset. .. GENERATED FROM PYTHON SOURCE LINES 290-294 .. code-block:: Python window = int(0.2 * ds_wasp.fps) ds_wasp_smooth.update({"position": ds_wasp.move.savgol_filter(window)}) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 head: 0/1085 (0.0%) stinger: 0/1085 (0.0%) Missing points (marked as NaN) in output Individual: individual_0 head: 0/1085 (0.0%) stinger: 0/1085 (0.0%) .. raw:: html
<xarray.Dataset> Size: 61kB
    Dimensions:      (time: 1085, individuals: 1, keypoints: 2, space: 2)
    Coordinates:
      * time         (time) float64 9kB 0.0 0.025 0.05 0.075 ... 27.05 27.07 27.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U7 56B 'head' 'stinger'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float64 35kB 1.086e+03...
        confidence   (time, individuals, keypoints) float64 17kB 0.05305 ... 0.0
    Attributes:
        fps:              40.0
        time_unit:        seconds
        source_software:  DeepLabCut
        source_file:      /home/runner/.movement/data/poses/DLC_single-wasp.predi...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-wasp_frame-10...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 295-298 .. code-block:: Python plot_raw_and_smooth_timeseries_and_psd( ds_wasp, ds_wasp_smooth, keypoint="stinger" ) .. image-sg:: /examples/images/sphx_glr_smooth_005.png :alt: Time Domain, Frequency Domain :srcset: /examples/images/sphx_glr_smooth_005.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 299-307 This example shows two important limitations of the Savitzky-Golay filter. First, the filter can introduce artefacts around sharp boundaries. For example, focus on what happens around the sudden drop in position during the final second. Second, the PSD appears to have large periodic drops at certain frequencies. Both of these effects vary with the choice of ``window`` and ``polyorder``. You can read more about these and other limitations of the Savitzky-Golay filter in `this paper `_. .. GENERATED FROM PYTHON SOURCE LINES 310-319 Combining multiple smoothing filters ------------------------------------ We can also combine multiple smoothing filters by applying them sequentially. For example, we can first apply the median filter with a small ``window`` to remove "spikes" and then apply the Savitzky-Golay filter with a larger ``window`` to further smooth the data. Between the two filters, we can interpolate over small gaps to avoid the excessive proliferation of NaN values. Let's try this on the mouse dataset. First, we will apply the median filter. .. GENERATED FROM PYTHON SOURCE LINES 319-325 .. code-block:: Python window = int(0.1 * ds_mouse.fps) ds_mouse_smooth.update( {"position": ds_mouse.move.median_filter(window, min_periods=2)} ) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 snout: 4494/18485 (24.3%) left_ear: 513/18485 (2.8%) right_ear: 533/18485 (2.9%) centre: 490/18485 (2.7%) tail_base: 704/18485 (3.8%) tail_end: 2496/18485 (13.5%) Missing points (marked as NaN) in output Individual: individual_0 snout: 4455/18485 (24.1%) left_ear: 487/18485 (2.6%) right_ear: 507/18485 (2.7%) centre: 465/18485 (2.5%) tail_base: 673/18485 (3.6%) tail_end: 2428/18485 (13.1%) .. raw:: html
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 326-327 Next, let's linearly interpolate over gaps smaller than 1 second (30 frames). .. GENERATED FROM PYTHON SOURCE LINES 327-332 .. code-block:: Python ds_mouse_smooth.update( {"position": ds_mouse_smooth.move.interpolate_over_time(max_gap=30)} ) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 snout: 4455/18485 (24.1%) left_ear: 487/18485 (2.6%) right_ear: 507/18485 (2.7%) centre: 465/18485 (2.5%) tail_base: 673/18485 (3.6%) tail_end: 2428/18485 (13.1%) Missing points (marked as NaN) in output Individual: individual_0 snout: 3011/18485 (16.3%) left_ear: 257/18485 (1.4%) right_ear: 294/18485 (1.6%) centre: 257/18485 (1.4%) tail_base: 257/18485 (1.4%) tail_end: 1101/18485 (6.0%) .. raw:: html
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 333-335 Finally, let's apply the Savitzky-Golay filter over a 0.4-second window (12 frames). .. GENERATED FROM PYTHON SOURCE LINES 335-341 .. code-block:: Python window = int(0.4 * ds_mouse.fps) ds_mouse_smooth.update( {"position": ds_mouse_smooth.move.savgol_filter(window)} ) .. rst-class:: sphx-glr-script-out .. code-block:: none Missing points (marked as NaN) in input Individual: individual_0 snout: 3011/18485 (16.3%) left_ear: 257/18485 (1.4%) right_ear: 294/18485 (1.6%) centre: 257/18485 (1.4%) tail_base: 257/18485 (1.4%) tail_end: 1101/18485 (6.0%) Missing points (marked as NaN) in output Individual: individual_0 snout: 3520/18485 (19.0%) left_ear: 306/18485 (1.7%) right_ear: 354/18485 (1.9%) centre: 306/18485 (1.7%) tail_base: 306/18485 (1.7%) tail_end: 1304/18485 (7.1%) .. raw:: html
<xarray.Dataset> Size: 1MB
    Dimensions:      (time: 18485, individuals: 1, keypoints: 6, space: 2)
    Coordinates:
      * time         (time) float64 148kB 0.0 0.03333 0.06667 ... 616.1 616.1 616.1
      * individuals  (individuals) <U12 48B 'individual_0'
      * keypoints    (keypoints) <U9 216B 'snout' 'left_ear' ... 'tail_end'
      * space        (space) <U1 8B 'x' 'y'
    Data variables:
        position     (time, individuals, keypoints, space) float32 887kB nan ... ...
        confidence   (time, individuals, keypoints) float32 444kB nan nan ... 0.7607
    Attributes:
        fps:              30.0
        time_unit:        seconds
        source_software:  SLEAP
        source_file:      /home/runner/.movement/data/poses/SLEAP_single-mouse_EP...
        ds_type:          poses
        frame_path:       /home/runner/.movement/data/frames/single-mouse_EPM_fra...
        video_path:       None


.. GENERATED FROM PYTHON SOURCE LINES 342-345 A record of all applied operations is stored in the ``log`` attribute of the ``ds_mouse_smooth.position`` data array. Let's inspect it to summarise what we've done. .. GENERATED FROM PYTHON SOURCE LINES 345-349 .. code-block:: Python for entry in ds_mouse_smooth.position.log: print(entry) .. rst-class:: sphx-glr-script-out .. code-block:: none {'operation': 'median_filter', 'datetime': '2024-09-06 12:30:59.785008', 'arg_1': 3, 'min_periods': 2} {'operation': 'interpolate_over_time', 'datetime': '2024-09-06 12:30:59.828414', 'max_gap': 30} {'operation': 'savgol_filter', 'datetime': '2024-09-06 12:30:59.850284', 'arg_1': 12} .. GENERATED FROM PYTHON SOURCE LINES 350-352 Now let's visualise the difference between the raw data and the final smoothed result. .. GENERATED FROM PYTHON SOURCE LINES 352-360 .. code-block:: Python plot_raw_and_smooth_timeseries_and_psd( ds_mouse, ds_mouse_smooth, keypoint="snout", time_range=slice(0, 80), ) .. image-sg:: /examples/images/sphx_glr_smooth_006.png :alt: Time Domain, Frequency Domain :srcset: /examples/images/sphx_glr_smooth_006.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 361-363 Feel free to play around with the parameters of the applied filters and to also look at other keypoints and time ranges. .. GENERATED FROM PYTHON SOURCE LINES 365-369 .. seealso:: :ref:`examples/filter_and_interpolate:Filtering multiple data variables` in the :ref:`sphx_glr_examples_filter_and_interpolate.py` example. .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.767 seconds) .. _sphx_glr_download_examples_smooth.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: binder-badge .. image:: images/binder_badge_logo.svg :target: https://mybinder.org/v2/gh/neuroinformatics-unit/movement/gh-pages?filepath=notebooks/examples/smooth.ipynb :alt: Launch binder :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: smooth.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: smooth.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: smooth.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_