"contour.py" module

13

Click here to load reader

description

This is "contour.py" which module is draw the contour using cdms and vcs. This is modified very slightly which is suitable to cdat 5.2

Transcript of "contour.py" module

Page 1: "contour.py" module

#!/usr/bin/python -tt#=======================================================================# General Documentation

#

"""Single-procedure module.

"

See procedure docstring for description.

Save this documet as “contour.py” . It is slighltly modified by myself (Arulalan.T) which is suitable to CDAT 5.2 ."""

"

#-----------------------------------------------------------------------# Additional Documentation## RCS Revision Code:# $Id: contour.py,v 1.6 2004/05/20 23:03:18 jlin Exp $## Modification History:# - 18 Dec 2003: Original by Johnny Lin, Computation Institute,# University of Chicago. Passed minimally passably reasonable # tests.# - 24 Dec 2003: Make VCS object names "unique". Passed minimally # passably reasonable tests.# - 11 May 2004: Make so it'll work with CDAT 4.0b2. Passed mini-# mally reasonable tests.## Notes:# - Written for Python 2.2.# - For dependencies see the import statements in the file.## Copyright (c) 2003 by Johnny Lin. For licensing, distribution # conditions, contact information, and additional documentation see# the URL http://www.johnny-lin.com/py_pkgs/IaGraph/.#=======================================================================

====

#---------------- Module General Import and Declarations ---------------

#

#- Set package version number: #arul commented the following lines'''import IaGraph_version__version__ = IaGraph_version.versiondel IaGraph_version'''

