Exemplo n.º 1
0
def polygon_annotation(tmpdir, psfile, extent, j_opt, ok_opt, annotate):
    """Polygon annotation.

    tmpdir   a temporary scratch directory
    psfile   output postscript file
    extent   extent of the map
    j_opt    GMT -J option string (unused!)
    ok_opt   GMT -O and -K option string
    annotate the annotation data:
             ('polygon', ((lon,lat),(lon',lat'),...), <kwargs>)

    By default the polygon will be closed.

    The optional <kwargs> will be a dictionary of extra parameters,
    such as line width, fill colour, etc.  The dictionary will be optional.

    """

    # set default polygon attributes
    linewidth = 1.0
    linecolour = '0/0/0'
    fillcolour = None
    l_opt = '-L'

    # unpack the annotate command object
    try:
        (_, points, kwargs) = annotate
    except ValueError:
        (_, points) = annotate
        kwargs = {}

    # set polygon attributes from kwargs
    linewidth = kwargs.get('linewidth', linewidth)
    linecolour = kwargs.get('linecolour', linecolour)
    fillcolour = kwargs.get('fillcolour', fillcolour)
    if kwargs.get('noclose', False):
        l_opt = ''

    # unpack extent, get -R option
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # file we fill with annotation text
    txt_file = os.path.join(tmpdir, 'polygon.txt')

    # write polygon data to the text file
    fd = open(txt_file, 'w')
    for (lon, lat) in points:
        fd.write('%f %f\n' % (lon, lat))
    fd.close()

    # do GMT command
    w_opt = '-W%.2f,%s' % (linewidth, linecolour)
    g_opt = ''
    if fillcolour:
        g_opt = '-G%s' % fillcolour
    cmd = ('psxy %s %s %s %s %s %s %s >> %s'
           % (txt_file, j_opt, r_opt, ok_opt, l_opt, w_opt, g_opt, psfile))
    util.do_cmd(cmd)
def polygon_annotation(tmpdir, psfile, extent, j_opt, ok_opt, annotate):
    """Polygon annotation.

    tmpdir   a temporary scratch directory
    psfile   output postscript file
    extent   extent of the map
    j_opt    GMT -J option string (unused!)
    ok_opt   GMT -O and -K option string
    annotate the annotation data:
             ('polygon', ((lon,lat),(lon',lat'),...), <kwargs>)

    By default the polygon will be closed.

    The optional <kwargs> will be a dictionary of extra parameters,
    such as line width, fill colour, etc.  The dictionary will be optional.

    """

    # set default polygon attributes
    linewidth = 1.0
    linecolour = '0/0/0'
    fillcolour = None
    l_opt = '-L'

    # unpack the annotate command object
    try:
        (_, points, kwargs) = annotate
    except ValueError:
        (_, points) = annotate
        kwargs = {}

    # set polygon attributes from kwargs
    linewidth = kwargs.get('linewidth', linewidth)
    linecolour = kwargs.get('linecolour', linecolour)
    fillcolour = kwargs.get('fillcolour', fillcolour)
    if kwargs.get('noclose', False):
        l_opt = ''

    # unpack extent, get -R option
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # file we fill with annotation text
    txt_file = os.path.join(tmpdir, 'polygon.txt')

    # write polygon data to the text file
    fd = open(txt_file, 'w')
    for (lon, lat) in points:
        fd.write('%f %f\n' % (lon, lat))
    fd.close()

    # do GMT command
    w_opt = '-W%.2f,%s' % (linewidth, linecolour)
    g_opt = ''
    if fillcolour:
        g_opt = '-G%s' % fillcolour
    cmd = ('psxy %s %s %s %s %s %s %s >> %s' %
           (txt_file, j_opt, r_opt, ok_opt, l_opt, w_opt, g_opt, psfile))
    util.do_cmd(cmd)
def generated_annotation(tmpdir, psfile, extent, mapsize, jok_opt):
    """
    Place 'generated at ...'  annotation on a GMT graph.

    tmpdir    is the path to a temporary scratch directory
    psfile    path to the POSTSCRIPT file to write to
    extent    the map extent ()
    mapsize   notional mapsize (cm)
    jok_opt   the GMT -J, -O and -K options string

    """

    # file we fill with annotation text
    txt_file = os.path.join(tmpdir, 'data.txt')

    # get string we are going to use
    ann_str = time.strftime('@:4:Generated at %H:%M:%S on %d %b %Y')

    # figure out where we are going to put the annotation
    # -1.0c from origin, -1.0c down
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    vert_deg = (ur_lat - ll_lat)
    offset_lon = ll_lon - (vert_deg / mapsize) * 2.0
    offset_lat = ll_lat - (vert_deg / mapsize) * 2.0

    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # create the annotation text file
    ann_hdr = '%f %f 6 0 0 bl ' % (offset_lon, offset_lat)
    fd = open(txt_file, 'w')
    fd.write(ann_hdr)
    fd.write(ann_str)
    fd.close()

    # annotate the plot
    cmd = 'pstext %s %s %s -N >> %s' % (txt_file, r_opt, jok_opt, psfile)
    util.do_cmd(cmd)
