123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276 |
- #!/usr/bin/env python3
- ############################################################################
- #
- # MODULE: i.spectral
- # AUTHOR(S): Markus Neteler, 18. August 1998
- # Converted to Python by Glynn Clements
- # PURPOSE: Displays spectral response at user specified locations in
- # group or raster images
- # COPYRIGHT: (C) 1999-2013 by the GRASS Development Team
- #
- # This program is free software under the GNU General Public
- # License (>=v2). Read the file COPYING that comes with GRASS
- # for details.
- #
- #############################################################################
- #
- # this script needs gnuplot for pretty rendering
- # TODO: use PyPlot like the wxGUI Profiling tool
- #
- # written by Markus Neteler 18. August 1998
- # neteler geog.uni-hannover.de
- #
- # bugfix: 25. Nov.98/20. Jan. 1999
- # 3 March 2006: Added multiple images and group support by Francesco Pirotti - CIRGEO
- #
- # %Module
- # % description: Displays spectral response at user specified locations in group or images.
- # % keyword: imagery
- # % keyword: querying
- # % keyword: raster
- # % keyword: multispectral
- # %End
- # %option G_OPT_I_GROUP
- # % required : no
- # % guisection: Input
- # %end
- # %option G_OPT_I_SUBGROUP
- # % required : no
- # % guisection: Input
- # %end
- # %option G_OPT_R_INPUTS
- # % key: raster
- # % required : no
- # % guisection: Input
- # %end
- # %option G_OPT_M_COORDS
- # % multiple: yes
- # % required: yes
- # % guisection: Input
- # %end
- # %option G_OPT_F_OUTPUT
- # % key: output
- # % description: Name for output image (or text file for -t)
- # % guisection: Output
- # % required : no
- # %end
- # %Option
- # % key: format
- # % type: string
- # % description: Graphics format for output file
- # % options: png,eps,svg
- # % answer: png
- # % multiple: no
- # % guisection: Output
- # %End
- # %flag
- # % key: c
- # % description: Show sampling coordinates instead of numbering in the legend
- # %end
- # % flag
- # % key: g
- # % description: Use gnuplot for display
- # %end
- # % flag
- # % key: t
- # % description: output to text file
- # %end
- import os
- import atexit
- from grass.script.utils import try_rmdir
- from grass.script import core as gcore
- def cleanup():
- try_rmdir(tmp_dir)
- def write2textf(what, output):
- outf = open(output, "w")
- i = 0
- for row in enumerate(what):
- i = i + 1
- outf.write("%d, %s\n" % (i, row))
- outf.close()
- def draw_gnuplot(what, xlabels, output, img_format, coord_legend):
- xrange = 0
- for i, row in enumerate(what):
- outfile = os.path.join(tmp_dir, "data_%d" % i)
- outf = open(outfile, "w")
- xrange = max(xrange, len(row) - 2)
- for j, val in enumerate(row[3:]):
- outf.write("%d %s\n" % (j + 1, val))
- outf.close()
- # build gnuplot script
- lines = []
- if output:
- if img_format == "png":
- term_opts = "png truecolor large size 825,550"
- elif img_format == "eps":
- term_opts = "postscript eps color solid size 6,4"
- elif img_format == "svg":
- term_opts = "svg size 825,550 dynamic solid"
- else:
- gcore.fatal(_("Programmer error (%s)") % img_format)
- lines += ["set term " + term_opts, "set output '%s'" % output]
- lines += [
- "set xtics (%s)" % xlabels,
- "set grid",
- "set title 'Spectral signatures'",
- "set xrange [0.5 : %d - 0.5]" % xrange,
- "set noclabel",
- "set xlabel 'Bands'",
- "set xtics rotate by -40",
- "set ylabel 'DN Value'",
- "set style data lines",
- ]
- cmd = []
- for i, row in enumerate(what):
- if not coord_legend:
- title = "Pick " + str(i + 1)
- else:
- title = str(tuple(row[0:2]))
- x_datafile = os.path.join(tmp_dir, "data_%d" % i)
- cmd.append(" '%s' title '%s'" % (x_datafile, title))
- cmd = ",".join(cmd)
- cmd = " ".join(["plot", cmd, "with linespoints pt 779"])
- lines.append(cmd)
- plotfile = os.path.join(tmp_dir, "spectrum.gnuplot")
- plotf = open(plotfile, "w")
- for line in lines:
- plotf.write(line + "\n")
- plotf.close()
- if output:
- gcore.call(["gnuplot", plotfile])
- else:
- gcore.call(["gnuplot", "-persist", plotfile])
- def draw_linegraph(what):
- yfiles = []
- xfile = os.path.join(tmp_dir, "data_x")
- xf = open(xfile, "w")
- for j, val in enumerate(what[0][3:]):
- xf.write("%d\n" % (j + 1))
- xf.close()
- for i, row in enumerate(what):
- yfile = os.path.join(tmp_dir, "data_y_%d" % i)
- yf = open(yfile, "w")
- for j, val in enumerate(row[3:]):
- yf.write("%s\n" % val)
- yf.close()
- yfiles.append(yfile)
- sienna = "#%02x%02x%02x" % (160, 82, 45)
- coral = "#%02x%02x%02x" % (255, 127, 80)
- gp_colors = ["red", "green", "blue", "magenta", "cyan", sienna, "orange", coral]
- colors = gp_colors
- while len(what) > len(colors):
- colors += gp_colors
- colors = colors[0 : len(what)]
- gcore.run_command(
- "d.linegraph",
- x_file=xfile,
- y_file=yfiles,
- y_color=colors,
- title=_("Spectral signatures"),
- x_title=_("Bands"),
- y_title=_("DN Value"),
- )
- def main():
- group = options["group"]
- subgroup = options["subgroup"]
- raster = options["raster"]
- output = options["output"]
- coords = options["coordinates"]
- img_fmt = options["format"]
- coord_legend = flags["c"]
- gnuplot = flags["g"]
- textfile = flags["t"]
- global tmp_dir
- tmp_dir = gcore.tempdir()
- if not group and not raster:
- gcore.fatal(_("Either group= or raster= is required"))
- if group and raster:
- gcore.fatal(_("group= and raster= are mutually exclusive"))
- # -t needs an output filename
- if textfile and not output:
- gcore.fatal(_("Writing to text file requires output=filename"))
- # check if gnuplot is present
- if gnuplot and not gcore.find_program("gnuplot", "-V"):
- gcore.fatal(_("gnuplot required, please install first"))
- # get data from group listing and set the x-axis labels
- if group:
- # Parse the group list output
- if subgroup:
- s = gcore.read_command(
- "i.group", flags="g", group=group, subgroup=subgroup, quiet=True
- )
- else:
- s = gcore.read_command("i.group", flags="g", group=group, quiet=True)
- rastermaps = s.splitlines()
- else:
- # get data from list of files and set the x-axis labels
- rastermaps = raster.split(",")
- xlabels = ["'%s' %d" % (n, i + 1) for i, n in enumerate(rastermaps)]
- xlabels = ",".join(xlabels)
- # get y-data for gnuplot-data file
- what = []
- s = gcore.read_command(
- "r.what", map=rastermaps, coordinates=coords, null="0", quiet=True
- )
- if len(s) == 0:
- gcore.fatal(_("No data returned from query"))
- for line in s.splitlines():
- f = line.split("|")
- for i, v in enumerate(f):
- if v in ["", "*"]:
- f[i] = 0
- else:
- f[i] = float(v)
- what.append(f)
- # build data files
- if gnuplot:
- draw_gnuplot(what, xlabels, output, img_fmt, coord_legend)
- elif textfile:
- write2textf(what, output)
- else:
- draw_linegraph(what)
- if __name__ == "__main__":
- options, flags = gcore.parser()
- atexit.register(cleanup)
- main()
|