Пример #1
0
def _wttab_eventcount(f, res, ec, count_filter, desclen, descfrm, caselen):
    # extrema count
    n = len(res.cases)
    f.write(f"Extrema Count\nFilter: {count_filter}\n\n")
    widths = [desclen, *([caselen] * n)]
    headers = ["Description", *res.cases]
    for j, frm, lbl in zip(
        (0, 1), (f"{{:{caselen}d}}", f"{{:{caselen}.1f}}"), ("Count", "Percent")
    ):
        formats = [descfrm, *([frm] * n)]
        hu_, frm_ = writer.formheader(
            headers, widths, formats, sep=[7, 1], just="c", ulchar="="
        )
        f.write(hu_)
        rowlabels, table = _rowlbls_table(lbl, ec, j)
        writer.vecwrite(f, frm_, rowlabels, table)
        if j == 0:
            f.write("\n")
Пример #2
0
def rptpct1(
    mxmn1,
    mxmn2,
    filename,
    *,
    title="PERCENT DIFFERENCE REPORT",
    names=("Self", "Reference"),
    desc=None,
    filterval=None,
    labels=None,
    units=None,
    ignorepv=None,
    uf_reds=None,
    use_range=True,
    numform=None,
    prtbad=None,
    prtbadh=None,
    prtbadl=None,
    flagbad=None,
    flagbadh=None,
    flagbadl=None,
    dohistogram=True,
    histogram_inc=1.0,
    domagpct=True,
    magpct_options=None,
    doabsmax=False,
    shortabsmax=False,
    roundvals=-1,
    rowhdr="Row",
    deschdr="Description",
    maxhdr="Maximum",
    minhdr="Minimum",
    absmhdr="Abs-Max",
    perpage=-1,
    tight_layout_args=None,
    show_figures=False,
    align_by_label=True,
):
    """
    Write a percent difference report between 2 sets of max/min data

    Parameters
    ----------
    mxmn1 : 2d array_like or SimpleNamespace
        The max/min data to compare to the `mxmn2` set. If 2-column
        array_like, its columns are: [max, min]. If SimpleNamespace,
        it must be as defined in :class:`DR_Results` and have these
        members:

        .. code-block:: none

            .ext = [max, min]
            .drminfo = SimpleNamespace which has (at least):
               .desc      = one line description of category
               .filterval = the filter value; (see `filterval`
                            description below)
               .labels    = a list of descriptions; one per row
               .ignorepv  = these rows will get 'n/a' for % diff
               .units     = string with units
               .uf_reds   = uncertainty factors

        Note that the inputs `desc`, `labels`, etc, override the
        values above.
    mxmn2 : 2d array_like or SimpleNamespace
        The reference set of max/min data. Format is the same as
        `mxmn1`.

        .. note::
            If both `mxmn1` and `mxmn2` are SimpleNamespaces and have
            the ``.drminfo.labels`` attribute, this routine will, by
            default, use the labels to align the data sets for
            comparison. To prevent this, set the `align_by_label`
            parameter to False.

    filename : string or file_like or 1 or None
        Either a name of a file, or is a file_like object as returned
        by :func:`open` or :class:`io.StringIO`. Input as integer 1 to
        write to stdout. Can also be the name of a directory or None;
        in these cases, a GUI is opened for file selection.
    title : string; must be named; optional
        Title for the report
    names : list/tuple; must be named; optional
        Two (short) strings identifying the two sets of data
    desc : string or None; must be named; optional
        A one line description of the table. Overrides
        `mxmn1.drminfo.desc`. If neither are input,
        'No description provided' is used.
    filterval : scalar, 1d array_like or None; must be named; optional
        Numbers with absolute value <= than `filterval` will get a
        'n/a' % diff. If vector, length must match number of rows in
        `mxmn1` and `mxmn2` data. Overrides `mxmn1.drminfo.filterval`.
        If neither are input, `filterval` is set to 1.e-6.
    labels : list or None; must be named; optional
        A list of strings briefly describing each row. Overrides
        `mxmn1.drminfo.labels`. If neither are input,
        ``['Row 1','Row 2',...]`` is used.
    units : string or None; must be named; optional
        Specifies the units. Overrides `mxmn1.drminfo.units`. If
        neither are input, 'Not specified' is used.
    ignorepv : 1d array or None; must be named; optional
        0-offset index vector specifying which rows of `mxmn1` to
        ignore (they get the 'n/a' % diff). Overrides
        `mxmn1.drminfo.ignorepv`. If neither are input, no rows are
        ignored (though `filterval` is still used).

        .. note::
            `ignorepv` applies *before* any alignment by labels is
            done (when `align_by_label` is True, which is the
            default).

    uf_reds : 1d array or None; must be named; optional
        Uncertainty factors: [rigid, elastic, dynamic, static].
        Overrides `mxmn1.drminfo.uf_reds`. If neither is input,
        'Not specified' is used.
    use_range : bool; must be named, optional
        If True, the denominator of the % diff calc for both the max
        & min for each row is the absolute maximum of the reference
        max & min for that row. If False, the denominator is the
        applicable reference max or min. A quick example shows why
        ``use_range=True`` might be useful:

        .. code-block:: none

            If [max1, min1] = [12345, -10] and
               [max2, min2] = [12300,  50]
            Then:
               % diff = [0.37%,   0.49%]  if use_range is True
               % diff = [0.37%, 120.00%]  if use_range is False

        Note that the sign of the % diff is defined such that a
        positive % diff means an exceedance: where ``max1 > max2`` or
        ``min1 < min2``.

        `use_range` is ignored if `doabsmax` is True.

    numform : string or None; must be named; optional
        Format of the max & min numbers. If None, it is set internally
        to be 13 chars wide and depends on the range of numbers to
        print:

           - if range is "small", numform='{:13.xf}' where "x" ranges
             from 0 to 7
           - if range is "large", numform='{:13.6e}'

    prtbad : scalar or None; must be named; optional
        Only print rows where ``abs(%diff) > prtbad``. For example, to
        print rows off by more than 5%, use ``prtbad=5``. `prtbad`
        takes precedence over `prtbadh` and `prtbadl`.
    prtbadh : scalar or None; must be named; optional
        Only print rows where ``%diff > prtbadh``. Handy for showing
        just the exceedances. `prtbadh` takes precedence over
        `prtbadl`.
    prtbadl : scalar or None; must be named; optional
        Only print rows where ``%diff < prtbadl``. Handy for showing
        where reference rows are higher.
    flagbad : scalar or None; must be named; optional
        Flag % diffs where ``abs(%diff) > flagbad``. Works similar to
        `prtbad`. The flag is an asterisk (*).
    flagbadh : scalar or None; must be named; optional
        Flag % diffs where ``%diff > flagbadh``. Works similar to
        `prtbadh`. Handy for flagging exceedances. `flagbadh` takes
        precedence over `flagbadl`.
    flagbadl : scalar or None; must be named; optional
        Flag % diffs where ``%diff < flagbadl``. Works similar to
        `prtbadl`.
    dohistogram : bool; must be named; optional
        If True, plot the histograms. Plots will be written to
        "`filename`.histogram.png".
    histogram_inc : scalar; must be named; optional
        The histogram increment; defaults to 1.0 (for 1%).
    domagpct : bool; must be named; optional
        If True, plot the percent differences versus magnitude via
        :func:`magpct`. Plots will be written to
        "`filename`.magpct.png". Filtering for the "magpct" plot is
        controlled by the ``magpct_options['filterval']`` and
        ``magpct_options['symlogy']`` options. By default, all percent
        differences are shown, but the larger values (according to the
        `filterval` filter) are emphasized by using a mixed linear/log
        y-axis. The percent differences for the `ignorepv` rows are
        not plotted.
    magpct_options : None or dict; must be named; optional
        If None, it is internally reset to::

            magpct_options = {'filterval': 'filterval'}

        Use this parameter to provide any options to :func:`magpct`
        but note that the `filterval` option for :func:`magpct` is
        treated specially. Here, in addition to any of the values that
        :func:`magpct` accepts, it can also be set to the string
        "filterval" as in the default case shown above. In that case,
        ``magpct_options['filterval']`` gets internally reset to the
        initial value of `filterval` (which is None by default).

        .. note::
            The call to :func:`magpct` is *after* applying `ignorepv`
            and doing any data aligning by labels.

        .. note::
           The two filter value options (`filterval` and
           ``magpct_options['filterval']``) have different defaults:
           None and 'filterval`, respectively. They also differ on how
           the ``None`` setting is used: for `filterval`, None is
           replaced by 1.e-6 while for `magpct_filterval`, None means
           that the "magpct" plot will not have any filters applied at
           all.

        .. note::
            The above means that, if you accept the default values for
            `filterval` and for ``magpct_options['filterval']``, then
            tables and the histogram plots will use a `filterval` of
            1.e-6 while the "magpct" plots will use no filter (it
            compares everything except perfect zeros).

    doabsmax : bool; must be named; optional
        If True, compare only absolute maximums.
    shortabsmax : bool; must be named; optional
        If True, set ``doabsmax=True`` and do not print the max1 and
        min1 columns.
    roundvals : integer; must be named; optional
        Round max & min numbers at specified decimal. If negative, no
        rounding.
    rowhdr : string; must be named; optional
        Header for row number column
    deschdr : string; must be named; optional
        Header for description column
    maxhdr : string; must be named; optional
        Header for the column 1 data
    minhdr : string; must be named; optional
        Header for the column 2 data
    absmhdr : string; must be named; optional
        Header for abs-max column
    perpage : integer; must be named; optional
        The number of lines to write perpage. If < 1, there is no
        limit (one page).
    tight_layout_args : dict or None; must be named; optional
        Arguments for :func:`matplotlib.pyplot.tight_layout`. If None,
        defaults to ``{'pad': 3.0}``.
    show_figures : bool; must be named; optional
        If True, plot figures will be displayed on the screen for
        interactive viewing. Warning: there may be many figures.
    align_by_label : bool; must be named; optional
        If True, use labels to align the two sets of data for
        comparison. See note above under the `mxmn2` option.

    Returns
    -------
    pdiff_info : dict
        Dictionary with 'amx' (abs-max), 'mx' (max), and 'mn' keys:

        .. code-block:: none

            <class 'dict'>[n=3]
                'amx': <class 'dict'>[n=5]
                    'hsto' : float64 ndarray 33 elems: (11, 3)
                    'mag'  : [n=2]: (float64 ndarray: (100,), ...
                    'pct'  : float64 ndarray 100 elems: (100,)
                    'prtpv': bool ndarray 100 elems: (100,)
                    'spct' : [n=100]: ['  -2.46', '  -1.50', ...
                'mn' : <class 'dict'>[n=5]
                    'hsto' : float64 ndarray 33 elems: (11, 3)
                    'mag'  : [n=2]: (float64 ndarray: (100,), ...
                    'pct'  : float64 ndarray 100 elems: (100,)
                    'prtpv': bool ndarray 100 elems: (100,)
                    'spct' : [n=100]: ['   1.55', '   1.53', ...
                'mx' : <class 'dict'>[n=5]
                    'hsto' : float64 ndarray 27 elems: (9, 3)
                    'mag'  : [n=2]: (float64 ndarray: (100,), ...
                    'pct'  : float64 ndarray 100 elems: (100,)
                    'prtpv': bool ndarray 100 elems: (100,)
                    'spct' : [n=100]: ['  -2.46', '  -1.50', ...

        Where:

        .. code-block:: none

            'hsto'  : output of :func:`histogram`: [center, count, %]
            'mag'   : inputs to :func:`magpct`
            'pct'   : percent differences
            'prtpv' : rows to print partition vector
            'spct'  : string version of 'pct'

    Examples
    --------
    >>> import numpy as np
    >>> from pyyeti import cla
    >>> ext1 = [[120.0, -8.0],
    ...         [8.0, -120.0]]
    >>> ext2 = [[115.0, -5.0],
    ...         [10.0, -125.0]]

    Run :func:`rptpct1` multiple times to get a more complete picture
    of all the output (the table is very wide). Also, the plots will
    be turned off for this example.

    First, the header:

    >>> opts = {'domagpct': False, 'dohistogram': False}
    >>> dct = cla.rptpct1(ext1, ext2, 1, **opts)  # doctest: +ELLIPSIS
    PERCENT DIFFERENCE REPORT
    <BLANKLINE>
    Description: No description provided
    Uncertainty: Not specified
    Units:       Not specified
    Filter:      1e-06
    Notes:       % Diff = +/- abs(Self-Reference)/max(abs(Reference...
                 Sign set such that positive % differences indicate...
    Date:        ...
    ...

    Then, the max/min/absmax percent difference table in 3 calls:

    >>> dct = cla.rptpct1(ext1, ext2, 1, **opts)  # doctest: +ELLIPSIS
    PERCENT DIFFERENCE REPORT
    ...
                                 Self        Reference             ...
      Row    Description       Maximum        Maximum      % Diff  ...
    -------  -----------    -------------  -------------  -------  ...
          1  Row      1         120.00000      115.00000     4.35  ...
          2  Row      2           8.00000       10.00000    -1.60  ...
    ...
    >>> dct = cla.rptpct1(ext1, ext2, 1, **opts)  # doctest: +ELLIPSIS
    PERCENT DIFFERENCE REPORT
    ...
                         ...     Self        Reference             ...
      Row    Description ...   Minimum        Minimum      % Diff  ...
    -------  ----------- ...-------------  -------------  -------  ...
          1  Row      1  ...     -8.00000       -5.00000     2.61  ...
          2  Row      2  ...   -120.00000     -125.00000    -4.00  ...
    ...
    >>> dct = cla.rptpct1(ext1, ext2, 1, **opts)  # doctest: +ELLIPSIS
    PERCENT DIFFERENCE REPORT
    ...
                         ...     Self        Reference
      Row    Description ...   Abs-Max        Abs-Max      % Diff
    -------  ----------- ...-------------  -------------  -------
          1  Row      1  ...    120.00000      115.00000     4.35
          2  Row      2  ...    120.00000      125.00000    -4.00
    ...

    Finally, the histogram summaries:

    >>> dct = cla.rptpct1(ext1, ext2, 1, **opts)  # doctest: +ELLIPSIS
    PERCENT DIFFERENCE REPORT
    ...
        No description provided - Maximum Comparison Histogram
    <BLANKLINE>
          % Diff      Count    Percent
         --------   --------   -------
            -2.00          1     50.00
             4.00          1     50.00
    <BLANKLINE>
        0.0% of values are within 1%
        50.0% of values are within 2%
        100.0% of values are within 5%
    <BLANKLINE>
        % Diff Statistics: [Min, Max, Mean, StdDev] = [-1.60, 4.35,...
    <BLANKLINE>
    <BLANKLINE>
        No description provided - Minimum Comparison Histogram
    <BLANKLINE>
          % Diff      Count    Percent
         --------   --------   -------
            -4.00          1     50.00
             3.00          1     50.00
    <BLANKLINE>
        0.0% of values are within 1%
        100.0% of values are within 5%
    <BLANKLINE>
        % Diff Statistics: [Min, Max, Mean, StdDev] = [-4.00, 2.61,...
    <BLANKLINE>
    <BLANKLINE>
        No description provided - Abs-Max Comparison Histogram
    <BLANKLINE>
          % Diff      Count    Percent
         --------   --------   -------
            -4.00          1     50.00
             4.00          1     50.00
    <BLANKLINE>
        0.0% of values are within 1%
        100.0% of values are within 5%
    <BLANKLINE>
        % Diff Statistics: [Min, Max, Mean, StdDev] = [-4.00, 4.35,...
    """
    if tight_layout_args is None:
        tight_layout_args = {"pad": 3.0}

    if magpct_options is None:
        magpct_options = {"filterval": "filterval"}
    else:
        magpct_options = magpct_options.copy()

    # magpct_options['filterval'] get special treatment:
    magpct_filterval = magpct_options["filterval"]
    del magpct_options["filterval"]

    if isinstance(magpct_filterval, str):
        if magpct_filterval != "filterval":
            raise ValueError("``magpct_options['filterval']`` is an invalid "
                             f"string: {magpct_filterval!r} (can only "
                             "be 'filterval' if a string)")
        # copy the initial `filterval` setting:
        magpct_filterval = filterval

    infovars = (
        "desc",
        "filterval",
        "magpct_filterval",
        "labels",
        "units",
        "ignorepv",
        "uf_reds",
    )
    dct = locals()
    infodct = {n: dct[n] for n in infovars}
    del dct

    # check mxmn1:
    if isinstance(mxmn1, SimpleNamespace):
        sns = mxmn1.drminfo
        for key, value in infodct.items():
            if value is None:
                infodct[key] = getattr(sns, key, None)
        del sns
        mxmn1 = mxmn1.ext
    else:
        mxmn1 = np.atleast_2d(mxmn1)
    row_number = np.arange(1, mxmn1.shape[0] + 1)

    # check mxmn2:
    if isinstance(mxmn2, SimpleNamespace) and getattr(mxmn2, "drminfo", None):
        labels2 = mxmn2.drminfo.labels
        mxmn2 = mxmn2.ext
        if align_by_label:
            # use labels and labels2 to align data; this is in case
            # the two sets of results recover some of the same items,
            # but not all
            mxmn1, mxmn2, row_number = _align_mxmn(mxmn1, mxmn2, labels2,
                                                   row_number, infodct)
    else:
        mxmn2 = np.atleast_2d(mxmn2)

    desc = infodct["desc"]
    if desc is None:
        desc = "No description provided"

    R = mxmn1.shape[0]
    if R != mxmn2.shape[0]:
        raise ValueError(
            f"`mxmn1` and `mxmn2` have a different number of rows: "
            f"{R} vs {mxmn2.shape[0]} for category with `desc` = {desc}")

    filterval = infodct["filterval"]
    magpct_filterval = infodct["magpct_filterval"]
    labels = infodct["labels"]
    units = infodct["units"]
    ignorepv = infodct["ignorepv"]
    uf_reds = infodct["uf_reds"]
    del infodct

    if filterval is None:
        filterval = 1.0e-6
    filterval = _proc_filterval(filterval, R, "filterval")
    magpct_filterval = _proc_filterval(magpct_filterval, R,
                                       "magpct_options['filterval']")

    if labels is None:
        labels = [f"Row {i + 1:6d}" for i in range(R)]
    elif len(labels) != R:
        raise ValueError("length of `labels` does not match number"
                         f" of rows in `mxmn1`: {len(labels)} vs {R} for "
                         f"category with `desc` = {desc}")
    if units is None:
        units = "Not specified"
    if numform is None:
        numform = _get_numform(mxmn1)

    pdhdr = "% Diff"
    nastring = "n/a "
    comppv = np.ones(R, bool)
    if ignorepv is not None:
        comppv[ignorepv] = False

    # for row labels:
    w = max(11, len(max(labels, key=len)))
    frm = f"{{:{w}}}"

    # start preparing for writer.formheader:
    print_info = SimpleNamespace(
        headers1=["", ""],
        headers2=[rowhdr, deschdr],
        formats=["{:7d}", frm],
        printargs=[row_number, labels],
        widths=[7, w],
        seps=[0, 2],
        justs=["c", "l"],
    )

    if shortabsmax:
        doabsmax = True
    if doabsmax:
        use_range = False
    if roundvals > -1:
        mxmn1 = np.round(mxmn1, roundvals)
        mxmn2 = np.round(mxmn2, roundvals)

    prtbads = (prtbad, prtbadh, prtbadl)
    flagbads = (flagbad, flagbadh, flagbadl)

    # compute percent differences
    pctinfo = {}
    kwargs = dict(
        names=names,
        mxmn1=mxmn1,
        comppv=comppv,
        histogram_inc=histogram_inc,
        numform=numform,
        prtbads=prtbads,
        flagbads=flagbads,
        maxhdr=maxhdr,
        minhdr=minhdr,
        absmhdr=absmhdr,
        pdhdr=pdhdr,
        nastring=nastring,
        doabsmax=doabsmax,
        shortabsmax=shortabsmax,
        print_info=print_info,
    )
    with warnings.catch_warnings():
        warnings.filterwarnings("ignore", r"All-NaN (slice|axis) encountered")
        mx1 = np.nanmax(abs(mxmn1), axis=1)
        mx2 = np.nanmax(abs(mxmn2), axis=1)
    if not doabsmax:
        max1, min1 = mxmn1[:, 0], mxmn1[:, 1]
        max2, min2 = mxmn2[:, 0], mxmn2[:, 1]
        mxmn_b = mxmn2 if use_range else None
        prtpv = np.zeros(R, bool)
        for i in zip(
            ("mx", "mn", "amx"),
            (max1, min1, mx1),
            (max2, min2, mx2),
            (True, False, True),
            (maxhdr, minhdr, absmhdr),
        ):
            lbl, ext1, ext2, ismax, valhdr = i
            pctinfo[lbl] = _proc_pct(
                ext1,
                ext2,
                filterval,
                magpct_filterval,
                mxmn_b=mxmn_b,
                ismax=ismax,
                valhdr=valhdr,
                **kwargs,
            )
            prtpv |= pctinfo[lbl]["prtpv"]
        prtpv &= comppv
    else:
        pctinfo["amx"] = _proc_pct(
            mx1,
            mx2,
            filterval,
            magpct_filterval,
            mxmn_b=None,
            ismax=True,
            valhdr=absmhdr,
            **kwargs,
        )
        prtpv = pctinfo["amx"]["prtpv"]
    hu, frm = writer.formheader(
        [print_info.headers1, print_info.headers2],
        print_info.widths,
        print_info.formats,
        sep=print_info.seps,
        just=print_info.justs,
    )

    # format page header:
    misc = _get_filtline(filterval) + _get_noteline(use_range, names, prtbads,
                                                    flagbads)
    hdrs = _get_rpt_headers(desc=desc, uf_reds=uf_reds, units=units, misc=misc)
    header = title + "\n\n" + hdrs + "\n"

    imode = plt.isinteractive()
    plt.interactive(show_figures)
    try:
        if domagpct:
            _plot_magpct(
                pctinfo,
                names,
                desc,
                doabsmax,
                filename,
                magpct_options,
                use_range,
                maxhdr,
                minhdr,
                absmhdr,
                show_figures,
                tight_layout_args,
            )
        if dohistogram:
            _plot_histogram(
                pctinfo,
                names,
                desc,
                doabsmax,
                filename,
                histogram_inc,
                maxhdr,
                minhdr,
                absmhdr,
                show_figures,
                tight_layout_args,
            )
    finally:
        plt.interactive(imode)

    # write results
    @guitools.write_text_file
    def _wtcmp(f, header, hu, frm, printargs, perpage, prtpv, pctinfo, desc):
        prtpv = prtpv.nonzero()[0]
        if perpage < 1:
            # one additional in case size is zero
            perpage = prtpv.size + 1
        pages = (prtpv.size + perpage - 1) // perpage
        if prtpv.size < len(printargs[0]):
            for i, item in enumerate(printargs):
                printargs[i] = [item[j] for j in prtpv]
        tabhead = header + hu
        pager = "\n"  # + chr(12)
        for p in range(pages):
            if p > 0:
                f.write(pager)
            f.write(tabhead)
            b = p * perpage
            e = b + perpage
            writer.vecwrite(f, frm, *printargs, so=slice(b, e))
        f.write(pager)
        for lbl, hdr in zip(("mx", "mn", "amx"), (maxhdr, minhdr, absmhdr)):
            if lbl in pctinfo:
                f.write(_get_histogram_str(desc, hdr, pctinfo[lbl]))

    _wtcmp(filename, header, hu, frm, print_info.printargs, perpage, prtpv,
           pctinfo, desc)
    return pctinfo