Exemplo n.º 4
0
def generated_annotation(tmpdir, psfile, extent, mapsize, jok_opt):
    """
    Place 'generated at ...'  annotation on a GMT graph.

    tmpdir    is the path to a temporary scratch directory
    psfile    path to the POSTSCRIPT file to write to
    extent    the map extent ()
    mapsize   notional mapsize (cm)
    jok_opt   the GMT -J, -O and -K options string

    """

    # file we fill with annotation text
    txt_file = os.path.join(tmpdir, 'data.txt')

    # get string we are going to use
    ann_str = time.strftime('@:4:Generated at %H:%M:%S on %d %b %Y')

    # figure out where we are going to put the annotation
    # -1.0c from origin, -1.0c down
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    vert_deg = (ur_lat - ll_lat)
    offset_lon = ll_lon - (vert_deg/mapsize)*2.0
    offset_lat = ll_lat - (vert_deg/mapsize)*2.0

    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # create the annotation text file
    ann_hdr = '%f %f 6 0 0 bl ' % (offset_lon, offset_lat)
    fd = open(txt_file, 'w')
    fd.write(ann_hdr)
    fd.write(ann_str)
    fd.close()

    # annotate the plot
    cmd = 'pstext %s %s %s -N >> %s' % (txt_file, r_opt, jok_opt, psfile)
    util.do_cmd(cmd)