'''

Page 2: "contour.py" module

#------------------------------- Function ------------------------------

#

def contour( data, x, y \ , annot=None \ , c_levels=None \ , colorbar=1 \ , continents=0 \ , ctindex=13 \ , plottype='both' \ , position=None \ , title=None \ , xrange=None, yrange=None \ , xtitle=None, ytitle=None \ ): """Interactively make 2-D contour plots.

Plots a contour plot onto the active VCS canvas. If there is a pre-existing plot on the active canvas, that plot is overwritten. Syntax of method call is based on IDL conventions. However, defaults for input parameters are set to my personal preferences, not IDL defaults; a call of contour(data,x,y) should give a generic contour plot of that type I would (subjectively) find generally suitable for publication.

Default plot is a generic contour plot with no axis titles or overall title, and with a colorbar legend plotted at the bottom. The plot is rainbow filled with contour lines overlain.

Method Arguments: * data: 2-D array of data to contour. Location of rows are described by y, and location of columns by x. Typically for plots on the earth, x is longitude and y is latitude so rows in data are bands of constant latitude. Numeric, MA, MV array. If data is Numeric only, there should be no missing values in data.

* x: Vector of x-axis variable values, which corresponds to iterating through the columns of data. Numeric, MA, or MV vector. There should be no missing values in x.

* y: Vector of y-axis variable values, which corresponds to iterating through the rows of data. Numeric, MA, or MV vector. There should be no missing values in y.

NB: If an input argument is MV, only the MA portion of the variable is used; this procedure does not read the additional attributes of the MV class.

Keyword Inputs: * annot: Extra text to annotate the graph with, placed in the

Page 3: "contour.py" module

very upper-left corner in small-sized text (1/2 the height of the overall title). String scalar. Different lines of text are separated by the os.linesep string.

* c_levels: Vector of contour levels. Can be list or Numeric array. Default is None.

* colorbar: If set true (i.e. not equal to 0), a color bar legend of the filled contour colors is plotted. Default is true, except when plottype is 'line' the colorbar keyword's value is ignored and no color bar is plotted.

* continents: If set true (i.e. not equal to 0), fine modern continent outlines are plotted. Default is false.

* ctindex: Index of color table to use, keyed into the values used by procedure loadct. The command loadct() will list all available values. Default is 13 (rainbow, violet to red, 390-680 nm).

* plottype: If set to 'fill', smooth filled contours only are plotted; if set to 'line', contour lines only are plotted; if set to 'both', smooth filled contours plus an overlay of contour lines are plotted. String scalar. Default is 'both'.

* position: 4-element list of [bbllx, bblly, bburx, bbury] of the bounding box (x,y) coordinates in normalized values. The data origin is the lower-left corner, and the upper-right cor- ner of the data box is the upper-right corner of position. If keyword not defined, IaGraph.Sysvar.__class__.p_position is used. If that system variable is not defined, this procedure uses the following values: position value | colorbar? | annot? ------------------------------------------- [0.2, 0.30, 0.9, 0.80] | Y | Y [0.2, 0.15, 0.9, 0.65] | N | Y [0.2, 0.35, 0.9, 0.85] | Y | N [0.2, 0.25, 0.9, 0.75] | N | N

* title: The overall plot title. String scalar. Only a single line of input is accepted.

* [xy]range: The range of the [xy]-axis used to calculate "neat" tickmarks, from which the actual axis range is set. Two-element list, where the first element is the minimum in the axis range and the second element is the maximum in the axis range. If keyword not defined, IaGraph.Sysvar.__class__.[xy]_range is used. If that system variable is not defined, this procedure uses the the minimum and maximum of each input axis vector.

* [xy]title: The x-axis and y-axis title. String scalar. Only a single line of input is accepted.

Page 4: "contour.py" module

##

Output: * Contour plot of data on screen. * The active_canvas system variable in IaGraph.Sysvar is set to the canvas (overwritten if a previous canvas exists) that is drawn by this procedure. This allows other procedures in IaGraph to operate on the canvas outside of the IaGraph.contour procedure.

Notes: * The font for the colorbar and the annot keyword text are set to be the overall title font. * Font heights for the axes labels are set to be the same as the axes titles. * Color of overall title, colorbar text, and axes tick labels and titles are forced to always be black. * The colorbar and annot font heights are set to 1/2 the overall title height. * The colorbar height is set to 0.03 (normalized units). * If contour lines are plotted, negative values are long dashed and positive values are solid.

Example to plot a simple contour plot with an overall title: import Numeric as N from contour import contour x = N.arange(25) * 15.0 - 180.0 y = N.arange(13) * 15.0 - 90.0 data = N.outerproduct(N.sin(y*N.pi/360.), N.cos(x*N.pi/360.)) contour(data, x, y, title='Example')

Example to make a contour plot with manually set contour levels: levs = [-0.3, -0.15, 0, 0.4, 0.6, 0.78] contour(data, x, y, c_levels=levs) """

#- Import modules and set system variable object:

#import MA import numpy.ma as MA import time #import Numeric as N import numpy as N import cdms2 as cdms import vcs import IaGraph from IaGraph.loadct import loadct

Page 5: "contour.py" module

sysvar = IaGraph.Sysvar()

#- Local variables based on keyword input: Set to colorbar_loc to # protect the input keyword colorbar; set colorbar_loc to 0 if # plottype is line. Set continents_loc (a non-Boolean variable) # based on continents keyword being true or false. colorbar_loc # is false if 0 and true if non-zero:

if plottype == 'line': colorbar_loc = 0 else: colorbar_loc = colorbar

if (continents == 0): continents_loc = 0 else: continents_loc = 1

#- Make sure data is MA and call it dataMA for use in rest of the # procedure. Calculate the max and min of the non-missing data # in data. If data is MV, the isMA function will return True, # and so we ensure dataMA has no MV attributes in this section:

if MA.isMA(data) ==0:#arul changed from 1 to 0 dataMA = MA.masked_values( data.filled(), data.fill_value() ) else: dataMA = MA.masked_array(data)

data_min = MA.minimum(dataMA) data_max = MA.maximum(dataMA)

#- Set range of axes, if not defined in keywords:

if xrange == None: xrange = sysvar.__class__.x_range if sysvar.__class__.x_range == None: xrange = [min(x), max(x)]

if yrange == None: yrange = sysvar.__class__.y_range if sysvar.__class__.y_range == None: yrange = [min(y), max(y)]

if len(xrange) != 2: raise ValueError, "contour: Bad x-axis ranges" if len(yrange) != 2: raise ValueError, "contour: Bad y-axis ranges"

Page 6: "contour.py" module

#- Open VCS canvas window (first closing and reseting any pre- # existing active canvas):

if sysvar.__class__.active_canvas != []: sysvar.__class__.active_canvas.clear() v = sysvar.__class__.active_canvas else: v = vcs.init()

#- Make unique string based on system time. This provides a way # of giving a unique name to VCS objects that is guaranteed to be # unique if the procedure is called again no sooner than 1 sec # and no later than ~100 days from the current call:

uniq_str = ('%.2f' % time.time())[-11:].replace('.','')

#- Create graphics method object for isoline and fill plots and # the template for isofill:

my_fill_gm = v.createisofill('fillgm'+uniq_str, 'default') my_line_gm = v.createisoline('linegm'+uniq_str, 'default') my_fill_tpl = v.createtemplate('filltp'+uniq_str, 'default')

#- Choose a color map and make it active:

loadct(v, ctindex, verbose=0)

#- Set coordinates (normalized units) for lower-left and upper- # right bounding box:

if position == None: position = sysvar.__class__.p_position if sysvar.__class__.p_position == None: if (colorbar_loc != 0) and (annot != None): position = [0.2, 0.3, 0.9, 0.8] elif (colorbar_loc == 0) and (annot != None): position = [0.2, 0.15, 0.9, 0.65] elif (colorbar_loc != 0) and (annot == None): position = [0.2, 0.35, 0.9, 0.85] elif (colorbar_loc == 0) and (annot == None): position = [0.2, 0.25, 0.9, 0.75] else: raise ValueError, "contour: Bad position state"

bbllx = position[0] bblly = position[1] bburx = position[2] bbury = position[3]

Page 7: "contour.py" module

øø

#- Set height of font for the axis labels and the title, and set # the tick length. Font height is in arbitary units and is # converted to normalized units by multiplying by fontht2norm. # Set maximum number of ticks for axis:

title_fontht = sysvar.__class__.p_fontht xtitle_fontht = sysvar.__class__.x_fontht ytitle_fontht = sysvar.__class__.y_fontht xticklabel_fontht = sysvar.__class__.x_fontht yticklabel_fontht = sysvar.__class__.y_fontht xticklength = sysvar.__class__.x_ticklen yticklength = sysvar.__class__.y_ticklen xtickmaxnum = sysvar.__class__.x_tickmaxnum ytickmaxnum = sysvar.__class__.y_tickmaxnum

#- Set conversion factor to multiply VCS font height coordinates # by to obtain the value in normalized coordinates:

fontht2norm = sysvar.__class__.p_fontht2norm[0]

#- Fonts:

title_font = sysvar.__class__.p_font xaxis_font = sysvar.__class__.x_font yaxis_font = sysvar.__class__.y_font

#- Create text-table and text-orientation objects for x- and # y-axis tick labels and using them set font and font height. # Also set y-axis tick labels to be vertically aligned at the # mid-way point:

ttab_xticklabel = v.createtexttable('ttxtic'+uniq_str, 'default') ttab_yticklabel = v.createtexttable('ttytic'+uniq_str, 'default') tori_xticklabel = v.createtextorientation('toxtic'+uniq_str, 'defcenter') tori_yticklabel = v.createtextorientation('toytic'+uniq_str, 'default')

ttab_xticklabel.font = xaxis_font ttab_yticklabel.font = yaxis_font ttab_xticklabel.color = 241 ttab_yticklabel.color = 241 tori_xticklabel.height = xticklabel_fontht tori_yticklabel.height = yticklabel_fontht tori_yticklabel.valign = 'half'

#- Create/set text-table and text-orientation objects for overall # title and axis title settings. Turn on these fields in the

Page 8: "contour.py" module

# template and set the new text-table/orientation objects to # those fields in the template:

ttab_title = v.createtexttable('tttitl'+uniq_str, 'default') tori_title = v.createtextorientation('totitl'+uniq_str, 'defcenter') ttab_title.font = title_font ttab_title.color = 241 tori_title.height = title_fontht

ttab_xtitle = v.createtexttable('ttxtit'+uniq_str, 'default') ttab_ytitle = v.createtexttable('ttytit'+uniq_str, 'default') ttab_xtitle.font = xaxis_font ttab_xtitle.color = 241 ttab_ytitle.font = yaxis_font ttab_ytitle.color = 241

tori_xtitle = v.createtextorientation('toxtit'+uniq_str, 'defcenter') tori_ytitle = v.createtextorientation('toytit'+uniq_str, 'defcentup') tori_xtitle.height = xtitle_fontht tori_ytitle.height = ytitle_fontht

my_fill_tpl.dataname.texttable = ttab_title my_fill_tpl.dataname.textorientation = tori_title my_fill_tpl.xname.texttable = ttab_xtitle my_fill_tpl.xname.textorientation = tori_xtitle my_fill_tpl.yname.texttable = ttab_ytitle my_fill_tpl.yname.textorientation = tori_ytitle

my_fill_tpl.dataname.priority = 0 #+ Default is for overall title my_fill_tpl.xname.priority = 0 # and axis titles to be off my_fill_tpl.yname.priority = 0

if title != None: my_fill_tpl.dataname.priority = 1 if xtitle != None: my_fill_tpl.xname.priority = 1 if ytitle != None: my_fill_tpl.yname.priority = 1

#- Turn off some default titling fields:

my_fill_tpl.mean.priority = 0 my_fill_tpl.max.priority = 0 my_fill_tpl.min.priority = 0

#- Set position of data field, plot box, and x-axis bottom ticks # and labels; set text-table and text-orientation of x-axis bottom # labels; turn off upper-right set of tick labels:

my_fill_tpl.data.x1 = my_fill_tpl.box1.x1 = bbllx my_fill_tpl.data.y1 = my_fill_tpl.box1.y1 = bblly my_fill_tpl.data.x2 = my_fill_tpl.box1.x2 = bburx my_fill_tpl.data.y2 = my_fill_tpl.box1.y2 = bbury

Page 9: "contour.py" module

my_fill_tpl.xtic1.y1 = bblly - xticklength my_fill_tpl.xtic1.y2 = bblly my_fill_tpl.xlabel1.y = bblly - (3.0 * xticklength) my_fill_tpl.xlabel1.texttable = ttab_xticklabel my_fill_tpl.xlabel1.textorientation = tori_xticklabel

my_fill_tpl.xtic2.priority = 0 my_fill_tpl.ytic2.priority = 0

#- Create "nice" x-axis labels (if the system variable for the # tick values is not defined) and set them into the graphics # methods. If the xlabels that are calculated are "too long" # (i.e. longest label is >= 5 characters), recalculate the # labels to have no more than 5 labeled ticks on the axis. # Set bounds of data frame to exactly span xlabels:

if sysvar.__class__.x_tickvalues == None: xlabels = \ vcs.mklabels( vcs.mkscale(xrange[0], xrange[1], xtickmaxnum) ) longest_xlabels = \ max([ len(xlabels.values()[i]) for i in range(len(xlabels))] ) if longest_xlabels >= 5: xlabels = vcs.mklabels( vcs.mkscale(xrange[0], xrange[1], 5) ) else: xlabels = sysvar.__class__.x_tickvalues

my_fill_gm.xticlabels1 = my_line_gm.xticlabels1 = xlabels my_fill_gm.datawc_x1 = my_line_gm.datawc_x1 = min(xlabels.keys()) my_fill_gm.datawc_x2 = my_line_gm.datawc_x2 = max(xlabels.keys())

#- Create "nice" y-axis labels (if the system variable for the # tick values is not defined) and set them in the graphics # methods. Set bounds of data frame to exactly span ylabels. # Calculate y-axis title location based on the longest label # length, set y-axis ticks and tick label locations, and set # text-table and text-orientation for y-axis tick labels:

if sysvar.__class__.y_tickvalues == None: ylabels = \ vcs.mklabels( vcs.mkscale(yrange[0], yrange[1], ytickmaxnum) ) else: ylabels = sysvar.__class__.y_tickvalues

my_fill_gm.yticlabels1 = my_line_gm.yticlabels1 = ylabels my_fill_gm.datawc_y1 = my_line_gm.datawc_y1 = min(ylabels.keys()) my_fill_gm.datawc_y2 = my_line_gm.datawc_y2 = max(ylabels.keys())

longest_ylabels = max([ len(ylabels.values()[i]) \ for i in range(len(ylabels)) ])

Page 10: "contour.py" module

my_fill_tpl.ytic1.x1 = bbllx - yticklength my_fill_tpl.ytic1.x2 = bbllx my_fill_tpl.ylabel1.x = bbllx - yticklength \ - ( longest_ylabels \ * yticklabel_fontht * fontht2norm ) my_fill_tpl.ylabel1.texttable = ttab_yticklabel my_fill_tpl.ylabel1.textorientation = tori_yticklabel

#- Position overall title, x-axis title, and y-axis title. If # there is no [xy]-axis title, the [yx]-location of the [xy]-axis # "title" is just the location of the labels; this allows us to # plot the color bar correctly:

my_fill_tpl.dataname.x = (bburx-bbllx)/2.0 + bbllx my_fill_tpl.dataname.y = bbury + ( 1.7 * title_fontht \ * fontht2norm )

my_fill_tpl.xname.x = (bburx-bbllx)/2.0 + bbllx if xtitle == None: my_fill_tpl.xname.y = my_fill_tpl.xlabel1.y else: my_fill_tpl.xname.y = my_fill_tpl.xlabel1.y \ - (2.0 * xtitle_fontht * fontht2norm)

if ytitle == None: my_fill_tpl.yname.x = my_fill_tpl.ylabel1.x else: my_fill_tpl.yname.x = my_fill_tpl.ylabel1.x \ - ( 1.6 * ytitle_fontht * fontht2norm ) my_fill_tpl.yname.y = (bbury-bblly)/2.0 + bblly

#- Legend formatting: Create text-table object that has color set # to black to use in making sure the legend (color bar) has black # lettering and set my isofill template legend text-table to that # object. Set locations of legend; legendht is the height of the # legend in normalized units; legend_fontht is the height of the # legend's text in font units:

if colorbar_loc == 0: my_fill_tpl.legend.priority = 0 else: my_fill_tpl.legend.priority = 1

legendht = 0.03 legend_fontht = 0.5 * title_fontht

ttab_legend = v.createtexttable('ttlegd'+uniq_str, 'default') tori_legend = v.createtextorientation('tolegd'+uniq_str, 'default') ttab_legend.color = 241

Page 11: "contour.py" module

ttab_legend.font = title_font tori_legend.height = legend_fontht my_fill_tpl.legend.texttable = ttab_legend my_fill_tpl.legend.textorientation = tori_legend

my_fill_tpl.legend.x2 = bburx my_fill_tpl.legend.y2 = my_fill_tpl.xname.y \ - (3.0 * xtitle_fontht * fontht2norm) \ - (3.0 * legend_fontht * fontht2norm) my_fill_tpl.legend.x1 = my_fill_tpl.yname.x my_fill_tpl.legend.y1 = my_fill_tpl.legend.y2 - legendht

#- Now that the good template settings are all done, copy it and # for the isoline graphics method. If the plottype is 'both', # turn things on/off as needed in the graphics methods to make # sure nothing is overwritten:

my_line_tpl = v.createtemplate('linetp'+uniq_str, 'filltp'+uniq_str)

if (plottype == 'both'): my_line_tpl.box1.priority = 0 my_line_tpl.dataname.priority = 0 my_line_tpl.legend.priority = 0 my_line_tpl.xname.priority = my_line_tpl.yname.priority = 0 my_line_tpl.xlabel1.priority = my_line_tpl.xlabel2.priority = 0 my_line_tpl.ylabel1.priority = my_line_tpl.ylabel2.priority = 0 my_line_tpl.xtic1.priority = my_line_tpl.xtic2.priority = 0 my_line_tpl.ytic1.priority = my_line_tpl.ytic2.priority = 0

#- Calculate and set filled-contour levels based upon the max and # min of the non-missing data in data, unless they are specified # as an input keyword. Make contour lines to be at the same place # as the filled contours and turn the contour labels on. Make the # linestyle for contour lines to be long dashed if contour are # negative and solid if they are positive or 0:

if c_levels != None: if type(c_levels) == type(N.array([])): con_levels = c_levels.tolist() else: con_levels = c_levels else: con_levels = \ vcs.mkscale(data_min, data_max, sysvar.__class__.p_maxnlev)

my_fill_gm.levels = con_levels my_fill_gm.fillareacolors = vcs.getcolors(con_levels, split=1)

my_line_gm.level = con_levels my_line_gm.label = 'y'

Page 12: "contour.py" module

i

line_pos_con = v.createline('clinep'+uniq_str, 'default') line_neg_con = v.createline('clinen'+uniq_str, 'default') line_pos_con.type = 'solid' line_neg_con.type = 'long-dash' my_line_gm.line = N.where( N.array(con_levels) >= 0.0 \ , line_pos_con, line_neg_con ).tolist()

#- Create x and y axis:

xAxis = cdms.createAxis(x[:]) yAxis = cdms.createAxis(y[:])

if xtitle != None: xAxis.id = xtitle if ytitle != None: yAxis.id = ytitle

#- Render plot, plot overall title, x-axis title, and y-axis title:

if (plottype == 'fill') or (plottype == 'both'): v.plot( dataMA, my_fill_gm, my_fill_tpl, xaxis=xAxis, yaxis=yAxis \ , continents=continents_loc \ , name=title ) sysvar.__class__.active_canvas_base_gm = 'fillgm' + uniq_str sysvar.__class__.active_canvas_base_tpl = 'filltp' + uniq_str if plottype == 'both': v.plot( dataMA, my_line_gm, my_line_tpl \ , xaxis=xAxis, yaxis=yAxis )

elif plottype == 'line': v.plot( dataMA, my_line_gm, my_line_tpl, xaxis=xAxis, yaxis=yAxis \ , continents=continents_loc \ , name=title ) sysvar.__class__.active_canvas_base_gm = 'linegm' + uniq_str sysvar.__class__.active_canvas_base_tpl = 'linetp' + uniq_str

else: raise ValueError, "contour: Bad plottype"

#- Add annotation in upper-left corner (if selected):

if annot != None: text_annot = \ v.createtext( 'ttanno'+uniq_str, 'default' \ , 'toanno'+uniq_str, '7left' ) text_annot.font = title_font text_annot.height = title_fontht * 0.5

annot_aslist = annot.splitlines() xval = N.zeros(len(annot_aslist)) + 0.03

Page 13: "contour.py" module

yval = 0.97 - ( N.arange(len(annot_aslist)) \ * 1.6 * text_annot.height * fontht2norm ) text_annot.x = xval.tolist() text_annot.y = yval.tolist() text_annot.string = annot_aslist v.plot(text_annot)

#- Set active_canvas in system variables object:

sysvar.__class__.active_canvas = v del v

# ===== end file =====