changeset 3:4d7f30a7e2f6 draft

"planemo upload commit d070f1ba04a5141a65487f45b29c22767639e44b"
author gregor.m
date Tue, 24 Nov 2020 13:06:26 +0000
parents c59d1373230e
children a4c6fcf2c456
files OutputReport.html SpyBOAT.xml __pycache__/output_report.cpython-38.pyc __pycache__/output_report.cpython-39.pyc amplitude_frame0.png amplitude_frame16.png amplitude_frame18.png amplitude_frame2.png amplitude_frame20.png amplitude_frame32.png amplitude_frame34.png amplitude_frame40.png amplitude_frame48.png amplitude_frame50.png amplitude_frame60.png amplitude_frame64.png amplitude_frame66.png amplitude_frame80.png amplitude_frame82.png amplitude_frame96.png amplitude_twosines_out.tif cl_wrapper.py input_frame0.png input_frame16.png input_frame18.png input_frame2.png input_frame20.png input_frame32.png input_frame34.png input_frame40.png input_frame48.png input_frame50.png input_frame60.png input_frame64.png input_frame66.png input_frame80.png input_frame82.png input_frame96.png output_report.py period_distr.png period_frame0.png period_frame16.png period_frame18.png period_frame2.png period_frame20.png period_frame32.png period_frame34.png period_frame40.png period_frame48.png period_frame50.png period_frame60.png period_frame64.png period_frame66.png period_frame80.png period_frame82.png period_frame96.png period_twosines_out.tif phase_distr.png phase_frame0.png phase_frame16.png phase_frame18.png phase_frame2.png phase_frame20.png phase_frame32.png phase_frame34.png phase_frame40.png phase_frame48.png phase_frame50.png phase_frame60.png phase_frame64.png phase_frame66.png phase_frame80.png phase_frame82.png phase_frame96.png phase_twosines_out.tif power_distr.png power_twosines_out.tif preproc_two_sines.tif run_tests.sh spyboat_cli.py
diffstat 80 files changed, 546 insertions(+), 236 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OutputReport.html	Tue Nov 24 13:06:26 2020 +0000
@@ -0,0 +1,247 @@
+
+    <html>
+    <title>SpyBOAT Output Report</title>
+    <head>
+        <!-- that doesn't work with galaxy.. -->
+        <!--link rel="stylesheet" href="styles.css"-->
+      <style type="text/css">
+        body{ margin:10 100; background:whitesmoke; }
+        /*body{ margin:10 100; background:darkslategrey; }*/
+        .center{
+            text-align: center;
+            display: block;
+            margin-left: auto;
+            margin-right: auto;
+            width: 100%;}
+
+        /* matplotlib output at 1600x1200  */
+        .distr_gallery {
+            display: grid;
+            margin: 0 auto;
+            text-align: center;
+            /* border: 1px dashed rgba(4, 4, 4, 0.35);     */
+            grid-template-columns: repeat(3,1fr);
+            grid-template-rows: 20vw;    
+            grid-gap: 0px;
+            column-gap: 0px
+        }
+        .distr_gallery__img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+        }
+
+
+        /* matplotlib output at 1600x1200  */
+        .snapshot_gallery {
+            display: grid;
+            margin: 0 auto;
+            border: 1px dashed rgba(4, 4, 4, 0.35);
+            text-align: center;
+            grid-template-columns: repeat(2,1fr);
+            grid-template-rows: repeat(2,20vw);
+            grid-gap: 5px;
+        }
+        .snapshot_gallery__img {
+            width: 100%;
+            height: 100%;
+            object-fit: contain;
+        }
+        .subheader{
+             text-align:center;
+             font-size: 160%;
+             color:#363333;}
+     </style>
+    </head>
+    <body>
+    <h1 style="text-align:center; color:#363333">SpyBOAT Results Report</h1>
+    <hr style="width:50%"> 
+    <h1 class="subheader"> Distribution Dynamics </h1>
+    <div class="distr_gallery">
+       <figure class=”distr_gallery__item distr_gallery__item--1">
+         <img src="period_distr.png" alt="Period" class="distr_gallery__img">
+       </figure>
+
+       <figure class=”distr_gallery__item distr_gallery__item--2">
+         <img src="power_distr.png" alt="Power" class="distr_gallery__img">
+       </figure>
+
+       <figure class=”distr_gallery__item distr_gallery__item--3">
+         <img src="phase_distr.png" alt="Phase" class="distr_gallery__img">
+       </figure>
+
+    </div>
+
+    <h1 class="subheader"> Output Movie Snapshots </h1>
+
+    <!-- trigger the javascript at the end--->
+    <div class="center">
+        <button class="w3-button" onclick="plusDivs(-1)">&#10094; Prev</button>
+        <button class="w3-button" onclick="plusDivs(1)">Next &#10095;</button>
+    </div>
+
+    <!-- defines all elements of the "FrameSlides" class --->
+    
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. 2 </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame2.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame2.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame2.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame2.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. 18 </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame18.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame18.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame18.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame18.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. 34 </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame34.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame34.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame34.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame34.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. 50 </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame50.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame50.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame50.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame50.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. 66 </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame66.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame66.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame66.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame66.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. 82 </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame82.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame82.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame82.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame82.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        
+    </div>
+
+    <!-- javascript with escaped '{'--->
+    <script>
+        var slideIndex = 1;
+        showDivs(slideIndex);
+
+        function plusDivs(n) {
+          showDivs(slideIndex += n);
+        }
+
+        function showDivs(n) {
+          var i;
+          var x = document.getElementsByClassName("FrameSlides");
+          if (n > x.length) {slideIndex = 1}
+          if (n < 1) {slideIndex = x.length} ;
+          for (i = 0; i < x.length; i++) {
+            x[i].style.display = "none";
+          }
+          x[slideIndex-1].style.display = "block";
+        }
+    </script>
+    </body>
+    </html>
+    
\ No newline at end of file
--- a/SpyBOAT.xml	Mon Nov 23 14:38:37 2020 +0000
+++ b/SpyBOAT.xml	Tue Nov 24 13:06:26 2020 +0000
@@ -1,10 +1,10 @@
-<tool id="SpyBOAT" name="SpyBOAT" version="0.0.2">
+<tool id="SpyBOAT" name="SpyBOAT" version="0.1.0">
     <requirements>
-        <requirement type="package" version="0.0.4">spyboat</requirement>
+        <requirement type="package" version="0.1.0">spyboat</requirement>
     </requirements>
-    <version_command>python $__tool_directory__/cl_wrapper.py --version</version_command>
+    <version_command>python $__tool_directory__/spyboat_cli.py --version</version_command>
     <command detect_errors="exit_code"><![CDATA[
-        python $__tool_directory__/cl_wrapper.py
+        python $__tool_directory__/spyboat_cli.py
           --input_path '$movie'
           #if $gauss_sigma:
              --gauss_sigma $gauss_sigma
@@ -13,8 +13,8 @@
               --rescale $rescale_factor
           #end if
 
-          #if $masking.selection_mode == "create_fixed_mask":
-	  --masking fixed
+          #if $masking.selection_mode == "create_static_mask":
+	  --masking static
           --mask_frame $masking.mask_frame
           --mask_thresh $masking.mask_thresh
           #else if $masking.selection_mode == "create_dynamic_mask":
@@ -54,7 +54,7 @@
 
         <!--
         The following Wavelet parameters must have the same numerical type as defined in the
-        argparse parser in cl_wrapper.py
+        argparse parser in spyboat_cli.py
         -->
 
         <param name="gauss_sigma" type="float" label="Sigma" 
@@ -71,12 +71,12 @@
         <conditional name="masking">
             <param label="Masking the output" name="selection_mode" type="select" help="Create a mask from the (blurred/rescaled) input to mask out regions without oscillations/signal in the output">
                 <option selected="true" value="no_masking">No masking</option>
-                <option value="create_fixed_mask">Create a fixed mask</option>
+                <option value="create_static_mask">Create a static mask</option>
 		<option value="create_dynamic_mask">Create a dynamic mask</option>
 	    </param>
-            <when value="create_fixed_mask">
+            <when value="create_static_mask">
                 <param name="mask_frame" type="integer" value="1" label="Create mask from frame"
-                       help="Creates a fixed mask from the chosen frame of the input movie.">
+                       help="Creates a static mask from the chosen frame of the input movie.">
                     <validator type="in_range" min="1" max="99999"/>
                 </param>
                 <param name="mask_thresh" type="float" value="0" label="Threshold"
@@ -154,7 +154,7 @@
     <help><![CDATA[
     **What it does**
 
-    Wavelet transforms a 3d-image stack (time,Y,X) pixel by pixel and extracts/evaluates the wavelet ridge. Removal of low-frequency trends is provided via sinc filtering. 
+    Wavelet transforms a 3d-image stack (time,Y,X) pixel by pixel along the time axis and extracts/evaluates the wavelet ridge. Removal of low-frequency trends is provided via sinc filtering. 
     There are four output movies generated (phase, period, amplitude and power). They have exactly the same dimensions (time,Y,X) as the (rescaled) input.
 
     Pre-smoothing of the data with Gaussian kernels is supported and often recommendable.
@@ -185,6 +185,8 @@
         Given in %, downsamples the spatial resolution of the input movie. This speeds
         up the whole analysis by a lot.
 
+    - Masking:
+       SpyBOAT offers 'static' and 'dynamic' masking. 'static' means that a single mask is created by thresholding from a user selected frame. 'dynamic' creates a mask for each frame by thresholding, works better for moving/expanding/shrinking oscillatory fields. 
     - Sampling interval:
 
         Time passed between consecutive measurements, e.g 'an image every 10 minutes'.
Binary file __pycache__/output_report.cpython-38.pyc has changed
Binary file __pycache__/output_report.cpython-39.pyc has changed
Binary file amplitude_frame0.png has changed
Binary file amplitude_frame16.png has changed
Binary file amplitude_frame18.png has changed
Binary file amplitude_frame2.png has changed
Binary file amplitude_frame20.png has changed
Binary file amplitude_frame32.png has changed
Binary file amplitude_frame34.png has changed
Binary file amplitude_frame40.png has changed
Binary file amplitude_frame48.png has changed
Binary file amplitude_frame50.png has changed
Binary file amplitude_frame60.png has changed
Binary file amplitude_frame64.png has changed
Binary file amplitude_frame66.png has changed
Binary file amplitude_frame80.png has changed
Binary file amplitude_frame82.png has changed
Binary file amplitude_frame96.png has changed
Binary file amplitude_twosines_out.tif has changed
--- a/cl_wrapper.py	Mon Nov 23 14:38:37 2020 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,196 +0,0 @@
-#!/usr/bin/env python
-
-## Gets interfaced by Galaxy or bash scripting
-import argparse
-import sys, os
-import logging
-
-from skimage import io
-from numpy import float32
-
-import spyboat
-import output_report
-
-logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
-logger = logging.getLogger('wrapper')
-
-# ----------command line parameters ---------------
-
-parser = argparse.ArgumentParser(description='Process some arguments.')
-
-# I/O
-parser.add_argument('--input_path', help="Input movie location", required=True)
-parser.add_argument('--phase_out', help='Phase output file name', required=True)
-parser.add_argument('--period_out', help='Period output file name', required=True)
-parser.add_argument('--power_out', help='Power output file name', required=True)
-parser.add_argument('--amplitude_out', help='Amplitude output file name', required=True)
-parser.add_argument('--preprocessed_out', help="Preprocessed-input output file name, 'None'", required=False)
-
-
-# (Optional) Multiprocessing
-
-parser.add_argument('--ncpu', help='Number of processors to use',
-                    required=False, type=int, default=1)
-
-# Optional spatial downsampling
-parser.add_argument('--rescale', help='Rescale the image by a factor given in %%, None means no rescaling',
-                    required=False, type=int)
-# Optional Gaussian smoothing
-parser.add_argument('--gauss_sigma', help='Gaussian smoothing parameter, None means no smoothing', required=False, type=float)
-
-# Wavelet Analysis Parameters
-parser.add_argument('--dt', help='Sampling interval', required=True, type=float)
-parser.add_argument('--Tmin', help='Smallest period', required=True, type=float)
-parser.add_argument('--Tmax', help='Biggest period', required=True, type=float)
-parser.add_argument('--nT', help='Number of periods to scan for', required=True, type=int)
-
-parser.add_argument('--Tcutoff', help='Sinc cut-off period, disables detrending if not set', required=False, type=float)
-parser.add_argument('--win_size', help='Sliding window size for amplitude normalization, None means no normalization',
-                    required=False, type=float)
-
-# Optional masking
-parser.add_argument('--masking', help="Set to either 'dynamic', 'fixed' or 'None' which is the default", default='None', required=False, type=str)
-
-parser.add_argument('--mask_frame',
-                    help="The frame of the input movie to create a fixed mask from, needs masking set to 'fixed'",
-                    required=False, type=int)
-
-
-parser.add_argument('--mask_thresh', help='The threshold of the mask, all pixels with less than this value get masked (if masking enabled).',
-                    required=False, type=float,
-                    default=0)
-
-# output overview/snapshots
-parser.add_argument('--html_fname', help="Name of the html report.",
-                    default='OutputReport.html', required=False, type=str)
-
-parser.add_argument('--report_img_path', help="For the html report, can be set in Galaxy. Defaults to cwd.", default='.', required=False, type=str)
-
-parser.add_argument('--version', action='version', version='0.0.1')
-
-arguments = parser.parse_args()
-
-logger.info("Received following arguments:")
-for arg in vars(arguments):
-    logger.info(f'{arg} -> {getattr(arguments, arg)}')
-
-# ------------Read the input----------------------------------------
-try:
-    movie = spyboat.open_tif(arguments.input_path)
-except FileNotFoundError:
-    logger.critical(f"Couldn't open {arguments.input_path}, check movie storage directory!")
-
-    sys.exit(1)
-
-# -------- Do (optional) spatial downsampling ---------------------------
-
-scale_factor = arguments.rescale
-
-# defaults to None
-if not scale_factor:
-    logger.info('No downsampling requested..')
-
-elif 0 < scale_factor < 100:
-    logger.info(f'Downsampling the movie to {scale_factor:d}% of its original size..')
-    movie = spyboat.down_sample(movie, scale_factor / 100)
-else:
-    raise ValueError('Scale factor must be between 0 and 100!')
-
-# -------- Do (optional) pre-smoothing -------------------------
-# note that downsampling already is a smoothing operation..
-
-# check if pre-smoothing requested
-if not arguments.gauss_sigma:
-    logger.info('No pre-smoothing requested..')
-else:
-    logger.info(f'Pre-smoothing the movie with Gaussians, sigma = {arguments.gauss_sigma:.2f}..')
-
-    movie = spyboat.gaussian_blur(movie, arguments.gauss_sigma)
-
-# ----- Set up Masking before processing ----
-
-mask = None
-if arguments.masking == 'fixed':
-    if not arguments.mask_frame:
-        logger.critical("Frame number for fixed masking is missing!")
-        sys.exit(1)
-
-    if (arguments.mask_frame > movie.shape[0]) or (arguments.mask_frame < 0):
-        logger.critical(f'Requested frame does not exist, input only has {movie.shape[0]} frames.. exiting')
-        sys.exit(1)
-
-    else:
-        logger.info(f'Creating fixed mask from frame {arguments.mask_frame} with threshold {arguments.mask_thresh}')  
-        mask = spyboat.create_fixed_mask(movie, arguments.mask_frame,
-                                         arguments.mask_thresh)
-elif arguments.masking == 'dynamic':
-    logger.info(f'Creating dynamic mask with threshold {arguments.mask_thresh}')
-    mask = spyboat.create_dynamic_mask(movie, arguments.mask_thresh)
-        
-else:
-    logger.info('No masking requested..')
-
-# ------ Retrieve  wavelet parameters ---------------------------
-
-Wkwargs = {'dt': arguments.dt,
-           'Tmin': arguments.Tmin,
-           'Tmax': arguments.Tmax,           
-           'nT': arguments.nT,
-           'T_c' : arguments.Tcutoff, # defaults to None
-           'win_size' : arguments.win_size # defaults to None          
-}
-
-# start parallel processing
-results = spyboat.run_parallel(movie, arguments.ncpu, **Wkwargs)
-
-# --- masking? ---
-
-if mask is not None:
-    # mask all output movies (in place!)
-    for key in results:
-        logger.info(f'Masking {key}')
-        spyboat.apply_mask(results[key], mask, fill_value=-1)
-
-# --- Produce Output Report Figures/png's ---
-
-# create the directory, yes we have to do that ourselves :)
-# galaxy then magically renders the  html from that
-try:
-
-    if arguments.report_img_path != '.':
-        logger.info(f'Creating report directory {arguments.report_img_path}')
-        os.mkdir(arguments.report_img_path)    
-
-    # jump to the middle of the movie
-    snapshot_frame = int(movie.shape[0]/2)
-    output_report.produce_snapshots(movie, results, snapshot_frame, Wkwargs, img_path=arguments.report_img_path)
-    
-    output_report.produce_distr_plots(results, Wkwargs, img_path=arguments.report_img_path)
-    
-    output_report.create_html(snapshot_frame, arguments.html_fname)
-                          
-    
-except FileExistsError as e:
-    logger.critical(f"Could not create html report directory: {repr(e)}")
-
-
-# --- save out result movies ---
-
-# save phase movie
-io.imsave(arguments.phase_out, results['phase'], plugin="tifffile")
-logger.info(f'Written {arguments.phase_out}')
-# save period movie
-io.imsave(arguments.period_out, results['period'], plugin="tifffile")
-logger.info(f'Written {arguments.period_out}')
-# save power movie
-io.imsave(arguments.power_out, results['power'], plugin="tifffile")
-logger.info(f'Written {arguments.power_out}')
-# save amplitude movie
-io.imsave(arguments.amplitude_out, results['amplitude'], plugin="tifffile")
-logger.info(f'Written {arguments.amplitude_out}')
-
-# save out the probably pre-processed (scaled and blurred) input movie for
-# direct comparison to results and coordinate mapping etc.
-if arguments.preprocessed_out:
-    io.imsave(arguments.preprocessed_out, movie, plugin='tifffile')
-    logger.info(f'Written {arguments.preprocessed_out}')
Binary file input_frame0.png has changed
Binary file input_frame16.png has changed
Binary file input_frame18.png has changed
Binary file input_frame2.png has changed
Binary file input_frame20.png has changed
Binary file input_frame32.png has changed
Binary file input_frame34.png has changed
Binary file input_frame40.png has changed
Binary file input_frame48.png has changed
Binary file input_frame50.png has changed
Binary file input_frame60.png has changed
Binary file input_frame64.png has changed
Binary file input_frame66.png has changed
Binary file input_frame80.png has changed
Binary file input_frame82.png has changed
Binary file input_frame96.png has changed
--- a/output_report.py	Mon Nov 23 14:38:37 2020 +0000
+++ b/output_report.py	Tue Nov 24 13:06:26 2020 +0000
@@ -39,11 +39,13 @@
     fig = ppl.gcf()
     out_path = os.path.join(img_path, f'input_frame{frame}.png')
     fig.savefig(out_path, dpi=DPI)
+    ppl.close(fig)
     
     spyplot.phase_snapshot(results['phase'][frame])
     fig = ppl.gcf()
     out_path = os.path.join(img_path, f'phase_frame{frame}.png')    
     fig.savefig(out_path, dpi=DPI)
+    ppl.close(fig)
 
     spyplot.period_snapshot(results['period'][frame],
                             Wkwargs,
@@ -52,13 +54,14 @@
     fig = ppl.gcf()
     out_path = os.path.join(img_path, f'period_frame{frame}.png')    
     fig.savefig(out_path, dpi=DPI)
+    ppl.close(fig)
     
     spyplot.amplitude_snapshot(results['amplitude'][frame])
     fig = ppl.gcf()
     out_path = os.path.join(img_path, f'amplitude_frame{frame}.png')    
     fig.savefig(out_path, dpi=DPI)
+    ppl.close(fig)
         
-
     logger.info(f'Produced 4 snapshots for frame {frame}..')
 
 def produce_distr_plots(results, Wkwargs, img_path='.'):
@@ -87,14 +90,44 @@
     logger.info(f'Produced 3 distribution plots..')
 
     
-def create_html(frame_num, html_fname='OutputReport.html'):
+def create_html(frame_nums, html_fname='OutputReport.html'):
 
     '''
-    The html generated assumes the respective png's (7 in total)
+    The html generated assumes the respective png's 
     have been created with 'produce_snapshots' and 'produce_distr_plots'
     and can be found at the cwd (that's how Galaxy works..)
     '''
 
+    # -- create a gallery for every frame in frame_nums --
+    
+    galleries = ''
+    for frame_num in frame_nums:
+        new_gal =f'''
+        <div class="FrameSlides"> 
+        <h3 style="text-align:center; color=#363333"> Frame Nr. {frame_num} </h3>
+
+            <div class="snapshot_gallery">
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
+                 <img src="input_frame{frame_num}.png" alt="The Input" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
+                 <img src="phase_frame{frame_num}.png" alt="Phase" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
+                 <img src="period_frame{frame_num}.png" alt="Period" class="snapshot_gallery__img">
+               </figure>
+
+               <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
+                 <img src="amplitude_frame{frame_num}.png" alt="Amplitude" class="snapshot_gallery__img">
+               </figure>
+            </div>
+        </div>
+        '''
+        galleries += new_gal
+    
     html_string =f'''
     <html>
     <title>SpyBOAT Output Report</title>
@@ -105,10 +138,11 @@
         body{{ margin:10 100; background:whitesmoke; }}
         /*body{{ margin:10 100; background:darkslategrey; }}*/
         .center{{
+            text-align: center;
             display: block;
             margin-left: auto;
             margin-right: auto;
-            width: 40%;}}
+            width: 100%;}}
 
         /* matplotlib output at 1600x1200  */
         .distr_gallery {{
@@ -117,7 +151,7 @@
             text-align: center;
             /* border: 1px dashed rgba(4, 4, 4, 0.35);     */
             grid-template-columns: repeat(3,1fr);
-            grid-template-rows: 25vw;    
+            grid-template-rows: 20vw;    
             grid-gap: 0px;
             column-gap: 0px
         }}
@@ -143,11 +177,16 @@
             height: 100%;
             object-fit: contain;
         }}
+        .subheader{{
+             text-align:center;
+             font-size: 160%;
+             color:#363333;}}
      </style>
     </head>
     <body>
-    <h1 style="text-align:center">SpyBOAT Results Report</h1>
+    <h1 style="text-align:center; color:#363333">SpyBOAT Results Report</h1>
     <hr style="width:50%"> 
+    <h1 class="subheader"> Distribution Dynamics </h1>
     <div class="distr_gallery">
        <figure class=”distr_gallery__item distr_gallery__item--1">
          <img src="period_distr.png" alt="Period" class="distr_gallery__img">
@@ -163,27 +202,38 @@
 
     </div>
 
-    <h2 style="text-align:center"> Snapshots - Frame {frame_num}</h2>
-    <div class="snapshot_gallery">
-       <figure class=”snapshot_gallery__item snapshot_gallery__item--1">
-         <img src="input_frame{frame_num}.png" alt="The Input" class="snapshot_gallery__img">
-       </figure>
+    <h1 class="subheader"> Output Movie Snapshots </h1>
 
-       <figure class=”snapshot_gallery__item snapshot_gallery__item--2">
-         <img src="phase_frame{frame_num}.png" alt="Phase" class="snapshot_gallery__img">
-       </figure>
+    <!-- trigger the javascript at the end--->
+    <div class="center">
+        <button class="w3-button" onclick="plusDivs(-1)">&#10094; Prev</button>
+        <button class="w3-button" onclick="plusDivs(1)">Next &#10095;</button>
+    </div>
+
+    <!-- defines all elements of the "FrameSlides" class --->
+    {galleries}
+    </div>
 
-       <figure class=”snapshot_gallery__item snapshot_gallery__item--3">
-         <img src="period_frame{frame_num}.png" alt="Period" class="snapshot_gallery__img">
-       </figure>
+    <!-- javascript with escaped '{{'--->
+    <script>
+        var slideIndex = 1;
+        showDivs(slideIndex);
+
+        function plusDivs(n) {{
+          showDivs(slideIndex += n);
+        }}
 
-       <figure class=”snapshot_gallery__item snapshot_gallery__item--4">
-         <img src="amplitude_frame{frame_num}.png" alt="Amplitude" class="snapshot_gallery__img">
-       </figure>
-    </div>
-    
-
-        <!-- *** Section 1 *** --->
+        function showDivs(n) {{
+          var i;
+          var x = document.getElementsByClassName("FrameSlides");
+          if (n > x.length) {{slideIndex = 1}}
+          if (n < 1) {{slideIndex = x.length}} ;
+          for (i = 0; i < x.length; i++) {{
+            x[i].style.display = "none";
+          }}
+          x[slideIndex-1].style.display = "block";
+        }}
+    </script>
     </body>
     </html>
     '''
@@ -196,4 +246,4 @@
     return html_string
 
 # for local testing
-# create_html(125)
+# create_html([0,20,40,60,80])
Binary file period_distr.png has changed
Binary file period_frame0.png has changed
Binary file period_frame16.png has changed
Binary file period_frame18.png has changed
Binary file period_frame2.png has changed
Binary file period_frame20.png has changed
Binary file period_frame32.png has changed
Binary file period_frame34.png has changed
Binary file period_frame40.png has changed
Binary file period_frame48.png has changed
Binary file period_frame50.png has changed
Binary file period_frame60.png has changed
Binary file period_frame64.png has changed
Binary file period_frame66.png has changed
Binary file period_frame80.png has changed
Binary file period_frame82.png has changed
Binary file period_frame96.png has changed
Binary file period_twosines_out.tif has changed
Binary file phase_distr.png has changed
Binary file phase_frame0.png has changed
Binary file phase_frame16.png has changed
Binary file phase_frame18.png has changed
Binary file phase_frame2.png has changed
Binary file phase_frame20.png has changed
Binary file phase_frame32.png has changed
Binary file phase_frame34.png has changed
Binary file phase_frame40.png has changed
Binary file phase_frame48.png has changed
Binary file phase_frame50.png has changed
Binary file phase_frame60.png has changed
Binary file phase_frame64.png has changed
Binary file phase_frame66.png has changed
Binary file phase_frame80.png has changed
Binary file phase_frame82.png has changed
Binary file phase_frame96.png has changed
Binary file phase_twosines_out.tif has changed
Binary file power_distr.png has changed
Binary file power_twosines_out.tif has changed
Binary file preproc_two_sines.tif has changed
--- a/run_tests.sh	Mon Nov 23 14:38:37 2020 +0000
+++ b/run_tests.sh	Tue Nov 24 13:06:26 2020 +0000
@@ -1,13 +1,10 @@
 #!/usr/bin/env bash
 
-# example command, minimal options: no detrending,
-# no rescaling, no masking, no amplitude norm., no blurring
 
 INPUT_PATH='./test-data/test-movie.tif'
-# INPUT_PATH='./test-data/SCN_L20_Evans2013-half.tif'
 SCRIPT_PATH='.'
 
-python3 $SCRIPT_PATH/cl_wrapper.py --input_path $INPUT_PATH --phase_out phase_twosines_out.tif --period_out period_twosines_out.tif --power_out power_twosines_out.tif  --amplitude_out amplitude_twosines_out.tif --dt .5 --Tmin 20 --Tmax 30 --nT 200 --ncpu 6 --masking dynamic --preprocessed_out preproc_two_sines.tif --gauss_sigma 3 --rescale 50 --Tcutoff 40 --masking fixed --mask_frame 10 --mask_thresh 8
+python3 $SCRIPT_PATH/spyboat_cli.py --input_path $INPUT_PATH --phase_out phase_twosines_out.tif --period_out period_twosines_out.tif --power_out power_twosines_out.tif  --amplitude_out amplitude_twosines_out.tif --dt 1 --Tmin 2 --Tmax 30 --nT 200 --ncpu 6 --masking dynamic --preprocessed_out preproc_two_sines.tif --gauss_sigma 3 --rescale 80 --Tcutoff 40 --masking static --mask_frame 10 --mask_thresh 8
 
 printf "\n"
 # printf "\nError examples:\n"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spyboat_cli.py	Tue Nov 24 13:06:26 2020 +0000
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+
+## Gets interfaced by Galaxy or can be used for bash scripting
+import argparse
+import sys, os
+import logging
+
+from skimage import io
+from numpy import float32
+
+import spyboat
+import output_report
+
+logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
+logger = logging.getLogger('wrapper')
+
+# ----------command line parameters ---------------
+
+parser = argparse.ArgumentParser(description='Process some arguments.')
+
+# I/O
+parser.add_argument('--input_path', help="Input movie location", required=True)
+parser.add_argument('--phase_out', help='Phase output file name', required=True)
+parser.add_argument('--period_out', help='Period output file name', required=True)
+parser.add_argument('--power_out', help='Power output file name', required=True)
+parser.add_argument('--amplitude_out', help='Amplitude output file name', required=True)
+parser.add_argument('--preprocessed_out', help="Preprocessed-input output file name, 'None'", required=False)
+
+
+# (Optional) Multiprocessing
+
+parser.add_argument('--ncpu', help='Number of processors to use',
+                    required=False, type=int, default=1)
+
+# Optional spatial downsampling
+parser.add_argument('--rescale', help='Rescale the image by a factor given in %%, None means no rescaling',
+                    required=False, type=int)
+# Optional Gaussian smoothing
+parser.add_argument('--gauss_sigma', help='Gaussian smoothing parameter, None means no smoothing', required=False, type=float)
+
+# Wavelet Analysis Parameters
+parser.add_argument('--dt', help='Sampling interval', required=True, type=float)
+parser.add_argument('--Tmin', help='Smallest period', required=True, type=float)
+parser.add_argument('--Tmax', help='Biggest period', required=True, type=float)
+parser.add_argument('--nT', help='Number of periods to scan for', required=True, type=int)
+
+parser.add_argument('--Tcutoff', help='Sinc cut-off period, disables detrending if not set', required=False, type=float)
+parser.add_argument('--win_size', help='Sliding window size for amplitude normalization, None means no normalization',
+                    required=False, type=float)
+
+# Optional masking
+parser.add_argument('--masking', help="Set to either 'dynamic', 'static' or 'None' which is the default", default='None', required=False, type=str)
+
+parser.add_argument('--mask_frame',
+                    help="The frame of the input movie to create a static mask from, needs masking set to 'static'",
+                    required=False, type=int)
+
+
+parser.add_argument('--mask_thresh', help='The threshold of the mask, all pixels with less than this value get masked (if masking enabled).',
+                    required=False, type=float,
+                    default=0)
+
+# output html report/snapshots
+parser.add_argument('--html_fname', help="Name of the html report.",
+                    default='OutputReport.html', required=False, type=str)
+
+parser.add_argument('--report_img_path', help="For the html report, to be set in Galaxy. Without galaxy leave at cwd!", default='.', required=False, type=str)
+
+parser.add_argument('--version', action='version', version='0.1.0')
+
+arguments = parser.parse_args()
+
+logger.info("Received following arguments:")
+for arg in vars(arguments):
+    logger.info(f'{arg} -> {getattr(arguments, arg)}')
+
+# ------------Read the input----------------------------------------
+try:
+    movie = spyboat.open_tif(arguments.input_path)
+except FileNotFoundError:
+    logger.critical(f"Couldn't open {arguments.input_path}, check movie storage directory!")
+
+    sys.exit(1)
+
+# -------- Do (optional) spatial downsampling ---------------------------
+
+scale_factor = arguments.rescale
+
+# defaults to None
+if not scale_factor:
+    logger.info('No downsampling requested..')
+
+elif 0 < scale_factor < 100:
+    logger.info(f'Downsampling the movie to {scale_factor:d}% of its original size..')
+    movie = spyboat.down_sample(movie, scale_factor / 100)
+else:
+    raise ValueError('Scale factor must be between 0 and 100!')
+
+# -------- Do (optional) pre-smoothing -------------------------
+# note that downsampling already is a smoothing operation..
+
+# check if pre-smoothing requested
+if not arguments.gauss_sigma:
+    logger.info('No pre-smoothing requested..')
+else:
+    logger.info(f'Pre-smoothing the movie with Gaussians, sigma = {arguments.gauss_sigma:.2f}..')
+
+    movie = spyboat.gaussian_blur(movie, arguments.gauss_sigma)
+
+# ----- Set up Masking before processing ----
+
+mask = None
+if arguments.masking == 'static':
+    if not arguments.mask_frame:
+        logger.critical("Frame number for static masking is missing!")
+        sys.exit(1)
+
+    if (arguments.mask_frame > movie.shape[0]) or (arguments.mask_frame < 0):
+        logger.critical(f'Requested frame does not exist, input only has {movie.shape[0]} frames.. exiting')
+        sys.exit(1)
+
+    else:
+        logger.info(f'Creating static mask from frame {arguments.mask_frame} with threshold {arguments.mask_thresh}')  
+        mask = spyboat.create_static_mask(movie, arguments.mask_frame,
+                                         arguments.mask_thresh)
+elif arguments.masking == 'dynamic':
+    logger.info(f'Creating dynamic mask with threshold {arguments.mask_thresh}')
+    mask = spyboat.create_dynamic_mask(movie, arguments.mask_thresh)
+        
+else:
+    logger.info('No masking requested..')
+
+# ------ Retrieve  wavelet parameters ---------------------------
+
+Wkwargs = {'dt': arguments.dt,
+           'Tmin': arguments.Tmin,
+           'Tmax': arguments.Tmax,           
+           'nT': arguments.nT,
+           'T_c' : arguments.Tcutoff, # defaults to None
+           'win_size' : arguments.win_size # defaults to None          
+}
+
+# --- start parallel processing ---
+
+results = spyboat.run_parallel(movie, arguments.ncpu, **Wkwargs)
+
+# --- masking? ---
+
+if mask is not None:
+    # mask all output movies (in place!)
+    for key in results:
+        logger.info(f'Masking {key}')
+        spyboat.apply_mask(results[key], mask, fill_value=-1)
+
+# --- Produce Output HTML Report Figures/png's ---
+
+# create the directory, yes we have to do that ourselves :)
+# galaxy then magically renders the  html from that directory
+try:
+
+    if arguments.report_img_path != '.':
+        logger.info(f'Creating report directory {arguments.report_img_path}')
+        os.mkdir(arguments.report_img_path)    
+
+    # make 6 times 4 snapshots each
+    Nsnap = 6
+    NFrames = movie.shape[0]
+    # show only frames at least one Tmin
+    # away from the edge (-effects)
+    start_frame = int(Wkwargs['Tmin']/Wkwargs['dt'])        
+    
+    if (start_frame > NFrames//2):
+        logger.warning("Smallest period already is larger than half the observation time!")
+        # set to 0 in this case
+        start_frame = 0
+        
+    frame_increment = int( (NFrames - 2*start_frame) / Nsnap)
+    snapshot_frames = range(start_frame, NFrames - start_frame, frame_increment)
+
+    for snapshot_frame in snapshot_frames:  
+        output_report.produce_snapshots(movie, results, snapshot_frame, Wkwargs, img_path=arguments.report_img_path)
+    
+    output_report.produce_distr_plots(results, Wkwargs, img_path=arguments.report_img_path)
+    
+    output_report.create_html(snapshot_frames, arguments.html_fname)
+                          
+except FileExistsError as e:
+    logger.critical(f"Could not create html report directory: {repr(e)}")
+
+
+# --- save out result movies ---
+
+# save phase movie
+io.imsave(arguments.phase_out, results['phase'], plugin="tifffile")
+logger.info(f'Written {arguments.phase_out}')
+# save period movie
+io.imsave(arguments.period_out, results['period'], plugin="tifffile")
+logger.info(f'Written {arguments.period_out}')
+# save power movie
+io.imsave(arguments.power_out, results['power'], plugin="tifffile")
+logger.info(f'Written {arguments.power_out}')
+# save amplitude movie
+io.imsave(arguments.amplitude_out, results['amplitude'], plugin="tifffile")
+logger.info(f'Written {arguments.amplitude_out}')
+
+# save out the probably pre-processed (scaled and blurred) input movie for
+# direct comparison to results and coordinate mapping etc.
+if arguments.preprocessed_out:
+    io.imsave(arguments.preprocessed_out, movie, plugin='tifffile')
+    logger.info(f'Written {arguments.preprocessed_out}')