.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/06-movie_metrics.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. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_06-movie_metrics.py: Movie properties over time ========================== This example demonstrates how to extract and inspect frame-level movie properties over time during movie processing: 1. Enable frame-level movie metrics calculation in :func:`massphoto.fit`. 2. Access the per-frame metric time-series from ``events.attrs["frame_metrics"]``. 3. Annotate detected events with their local frame properties using :func:`massphoto.events.annotate_frame_metrics`. 4. Plot the time-series of raw intensity, sharpness, ratiometric signal, and drift speed. 5. Use frame metrics to identify unstable movie segments and filter events. .. GENERATED FROM PYTHON SOURCE LINES 17-19 Imports and Setup ----------------- .. GENERATED FROM PYTHON SOURCE LINES 19-37 .. code-block:: Python import matplotlib.pyplot as plt from zenodozipdownloader import ZenodoZipDownloader import massphoto as mp # Download example movie from Zenodo files = ZenodoZipDownloader( doi="10.5281/zenodo.15800729", download_dir="example_data", ).download("Figure 2.zip/006_dynamin_6.mp") if not files: raise RuntimeError( "Failed to download example data. Please download it manually from https://zenodo.org/record/15800729 " "or set path_movie to your own movie." ) path_movie = files[0] .. GENERATED FROM PYTHON SOURCE LINES 38-48 Process Movie with Movie Metrics -------------------------------- When ``compute_movie_metrics=True`` is passed to :func:`massphoto.fit`, massphoto calculates frame-level summary metrics alongside candidate detection: - ``intensity``: mean raw camera counts per frame (detects illumination fluctuations or laser drift). - ``sharpness``: relative standard deviation of the raw frame after median-filter background subtraction (detects focus drift or dirt). - ``signal``: standard deviation of the ratiometric frame (noise floor and crowding). - ``drift_speed``: frame-to-frame displacement speed in pixels/frame (when drift correction is enabled). .. GENERATED FROM PYTHON SOURCE LINES 48-63 .. code-block:: Python mp.defaults.set("progress_bar", False) mp.defaults.set("mass_calibration", (-5.2, 3.1e4)) fitres = mp.fit( path_movie, compute_movie_metrics=True, movie_correct_drift=True, ) # The full frame-level time-series is stored in the DataFrame's attrs. Note that the DataFrame's attrs can get lost on copying or slicing. Therefore, it makes sense to make a copy when the metrics are required. frame_metrics = fitres.attrs["frame_metrics"] frame_metrics.head() .. raw:: html
intensity sharpness signal drift_y drift_x drift_speed
frame
0 50319.468750 0.067943 NaN 0.088829 0.154645 0.000000
1 50319.156250 0.067933 NaN 0.089695 0.154840 0.000888
2 50319.722656 0.067940 NaN 0.089387 0.154368 0.000564
3 50317.429688 0.067943 NaN 0.088567 0.153452 0.001229
4 50316.531250 0.067924 NaN 0.089755 0.153752 0.001225


.. GENERATED FROM PYTHON SOURCE LINES 64-70 Annotate Events with Frame Metrics ---------------------------------- :func:`massphoto.events.annotate_frame_metrics` maps the per-frame metrics from ``fitres.attrs["frame_metrics"]`` onto each detected event based on its ``frame`` index: .. GENERATED FROM PYTHON SOURCE LINES 70-74 .. code-block:: Python fitres = mp.annotate_frame_metrics(fitres) fitres[["frame", "x", "y", "masses_kDa", "intensity", "sharpness", "signal", "drift_speed"]].head() .. raw:: html
frame x y masses_kDa intensity sharpness signal drift_speed
0 20 85.941323 6.727391 96.739078 50317.410156 0.067948 0.000759 0.000469
1 20 194.049701 70.878965 169.846151 50317.410156 0.067948 0.000759 0.000469
2 20 164.925642 72.253984 185.299948 50317.410156 0.067948 0.000759 0.000469
3 20 205.242135 74.105405 194.872501 50317.410156 0.067948 0.000759 0.000469
4 20 124.881893 80.847654 179.689714 50317.410156 0.067948 0.000759 0.000469


.. GENERATED FROM PYTHON SOURCE LINES 75-82 Inspect Frame Properties Over Time ----------------------------------- We visualize how illumination intensity, sharpness, ratiometric noise floor (signal), and drift speed evolve across the acquisition. An upper threshold of :math:`\mu + 3\sigma` on the ratiometric signal is marked as a dashed line to flag frames affected by transient noise or crowding spikes. .. GENERATED FROM PYTHON SOURCE LINES 82-109 .. code-block:: Python signal_limit = frame_metrics["signal"].mean() + 3 * frame_metrics["signal"].std() fig, axes = plt.subplots(4, 1, figsize=(8, 8), sharex=True) axes[0].plot(frame_metrics.index, frame_metrics["intensity"], color="tab:blue") axes[0].set_ylabel("Intensity\n(counts)") axes[0].grid(True, linestyle="--", alpha=0.4) axes[1].plot(frame_metrics.index, frame_metrics["sharpness"], color="tab:orange") axes[1].set_ylabel("Sharpness\n(rel. std)") axes[1].grid(True, linestyle="--", alpha=0.4) axes[2].plot(frame_metrics.index, frame_metrics["signal"], color="tab:green") axes[2].axhline(signal_limit, color="black", linestyle="--", lw=1, label=r"Mean + 3$\sigma$") axes[2].set_ylabel("Signal\n(ratiometric std)") axes[2].legend(frameon=False, loc="upper right") axes[2].grid(True, linestyle="--", alpha=0.4) axes[3].plot(frame_metrics.index, frame_metrics["drift_speed"], color="tab:red") axes[3].set_ylabel("Drift Speed\n(px/frame)") axes[3].set_xlabel("Frame number") axes[3].grid(True, linestyle="--", alpha=0.4) plt.tight_layout() plt.show() .. image-sg:: /auto_examples/images/sphx_glr_06-movie_metrics_001.png :alt: 06 movie metrics :srcset: /auto_examples/images/sphx_glr_06-movie_metrics_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 110-115 Filter Events Using Frame Metrics --------------------------------- Using the annotated ``signal`` column, we can exclude events recorded during frames where the ratiometric signal exceeds :math:`3\sigma` above the mean: .. GENERATED FROM PYTHON SOURCE LINES 115-118 .. code-block:: Python fitres_filtered = fitres[fitres["signal"] <= signal_limit] print(f"Retained {len(fitres_filtered)} of {len(fitres)} events (signal <= {signal_limit:.5f})") .. rst-class:: sphx-glr-script-out .. code-block:: none Retained 14445 of 14629 events (signal <= 0.00111) .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 33.952 seconds) .. _sphx_glr_download_auto_examples_06-movie_metrics.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: 06-movie_metrics.ipynb <06-movie_metrics.ipynb>` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: 06-movie_metrics.py <06-movie_metrics.py>` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: 06-movie_metrics.zip <06-movie_metrics.zip>` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_