def plot_gmt_xyz_contour(data, output_file, title=None,
                         np_posn=None, s_posn=None,
                         cb_label=None, cb_steps=None,
                         colourmap=None, annotate=[], linewidth=1.0,
                         show_graph=False, map_extent=None, 
                         annot_lat = '30m', grid_lat = '30m',
                         annot_lon = '30m', grid_lon = '30m'):
    """A function to take XYZ data and plot contours onto a GMT map.
    
    data         an iterable of values in xyz format (lon, lat, val)
    output_file  path to file that should be generated (*.png, *.eps, etc)
    title        string used to title the plot
    np_posn      code string for north pointer placement, one of:
                     'C'   - centre of plot
                     'NE'  - inside plot, northeast corner
                     'CE'  - inside plot, centre of east edge
                     'NNE' - outside plot, north of NE corner
                     'ENE' - outside plot, east of NE corner
                      etc (see the documentation for 'placement')
    s_posn       code string for scale placement
                     see examples for 'np_posn' above
    cb_label     string containing the label text for the colorbar
                 (if not supplied, no colourbar)
    cb_steps     if supplied is a sequence of discrete values at
                 the colour changes
    colourmap    string containing name of required colormap
                 this could be a GMT name or a local name
    annotate     list of user annotations:
                     if None, no user or system annotations
                     if [],   only system annotations
                     else system and user annotations
    linewidth    width of countour lines in pixels
    show_graph   if True try to display final image in system-independant way
    map_extent   set the extent of the displayed map if supplied
                 (get extent from data if not supplied)
    annot_lat    Spacing in minutes for latitude annotations (e.g. 30m = 0.5 degress) 
    grid_lat     Spacing in minutes for latitude grid lines (e.g. 30m = 0.5 degress) 
    annot_lon    Spacing in minutes for longitude annotations (e.g. 30m = 0.5 degress) 
    grid_lon     Spacing in minutes for longitude grid lines (e.g. 30m = 0.5 degress) 
    """

    # create a scratch directory for ephemeral files
    tmp_dir = tempfile.mkdtemp(prefix='plot_gmt_xyz_contour_')

    # set up the GMT default values
    util.set_gmt_defaults(tmp_dir)

    # handle optional parameters
    if title is None:
        title = ''

    # if no colourmap supplied, use default
    c_map = ColourMap
    if colourmap is not None:
        c_map = colourmap
    if not os.path.exists(c_map):
        c_map = util.get_colourmap(c_map)
    

    # get maximum and minimum values
    max_val = util.max_nan(data[:,2])
    min_val = util.min_nan(data[:,2])

    # get extent of data
    if map_extent:
        extent = map_extent
    else:
        extent = ugxe.get_extent(data, margin=0)
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # set the -J option for Mercator projection
    j_opt = '-JM%fc' % cfg.MapWidthCentimetres

    # write a GMT XYZ file (required by GMT)
    my_xyz_file = os.path.join(tmp_dir, 'data.xyz')
    num.savetxt(my_xyz_file, data)

    # generate CPT file
    my_cpt_file = os.path.join(tmp_dir, 'data.cpt')
    if cb_steps is None:
        cb_steps = []
    if len(cb_steps) > 0:
        util.make_discrete_cpt(my_cpt_file, c_map, cb_steps)
    else:
        (start, stop, step) = util.get_scale_min_max_step(max_val, min_val)
        if os.path.exists(c_map):
            cm = c_map
        else:
            cm = util.get_colourmap(c_map)
        util.do_cmd('makecpt -C%s.cpt -T%f/%f/%f > %s'
                    % (cm, start, stop, step, my_cpt_file))

    # think of a postscript filename for plot output
    my_ps_file = os.path.join(tmp_dir, 'data.ps')

    # linewidth checking - if width < 1.0, no lines
    w_opt = '-W%.1f/0' % linewidth
    if linewidth < 1.0:
        w_opt = '-W+1'

    
    #Apply blockmean to avoid aliasing short wavelengths
    my_grd_file = os.path.join(tmp_dir, 'temp.grd')
    my_grd_file2 = os.path.join(tmp_dir, 'temp2.grd')
    my_grd_file3 = os.path.join(tmp_dir, 'temp3.grd')
    my_mask_file = os.path.join(tmp_dir, 'mask.grd')
    my_hzd_file = os.path.join(tmp_dir, 'hazard.grd')
    print my_grd_file    
    print my_grd_file2 
    
    
    util.do_cmd('surface %s -G%s %s -I0.001 -T0.5'
                % (my_xyz_file, my_grd_file,r_opt))
    util.do_cmd('grdimage %s -K -Q -C%s %s %s > %s'
                % (my_grd_file, my_cpt_file, r_opt, j_opt,
                   my_ps_file))
    
    """
    # METHOD 1
    util.do_cmd('surface %s -G%s %s -I0.001 -T0.5'
                % (my_xyz_file, my_grd_file,r_opt))
    
    util.do_cmd('grdmask %s %s -I0.001 -G%s -NNaN/NaN/1'
                % (my_xyz_file,r_opt,my_mask_file))
    
    util.do_cmd('grdmath %s %s MUL = %s'
                % (my_mask_file, my_grd_file,my_hzd_file))
    
    util.do_cmd('grdimage %s -K -Q -C%s %s %s > %s'
                % (my_hzd_file, my_cpt_file, r_opt, j_opt,
                   my_ps_file))
    """
    
    """
    # METHOD 2
    
    util.do_cmd('xyz2grd %s %s -I0.001 -G%s'
                % (my_xyz_file,r_opt,my_grd_file))
    
    util.do_cmd('grdsample %s %s -I0.005 -G%s'
                % (my_grd_file,r_opt,my_grd_file2))
    
    util.do_cmd('grdmask %s %s -I0.005 -G%s -NNaN/NaN/1'
                % (my_xyz_file,r_opt,my_mask_file))
    
    util.do_cmd('grdmath %s %s MUL = %s'
                % (my_mask_file, my_grd_file2,my_hzd_file))
    
    util.do_cmd('grdimage %s -K -Q -C%s %s %s > %s'
                % (my_hzd_file, my_cpt_file, r_opt, j_opt,
                   my_ps_file))
    """
    
    """
    # METHOD 3
    util.do_cmd('xyz2grd %s %s -I0.001 -G%s'
                % (my_xyz_file,r_opt,my_grd_file))
                
    util.do_cmd('grdmask %s %s -I0.001 -G%s -NNaN/NaN/1'
                % (my_xyz_file,r_opt,my_mask_file))
    
    util.do_cmd('grdmath %s %s MUL = %s'
                % (my_mask_file, my_grd_file,my_hzd_file))
    
    util.do_cmd('psxy %s %s %s -W0.5p/100 -G200 -O -K -M >%s'
                % (my_xyz_file, r_opt,j_opt,my_ps_file)) 
    
    util.do_cmd('grdimage %s -K -Q -C%s %s %s > %s'
                % (my_hzd_file, my_cpt_file, r_opt, j_opt,
                   my_ps_file))
    """
    
    """
    # METHOD 4
    util.do_cmd('xyz2grd %s %s -I0.001 -G%s'
                % (my_xyz_file,r_opt,my_grd_file))
                
    util.do_cmd('grdmask %s %s -I0.001 -G%s -NNaN/NaN/1'
                % (my_xyz_file,r_opt,my_mask_file))
    
    util.do_cmd('grdmath %s %s MUL = %s'
                % (my_mask_file, my_grd_file,my_hzd_file))
    
    util.do_cmd('psxy %s %s %s -W0.5p/100 -K >%s'
                % (my_xyz_file, r_opt,j_opt,my_ps_file)) 
    
    util.do_cmd('grdimage %s -K -Q -C%s %s -O %s > %s'
                % (my_hzd_file, my_cpt_file, r_opt, j_opt,
                   my_ps_file))
    util.do_cmd('psxy %s %s %s -W0.5p/100 -M -O -K >%s'
                % (my_xyz_file, r_opt,j_opt,my_ps_file))                          
     """
               
    
   
    # draw the coast
    util.do_cmd('pscoast %s -K -O %s -Df -W -S192/216/255 >> %s'
                % (r_opt, j_opt, my_ps_file))

    # do annotations
    if annotate is not None:
        ok_opt = '-K -O'
        jok_opt = '%s %s' % (ok_opt, j_opt)
        uga.generated_annotation(tmp_dir, my_ps_file, extent,
                                 cfg.MapWidthCentimetres, jok_opt)
        uga.user_annotation(tmp_dir, my_ps_file, extent, j_opt, ok_opt, annotate)

    # draw the colorbar
    if cb_label:
        x_offset = cfg.MapWidthCentimetres + 0.5 
        y_offset = cfg.MapHeightCentimetres/2.0 - 1.75
        util.do_cmd('psscale -K -O -E -C%s -D%.1fc/%.1fc/9.0c/0.8c "-B:%s:" >> %s'
                    % (my_cpt_file, x_offset, y_offset, cb_label, my_ps_file))

    # draw the rest of the map
    t_opt = ''
    if np_posn:
        t_opt = ugp.get_northpointer_placement(np_posn, extent)
    l_opt = ''
    if s_posn:
        l_opt = ugp.get_scale_placement(s_posn, extent)

    util.do_cmd('psbasemap %s -O %s "-Ba%s/a%s:.%s:WSen" -Bg%s/g%s %s %s >> %s'
                % (r_opt, j_opt, annot_lon, annot_lat, title, grid_lon, grid_lat, t_opt, l_opt, my_ps_file))

    # convert PS to required type
    (_, file_extension) = output_file.rsplit('.', 1)
    try:
        t_opt = util.Extension2TOpt[file_extension.lower()]
    except KeyError:
        raise RuntimeError("Can't handle plot outputfile type: %s" %
                           file_extension)

    util.do_cmd('ps2raster %s -A -T%s' % (my_ps_file, t_opt))
    (my_output_file, _) = my_ps_file.rsplit('.', 1)
    my_output_file += '.' + file_extension
    shutil.copyfile(my_output_file, output_file)

    # if it's required to show the graph ...
    # TODO: Experimental - leave?
    if show_graph:
        import sys
        if sys.platform == 'win32':
            os.startfile(my_output_file)
        else:
            import subprocess
            try:
                subprocess.Popen(['xdg-open', my_output_file])
            except OSError:
                print("Sorry, the 'xdg-open' application is required to "
                      "automatically display images.\nYou can see the image "
                      "in file %s." % output_file)

    # remove the temp directory
    shutil.rmtree(tmp_dir)