Пример #3
0
def rpttab1(res, filename, title, count_filter=1e-6, name=None):
    """
    Write results tables with bin count information.

    Parameters
    ----------
    res : SimpleNamespace
        Results data structure with attributes `.ext`, `.cases`,
        `.drminfo`, etc (see example in :class:`DR_Results`)
    filename : string or file_like or 1 or None
        If a string that ends with '.xlsx', a Microsoft Excel file is
        written.

        Otherwise, `filename` is either a name of a file, or is a
        file_like object as returned by :func:`open` or
        :class:`io.StringIO`. Input as integer 1 to write to
        stdout. Can also be the name of a directory or None; in these
        cases, a GUI is opened for file selection.
    title : string
        Title for report
    count_filter : scalar; optional
        Filter to use for the bin count; only numbers larger (in
        the absolute value sense) than the filter are counted
    name : string or None; optional
        For '.xlsx' files, this string is used for sheet naming. If
        None and writing an '.xlsx' file, a ValueError is raised.

    Notes
    -----
    The output files contain the maximums, minimums, abs-max
    tables. The extrema value is also included along with the case
    that produced it.

    After those three tables, a table of bin counts is printed
    showing the number of extrema values produced by each event.
    """

    if len(res.drminfo.labels) != res.mx.shape[0]:
        raise ValueError("length of `labels` does not match number of"
                         f" rows in `res.mx` (`desc` = {res.drminfo.desc})")

    rows = np.arange(res.mx.shape[0]) + 1
    headers = ["Row", "Description", *res.cases, "Maximum", "Case"]
    header = title + "\n\n" + _get_rpt_headers(res) + "\n"

    amx, amxcase, aext = _get_absmax(res)
    # order of tables: max, min, abs-max with sign:
    loop_vars = (
        ("Maximum", res.mx, np.nanargmax(res.mx,
                                         axis=1), res.ext[:, 0], res.maxcase),
        ("Minimum", res.mn, np.nanargmin(res.mn,
                                         axis=1), res.ext[:, 1], res.mincase),
        ("Abs-Max", amx, np.nanargmax(abs(amx), axis=1), aext, amxcase),
    )

    if isinstance(filename, xlsxwriter.workbook.Workbook):
        excel = "old"
    elif isinstance(filename, str) and filename.endswith(".xlsx"):
        excel = "new"
    else:
        excel = ""

    if not excel:
        desclen = max(15, len(max(res.drminfo.labels, key=len)))
        caselen = max(13, len(max(res.cases, key=len)))
        n = len(res.cases)
        widths = [6, desclen, *([caselen] * n), caselen, caselen]
        descfrm = f"{{:{desclen:d}}}"
        numform = f"{{:{caselen}.6e}}"
        formats = ["{:6d}", descfrm, *([numform] * n), numform, "{}"]
        hu, frm = writer.formheader(headers,
                                    widths,
                                    formats,
                                    sep=[0, 1],
                                    just="c",
                                    ulchar="=")
        _wttab(
            filename,
            header,
            hu,
            frm,
            res,
            loop_vars,
            rows,
            count_filter,
            desclen,
            descfrm,
            caselen,
        )
    else:
        if not name:
            raise ValueError('`name` must be input when writing ".xlsx" files')
        if excel == "new":
            opts = {"nan_inf_to_errors": True}
            with xlsxwriter.Workbook(filename, opts) as workbook:
                _wtxlsx(workbook, header, headers, res, loop_vars, name, rows,
                        count_filter)
        else:
            _wtxlsx(filename, header, headers, res, loop_vars, name, rows,
                    count_filter)
