# HG changeset patch
# User iuc
# Date 1606571134 0
# Node ID 76733d05d8ef25433e3e129883e8e337b38be36d
"planemo upload for repository https://github.com/galaxyproject/tools-iuc/tree/master/packages/spyboat commit 5c60a414c785246371beac23ce52d8bbab3602d1"
diff -r 000000000000 -r 76733d05d8ef output_report.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/output_report.py Sat Nov 28 13:45:34 2020 +0000
@@ -0,0 +1,253 @@
+""" Produces plots and a summary html 'headless' """
+import logging
+import os
+
+import matplotlib
+import matplotlib.pyplot as ppl
+import spyboat.plotting as spyplot
+
+ppl.switch_backend('Agg')
+matplotlib.rcParams["text.usetex"] = False
+logger = logging.getLogger(__name__)
+
+# figure resolution
+DPI = 250
+
+
+def produce_snapshots(input_movie, results, frame, Wkwargs, img_path="."):
+ """
+ Takes the *input_movie* and the *results* dictionary
+ from spyboat.processing.run_parallel and produces phase,
+ period and amplitude snapshot png's.
+
+ For the period snapshot also the period range is needed,
+ hence the analysis dictionary 'Wkwargs' also gets passed.
+
+ The output files name pattern is:
+ [input, phase, period, amplitude]_frame{frame}.png
+ and the storage location in *img_path*.
+
+ These get picked up by 'create_html'
+ """
+
+ spyplot.input_snapshot(input_movie[frame])
+ 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["Tmin"],
+ Wkwargs["Tmax"], time_unit="a.u."
+ )
+
+ 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="."):
+ """
+ Output file names are:
+
+ period_distr.png, power_distr.png and phase_distr.png
+ """
+
+ spyplot.period_distr_dynamics(results["period"], Wkwargs)
+ fig = ppl.gcf()
+ out_path = os.path.join(img_path, "period_distr.png")
+ fig.savefig(out_path, dpi=DPI)
+
+ spyplot.power_distr_dynamics(results["power"], Wkwargs)
+ fig = ppl.gcf()
+ out_path = os.path.join(img_path, "power_distr.png")
+ fig.savefig(out_path, dpi=DPI)
+
+ spyplot.phase_coherence_dynamics(results["phase"], Wkwargs)
+ fig = ppl.gcf()
+ out_path = os.path.join(img_path, "phase_distr.png")
+ fig.savefig(out_path, dpi=DPI)
+
+ logger.info("Produced 3 distribution plots..")
+
+
+def create_html(frame_nums, html_fname="OutputReport.html"):
+ """
+ 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"""
+
+
+ Frame Nr. {frame_num}
+
+
+
+
+
+
+
+
+
+
+
+
+ """
+ galleries += new_gal
+
+ html_string = f"""
+
+
+ SpyBOAT Output Report
+
+
+
+
+
+
+ SpyBOAT Results Report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {galleries}
+
+
+
+
+
+
+ """
+
+ with open(html_fname, "w") as OUT:
+ OUT.write(html_string)
+
+ logger.info("Created html report")
+ return html_string
+
+# for local testing
+# create_html([0,20,40,60,80])
diff -r 000000000000 -r 76733d05d8ef run_tests.sh
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/run_tests.sh Sat Nov 28 13:45:34 2020 +0000
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+
+INPUT_PATH='./test-data/test-movie.tif'
+SCRIPT_PATH='.'
+
+# set to galaxy defaults!!
+python3 $SCRIPT_PATH/spyboat_cli.py --input_path $INPUT_PATH --phase_out phase_out.tif --period_out period_out.tif --dt 1 --Tmin 20 --Tmax 30 --nT 150 --ncpu 6 --Tcutoff 40
+
+# additional paramters
+#--masking static --mask_frame 10 --mask_thresh 300 --rescale 80 --gauss_sigma 1
+
+printf "\n"
+# printf "\nError examples:\n"
+
diff -r 000000000000 -r 76733d05d8ef spyboat.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/spyboat.xml Sat Nov 28 13:45:34 2020 +0000
@@ -0,0 +1,264 @@
+
+wavelet transforms image stacks
+
+ 0.1.1
+
+
+ spyboat
+
+ python '$__tool_directory__/spyboat_cli.py' --version
+ /dev/null &&
+ ## run tool
+ python '$__tool_directory__/spyboat_cli.py'
+ --input_path '$movie'
+ #if str($PreProc.gauss_sigma):
+ --gauss_sigma $PreProc.gauss_sigma
+ #end if
+ #if str($PreProc.rescale_factor):
+ --rescale $PreProc.rescale_factor
+ #end if
+
+ #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":
+ --masking dynamic
+ --mask_thresh $masking.mask_thresh
+ #end if
+
+ --dt $wavana.dt
+ --Tmin $wavana.tmin
+ --Tmax $wavana.tmax
+ --nT $wavana.nt
+ #if str($wavana.tcutoff)
+ --Tcutoff $wavana.tcutoff
+ #end if
+ #if str($wavana.win_size):
+ --win_size $wavana.win_size
+ #end if
+
+ #if 'save_phase' in $outputs:
+ --phase_out '$phase_out'
+ #end if
+
+ #if 'save_period' in $outputs:
+ --period_out '$period_out'
+ #end if
+
+ #if 'save_power' in $outputs:
+ --power_out '$power_out'
+ #end if
+
+ #if 'save_amplitude' in $outputs:
+ --amplitude_out '$amplitude_out'
+ #end if
+
+ #if 'save_preprocessed' in $outputs:
+ --preprocessed_out '$preprocessed_out'
+ #end if
+
+ --html_fname '$html_out'
+ --report_img_path '$html_out.extra_files_path'
+
+ --ncpu "\${GALAXY_SLOTS:-8}"
+
+
+ ]]>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 'save_phase' in ouputs
+
+
+ 'save_period' in outputs
+
+
+ 'save_power' in outputs
+
+
+ 'save_amplitude' in outputs
+
+
+ 'save_preprocessed' in outputs
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10.1101/2020.04.29.067744
+
+
diff -r 000000000000 -r 76733d05d8ef spyboat_cli.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/spyboat_cli.py Sat Nov 28 13:45:34 2020 +0000
@@ -0,0 +1,217 @@
+#!/usr/bin/env python
+
+# Gets interfaced by Galaxy or can be used for bash scripting
+import argparse
+import logging
+import os
+import sys
+
+import output_report
+import spyboat
+from numpy import float32
+from skimage import io
+
+logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)
+logger = logging.getLogger('spyboat-cli')
+
+# ----------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=False)
+parser.add_argument('--period_out', help='Period output file name', required=False)
+parser.add_argument('--power_out', help='Power output file name', required=False)
+parser.add_argument('--amplitude_out', help='Amplitude output file name', required=False)
+parser.add_argument('--preprocessed_out', help="Preprocessed-input output file name", 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_factor', 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)
+# problems get logged in 'open_tif'
+if movie is None:
+ sys.exit(1)
+# -------- Do (optional) spatial downsampling ---------------------------
+
+scale_factor = arguments.rescale_factor
+
+# 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)
+
+ # 4 snapshots each
+ Nsnap = 7
+ 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 ---
+
+# None means output is filtered from galaxy settings
+if arguments.phase_out is not None:
+ # save phase movie
+ io.imsave(arguments.phase_out, results['phase'], plugin="tifffile")
+ logger.info(f'Written phase to {arguments.phase_out}')
+if arguments.period_out is not None:
+ # save period movie
+ io.imsave(arguments.period_out, results['period'], plugin="tifffile")
+ logger.info(f'Written period to {arguments.period_out}')
+if arguments.power_out is not None:
+ # save power movie
+ io.imsave(arguments.power_out, results['power'], plugin="tifffile")
+ logger.info(f'Written power to {arguments.power_out}')
+if arguments.amplitude_out is not None:
+ # save amplitude movie
+ io.imsave(arguments.amplitude_out, results['amplitude'], plugin="tifffile")
+ logger.info(f'Written amplitude to {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 is not None:
+ io.imsave(arguments.preprocessed_out, movie.astype(float32), plugin='tifffile')
+ logger.info(f'Written preprocessed to {arguments.preprocessed_out}')
diff -r 000000000000 -r 76733d05d8ef test-data/output1.html
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test-data/output1.html Sat Nov 28 13:45:34 2020 +0000
@@ -0,0 +1,334 @@
+
+
+
+ SpyBOAT Output Report
+
+
+
+
+
+
+ SpyBOAT Results Report
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 28
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 36
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 44
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 52
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 60
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Frame Nr. 68
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff -r 000000000000 -r 76733d05d8ef test-data/test-movie.tif
Binary file test-data/test-movie.tif has changed