Exemplo n.º 6
0
def plot_gmt_map(extent, output_file, title=None, np_posn=None,
                 s_posn=None, annotate=[], show_graph=False):
    """A function to draw a GMT map, no data, just annotations.
    
    extent       the map extent (ll_lat, ll_lon, ur_lat, ur_lon)
    output_file  path to file that should be generated (*.png, *.eps, etc)
    title        string used to title the plot
    np_posn      position tuple or code string for north pointer placement,
                 one of:
                     'C'   - centre of plot
                     'NE'  - inside plot, northeast corner
                     'CE'  - inside plot, centre of east edge
                     'NNE' - outside plot, north of NE corner
                     'ENE' - outside plot, east of NE corner
                      etc (see the documentation for 'placement')
    s_posn       code string for scale placement
                     see examples for 'np_posn' above
    annotate     list of user annotations:
                     if None, no user or system annotations
                     if [],   only system annotations
                     else     system and user annotations
    show_graph   if True try to display final image in system-independant way

    Probably useful only for testing.

    """

    # unpack the extent
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # create a scratch directory for ephemeral files
    tmp_dir = tempfile.mkdtemp(prefix='plot_gmt_map_')

    # set up the GMT default values
    util.set_gmt_defaults(tmp_dir)

    # handle optional parameters
    if title is None:
        title = ''

    # think of a postscript filename
    my_ps_file = os.path.join(tmp_dir, 'data.ps')

    # draw the coast
    util.do_cmd('pscoast %s -K -JM%fc -Df -W -S192/216/255 >> %s'
                % (r_opt, cfg.MapWidthCentimetres, my_ps_file))

    # draw the rest of the map
    t_opt = ''
    if np_posn:
        t_opt = ugp.get_northpointer_placement(np_posn, extent)
    l_opt = ''
    if s_posn:
        l_opt = ugp.get_scale_placement(s_posn, extent)

    # do annotations
    if annotate is not None:
        j_opt = '-JM%fc' % cfg.MapWidthCentimetres
        ok_opt = '-K -O'
        jok_opt = '%s %s' % (j_opt, ok_opt)
        uga.generated_annotation(tmp_dir, my_ps_file, extent,
                                 cfg.MapWidthCentimetres, jok_opt)
        uga.user_annotation(tmp_dir, my_ps_file, extent, j_opt, ok_opt, annotate)

    util.do_cmd('psbasemap %s -K -O -JM%fc -Ba30m:".%s":WSen -Bg30m %s %s >> %s'
                % (r_opt, cfg.MapWidthCentimetres, title, t_opt, l_opt,
                   my_ps_file))

    cmd = ('psimage austgov-stacked.sun -O -W3.0/2.0 -C144.200/-38.800 '
           '-F1.0,255/0/0 >> %s' % my_ps_file)
    util.do_cmd(cmd)

    # convert PS to required type
    (_, file_extension) = output_file.rsplit('.', 1)
    try:
        t_opt = util.Extension2TOpt[file_extension.lower()]
    except KeyError:
        raise RuntimeError("Can't handle plot outputfile type: %s" %
                           file_extension)

    util.do_cmd('ps2raster %s -A -T%s' % (my_ps_file, t_opt))
    (my_output_file, _) = my_ps_file.rsplit('.', 1)
    my_output_file += '.' + file_extension
    shutil.copyfile(my_output_file, output_file)

    # if it's required to show the graph ...
    # TODO: Experimental - leave?
    if show_graph:
        import sys
        if sys.platform == 'win32':
            os.startfile(my_output_file)
        else:
            import subprocess
            try:
                subprocess.Popen(['xdg-open', my_output_file])
            except OSError:
                print("Sorry, the 'xdg-open' application is required to "
                      "automatically display images.\nYou can see the image "
                      "in file %s." % output_file)

    # remove the temp directory
    shutil.rmtree(tmp_dir)
def text_annotation(tmpdir, psfile, extent, j_opt, ok_opt, annotate):
    """
    Place user text annotation on a GMT graph.

    tmpdir    is the path to a temporary scratch directory
    psfile    path to the POSTSCRIPT file to write to
    extent    extent of the map
    j_opt     the GMT J option string
    ok_opt    the GMT O and K option string
    annotate  user annotations
              a list of tuples like
                  (type, (lon, lat), str) or
                  (type, (lon, lat), str, dict)
              where lon, lat are lon/lat coordinate values
                    str      is the text string to write
                    dict     is a set of args controlling
                             the text write

    The 'dict' annotate parameter has the form:
        {'fontsize': <fontsize float>,
         'colour': <colour>,
        }

    The user annotation string may contain any of the '@' escape sequences
    described at:
    http://gmt.soest.hawaii.edu/gmt/doc/gmt/html/man/pstext.html#DESCRIPTION
    
    """

    # file we fill with annotation text
    txt_file = os.path.join(tmpdir, 'data.txt')

    # unpack the annotation sequence
    if len(annotate) == 3:
        (_, point, annstr) = annotate
        anndict = {}
    elif len(annotate) == 4:
        (_, point, annstr, anndict) = annotate
    else:  # handle overflow
        (_, point, annstr, anndict, _) = annotate

    (x, y) = point

    # set defaults, if required
    fontsize = anndict.get('fontsize', DefaultFontSize)
    fontno = anndict.get('fontno', DefaultFontNo)
    colour = anndict.get('colour', DefaultColour)
    angle = anndict.get('angle', DefaultAngle)
    justify = anndict.get('justify', DefaultJustify)
    linespace = anndict.get('linespace', DefaultLinespace)
    parwidth = anndict.get('parwidth', DefaultParWidth)
    parjust = anndict.get('parjust', DefaultParJust)

    # unpack extent
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # create the annotation text file
    ann_hdr = ('%f %f %s %s %s %s %s' %
               (x, y, fontsize, angle, fontno, justify, colour))
    fd = open(txt_file, 'w')
    fd.write(ann_hdr)
    fd.write(annstr)
    fd.close()

    # annotate the plot
    cmd = ('pstext %s %s %s %s -N >> %s' %
           (txt_file, r_opt, j_opt, ok_opt, psfile))
    util.do_cmd(cmd)
