[GRASS-SVN] r72026 - grass-addons/grass7/raster/r.out.legend

svn_grass at osgeo.org svn_grass at osgeo.org
Wed Jan 3 12:03:59 PST 2018


Author: pvanbosgeo
Date: 2018-01-03 12:03:59 -0800 (Wed, 03 Jan 2018)
New Revision: 72026

Modified:
   grass-addons/grass7/raster/r.out.legend/r.out.legend.html
   grass-addons/grass7/raster/r.out.legend/r.out.legend.py
Log:
Code cleanup
add missing options from d.legend

Modified: grass-addons/grass7/raster/r.out.legend/r.out.legend.html
===================================================================
--- grass-addons/grass7/raster/r.out.legend/r.out.legend.html	2018-01-03 17:43:19 UTC (rev 72025)
+++ grass-addons/grass7/raster/r.out.legend/r.out.legend.html	2018-01-03 20:03:59 UTC (rev 72026)
@@ -1,100 +1,100 @@
 <h2>DESCRIPTION</h2>
 
-The <em>r.out.legend</em> script provides a convenient way to 
-quickly create a smoothed legend image for floating point raster 
-maps (continuous values as opposed to categories), with the 
-dimensions and resolution required. Optionally, a histogram can be 
-added along side the legend by setting the -d flag. It is 
-furthermore possible to set the font (default is 'Arial') and font 
-size (default=10). The legend can be saved as 
-<a href="https://grass.osgeo.org/grass64/manuals/pngdriver.html">PNG</a>, 
-<a href="https://grass.osgeo.org/grass64/manuals/psdriver.html">PS</a> 
-(postscript), BMP, PPM, PDF AND SVG. The latter four are supported 
-through the Cairo driver (see Notes). The images can be used to add 
-a continuous legends in maps created in e.g., QGIS composer or as 
+The <em>r.out.legend</em> script provides a quick way to create a smoothed
+legend image for floating point raster maps (continuous values as opposed
+to categories), with the dimensions and resolution required. Optionally,
+a histogram can be added along side the legend by setting the -d flag. In
+addition, most option for d.label are available in this addon as well.
+The legend can be saved as
+<a href="https://grass.osgeo.org/grass75/manuals/pngdriver.html">PNG</a>,
+<a href="https://grass.osgeo.org/grass75/manuals/psdriver.html">PS</a>
+(postscript), BMP, PPM, PDF AND SVG. The latter four are supported
+through the Cairo driver (see Notes). The images can be used to add
+a continuous legends in maps created in e.g., QGIS composer or as
 part of a Google Earth map.
 
 <h2>NOTES</h2>
 
-The user is required to set the dimensions of the legend bar. This 
-does not include the category values, which will thus add to the 
+The user is required to set the dimensions of the legend bar. This
+does not include the category values and histogram. Both will thus add to the
 size of the output image. The size of the output image in pixels and the
 unit set by the user is given in the console (see example 1).
 
 <p>
 Note that one can use category maps as input, but <em>
-r.out.legend</em> will still create a smooth legend (by setting the 
--f flag, see <em>d.legend</em>). 
+r.out.legend</em> will still create a smooth legend (by setting the
+-f flag, see <em>d.legend</em>).
 
 <p>
-The user may create a horizontal legend by making the box wider 
-than it is tall. Note that for vertical legends labels are placed to 
-the right of the legend box. For horizontal legends the text will 
+The user may create a horizontal legend by making the box wider
+than it is tall. Note that for vertical legends labels are placed to
+the right of the legend box. For horizontal legends the text will
 be places below the legend.
 
-<p> The -d flag is used to display a histogram distribution along 
-side the legend. For vertical legends, the histogram will be placed 
-left of the legend; if horizontal, it will be placed above the 
-legend bar. The histogram is 1.75 x the width (or height if 
-horizontal) of the legend bar. This thus adds to the final width of 
-the output image. Note that the statistics are calculated on the 
-current computational region settings set by g.region. The default 
-range however covers the entire natural bounds of the input map. If 
-the histogram appears empty, check your region settings. 
+<p> The -d flag is used to display a histogram distribution along
+side the legend. For vertical legends, the histogram will be placed
+left of the legend; if horizontal, it will be placed above the
+legend bar. The histogram is 1.75 x the width (or height if
+horizontal) of the legend bar. This thus adds to the final width of
+the output image. Note that the statistics are calculated on the
+current computational region settings set by g.region. The default
+range however covers the entire natural bounds of the input map. If
+the histogram appears empty, check your region settings.
 
 <p>
