Source code for raytraverse.utility.cli

# -*- coding: utf-8 -*-

# Copyright (c) 2021 Stephen Wasilewski
# =======================================================================
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# =======================================================================
import os
import sys

import numpy as np
from clasp import click
import clasp.click_ext as clk

from raytraverse import io
from raytraverse.lightfield import LightResult, ZonalLightResult
from raytraverse.mapper import PlanMapper
from raytraverse.sky import SkyData


[docs]@clk.pretty_name("NPY, TSV, FLOATS,FLOATS") def np_load(ctx, param, s): """read np array from command line trys np.load (numpy binary), then np.loadtxt (space seperated txt file) then split row by spaces and columns by commas. """ if s is None: return s if s == '-': s = clk.tmp_stdin(ctx) if os.path.exists(s): try: ar = np.load(s) except ValueError: try: ar = io.load_txt(s) except ValueError: ar = io.load_txt(s, skiprows=1) if len(ar.shape) == 1: ar = ar.reshape(1, -1) return ar else: return np.array([[float(i) for i in j.split(',')] for j in s.split()])
[docs]@clk.pretty_name("NPY, TSV, FLOATS,FLOATS, FILE") def np_load_safe(ctx, param, s): if s in [None, "None", ""]: return None try: return np_load(ctx, param, s) except ValueError as ex: if os.path.exists(s): return s else: print(f"could not process parameter -{param.name}: '{s}'", file=sys.stderr) raise click.Abort
pull_decs = [ click.option("-lr", callback=clk.is_file, help=".npz LightResult, overrides lightresult from chained " "commands (evaluate/imgmetric). required if not chained " "with evaluate or imgmetric."), click.option("-col", default='metric', callback=clk.split_str, help="axis to preserve and order for flattening, if not all axes" " are specified default order is (sky, point, view, metric)" " the first value is the column preserved, the second (with" " -ofiles) is the file to write, and the rest determine the" " order for ravelling into rows."), click.option("-ofiles", help="if given output serialized files along first axis " "(given by order) with naming [ofiles]_XXXX.txt"), click.option("-spd", default=24, help="steps per day. for use with --gridhdr col != sky matches" " data underlying -skyfill"), click.option("-ptfilter", callback=clk.split_int, help="point indices to return (ignored for imgmetric result)"), click.option("-viewfilter", callback=clk.split_int, help="view direction indices to return " "(ignored for imgmetric result)"), click.option("-skyfilter", callback=clk.split_int, help="sky indices to return (ignored for imgmetric result)"), click.option("-imgfilter", callback=clk.split_int, help="image indices to return (ignored for lightfield result)"), click.option("-metricfilter", callback=clk.split_str, help="metrics to return (non-existant are ignored)"), click.option("-skyfill", callback=clk.is_file, help="path to skydata file. assumes rows are timesteps." " skyfilter should be None and other beside col " "should reduce to 1 or ofiles is given and sky is" " not first in order and all but first reduces to 1." " LightResult should be a full evaluation (not masked)"), click.option("--header/--no-header", default=True, help="print col labels"), click.option("--rowlabel/--no-rowlabel", default=True, help="label row"), click.option("--info/--no-info", default=False, help="skip execution and return shape and axis info about " "LightResult"), click.option("--gridhdr/--no-gridhdr", default=False, help="use with 'ofiles', order 'X point/sky Y' and make sure Y" " only has one value (with appropriate filter)"), click.option("-imgzone", default=None, help="for making images from ZonalLightResult, path to area" "to sample over."), click.option("-res", default=480, help="image resolution for plan based image pulls.") ]
[docs]def shared_pull(ctx, lr=None, col=("metric",), ofiles=None, ptfilter=None, viewfilter=None, skyfilter=None, imgfilter=None, metricfilter=None, skyfill=None, header=True, spd=24, rowlabel=True, info=False, gridhdr=False, imgzone=None, res=480, **kwargs): """used by both raytraverse.cli and raytu, add pull_decs and clk.command_decs as clk.shared_decs in main script so click can properly load options""" if lr is not None: try: result = LightResult(lr) except KeyError: result = ZonalLightResult(lr) elif 'lightresult' in ctx.obj: result = ctx.obj['lightresult'] else: click.echo("Please provide an -lr (path to light result file)", err=True) raise click.Abort if info: click.echo(result.info(), err=True) return None filters = dict(metric=metricfilter, sky=skyfilter, point=ptfilter, view=viewfilter, image=imgfilter) if metricfilter is not None: try: metricfilter = [int(i) for i in metricfilter] except ValueError: av = result.axis("metric").values else: av = list(range(len(result.axis("metric").values))) [click.echo(f"Warning! {i} not in LightResult", err=True) for i in metricfilter if i not in av] filters["metric"] = np.flatnonzero([i in metricfilter for i in av]) # translate sky index to skydata shape if skyfill is not None: skydata = SkyData(skyfill) if skyfilter is not None: skydata.mask = skyfilter else: skydata = None if skyfilter is not None and "sky" in result.names: av = result.axis("sky").values if skydata is None: skyf = np.flatnonzero(np.isin(np.arange(av.size), skyfilter)) else: skyf = np.arange(len(av))[skydata.mask] if len(skyf) == 0: click.echo(f"skyfilter leaves no values! include skyfill?", err=True) raise click.Abort filters["sky"] = skyf skydata = None pargs = dict(header=header, rowlabel=rowlabel) if ofiles is None: result.print(col, skyfill=skydata, **pargs, **filters) else: if gridhdr: if imgzone is not None: result.boundary = imgzone result.pull2hdr(ofiles, col=col, skyfill=skydata, spd=spd, res=res, **filters) else: result.print_serial(col, ofiles, skyfill=skydata, **pargs, **filters)