def image_annotation(tmpdir, psfile, extent, j_opt, ok_opt, annotate):
    """Image annotation.

    tmpdir   a temporary scratch directory
    psfile   output postscript file
    extent   extent of the map
    j_opt    GMT -J option string
    ok_opt   GMT -O and -K option string
    annotate the annotation data:
             ('image', <posn>, <imagefile>, <kwargs>)
             where <posn>      is a position specifier
                               (string or lon,lat tuple)
                   <imagefile> is the path to the EPS image file
                   <kwargs>    is a dictionary of extra args
                               (optional)

    """

    # set default polygon attributes
    framewidth = 1.0
    framecolour = '0/0/0'
    imagewidth = 4.0
    imageheight = 3.0

    # unpack the annotate command object
    try:
        (_, posn, imagefile, kwargs) = annotate
    except ValueError:
        (_, posn, imagefile) = annotate
        kwargs = {}

    # if given image height but not width, calculate width assuming
    # aspect ratio of default image width and height, etc
    if (kwargs.get('imagewidth', None) is None
            and kwargs.get('imageheight', None) is not None):
        kwargs['imagewidth'] = kwargs['imageheight'] * imagewidth / imageheight
    elif (kwargs.get('imageheight', None) is None
          and kwargs.get('imagewidth', None) is not None):
        kwargs['imageheight'] = kwargs['imagewidth'] * imageheight / imagewidth

    # override default polygon attributes from kwargs
    framewidth = float(kwargs.get('framewidth', framewidth))
    framecolour = kwargs.get('framecolour', framecolour)
    imagewidth = float(kwargs.get('imagewidth', imagewidth))
    imageheight = float(kwargs.get('imageheight', imageheight))
    want_frame = not kwargs.get('noframe', False)

    # set X and Y margins
    margin_x = 1.0
    margin_y = 1.0

    # unpack the extent and get map size in cm
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    (map_width, map_height) = util.get_coords_cm(ur_lon, ur_lat, extent, j_opt)

    # figure out image placement, convert to cm
    if isinstance(posn, basestring):
        lower_posn = posn.lower()
        try:
            eval_str = ImagePlacement[lower_posn]
        except KeyError:
            raise RuntimeError("Placement string '%s' is not recognised" %
                               posn)
    else:
        # we have a (lon, lat) tuple
        # TODO: implement!
        pass

    # execute the posn eval_str - gives us x, y and justify
    exec(eval_str)

    # set -W option - final image size
    w_opt = '-W%.2f/%.2f' % (imagewidth, imageheight)

    # do -C option as well as the frame, if required
    c_opt = '-C%.3f/%.3f/%s' % (x, y, justify)
    if want_frame:
        f_opt = '-F%.1f,%s' % (framewidth, framecolour)

    # now put image into PS file
    cmd = ('psimage %s %s %s %s %s >> %s' %
           (imagefile, ok_opt, w_opt, c_opt, f_opt, psfile))
    util.do_cmd(cmd)