-The script is a wrapper of <a href="https://grass.osgeo.org/grass71/manuals/d.mon.html">d.mon</a> 
-and <a href="https://grass.osgeo.org/grass71/manuals/d.legend.html"> d.legend</a>. 
-For detailed explanations of the different options, 
-see the manual pages of these two functions. To find out the fonts 
-available on your system, you can run <a href="d.font">d.font -l</a>. For 
-a more interactive way to generate legend images, you can also try 
-<a href="https://grass.osgeo.org/grass70/manuals/ps.map.html">ps.map</a>.
+The script is a wrapper of
+<a href="d.legend"> d.legend</a>.
+For detailed explanations of the different options,
+see the manual pages of this functions. To find out the fonts
+available on your system, you can run <a href="d.font">d.font -l</a>. For
+a more interactive way to generate legend images, you can also try
+<a href="ps.map">ps.map</a>.
 
 <p>
-With file type set to 'png', the png driver is used to create 
-the image. An alternative way to create a png image file is to set 
-as file type 'cairo' and provide an output file name with as 
-extension '.png'. This will use the cairo driver to generate the png 
-image. One advantage of the cairo driver is that it uses 
-anti-aliasing, which might give nicer results (smoother lines and 
+With file type set to 'png', the png driver is used to create
+the image. An alternative way to create a png image file is to set
+as file type 'cairo' and provide an output file name with as
+extension '.png'. This will use the cairo driver to generate the png
+image. One advantage of the cairo driver is that it uses
+anti-aliasing, which might give nicer results (smoother lines and
 numbers). Compare the output for example 1 and 4.
 
-<p> The default resolution is 300 px/inch (ppi), except when the unit is 
-set to <em>px</em>, in which case the default resolution is set to 
-96 ppi. 
+<p> The default resolution is 300 px/inch (ppi), except when the unit is
+set to <em>px</em>, in which case the default resolution is set to
+96 ppi.
 
 <p>
-It is important to realize that setting the resolution will 
-determine the height and width of your image in pixels. It does not, 
-however, set the image print resolution. Other programs, like 
-Libreoffice, Word or the QGIS print composer will therefore not know 
-the intended image print resolution. This means you will have to set the
-image size manually in the document. The exact dimention of the output
-file is given in the console.
+If the output image is in png or jpg format, the addon will attempt to set
+the print resolution of the image so that other programs, such as Libreoffice
+or Word document, know the intended size of the image. It uses the Python
+Imaging Library
+(<a href="http://www.pythonware.com/products/pil/">PIL</a>) to do so. If not
+installed this step will silently be skipped. However, note that the dimensions
+of the image (in the user-defined unit, and based on the user-defined image
+resolution) will be printed to the console.
 
 <p>
-The <em>range</em> option lets the user define the limits of the 
-legend. Note however that the color scale will remain faithful to 
+The <em>range</em> option lets the user define the limits of the
+legend. Note however that the color scale will remain faithful to
 the values as defined with r.colors.
 
 <p>
-The <a href="https://grass.osgeo.org/grass64/manuals/cairodriver.html">Cairo driver</a> 
-generates PNG, BMP, PPM, PS, PDF or SVG images 
-using the Cairo graphics library. The image format is selected from 
-the extension of the output file. For this option to work, GRASS has 
-to be configured with CAIRO support (if you compile GRASS yourself, 
-use --with-cairo when configuring GRASS). 
+The <a href="https://grass.osgeo.org/grass64/manuals/cairodriver.html">
+Cairo driver</a> generates PNG, BMP, PPM, PS, PDF or SVG images
+using the Cairo graphics library. The image format is selected from
+the extension of the output file. For this option to work, GRASS has
+to be configured with CAIRO support (if you compile GRASS yourself,
+use --with-cairo when configuring GRASS).
 
 <h2>EXAMPLES</h2>
 
-The raster layers in the examples below are from the 
-<a href="https://grass.osgeo.org/download/sample-data/">North Carolina 
-sample data set</a>. 
+The raster layers in the examples below are from the
+<a href="https://grass.osgeo.org/download/sample-data/">North Carolina
+sample data set</a>.
 
 <h3>Example 1</h3>
 
-Note that because width > height, the legend is 
+Note that because width > height, the legend is
 printed horizontal, with the labels below the legend bar.
 
 <div class="code"><pre>
@@ -132,7 +132,7 @@
 
 <h3>Example 3</h3>
 
-Like example 1, but without the raster values 
+Like example 1, but without the raster values
 printed (done by setting fontsize to 0).
 
 <div class="code"><pre>
@@ -144,7 +144,7 @@
 
 <h3>Example 4</h3>
 
-Like example 1, but using the cairo driver to create the png image. 
+Like example 1, but using the cairo driver to create the png image.
 The difference is that the cairo driver uses anti-aliasing.
 
 <div class="code"><pre>
@@ -169,8 +169,8 @@
 
 <h3>Example 5</h3>
 
-Like example 4, but adding a histogram. Note that the histogram adds 
-to the size of the image (while the dimensions of the bar remain the 
+Like example 4, but adding a histogram. Note that the histogram adds
+to the size of the image (while the dimensions of the bar remain the
 same as in the previous example).
 
 <div class="code"><pre>
@@ -195,9 +195,9 @@
 
 <h2>SEE ALSO</h2>
 
-<em><a href="d.mon.html">d.mon</a></em>, 
-<em><a href="d.legend.html">d.legend</a></em>, 
-<em><a href="d.font.html">d.font</a></em>,
+<em><a href="d.mon">d.mon</a></em>,
+<em><a href="d.legend">d.legend</a></em>,
+<em><a href="d.font">d.font</a></em>,
 <em><a href="d.out.file.html">d.out.file</a></em>,
 <em><a href="ps.map.html">ps.map</a></em>,
 <em><a href="r.category.trim">r.category.trim</a></em>

Modified: grass-addons/grass7/raster/r.out.legend/r.out.legend.py
===================================================================
--- grass-addons/grass7/raster/r.out.legend/r.out.legend.py	2018-01-03 17:43:19 UTC (rev 72025)
+++ grass-addons/grass7/raster/r.out.legend/r.out.legend.py	2018-01-03 20:03:59 UTC (rev 72026)
@@ -8,9 +8,7 @@
 # DESCRIPTION:  Export the legend of a raster as image, which can be used
 #               in e.g., the map composer in QGIS.
 #
-# COPYRIGHT: (C) 2015 Paulo van Breugel
-#            http://ecodiv.org
-#            http://pvanb.wordpress.com/
+# COPYRIGHT: (C) 2014-2017 by Paulo van Breugel and the GRASS Development Team
 #
 #            This program is free software under the GNU General Public
 #            License (>=v2). Read the file COPYING that comes with GRASS
@@ -19,7 +17,7 @@
 ########################################################################
 #
 #%Module
-#% description: Create and export image file with legend of a raster map
+#% description: Create an image file showing the legend of a raster map
 #% keyword: raster
 #% keyword: color
 #% keyword: color table
@@ -32,7 +30,7 @@
 
 #%option G_OPT_F_OUTPUT
 #% key:file
-#% description: Name of the output file
+#% description: Name of the output file (including file extension)
 #% key_desc: name
 #%end
 
@@ -42,6 +40,7 @@
 #% description: File type
 #% key_desc: extension
 #% options: png,ps,cairo
+#% answer: cairo
 #% required: yes
 #% multiple: no
 #%end
@@ -78,12 +77,8 @@
 #%end
 
 #%option G_OPT_CN
-#% key: bgcolor
-#% description: background colour
-#% key_desc: name
-#% required: no
-#% answer: none
 #% guisection: Image settings
+#% answer: white
 #%end
 
 #------------------------------------------------------------------------------
@@ -108,6 +103,26 @@
 #%end
 
 #%option
+#% key: label_values
+#% type: string
+#% key_desc: float
+#% description: Specific values to draw ticks
+#% required: no
+#% multiple: yes
+#% guisection: Extra options
+#%end
+
+#%option
+#% key: label_step
+#% type: string
+#% key_desc: float
+#% description: Display label every step
+#% required: no
+#% multiple: no
+#% guisection: Extra options
+#%end
+
+#%option
 #% key: digits
 #% type: integer
 #% description: Maximum number of digits for raster value display
@@ -128,6 +143,12 @@
 #% guisection: Extra options
 #%end
 
+#%flag:
+#% key: t
+#% description: Draw legend ticks for labels
+#% guisection: Extra options
+#%end
+
 #------------------------------------------------------------------------------
 
 #%option
@@ -150,169 +171,218 @@
 #% guisection: Font settings
 #%end
 
-#=======================================================================
-## General
-#=======================================================================
+# =======================================================================
+# General
+# =======================================================================
 
 # import libraries
 import os
 import sys
 import math
 import grass.script as grass
+from grass.pygrass.modules import Module
+from grass.script.utils import parse_key_val
+import imp
+try:
+    imp.find_module('PIL')
+    found = True
+    from PIL import Image
+except ImportError:
+    found = False
 
-# Check if running in GRASS
-if not os.environ.has_key("GISBASE"):
-    grass.message("You must be in GRASS GIS to run this program.")
-    sys.exit(1)
 
-# Check if layers exist
-def CheckLayer(raster):
-    ffile = grass.find_file(raster, element = 'cell')
-    if ffile['fullname'] == '':
-        grass.fatal("The layer " + raster + " does not exist.")
-
 # main function
 def main():
 
-    # Variables / parameters
-    outputfile    = options['file']
-    filetype      = options['filetype']
-    unit          = options['unit']
-    resol         = options['resolution']
+    # parameters - file name and extension
+    outputfile = options['file']
+    ext = outputfile.split('.')
+    if len(ext) == 1:
+        grass.fatal("Please provide the file extension of the output file")
+    filetype = options['filetype']
+    if filetype == 'cairo':
+        allowed = ('.png', '.bmp', 'ppm', 'pdf', 'ps', 'svg')
+        if not outputfile.lower().endswith(allowed):
+            grass.fatal("Unknown display driver <{}>".format(ext[1]))
+    if filetype == "ps" and not ext[1] == "ps":
+        grass.fatal("The file type <{}> does not match the file extension <"
+                    "{}>".format(filetype, ext[1]))
+    if filetype == "png" and not ext[1] == "png":
+        grass.fatal("The file type <{}> does not match the file extension <"
+                    "{}>".format(filetype, ext[1]))
+
+    # parameters - image settings
+    unit = options['unit']
+    resol = options['resolution']
     if resol == '':
-        if unit=='px':
-            resol=96
+        if unit == 'px':
+            resol = 96
         else:
-            resol=300
+            resol = 300
     else:
         resol = int(resol)
-    dimensions    = options['dimensions']
+    dimensions = options['dimensions']
     width, height = dimensions.split(",")
-    bgcolor       = options['bgcolor']
-    inmap         = options['raster']
-    labelnum      = options['labelnum']
-    val_range     = options['range']
-    font          = options['font']
-    fontsize      = int(options['fontsize'])
-    digits        = int(options['digits'])
-    flag_f        = flags['f']
-    flag_d        = flags['d']
+    bgcolor = options['color']
+    inmap = options['raster']
+    labelnum = options['labelnum']
+    vr = options['range']
+    font = options['font']
+    fontsize = int(options['fontsize'])
+    digits = int(options['digits'])
+    labval = options['label_values']
+    labstep = options['label_step']
 
-    # Check if input layer exists
-    CheckLayer(inmap)
+    # flag parameters
+    flag_f = flags['f']
+    flag_d = flags['d']
+    flag_t = flags['t']
+    if flag_t:
+        tagmargin = 9
+    else:
+        tagmargin = 4
 
     # Compute output size of legend bar in pixels
-    if unit=='cm':
+    if unit == 'cm':
         bw = math.ceil(float(width)/2.54*float(resol))
         bh = math.ceil(float(height)/2.54*float(resol))
-    elif unit=='mm':
+    elif unit == 'mm':
         bw = math.ceil(float(width)/25.4*float(resol))
         bh = math.ceil(float(height)/25.4*float(resol))
-    elif unit=='inch':
+    elif unit == 'inch':
         bw = math.ceil(float(width)*float(resol))
         bh = math.ceil(float(height)*float(resol))
-    elif unit=="px":
-        bw=float(width)
-        bh=float(height)
+    elif unit == "px":
+        bw = float(width)
+        bh = float(height)
     else:
         grass.error('Unit must be inch, cm, mm or px')
 
     # Add size of legend to w or h, if flag_d is set
+    # Add size of tics
     if flag_d:
-        if float(height)>float(width):
-            w = bw * 2.75 + 4
-            h = bh + 4
-        else:
-           h  = bh * 2.75 + 4
-           w = bw + 4
+        histmargin = 2.75
     else:
+        histmargin = 1
+    if float(height) > float(width):
+        w = bw * histmargin + tagmargin
+        h = bh + 4
+    else:
+        h = bh * histmargin + tagmargin
         w = bw + 4
-        h = bh + 4
 
     # Determine image width and height
-    if fontsize==0:
-        iw = w; ih = h; fz = 1
-        mw = 2 / w * 100
-        mh = 2 / h * 100
-        at = str(mw) + "," + str(100-mw) + "," + str(mh) + "," + str(100-mh)
+    if fontsize == 0:
+        fz = 1
     else:
         fz = round(float(fontsize) * (float(resol)/72.272))
 
-        # Allow for extra space at left (low) side if number with digits
-        maprange = grass.raster_info(inmap)
-        maxval = round(maprange['max'],digits)
-        if maxval<1:
-            maxl=len(str(maxval)) -1
-        else:
-            maxl=len(str(maxval)) - 2
+    # Determine space at left and right (or top and bottom)
+    # based on fontsize (fz) and number of digits
+    maprange = grass.raster_info(inmap)
+    maxval = round(maprange['max'], digits)
+    minval = round(maprange['min'], digits)
+    if maxval < 1:
+        maxl = len(str(maxval)) - 1
+    else:
+        maxl = len(str(maxval)) - 2
+    if minval < 1:
+        minl = len(str(minval)) - 1
+    else:
+        minl = len(str(minval)) - 2
+    margin_left = 0.5 * minl * fz
+    margin_right = 0.5 * maxl * fz
 
-        # Page width and height + position bar
-        if float(height)>float(width):
-            iw = w + fz * maxl; ih = h
-            if flag_d:
-                mw = (2 + (bw * 1.75)) / iw * 100
-                mh = 2 / ih * 100
-            else:
-                mw = 2 / iw * 100
-                mh = 2 / ih * 100
-            at = str(mh) + "," + str(100-mh) + "," + str(mw) + "," + str((100*w/iw)-1)
+    # Page width and height (iw, ih)
+    # Position bar in percentage (*margin)
+    # Here we take into account the extra space for the numbers and ticks
+
+    if float(height) > float(width):
+        iw = w + fz * maxl
+        ih = h + margin_left + margin_right
+        bmargin = str(margin_left / ih * 100)
+        tmargin = str(100 - (margin_right / ih * 100))
+        rmargin = str(100 * (w - tagmargin) / iw - 1)
+        if flag_d:
+            lmargin = str((2 + (bw * 1.75)) / iw * 100)
         else:
-            minval = round(maprange['min'],digits)
-            margin_left = 0.5 * (len(str(minval)) - 1)
-            margin_right = 0.5 * maxl
-            iw = w + fz * (margin_left + margin_right)
-            ih = h + fz * 1.5
-            if flag_d:
-                mh = (2 + (bh * 1.75)) / ih * 100
-                mw = 2 / iw * 100
-            else:
-                mw = 2 / w * 100
-                mh = 2 / h * 100
-            at = str(100 - (100*h/ih)) + "," + str(100-mh) + "," + \
-            str((100 * fz * margin_left / iw)) + "," + \
-            str(100 - (100 * fz * margin_right / iw))
+            lmargin = str(2 / iw * 100)
+    else:
+        iw = w + margin_left + margin_right
+        ih = h + fz * 1.5
+        bmargin = str((2 + tagmargin + fz * 1.5) / ih * 100)
+        if flag_d:
+            tmargin = str(100 - (2 + (bh * 1.75)) / ih * 100)
+        else:
+            tmargin = str(100 - 2 / ih * 100)
+        lmargin = str(margin_left / iw * 100)
+        rmargin = str(100 - margin_right / iw * 100)
+    at = (bmargin, tmargin, lmargin, rmargin)
 
-    # Open file connection, set font, write legend and close file
-    grass.run_command("d.mon", start=filetype, output=outputfile, width=iw, height=ih,
-                      resolution=1, bgcolor=bgcolor)
-    if flag_f and fontsize==0:
-        flag='cfsv'
+    # Open file connection, set font
+    os.environ['GRASS_RENDER_IMMEDIATE'] = filetype
+    os.environ['GRASS_RENDER_FILE'] = outputfile
+    os.environ['GRASS_RENDER_HEIGHT'] = str(ih)
+    os.environ['GRASS_RENDER_WIDTH'] = str(iw)
+    if bgcolor == 'none':
+        os.environ['GRASS_RENDER_TRANSPARENT'] = "TRUE"
+    else:
+        os.environ['GRASS_RENDER_BACKGROUNDCOLOR'] = bgcolor
+    if flag_f and fontsize == 0:
+        flag = 'cfsv'
     elif flag_f:
-        flag='fsv'
-    elif fontsize==0:
-        flag='csv'
+        flag = 'fsv'
+    elif fontsize == 0:
+        flag = 'csv'
     else:
-        flag='sv'
+        flag = 'sv'
     if flag_d:
-        flag=flag + 'd'
-    if val_range=='':
-        grass.run_command("d.legend", flags=flag, raster=inmap, font=font,
-                      at=at, fontsize=fz, labelnum=labelnum)
-    else:
-        grass.run_command("d.legend", flags=flag, raster=inmap, font=font,
-                      at=at, fontsize=fz, labelnum=labelnum, range=val_range)
+        flag = flag + 'd'
+    if flag_t:
+        flag = flag + 't'
 
-    grass.run_command("d.mon", flags="r", stop=filetype)
-    grass.info("----------------------------\n")
-    grass.info("File saved as " + outputfile)
-    grass.info("The image dimensions are:\n")
-    grass.info(str(int(iw)) + "px wide and " + str(int(ih)) + "px heigh\n")
-    if unit=='inch':
-        wr = iw/resol
-        hr = ih/resol
-    elif unit=='cm':
-        wr = iw/resol*2.54
-        hr = ih/resol*2.54
-    elif unit=='mm':
-        wr = iw/resol*2.54*10
-        hr = ih/resol*2.54*10
+    # Write legend with various options
+    d_legend = Module("d.legend", flags=flag, raster=inmap, font=font,
+                      at=at, fontsize=fz, labelnum=labelnum, run_=False)
+    if vr:
+        val_range = map(float, vr.split(','))
+        d_legend.inputs.range = val_range
+    if labval:
+        label_values = map(float, labval.split(','))
+        d_legend.inputs.label_values = label_values
+    if labstep:
+        label_step = float(labstep)
+        d_legend.inputs.label_step = label_step
+    d_legend.run()
+
+    # Set image resolution
+    if found and outputfile.lower().endswith(('.png', '.bmp')):
+        im = Image.open(outputfile)
+        im.save(outputfile, dpi=(resol, resol))
+
+    # Provide informatie about image on standard output
+    grass.message("----------------------------\n")
+    grass.message("File saved as {}".format(outputfile))
+    grass.message("The image dimensions are:\n")
+    grass.message("{} px wide and {} px heigh\n".format(str(int(iw)),
+                  str(int(ih))))
+    if unit == 'inch':
+        wr = round(iw/resol, 3)
+        hr = round(ih/resol, 3)
+    elif unit == 'cm':
+        wr = round(iw/resol*2.54, 3)
+        hr = round(ih/resol*2.54, 3)
+    elif unit == 'mm':
+        wr = round(iw/resol*2.54*10, 3)
+        hr = round(ih/resol*2.54*10, 3)
     else:
         wr = "same"
     if wr != "same":
-        grass.info("at a resolution of " + str(resol) + " ppi this is:")
-        grass.info(str(wr) + " " + unit + " x " + str(hr) + " " + unit + "\n")
-    grass.info("----------------------------\n")
+        grass.message("at a resolution of {} ppi this is:".format(str(resol)))
+        grass.message("{0} {2} x {1} {2}\n".format(str(wr), str(hr), unit))
+    grass.message("----------------------------\n")
 
+
 if __name__ == "__main__":
     options, flags = grass.parser()
     sys.exit(main())



More information about the grass-commit mailing list