i.spectral.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. #!/usr/bin/env python
  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_R_INPUTS
  38. #% key: raster
  39. #% required : no
  40. #% guisection: Input
  41. #%end
  42. #%option G_OPT_M_COORDS
  43. #% multiple: yes
  44. #% required: yes
  45. #% guisection: Input
  46. #%end
  47. #%option G_OPT_F_OUTPUT
  48. #% key: output
  49. #% description: Name for output image (or text file for -t)
  50. #% guisection: Output
  51. #% required : no
  52. #%end
  53. #%Option
  54. #% key: format
  55. #% type: string
  56. #% description: Graphics format for output file
  57. #% options: png,eps,svg
  58. #% answer: png
  59. #% multiple: no
  60. #% guisection: Output
  61. #%End
  62. #%flag
  63. #% key: c
  64. #% description: Show sampling coordinates instead of numbering in the legend
  65. #%end
  66. #% flag
  67. #% key: g
  68. #% description: Use gnuplot for display
  69. #%end
  70. #% flag
  71. #% key: t
  72. #% description: output to text file
  73. #%end
  74. import os
  75. import atexit
  76. from grass.script.utils import try_rmdir
  77. from grass.script import core as gcore
  78. # i18N
  79. import gettext
  80. gettext.install('grassmods', os.path.join(os.getenv("GISBASE"), 'locale'))
  81. def cleanup():
  82. try_rmdir(tmp_dir)
  83. def write2textf(what, output):
  84. outf = open(output, 'w')
  85. i = 0
  86. for row in enumerate(what):
  87. i = i + 1
  88. outf.write("%d, %s\n" % (i, row))
  89. outf.close()
  90. def draw_gnuplot(what, xlabels, output, img_format, coord_legend):
  91. xrange = 0
  92. for i, row in enumerate(what):
  93. outfile = os.path.join(tmp_dir, 'data_%d' % i)
  94. outf = open(outfile, 'w')
  95. xrange = max(xrange, len(row) - 2)
  96. for j, val in enumerate(row[3:]):
  97. outf.write("%d %s\n" % (j + 1, val))
  98. outf.close()
  99. # build gnuplot script
  100. lines = []
  101. if output:
  102. if img_format == 'png':
  103. term_opts = "png truecolor large size 825,550"
  104. elif img_format == 'eps':
  105. term_opts = "postscript eps color solid size 6,4"
  106. elif img_format == 'svg':
  107. term_opts = "svg size 825,550 dynamic solid"
  108. else:
  109. gcore.fatal(_("Programmer error (%s)") % img_format)
  110. lines += [
  111. "set term " + term_opts,
  112. "set output '%s'" % output
  113. ]
  114. lines += [
  115. "set xtics (%s)" % xlabels,
  116. "set grid",
  117. "set title 'Spectral signatures'",
  118. "set xrange [0.5 : %d - 0.5]" % xrange,
  119. "set noclabel",
  120. "set xlabel 'Bands'",
  121. "set xtics rotate by -40",
  122. "set ylabel 'DN Value'",
  123. "set style data lines"
  124. ]
  125. cmd = []
  126. for i, row in enumerate(what):
  127. if not coord_legend:
  128. title = 'Pick ' + str(i + 1)
  129. else:
  130. title = str(tuple(row[0:2]))
  131. x_datafile = os.path.join(tmp_dir, 'data_%d' % i)
  132. cmd.append(" '%s' title '%s'" % (x_datafile, title))
  133. cmd = ','.join(cmd)
  134. cmd = ' '.join(['plot', cmd, "with linespoints pt 779"])
  135. lines.append(cmd)
  136. plotfile = os.path.join(tmp_dir, 'spectrum.gnuplot')
  137. plotf = open(plotfile, 'w')
  138. for line in lines:
  139. plotf.write(line + '\n')
  140. plotf.close()
  141. if output:
  142. gcore.call(['gnuplot', plotfile])
  143. else:
  144. gcore.call(['gnuplot', '-persist', plotfile])
  145. def draw_linegraph(what):
  146. yfiles = []
  147. xfile = os.path.join(tmp_dir, 'data_x')
  148. xf = open(xfile, 'w')
  149. for j, val in enumerate(what[0][3:]):
  150. xf.write("%d\n" % (j + 1))
  151. xf.close()
  152. for i, row in enumerate(what):
  153. yfile = os.path.join(tmp_dir, 'data_y_%d' % i)
  154. yf = open(yfile, 'w')
  155. for j, val in enumerate(row[3:]):
  156. yf.write("%s\n" % val)
  157. yf.close()
  158. yfiles.append(yfile)
  159. sienna = '#%02x%02x%02x' % (160, 82, 45)
  160. coral = '#%02x%02x%02x' % (255, 127, 80)
  161. gp_colors = ['red', 'green', 'blue', 'magenta', 'cyan', sienna, 'orange',
  162. coral]
  163. colors = gp_colors
  164. while len(what) > len(colors):
  165. colors += gp_colors
  166. colors = colors[0:len(what)]
  167. gcore.run_command('d.linegraph', x_file=xfile, y_file=yfiles,
  168. y_color=colors, title='Spectral signatures',
  169. x_title='Bands', y_title='DN Value')
  170. def main():
  171. group = options['group']
  172. raster = options['raster']
  173. output = options['output']
  174. coords = options['coordinates']
  175. img_fmt = options['format']
  176. coord_legend = flags['c']
  177. gnuplot = flags['g']
  178. textfile = flags['t']
  179. global tmp_dir
  180. tmp_dir = gcore.tempdir()
  181. if not group and not raster:
  182. gcore.fatal(_("Either group= or raster= is required"))
  183. if group and raster:
  184. gcore.fatal(_("group= and raster= are mutually exclusive"))
  185. # -t needs an output filename
  186. if textfile and not output:
  187. gcore.fatal(_("Writing to text file requires output=filename"))
  188. # check if gnuplot is present
  189. if gnuplot and not gcore.find_program('gnuplot', '-V'):
  190. gcore.fatal(_("gnuplot required, please install first"))
  191. # get data from group listing and set the x-axis labels
  192. if group:
  193. # Parse the group list output
  194. s = gcore.read_command('i.group', flags='g', group=group, quiet=True)
  195. rastermaps = s.splitlines()
  196. else:
  197. # get data from list of files and set the x-axis labels
  198. rastermaps = raster.split(',')
  199. xlabels = ["'%s' %d" % (n, i + 1) for i, n in enumerate(rastermaps)]
  200. xlabels = ','.join(xlabels)
  201. # get y-data for gnuplot-data file
  202. what = []
  203. s = gcore.read_command('r.what', map=rastermaps, coordinates=coords,
  204. null='0', quiet=True)
  205. if len(s) == 0:
  206. gcore.fatal(_('No data returned from query'))
  207. for l in s.splitlines():
  208. f = l.split('|')
  209. for i, v in enumerate(f):
  210. if v in ['', '*']:
  211. f[i] = 0
  212. else:
  213. f[i] = float(v)
  214. what.append(f)
  215. # build data files
  216. if gnuplot:
  217. draw_gnuplot(what, xlabels, output, img_fmt, coord_legend)
  218. elif textfile:
  219. write2textf(what, output)
  220. else:
  221. draw_linegraph(what)
  222. if __name__ == "__main__":
  223. options, flags = gcore.parser()
  224. atexit.register(cleanup)
  225. main()