Exemplo n.º 9
0
def plot_gmt_xyz(data, output_file, bins=100, title=None, np_posn=None,
                 s_posn=None, cb_label=None, colourmap=None, cb_steps=None,
                 annotate=[], show_graph=False, map_extent=None):
    """A function to take gridded XYZ data and plot onto a GMT map.
    Use a discrete colourbar.
    
    data         an iterable of *gridded* values in xyz format (lon, lat, val)
    output_file  path to file that should be generated (*.png, *.eps, etc)
    bins         number of bins in the X direction if a single integer, else
                 expect 2-tuple of integers (bins_x, bins_y)
    title        string used to title the plot
    np_posn      code string for north pointer placement, one of:
                     'C'   - centre of plot
                     'NE'  - inside plot, northeast corner
                     'CE'  - inside plot, centre of east edge
                     'NNE' - outside plot, north of NE corner
                     'ENE' - outside plot, east of NE corner
                      etc (see the documentation for 'placement')
                   OR
                     (lon,lat) tuple
    s_posn       code string for scale placement
                     see examples for 'np_posn' above
    cb_label     string containing the label text for the colorbar
                 (if not supplied, no colourbar)
    colourmap    string containing name of required colormap
                 (a local file 'hazmap.cpt' or GMT name 'cool')
    cb_steps     an iterable of desired discrete steps in the DISCRETE
                 colourmap, or an empty list (code chooses steps), or None
                 which gives the default continuous colourmap
    annotate     list of user annotations:
                     if None, no user or system annotations
                     if [],   only system annotations
                     else     system and user annotations
    show_graph   if True try to display final image in system-independant way
    map_extent   sets the extent of the displayed map if supplied
                 (get extent from data if not supplied)

    """

    # create a scratch directory for ephemeral files
    tmp_dir = tempfile.mkdtemp(prefix='plot_map_')

    # set up the GMT default values
    util.set_gmt_defaults(tmp_dir)

    # handle bins parameter
    try:
        (bins_y, bins_x) = bins
    except TypeError:
        bins_x = bins_y = bins

    # handle optional parameters
    if title is None:
        title = ''

    c_map = DefaultColourMap
    if colourmap:
        c_map = colourmap
    c_map = util.get_colourmap(c_map)

    # get extent of data (user-specified, or we get from data)
    if map_extent:
        extent = map_extent
    else:
        extent = ugxe.get_extent(data, margin=0)
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # get max NON-NAN value from XYZ data
    max_val = util.max_nan(data[:,2])
    min_val = util.min_nan(data[:,2])

    # write a GMT XYZ file
    my_xyz_file = os.path.join(tmp_dir, 'data.xyz')
    scipy.savetxt(my_xyz_file, data)

    # convert XYZ to GRD file
    my_grd_file = os.path.join(tmp_dir, 'data.grd')
    util.do_cmd('xyz2grd %s %s -I%d+/%d+ -G%s'
                % (my_xyz_file, r_opt, bins_x, bins_y, my_grd_file))

    # generate CPT file
    my_cpt_file = os.path.join(tmp_dir, 'data.cpt')
    if cb_steps is None:
        util.do_cmd('grd2cpt %s -C%s -Z > %s'
                    % (my_grd_file, c_map, my_cpt_file))
    elif hasattr(cb_steps, '__iter__'):
        if len(cb_steps) == 0:           # code chooses steps
            (start, stop, step) = util.get_scale_min_max_step(max_val, min_val)
            util.do_cmd('makecpt -C%s.cpt -T%f/%f/%f > %s'
                        % (c_map, start, stop, step, my_cpt_file))
        else:                               # user chooses steps
            util.make_discrete_cpt(my_cpt_file, c_map, cb_steps)
    else:
        msg = "cb_steps param must be None or list: got %s" % type(cb_steps)
        raise RuntimeError(msg)

    # think of a postscript filename
    my_ps_file = os.path.join(tmp_dir, 'data.ps')

    # draw GRD data on map
    util.do_cmd('grdimage %s -K %s -JM%fc -C%s -Q > %s'
                % (my_grd_file, r_opt, cfg.MapWidthCentimetres,
                   my_cpt_file, my_ps_file))

    # draw the coast
    util.do_cmd('pscoast %s -K -O -JM%fc -Df -W -S192/216/255 >> %s'
                % (r_opt, cfg.MapWidthCentimetres, my_ps_file))

    # draw the rest of the map
    t_opt = ''
    if np_posn:
        t_opt = ugp.get_northpointer_placement(np_posn, extent)
    l_opt = ''
    if s_posn:
        l_opt = ugp.get_scale_placement(s_posn, extent)

    util.do_cmd('psbasemap %s -K -O -JM%fc -Ba30m:".%s":WSen -Bg30m %s %s >> %s'
                % (r_opt, cfg.MapWidthCentimetres, title, t_opt, l_opt, my_ps_file))

    # do annotations
    if annotate is not None:
        j_opt = '-JM%fc' % cfg.MapWidthCentimetres
        ok_opt = '-K -O'
        jok_opt = '%s %s' % (j_opt, ok_opt)
        uga.generated_annotation(tmp_dir, my_ps_file, extent,
                                 cfg.MapWidthCentimetres, jok_opt)
        uga.user_annotation(tmp_dir, my_ps_file, extent, j_opt, ok_opt, annotate)

    # figure out scale skip from max data value
    skip = util.get_scale_skip(max_val)

    # draw the colorbar
    if cb_label:
        x_offset = cfg.MapWidthCentimetres + 0.5
        util.do_cmd('psscale -O -K -C%s -D%.1fc/8.0c/9.0c/0.8c -B%f:"%s": >> %s'
                    % (my_cpt_file, x_offset, skip, cb_label, my_ps_file))
    # force close
    util.do_cmd('psxy -O -J -R -T  >> %s'
                    % (my_ps_file))

    # convert PS to required type
    (_, file_extension) = output_file.rsplit('.', 1)
    print output_file
    try:
        t_opt = util.Extension2TOpt[file_extension.lower()]
        print t_opt
    except KeyError:
        raise RuntimeError("Can't handle plot outputfile type: %s" %
                           file_extension)

    print my_ps_file
    util.do_cmd('ps2raster %s -A -T%s' % (my_ps_file, t_opt))
    (my_output_file, _) = my_ps_file.rsplit('.', 1)
    my_output_file += '.' + file_extension
    print my_ps_file
    print my_output_file
    shutil.copyfile(my_output_file, output_file)
    print my_output_file
    

    # if it's required to show the graph ...
    # TODO: Experimental - leave?
    if show_graph:
        import sys
        if sys.platform == 'win32':
            os.startfile(my_output_file)
        else:
            import subprocess
            try:
                subprocess.Popen(['xdg-open', my_output_file])
            except OSError:
                print("Sorry, the 'xdg-open' application is required to "
                      "automatically display images.\nYou can see the image "
                      "in file %s." % output_file)

    # remove the temp directory
    shutil.rmtree(tmp_dir)
