Source code for vis_tools.SpatialReports
# ==============================================================================
# SpatialReports.py - Python collection wrapper for set of spatial reports
# ==============================================================================
"""SpatialReports.py
This class is a collection class that keeps track of all the SpatialReport_*
files in a given directory. It is used by VisSet.
Usage::
reports = SpatialReports("output/")
print reports
"""
# imports
from builtins import range
from builtins import object
from glob import glob
from os import path
import json
import sys
import re
# ==============================================================================
# SpatialReports - a collection class representing set of spatial reports
# ==============================================================================
[docs]class SpatialReports(object):
"""Collection class for a set of spatial reports.
The class is constructed with the directory in which SpatialReport_* files
reside. Thereafter the public data members described below, and the various
accessor functions, can be used to get access to the list.
Additionally, since SpatialReports implements __len__, __iter__, and
__getitem__, the SpatialReports object can be treated as a list:, e.g.::
spatial_reports = SpatialReports("/output")
path = spatial_reports[0]
Public members:
source_dir (str): The source directory used to construct the
SpatialReports object.
paths (array): Array of strings with paths to the SpatialReport_* files.
properties (dict): Dictionary<friendlyName, dict<key,value>> of
additional properties to associate with each SpatialBinary file
path. Currently these are unused, but will be used in an upcoming
version.
"""
# --------------------------------------------------------------------------
# Constants
# --------------------------------------------------------------------------
k_spatial_filename_glob = "SpatialReport*_*.bin"
k_spatial_leaf_re = "^SpatialReport[^_]*_(.*)"
# --------------------------------------------------------------------------
def __init__(self, spatial_dir="", verbose=False):
"""Construct a SpatialReports.
Args:
spatial_dir (str): The directory path to inspect.
Raises:
I/O exceptions.
"""
# data members
self.source_dir = spatial_dir
self.paths = []
self.properties = {} # key: friendlyName, value: {} key/value pairs
self._verbose = verbose
if not spatial_dir == "":
self._discover_spatial_reports()
# --------------------------------------------------------------------------
def __str__(self):
"""Generates a textual representation of a SpatialReports.
This method allows the SpatialReports object to report the directory and
number of spatial report files it found in the target directory when it
is printed.
Returns:
str: String containing the number of spatial report files found.
"""
if len(self.source_dir) == 0:
return "(empty)"
else:
return "%s: %d spatial reports" % (self.source_dir, len(self.paths))
# --------------------------------------------------------------------------
def __len__(self):
"""Returns the number of files found in the target directory.
Returns:
int: Number of SpatialReport_* files found.
"""
return len(self.paths)
# --------------------------------------------------------------------------
def __iter__(self):
"""Returns an iterator for the SpatialReport list.
Returns:
iterator: Iterator for the SpatialReport_* file paths.
"""
return self.paths.__iter__()
# --------------------------------------------------------------------------
def __getitem__(self, index):
"""Returns a spatial binary path by index.
Returns:
str: Spatial binary file path.
Args:
index (int): Index, 0-based, into path list.
"""
return self.paths[index]
# --------------------------------------------------------------------------
[docs] def get(self, index):
"""Returns detailed information on spatial binary by index.
Returns:
obj: An object containing the name, friendly name, and path (url) to
the spatial binary at the provided index.
Args:
index (int): Index, 0-based, into path list.
"""
return {
"name": path.splitext(path.basename(self.paths[index]))[0],
"friendlyName": self._friendly_name(self.paths[index]),
"url": self.paths[index]
}
[docs] def add(self, report_path):
"""Manually add a spatial binary to the list.
This method can be used to manually add a spatial binary to the list
even if it is not in the source_dir where spatial_binaries normally
live. This is useful for adding a programmatically-generated spatial
binary to the list. Such generated spatial binaries are generally
located in the preprocessing script's products directory.
Example::
reports = SpatialReports("output/")
reports.add(path.join(k_products_dir,
'SpatialReport_Infectious_Vector_Count'))
Returns:
None.
Args:
report_path (str): The path to the spatial binary. Note that this
path need not be within source_dir.
"""
self.paths.append(report_path)
# --------------------------------------------------------------------------
[docs] def emit_object(self):
"""Emits an object used by VisSet to represent spatial binary channels.
Result:
object: A Dictionary<friendly_name, file_path> for the spatial
binaries found in the target directory.
Args:
None.
"""
result = {}
for fp in self.paths:
friendly_name = self._friendly_name(fp)
result[friendly_name] = fp
if self._verbose:
print("SpatialReports.emit_object: emitted object containing %d "
"spatial binaries" % len(self.paths))
return result
# --------------------------------------------------------------------------
# Later, when I want more metadata about each spatial report (namely,
# value min and value max), switch to this, and change the client.
# def emit_object(self):
# result = {}
# for fp in self.paths:
# friendly_name = self._friendly_name(fp)
# result[friendly_name] = {
# "path": fp
# }
# # Add additional properties if any
# if friendly_name in self.properties:
# result[friendly_name].update(self.properties[friendly_name])
# return result
# --------------------------------------------------------------------------
[docs] def emit_object_json(self):
"""Emits the JSON for the object from emit_object.
Result:
str: JSON representation of the emit_object() result.
Args:
None.
"""
return json.dumps(self.emit_object())
# --------------------------------------------------------------------------
[docs] def remove(self, friendly_name):
"""Removes a spatial binary from the list by friendly name.
Returns:
None.
Args:
friendly_name (str): The friendly name of the spatial binary path
to remove. E.g., for SpatialReport_Adult_Vectors, the friendly
name is "Adult Vectors".
"""
for a_path in self.paths:
if self._friendly_name(a_path) == friendly_name:
self.paths.remove(a_path)
if friendly_name in self.properties:
del self.properties[friendly_name]
# --------------------------------------------------------------------------
# Implementation
# --------------------------------------------------------------------------
def _discover_spatial_reports(self):
try:
if not path.isdir(self.source_dir):
raise IOError("Directory %s is missing or inaccessible." %
self.source_dir)
self.paths = glob(path.join(self.source_dir,
self.k_spatial_filename_glob))
for i in range(0, len(self.paths)):
self.paths[i] = self.paths[i].replace("\\", "/")
except BaseException:
# print(sys.exc_info()[0])
if self._verbose:
print("SpatialReports._discover_spatial_reports: Exception "
"discovering spatial binaries", file=sys.stderr)
raise
# --------------------------------------------------------------------------
def _friendly_name(self, fp):
leaf = path.splitext(path.basename(fp))[0] # Basename with no ext
m = re.match(self.k_spatial_leaf_re, leaf)
if m is not None:
return m.group(1).replace("_", " ")
else:
return leaf