i.spectral.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #!/usr/bin/env python3
  2. ############################################################################
  3. #
  4. # MODULE: i.spectral
  5. # AUTHOR(S): Markus Neteler, 18. August 1998
  6. # Converted to Python by Glynn Clements
  7. # PURPOSE: Displays spectral response at user specified locations in
  8. # group or raster images
  9. # COPYRIGHT: (C) 1999-2013 by the GRASS Development Team
  10. #
  11. # This program is free software under the GNU General Public
  12. # License (>=v2). Read the file COPYING that comes with GRASS
  13. # for details.
  14. #
  15. #############################################################################
  16. #
  17. # this script needs gnuplot for pretty rendering
  18. # TODO: use PyPlot like the wxGUI Profiling tool
  19. #
  20. # written by Markus Neteler 18. August 1998
  21. # neteler geog.uni-hannover.de
  22. #
  23. # bugfix: 25. Nov.98/20. Jan. 1999
  24. # 3 March 2006: Added multiple images and group support by Francesco Pirotti - CIRGEO
  25. #
  26. # %Module
  27. # % description: Displays spectral response at user specified locations in group or images.
  28. # % keyword: imagery
  29. # % keyword: querying
  30. # % keyword: raster
  31. # % keyword: multispectral
  32. # %End
  33. # %option G_OPT_I_GROUP
  34. # % required : no
  35. # % guisection: Input
  36. # %end
  37. # %option G_OPT_I_SUBGROUP
  38. # % required : no
  39. # % guisection: Input
  40. # %end
  41. # %option G_OPT_R_INPUTS
  42. # % key: raster
  43. # % required : no
  44. # % guisection: Input
  45. # %end
  46. # %option G_OPT_M_COORDS
  47. # % multiple: yes
  48. # % required: yes
  49. # % guisection: Input
  50. # %end
  51. # %option G_OPT_F_OUTPUT
  52. # % key: output
  53. # % description: Name for output image (or text file for -t)
  54. # % guisection: Output
  55. # % required : no
  56. # %end
  57. # %Option
  58. # % key: format
  59. # % type: string
  60. # % description: Graphics format for output file
  61. # % options: png,eps,svg
  62. # % answer: png
  63. # % multiple: no
  64. # % guisection: Output
  65. # %End
  66. # %flag
  67. # % key: c
  68. # % description: Show sampling coordinates instead of numbering in the legend
  69. # %end
  70. # % flag
  71. # % key: g
  72. # % description: Use gnuplot for display
  73. # %end
  74. # % flag
  75. # % key: t
  76. # % description: output to text file
  77. # %end
  78. import os
  79. import atexit
  80. from grass.script.utils import try_rmdir
  81. from grass.script import core as gcore
  82. def cleanup():
  83. try_rmdir(tmp_dir)
  84. def write2textf(what, output):
  85. outf = open(output, "w")
  86. i = 0
  87. for row in enumerate(what):
  88. i = i + 1
  89. outf.write("%d, %s\n" % (i, row))
  90. outf.close()
  91. def draw_gnuplot(what, xlabels, output, img_format, coord_legend):
  92. xrange = 0
  93. for i, row in enumerate(what):
  94. outfile = os.path.join(tmp_dir, "data_%d" % i)
  95. outf = open(outfile, "w")
  96. xrange = max(xrange, len(row) - 2)
  97. for j, val in enumerate(row[3:]):
  98. outf.write("%d %s\n" % (j + 1, val))
  99. outf.close()
  100. # build gnuplot script
  101. lines = []
  102. if output:
  103. if img_format == "png":
  104. term_opts = "png truecolor large size 825,550"
  105. elif img_format == "eps":
  106. term_opts = "postscript eps color solid size 6,4"
  107. elif img_format == "svg":
  108. term_opts = "svg size 825,550 dynamic solid"
  109. else:
  110. gcore.fatal(_("Programmer error (%s)") % img_format)
  111. lines += ["set term " + term_opts, "set output '%s'" % output]
  112. lines += [
  113. "set xtics (%s)" % xlabels,
  114. "set grid",
  115. "set title 'Spectral signatures'",
  116. "set xrange [0.5 : %d - 0.5]" % xrange,
  117. "set noclabel",
  118. "set xlabel 'Bands'",
  119. "set xtics rotate by -40",
  120. "set ylabel 'DN Value'",
  121. "set style data lines",
  122. ]
  123. cmd = []
  124. for i, row in enumerate(what):
  125. if not coord_legend:
  126. title = "Pick " + str(i + 1)
  127. else:
  128. title = str(tuple(row[0:2]))
  129. x_datafile = os.path.join(tmp_dir, "data_%d" % i)
  130. cmd.append(" '%s' title '%s'" % (x_datafile, title))
  131. cmd = ",".join(cmd)
  132. cmd = " ".join(["plot", cmd, "with linespoints pt 779"])
  133. lines.append(cmd)
  134. plotfile = os.path.join(tmp_dir, "spectrum.gnuplot")
  135. plotf = open(plotfile, "w")
  136. for line in lines:
  137. plotf.write(line + "\n")
  138. plotf.close()
  139. if output:
  140. gcore.call(["gnuplot", plotfile])
  141. else:
  142. gcore.call(["gnuplot", "-persist", plotfile])
  143. def draw_linegraph(what):
  144. yfiles = []
  145. xfile = os.path.join(tmp_dir, "data_x")
  146. xf = open(xfile, "w")
  147. for j, val in enumerate(what[0][3:]):
  148. xf.write("%d\n" % (j + 1))
  149. xf.close()
  150. for i, row in enumerate(what):
  151. yfile = os.path.join(tmp_dir, "data_y_%d" % i)
  152. yf = open(yfile, "w")
  153. for j, val in enumerate(row[3:]):
  154. yf.write("%s\n" % val)
  155. yf.close()
  156. yfiles.append(yfile)
  157. sienna = "#%02x%02x%02x" % (160, 82, 45)
  158. coral = "#%02x%02x%02x" % (255, 127, 80)
  159. gp_colors = ["red", "green", "blue", "magenta", "cyan", sienna, "orange", coral]
  160. colors = gp_colors
  161. while len(what) > len(colors):
  162. colors += gp_colors
  163. colors = colors[0 : len(what)]
  164. gcore.run_command(
  165. "d.linegraph",
  166. x_file=xfile,
  167. y_file=yfiles,
  168. y_color=colors,
  169. title=_("Spectral signatures"),
  170. x_title=_("Bands"),
  171. y_title=_("DN Value"),
  172. )
  173. def main():
  174. group = options["group"]
  175. subgroup = options["subgroup"]
  176. raster = options["raster"]
  177. output = options["output"]
  178. coords = options["coordinates"]
  179. img_fmt = options["format"]
  180. coord_legend = flags["c"]
  181. gnuplot = flags["g"]
  182. textfile = flags["t"]
  183. global tmp_dir
  184. tmp_dir = gcore.tempdir()
  185. if not group and not raster:
  186. gcore.fatal(_("Either group= or raster= is required"))
  187. if group and raster:
  188. gcore.fatal(_("group= and raster= are mutually exclusive"))
  189. # -t needs an output filename
  190. if textfile and not output:
  191. gcore.fatal(_("Writing to text file requires output=filename"))
  192. # check if gnuplot is present
  193. if gnuplot and not gcore.find_program("gnuplot", "-V"):
  194. gcore.fatal(_("gnuplot required, please install first"))
  195. # get data from group listing and set the x-axis labels
  196. if group:
  197. # Parse the group list output
  198. if subgroup:
  199. s = gcore.read_command(
  200. "i.group", flags="g", group=group, subgroup=subgroup, quiet=True
  201. )
  202. else:
  203. s = gcore.read_command("i.group", flags="g", group=group, quiet=True)
  204. rastermaps = s.splitlines()
  205. else:
  206. # get data from list of files and set the x-axis labels
  207. rastermaps = raster.split(",")
  208. xlabels = ["'%s' %d" % (n, i + 1) for i, n in enumerate(rastermaps)]
  209. xlabels = ",".join(xlabels)
  210. # get y-data for gnuplot-data file
  211. what = []
  212. s = gcore.read_command(
  213. "r.what", map=rastermaps, coordinates=coords, null="0", quiet=True
  214. )
  215. if len(s) == 0:
  216. gcore.fatal(_("No data returned from query"))
  217. for line in s.splitlines():
  218. f = line.split("|")
  219. for i, v in enumerate(f):
  220. if v in ["", "*"]:
  221. f[i] = 0
  222. else:
  223. f[i] = float(v)
  224. what.append(f)
  225. # build data files
  226. if gnuplot:
  227. draw_gnuplot(what, xlabels, output, img_fmt, coord_legend)
  228. elif textfile:
  229. write2textf(what, output)
  230. else:
  231. draw_linegraph(what)
  232. if __name__ == "__main__":
  233. options, flags = gcore.parser()
  234. atexit.register(cleanup)
  235. main()