Exemplo n.º 10
0
def text_annotation(tmpdir, psfile, extent, j_opt, ok_opt, annotate):
    """
    Place user text annotation on a GMT graph.

    tmpdir    is the path to a temporary scratch directory
    psfile    path to the POSTSCRIPT file to write to
    extent    extent of the map
    j_opt     the GMT J option string
    ok_opt    the GMT O and K option string
    annotate  user annotations
              a list of tuples like
                  (type, (lon, lat), str) or
                  (type, (lon, lat), str, dict)
              where lon, lat are lon/lat coordinate values
                    str      is the text string to write
                    dict     is a set of args controlling
                             the text write

    The 'dict' annotate parameter has the form:
        {'fontsize': <fontsize float>,
         'colour': <colour>,
        }

    The user annotation string may contain any of the '@' escape sequences
    described at:
    http://gmt.soest.hawaii.edu/gmt/doc/gmt/html/man/pstext.html#DESCRIPTION
    
    """

    # file we fill with annotation text
    txt_file = os.path.join(tmpdir, 'data.txt')

    # unpack the annotation sequence
    if len(annotate) == 3:
        (_, point, annstr) = annotate
        anndict = {}
    elif len(annotate) == 4:
        (_, point, annstr, anndict) = annotate
    else:   # handle overflow
        (_, point, annstr, anndict, _) = annotate

    (x, y) = point

    # set defaults, if required
    fontsize = anndict.get('fontsize', DefaultFontSize)
    fontno = anndict.get('fontno', DefaultFontNo)
    colour = anndict.get('colour', DefaultColour)
    angle = anndict.get('angle', DefaultAngle)
    justify = anndict.get('justify', DefaultJustify)
    linespace = anndict.get('linespace', DefaultLinespace)
    parwidth = anndict.get('parwidth', DefaultParWidth)
    parjust = anndict.get('parjust', DefaultParJust)

    # unpack extent
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # create the annotation text file
    ann_hdr = ('%f %f %s %s %s %s %s'
                % (x, y, fontsize, angle, fontno, justify, colour))
    fd = open(txt_file, 'w')
    fd.write(ann_hdr)
    fd.write(annstr)
    fd.close()

    # annotate the plot
    cmd = ('pstext %s %s %s %s -N >> %s'
           % (txt_file, r_opt, j_opt, ok_opt, psfile))
    util.do_cmd(cmd)
Exemplo n.º 11
0
def image_annotation(tmpdir, psfile, extent, j_opt, ok_opt, annotate):
    """Image annotation.

    tmpdir   a temporary scratch directory
    psfile   output postscript file
    extent   extent of the map
    j_opt    GMT -J option string
    ok_opt   GMT -O and -K option string
    annotate the annotation data:
             ('image', <posn>, <imagefile>, <kwargs>)
             where <posn>      is a position specifier
                               (string or lon,lat tuple)
                   <imagefile> is the path to the EPS image file
                   <kwargs>    is a dictionary of extra args
                               (optional)

    """
   
    # set default polygon attributes
    framewidth = 1.0
    framecolour = '0/0/0'
    imagewidth = 4.0
    imageheight = 3.0

    # unpack the annotate command object
    try:
        (_, posn, imagefile, kwargs) = annotate
    except ValueError:
        (_, posn, imagefile) = annotate
        kwargs = {}

    # if given image height but not width, calculate width assuming
    # aspect ratio of default image width and height, etc
    if (kwargs.get('imagewidth', None) is None
            and kwargs.get('imageheight', None) is not None):
        kwargs['imagewidth'] = kwargs['imageheight']*imagewidth/imageheight
    elif (kwargs.get('imageheight', None) is None
              and kwargs.get('imagewidth', None) is not None):
        kwargs['imageheight'] = kwargs['imagewidth']*imageheight/imagewidth

    # override default polygon attributes from kwargs
    framewidth = float(kwargs.get('framewidth', framewidth))
    framecolour = kwargs.get('framecolour', framecolour)
    imagewidth = float(kwargs.get('imagewidth', imagewidth))
    imageheight = float(kwargs.get('imageheight', imageheight))
    want_frame = not kwargs.get('noframe', False)

    # set X and Y margins
    margin_x = 1.0
    margin_y = 1.0

    # unpack the extent and get map size in cm
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    (map_width, map_height) = util.get_coords_cm(ur_lon, ur_lat, extent, j_opt)

    # figure out image placement, convert to cm
    if isinstance(posn, basestring):
        lower_posn = posn.lower()
        try:
            eval_str = ImagePlacement[lower_posn]
        except KeyError:
            raise RuntimeError("Placement string '%s' is not recognised" % posn)
    else:
        # we have a (lon, lat) tuple
        # TODO: implement!
        pass

    # execute the posn eval_str - gives us x, y and justify
    exec(eval_str)

    # set -W option - final image size
    w_opt = '-W%.2f/%.2f' % (imagewidth, imageheight)

    # do -C option as well as the frame, if required
    c_opt = '-C%.3f/%.3f/%s' % (x, y, justify)
    if want_frame:
        f_opt = '-F%.1f,%s' % (framewidth, framecolour)

    # now put image into PS file
    cmd = ('psimage %s %s %s %s %s >> %s'
           % (imagefile, ok_opt, w_opt, c_opt, f_opt, psfile))
    util.do_cmd(cmd)