Пример #4
0
        if doabsmax and not one_col:
            mx = nan_absmax(res.ext[:, 0], res.ext[:, 1])[0]
        else:
            mx = res.ext if one_col else res.ext[:, col]
        _add_column(hdr, numform, mx, w, 4, "c", print_info)

        # x
        if res.ext_x is not None:
            t = res.ext_x if one_col else res.ext_x[:, col]
            _add_column(domain, "{:8.3f}", t, 8, 2, "c", print_info)

        # case
        if case is not None:
            _add_column("Case", casefrm, case, casewidth, 2, "l", print_info)

        if doabsmax or one_col:
            break

    hu, frm = writer.formheader(
        print_info.headers,
        print_info.widths,
        print_info.formats,
        print_info.seps,
        print_info.justs,
    )

    # format page header:
    header = title + "\n\n" + _get_rpt_headers(res) + "\n" + hu

    _wtext(filename, header, frm, print_info.printargs, perpage, nrows)
Пример #5
0
def test_formheader():
    descs = ["Item 1", "A different item"]
    mx = np.array([[1.2, 2.3], [3.4, 4.5]]) * 1000
    time = np.array([[1.234], [2.345]])
    formats = ["{:<25s}", "{:10.2f}", "{:8.3f}"]
    widths = [25, 10, 8]
    assert_raises(ValueError,
                  writer.formheader,
                  44,
                  widths,
                  formats,
                  sep=[4, 5, 2],
                  just=0)
    headers = [["The"] * 3, ["Descriptions", "Maximum", "Time", "BAD"]]
    assert_raises(ValueError,
                  writer.formheader,
                  headers,
                  widths,
                  formats,
                  sep=[4, 5, 2],
                  just=0)
    headers = [["The"] * 3, ["Descriptions", "Maximum", "Time"]]
    assert_raises(ValueError,
                  writer.formheader,
                  headers, [25, 10],
                  formats,
                  sep=[4, 5, 2],
                  just=0)
    hu, f = writer.formheader(headers, widths, formats, sep=[4, 5, 2], just=0)
    with StringIO() as fout:
        fout.write(hu)
        writer.vecwrite(fout, f, descs, mx, time)
        s = fout.getvalue()
    sbe = ("               The                   The        The\n"
           "           Descriptions            Maximum      Time\n"
           "    -------------------------     ----------  --------\n"
           "    Item 1                           1200.00  2300.000\n"
           "    A different item                 3400.00  4500.000\n")
    assert sbe == s

    headers = ["Descriptions", "Maximum", "Time"]
    hu, f = writer.formheader(headers, widths, formats, sep=[4, 5, 2], just=0)
    with StringIO() as fout:
        fout.write(hu)
        writer.vecwrite(fout, f, descs, mx, time)
        s = fout.getvalue()
    sbe = ("           Descriptions            Maximum      Time\n"
           "    -------------------------     ----------  --------\n"
           "    Item 1                           1200.00  2300.000\n"
           "    A different item                 3400.00  4500.000\n")
    assert sbe == s

    headers = ["Descriptions", "Maximum", "Time"]
    hu, f = writer.formheader(headers,
                              widths,
                              formats,
                              sep=2,
                              just=("l", "c", "r"))
    with StringIO() as fout:
        fout.write(hu)
        writer.vecwrite(fout, f, descs, mx, time)
        s = fout.getvalue()
    sbe = ("  Descriptions                Maximum        Time\n"
           "  -------------------------  ----------  --------\n"
           "  Item 1                        1200.00  2300.000\n"
           "  A different item              3400.00  4500.000\n")
    assert sbe == s