diff --git a/src/draw/fdrw.py b/src/draw/fdrw.py index fe4db452..898f5525 100755 --- a/src/draw/fdrw.py +++ b/src/draw/fdrw.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -26,45 +25,7 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw graphs") - parser.add_argument( - metavar="infile", - dest="in_file", - default=None, - nargs="?", - type=str, - help="data sequence (double)", - ) - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", - ) + parser = utils.get_default_parser("draw a graph", input_name="data sequence") parser.add_argument( "-g", dest="grid", @@ -221,22 +182,6 @@ def get_arguments(): type=float, help="marker line width", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() @@ -311,12 +256,12 @@ def main(): args = get_arguments() if args.in_file is None: - data = utils.read_stdin() + data = utils.read_stdin(dtype=args.dtype) else: if not os.path.exists(args.in_file): utils.print_error_message("fdrw", f"Cannot open {args.in_file}") sys.exit(1) - data = utils.read_binary(args.in_file) + data = utils.read_binary(args.in_file, dtype=args.dtype) if args.marker_symbol == 0: mode = "lines" diff --git a/src/draw/glogsp.py b/src/draw/glogsp.py index f548eef4..25e623e0 100755 --- a/src/draw/glogsp.py +++ b/src/draw/glogsp.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -26,44 +25,8 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw a log spectrum graph") - parser.add_argument( - metavar="infile", - dest="in_file", - default=None, - nargs="?", - type=str, - help="log spectrum (double)", - ) - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", + parser = utils.get_default_parser( + "draw a log spectrum", input_name="log spectrum", allow_dtype=False ) parser.add_argument( "-g", @@ -128,22 +91,6 @@ def get_arguments(): type=float, help="line width", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() diff --git a/src/draw/gpolezero.py b/src/draw/gpolezero.py index f001597f..57f69541 100755 --- a/src/draw/gpolezero.py +++ b/src/draw/gpolezero.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -26,37 +25,7 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw poles and zeros") - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", - ) + parser = utils.get_default_parser("draw poles and zeros", allow_dtype=False) parser.add_argument( "-g", dest="grid", @@ -137,27 +106,11 @@ def get_arguments(): type=float, help="marker line width", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() ## -# @a gpolezero [ @e option ] [ @e infile ] @e outfile +# @a gpolezero [ @e option ] @e outfile # # - @b -F @e float # - scale of figure @@ -207,12 +160,8 @@ def main(): args = get_arguments() in_files = [] - if args.zero_file is not None: - in_files.append(args.zero_file) - if args.pole_file is not None: - in_files.append(args.pole_file) - if 0 == len(in_files): - in_files.append(None) + in_files.append(None if args.zero_file is None else args.zero_file) + in_files.append(None if args.pole_file is None else args.pole_file) markers = ( dict( @@ -233,7 +182,7 @@ def main(): fig = go.Figure() - # Draw unit circle. + # Draw a unit circle. fig.add_shape( type="circle", xref="x", @@ -247,12 +196,12 @@ def main(): # Draw zeros and poles. for in_file, marker in zip(in_files, markers): if in_file is None: - data = utils.read_stdin(dim=2) - else: - if not os.path.exists(in_file): - utils.print_error_message("gpolezero", f"Cannot open {in_file}") - sys.exit(1) - data = utils.read_binary(in_file, dim=2) + continue + + if not os.path.exists(in_file): + utils.print_error_message("gpolezero", f"Cannot open {in_file}") + sys.exit(1) + data = utils.read_binary(in_file, dim=2) if 0 == args.input_format: x = data[:, 0] @@ -276,11 +225,13 @@ def main(): ) fig.update_layout( xaxis=dict( + title_text="Real part", range=args.xlim, showgrid=args.grid, zeroline=True, ), yaxis=dict( + title_text="Imaginary part", range=args.ylim, showgrid=args.grid, zeroline=True, diff --git a/src/draw/grlogsp.py b/src/draw/grlogsp.py index 568de808..1d7965c9 100755 --- a/src/draw/grlogsp.py +++ b/src/draw/grlogsp.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -26,44 +25,8 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw a running log spectrum graph") - parser.add_argument( - metavar="infile", - dest="in_file", - default=None, - nargs="?", - type=str, - help="log spectrum (double)", - ) - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", + parser = utils.get_default_parser( + "draw a running log spectrum", input_name="log spectrum", allow_dtype=False ) parser.add_argument( "-g", @@ -141,22 +104,6 @@ def get_arguments(): type=float, help="line width", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() diff --git a/src/draw/gseries.py b/src/draw/gseries.py index 747dc930..6ad5b7be 100755 --- a/src/draw/gseries.py +++ b/src/draw/gseries.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -27,44 +26,8 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw a discrete series") - parser.add_argument( - metavar="infile", - dest="in_file", - default=None, - nargs="?", - type=str, - help="discrete series (double)", - ) - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", + parser = utils.get_default_parser( + "draw a dicrete series", input_name="discrete series" ) parser.add_argument( "-g", @@ -104,6 +67,26 @@ def get_arguments(): type=int, help="number of screens", ) + parser.add_argument( + "-t", + dest="transpose", + action="store_true", + help="align screens horizontally instead of vertically (valid with -i)", + ) + parser.add_argument( + "-r", + dest="reset", + action="store_true", + help="does not succeed time across screens (valid with -i)", + ) + parser.add_argument( + "-x", + metavar="x", + dest="sr", + default=None, + type=float, + help="sampling rate [kHz]", + ) parser.add_argument( "-y", metavar=("YMIN", "YMAX"), @@ -113,14 +96,6 @@ def get_arguments(): type=float, help="y-axis limits", ) - parser.add_argument( - "-xname", - metavar="XNAME", - dest="xname", - default="Time [sample]", - type=str, - help="x-axis title", - ) parser.add_argument( "-lc", metavar="lc", @@ -177,22 +152,6 @@ def get_arguments(): type=float, help="marker line width", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() @@ -215,6 +174,12 @@ def get_arguments(): # - number of samples per screen # - @b -i @e int # - number of screens +# - @b -t @e bool +# - align figures horizontally instead of vertically +# - @b -r @e bool +# - does not succeed time across screens +# - @b -x @e float +# - sampling rate in kHz # - @b -y @e float @e float # - y-axis limits # - @b -lc @e str @@ -248,15 +213,22 @@ def main(): args = get_arguments() if args.in_file is None: - data = utils.read_stdin() + data = utils.read_stdin(dtype=args.dtype) else: if not os.path.exists(args.in_file): utils.print_error_message("gseries", f"Cannot open {args.in_file}") sys.exit(1) - data = utils.read_binary(args.in_file) + data = utils.read_binary(args.in_file, dtype=args.dtype) y = data[args.start_point : None if args.end_point is None else args.end_point + 1] x = np.arange(len(y)) + args.start_point + if args.sr is not None: + x = x / (args.sr * 1000) + + if 100000 < len(y): + utils.print_warn_message( + "gseries", "Too many data points. This takes a long time." + ) if args.ylim[0] is None: ymax = np.amax(np.abs(y)) @@ -269,30 +241,40 @@ def main(): else: n = args.num_samples - fig = make_subplots(rows=args.num_screens, cols=1) + fig = make_subplots( + rows=1 if args.transpose else args.num_screens, + cols=args.num_screens if args.transpose else 1, + ) s = 0 for i in range(args.num_screens): last = i == args.num_screens - 1 + row_col = { + "row": 1 if args.transpose else i + 1, + "col": i + 1 if args.transpose else 1, + } if args.num_samples is None and last: e = len(y) else: e = s + n fig.add_trace( go.Bar( - x=x[s:e], + x=x[: e - s] if args.reset else x[s:e], y=y[s:e], - width=args.line_width, + width=( + args.line_width + if args.sr is None + else args.line_width / (args.sr * 1000) + ), marker=dict( color=args.line_color, line_width=0, ), ), - row=i + 1, - col=1, + **row_col, ) fig.add_trace( go.Scatter( - x=x[s:e], + x=x[: e - s] if args.reset else x[s:e], y=y[s:e], mode="markers", marker=dict( @@ -303,20 +285,18 @@ def main(): line_width=args.marker_line_width, ), ), - row=i + 1, - col=1, + **row_col, ) + xname = "Time [samples]" if args.sr is None else "Time [sec]" fig.update_xaxes( - title_text=args.xname if last else "", + title_text=xname if last or args.transpose else "", showgrid=args.grid, - row=i + 1, - col=1, + **row_col, ) fig.update_yaxes( range=ylim, showgrid=args.grid, - row=i + 1, - col=1, + **row_col, ) s = e diff --git a/src/draw/gspecgram.py b/src/draw/gspecgram.py index fc2f84c9..0b8461c5 100755 --- a/src/draw/gspecgram.py +++ b/src/draw/gspecgram.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -28,45 +27,7 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw a spectrogram") - parser.add_argument( - metavar="infile", - dest="in_file", - default=None, - nargs="?", - type=str, - help="waveform (double)", - ) - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", - ) + parser = utils.get_default_parser("draw spectrogram", input_name="waveform") parser.add_argument( "-s", metavar="s", @@ -100,7 +61,7 @@ def get_arguments(): help="number of screens", ) parser.add_argument( - "-T", + "-t", dest="transpose", action="store_true", help="align screens horizontally instead of vertically (valid with -i)", @@ -151,22 +112,6 @@ def get_arguments(): type=float, help="power parameter", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() @@ -187,7 +132,7 @@ def get_arguments(): # - number of samples per screen # - @b -i @e int # - number of screens -# - @b -T @e bool +# - @b -t @e bool # - align figures horizontally instead of vertically # - @b -r @e bool # - does not succeed time across screens @@ -218,12 +163,12 @@ def main(): args = get_arguments() if args.in_file is None: - data = utils.read_stdin() + data = utils.read_stdin(dtype=args.dtype) else: if not os.path.exists(args.in_file): utils.print_error_message("gspecgram", f"Cannot open {args.in_file}") sys.exit(1) - data = utils.read_binary(args.in_file) + data = utils.read_binary(args.in_file, dtype=args.dtype) y = data[args.start_point : None if args.end_point is None else args.end_point + 1] @@ -241,6 +186,10 @@ def main(): for i in range(args.num_screens): first = i == 0 last = i == args.num_screens - 1 + row_col = { + "row": 1 if args.transpose else i + 1, + "col": i + 1 if args.transpose else 1, + } if args.num_samples is None and last: e = len(y) else: @@ -260,18 +209,15 @@ def main(): z=spec, colorscale=args.color_scale, ), - row=1 if args.transpose else i + 1, - col=i + 1 if args.transpose else 1, + **row_col, ) fig.update_xaxes( title_text="Time [sec]" if last or args.transpose else "", - row=1 if args.transpose else i + 1, - col=i + 1 if args.transpose else 1, + **row_col, ) fig.update_yaxes( title_text="Frequency [kHz]" if first or not args.transpose else "", - row=1 if args.transpose else i + 1, - col=i + 1 if args.transpose else 1, + **row_col, ) s = e if not args.reset: diff --git a/src/draw/gwave.py b/src/draw/gwave.py index c38e2f5f..3257fec4 100755 --- a/src/draw/gwave.py +++ b/src/draw/gwave.py @@ -15,7 +15,6 @@ # limitations under the License. # # ------------------------------------------------------------------------ # -import argparse import os import sys @@ -27,45 +26,7 @@ def get_arguments(): - parser = argparse.ArgumentParser(description="draw a waveform") - parser.add_argument( - metavar="infile", - dest="in_file", - default=None, - nargs="?", - type=str, - help="waveform (double)", - ) - parser.add_argument( - metavar="outfile", - dest="out_file", - type=str, - help="figure", - ) - parser.add_argument( - "-F", - metavar="F", - dest="factor", - default=1.0, - type=float, - help="scale of figure", - ) - parser.add_argument( - "-W", - metavar="W", - dest="width", - default=None, - type=int, - help="width of figure [px]", - ) - parser.add_argument( - "-H", - metavar="H", - dest="height", - default=None, - type=int, - help="height of figure [px]", - ) + parser = utils.get_default_parser("draw a waveform", input_name="waveform") parser.add_argument( "-g", dest="grid", @@ -104,6 +65,26 @@ def get_arguments(): type=int, help="number of screens", ) + parser.add_argument( + "-t", + dest="transpose", + action="store_true", + help="align screens horizontally instead of vertically (valid with -i)", + ) + parser.add_argument( + "-r", + dest="reset", + action="store_true", + help="does not succeed time across screens (valid with -i)", + ) + parser.add_argument( + "-x", + metavar="x", + dest="sr", + default=None, + type=float, + help="sampling rate [kHz]", + ) parser.add_argument( "-y", metavar=("YMIN", "YMAX"), @@ -113,14 +94,6 @@ def get_arguments(): type=float, help="y-axis limits", ) - parser.add_argument( - "-xname", - metavar="XNAME", - dest="xname", - default="Time [sample]", - type=str, - help="x-axis title", - ) parser.add_argument( "-ls", dest="line_style", @@ -145,22 +118,6 @@ def get_arguments(): type=float, help="line width", ) - parser.add_argument( - "-ff", - metavar="ff", - dest="font_family", - default=None, - type=str, - help="font family", - ) - parser.add_argument( - "-fs", - metavar="fs", - dest="font_size", - default=None, - type=int, - help="font size", - ) return parser.parse_args() @@ -183,6 +140,12 @@ def get_arguments(): # - number of samples per screen # - @b -i @e int # - number of screens +# - @b -t @e bool +# - align figures horizontally instead of vertically +# - @b -r @e bool +# - does not succeed time across screens +# - @b -x @e float +# - sampling rate in kHz # - @b -y @e float @e float # - y-axis limits # - @b -ls @e str @@ -208,15 +171,17 @@ def main(): args = get_arguments() if args.in_file is None: - data = utils.read_stdin() + data = utils.read_stdin(dtype=args.dtype) else: if not os.path.exists(args.in_file): utils.print_error_message("gwave", f"Cannot open {args.in_file}") sys.exit(1) - data = utils.read_binary(args.in_file) + data = utils.read_binary(args.in_file, dtype=args.dtype) y = data[args.start_point : None if args.end_point is None else args.end_point + 1] x = np.arange(len(y)) + args.start_point + if args.sr is not None: + x = x / (args.sr * 1000) if args.ylim[0] is None: ymax = np.amax(np.abs(y)) @@ -229,17 +194,24 @@ def main(): else: n = args.num_samples - fig = make_subplots(rows=args.num_screens, cols=1) + fig = make_subplots( + rows=1 if args.transpose else args.num_screens, + cols=args.num_screens if args.transpose else 1, + ) s = 0 for i in range(args.num_screens): last = i == args.num_screens - 1 + row_col = { + "row": 1 if args.transpose else i + 1, + "col": i + 1 if args.transpose else 1, + } if args.num_samples is None and last: e = len(y) else: e = s + n fig.add_trace( go.Scatter( - x=x[s:e], + x=x[: e - s] if args.reset else x[s:e], y=y[s:e], line=dict( color=args.line_color, @@ -247,20 +219,18 @@ def main(): dash=args.line_style, ), ), - row=i + 1, - col=1, + **row_col, ) + xname = "Time [samples]" if args.sr is None else "Time [sec]" fig.update_xaxes( - title_text=args.xname if last else "", + title_text=xname if last or args.transpose else "", showgrid=args.grid, - row=i + 1, - col=1, + **row_col, ) fig.update_yaxes( range=ylim, showgrid=args.grid, - row=i + 1, - col=1, + **row_col, ) s = e diff --git a/src/draw/sptk/draw_utils.py b/src/draw/sptk/draw_utils.py index 78ace8e1..fd1d2379 100644 --- a/src/draw/sptk/draw_utils.py +++ b/src/draw/sptk/draw_utils.py @@ -14,8 +14,10 @@ # limitations under the License. # # ------------------------------------------------------------------------ # +import argparse import struct import sys +import warnings import numpy as np @@ -113,5 +115,148 @@ def read_stdin(dim=1, dtype="d"): return asarray(data, dim=dim, dtype=dtype) +def print_warn_message(name, message): + warnings.warn(f"{name}: {message}", RuntimeWarning) + + def print_error_message(name, message): print(f"{name}: {message}!", file=sys.stderr) + + +def get_default_parser(description, input_name=None, allow_dtype=True): + parser = argparse.ArgumentParser(description=description, prefix_chars="-+") + if input_name is not None: + parser.add_argument( + metavar="infile", + dest="in_file", + default=None, + nargs="?", + type=str, + help=input_name, + ) + parser.add_argument( + metavar="outfile", + dest="out_file", + type=str, + help="figure", + ) + parser.add_argument( + "-F", + metavar="F", + dest="factor", + default=1, + type=float, + help="scale of figure", + ) + parser.add_argument( + "-W", + metavar="W", + dest="width", + default=None, + type=int, + help="width of figure [px]", + ) + parser.add_argument( + "-H", + metavar="H", + dest="height", + default=None, + type=int, + help="height of figure [px]", + ) + parser.add_argument( + "-ff", + metavar="ff", + dest="font_family", + default=None, + type=str, + help="font family", + ) + parser.add_argument( + "-fs", + metavar="fs", + dest="font_size", + default=None, + type=int, + help="font size", + ) + if allow_dtype: + parser.add_argument( + "+c", + dest="dtype", + action="store_const", + const="c", + help="(data type) char, 1byte", + ) + parser.add_argument( + "+C", + dest="dtype", + action="store_const", + const="C", + help="(data type) unsigned char, 1byte", + ) + parser.add_argument( + "+s", + dest="dtype", + action="store_const", + const="s", + help="(data type) short, 2byte", + ) + parser.add_argument( + "+S", + dest="dtype", + action="store_const", + const="S", + help="(data type) unsigned short, 2byte", + ) + parser.add_argument( + "+i", + dest="dtype", + action="store_const", + const="i", + help="(data type) int, 4byte", + ) + parser.add_argument( + "+I", + dest="dtype", + action="store_const", + const="I", + help="(data type) unsigned int, 4byte", + ) + parser.add_argument( + "+l", + dest="dtype", + action="store_const", + const="l", + help="(data type) long, 8byte", + ) + parser.add_argument( + "+L", + dest="dtype", + action="store_const", + const="L", + help="(data type) unsigned long, 8byte", + ) + parser.add_argument( + "+f", + dest="dtype", + action="store_const", + const="f", + help="(data type) float, 4byte", + ) + parser.add_argument( + "+d", + dest="dtype", + action="store_const", + const="d", + help="(data type) double, 8byte", + ) + parser.add_argument( + "+e", + dest="dtype", + action="store_const", + const="d", + help="(data type) long double, 16byte", + ) + parser.set_defaults(dtype="d") + return parser diff --git a/tools/requirements.txt b/tools/requirements.txt index ec095f80..50699eb5 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -1,4 +1,4 @@ kaleido>=0.1.0 numpy -plotly>=4.9.0,<=4.14.3 +plotly>=4.9.0 scipy