def plot_gmt_xyz_image_contour(data, output_file, title=None, colourmap=None,
                               cb_label=None, cb_steps=None, annotate=[],
                               show_graph=False, bin_sum=False,
                               map_extent=None):
    """Plot XYZ data as a 'heatmap' and contours onto a GMT map.
    
    data         an iterable of values in xyz format (lon, lat, val)
                 (must be 'binned' XYZ data)
    output_file  path to file that should be generated (*.png, *.eps, etc)
    title        string used to title the plot
    colourmap    name of the colourmap to use, may be name of *.cpt file or 
                 internal GMT colourmap name
    cb_label    label on colourmap legend
    cb_steps     sequence of contour values (default is no contours drawn)
    annotate     list of user annotations:
                     if None, no user or system annotations
                     if [],   only system annotations
                     else     system and user annotations
                 (see documentation for form of user annotations)
    show_graph   if True try to display final image in system-independant way
    bin_sum      True if values in grid bin are to be summed (default: mean)
    map_extent   sets the extent of the displayed map if supplied
                 (get extent from data if not supplied)

    """

    # create a scratch directory for ephemeral files
    tmp_dir = tempfile.mkdtemp(prefix='plot_gmt_xyz_image_contour_')

    # use XYZ data bin numbers
    bins = util.get_xyz_bin_inc(data, 1.0e-4)
    if bins is None:
        raise RuntimeError("plot_gmt_xyz_image_contour(): "
                           "XYZ data has no implicit binning")
    (x_bins, y_bins) = bins
    x_inc = '%d+' % x_bins
    y_inc = '%d+' % y_bins

    # set up the default GMT environment
    util.set_gmt_defaults(tmp_dir)

    # handle optional parameters
    if title is None:
        title = ''

    if colourmap is None:
        colourmap = DefaultColourmap

    # get maximum/minimum values
    max_val = num.max(data[:,2])
    min_val = num.min(data[:,2])

    # get extent of data
    if map_extent:
        extent = map_extent
    else:
        extent = ugxe.get_extent(data, margin=0)
    (ll_lat, ll_lon, ur_lat, ur_lon) = extent
    r_opt = '-R%f/%f/%f/%f' % (ll_lon, ur_lon, ll_lat, ur_lat)

    # set the -J option for Mercator projection
    j_opt = '-JM%fc' % cfg.MapWidthCentimetres

    # write a GMT XYZ *file* (required by GMT)
    tmp_xyz = os.path.join(tmp_dir, 'data.xyz')
    num.savetxt(tmp_xyz, data)

    # create GRD file from XYZ data
    tmp_grd = os.path.join(tmp_dir, 'data.grd')
    a_opt = ''
    if bin_sum:
        a_opt = '-A'
    util.do_cmd('xyz2grd %s -G%s -I%s/%s -F %s %s'
                % (tmp_xyz, tmp_grd, x_inc, y_inc, r_opt, a_opt))

    # generate CPT file
    tmp_cpt = os.path.join(tmp_dir, 'data.cpt')
    if cb_steps is None:
        cb_steps = []
    if len(cb_steps) > 0:
        util.make_discrete_cpt_from_seq(tmp_cpt, cb_steps)
    else:
        (start, stop, step) = util.get_scale_min_max_step(max_val, min_val)
        cm = util.get_colourmap(c_map)
        util.do_cmd('makecpt -C%s.cpt -T%f/%f/%f > %s'
                    % (cm, start, stop, step, tmp_cpt))

    # think of a postscript filename for plot output
    tmp_ps = os.path.join(tmp_dir, 'data.ps')

    # draw image of gridded data
    util.do_cmd('grdimage %s -K -C%s %s -Q -Sc -Ei > %s'
                % (tmp_grd, tmp_cpt, j_opt, tmp_ps))

    # draw contours on the image
    if contours:
        # make a contour file
        tmp_cnt = os.path.join(tmp_dir, 'data.cnt')
        fd = open(tmp_cnt, 'w')
        for n in contours:
            fd.write('%f A\n' % n)
        fd.close()

        # draw the contours
        util.do_cmd('grdcontour %s -K -O -C%s %s %s >> %s'
                    % (tmp_grd, tmp_cnt, j_opt, r_opt, tmp_ps))

    # draw the coast
    util.do_cmd('pscoast %s -K -O %s -Df -W -S192/216/255 >> %s'
                % (r_opt, j_opt, tmp_ps))

    # draw the colorbar
    if cb_label:
        x_offset = cfg.MapWidthCentimetres + 0.5 
        util.do_cmd('psscale -K -O -E -C%s -D%.1fc/8.0c/9.0c/0.8c "-B:%s:" >> %s'
                    % (tmp_cpt, x_offset, cb_label, tmp_ps))

    # do annotations
    if annotate is not None:
        ok_opt = '-K -O'
        jok_opt = '%s %s' % (ok_opt, j_opt)
        uga.generated_annotation(tmp_dir, tmp_ps, extent,
                                 cfg.MapWidthCentimetres, jok_opt)
        uga.user_annotation(tmp_dir, tmp_ps, extent, j_opt, ok_opt, annotate)

    # draw the rest of the map
    util.do_cmd('psbasemap %s -O %s "-Ba30m:.%s:WSen" -Bg30m >> %s'
                % (r_opt, j_opt, title, tmp_ps))

    # convert PS to required type
    (_, file_extension) = output_file.rsplit('.', 1)
    try:
        t_opt = util.Extension2TOpt[file_extension.lower()]
    except KeyError:
        raise RuntimeError("Can't handle plot outputfile type: %s" %
                           file_extension)

    util.do_cmd('ps2raster %s -A -T%s' % (tmp_ps, t_opt))
    (tmp_output, _) = tmp_ps.rsplit('.', 1)
    tmp_output += '.' + file_extension
    shutil.copyfile(tmp_output, output_file)

    # if it's required to show the graph ...
    # TODO: Experimental - leave?
    if show_graph:
        import sys
        if sys.platform == 'win32':
            os.startfile(my_output_file)
        else:
            import subprocess
            try:
                subprocess.Popen(['xdg-open', my_output_file])
            except OSError:
                print("Sorry, the 'xdg-open' application is required to "
                      "automatically display images.\nYou can see the image "
                      "in file %s." % output_file)

    # remove the temp directory
    shutil.rmtree(tmp_dir)