Deniz,
Please, copy the attached files to your NCL directory to solve this
problem. I already had this problem and Mary Haley send me the
gsn_code.ncl and gsn_csm.ncl scripts that allow you to use this
resource. Please, rename the old files to avoid losses.
Mateus
deni boz escreveu:
> Hi all,
>
> I want to change the thickness of the zero contour lines in plot
> consisting of both vector and contour fields. However, I got the
> following warning message
>
> "warning:gsnContourZeroLineThicknessF is not a valid resource in
> wind_aylik-2_vector at this time". Same warning was also appeared when
> I tried to change the pattern of negative contour lines.
>
> I think using "gsn_csm_vector_scalar_map" is accounted for this
> warning message. So, how can I arrange my contour lines in plots
> consisting of both vector and contour fields?
>
> Any comment will be appreciated. Thanks a lot!
>
> Deniz
>
> ------------------------------------------------------------------------
>
> _______________________________________________
> ncl-talk mailing list
> ncl-talk_at_ucar.edu
> http://mailman.ucar.edu/mailman/listinfo/ncl-talk
>
;
; $Id: gsn_code.ncl,v 1.188 2006/10/15 05:42:03 haley Exp $
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; Copyright (C) 1998 ;
; University Corporation for Atmospheric Research ;
; All Rights Reserved ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;; File: gsn_code.ncl
;;
;; Author: Mary Haley
;; National Center for Atmospheric Research
;; PO 3000, Boulder, Colorado
;;
;; Date: Sat Apr 11 12:42:53 MST 1998
;;
;; Description: This script defines all of the basic plotting and
;; miscellaneous functions and procedures used in the
;; examples in the "Getting started using NCL" documention.
;; The URL for this document is:
;;
;; http://ngwww.ucar.edu/ngdoc/ng/ug/ncl/gsun/
;;
;; To use the functions and procedures in this script,
;; you must have the line:
;;
;; load "gsn_code.ncl"
;;
;; at the top of your NCL script, before the begin statement.
;;
;***********************************************************************;
; For every function and procedure defined in this script, undefine it ;
; with a call to "undef" so it doesn't clash with other functions and ;
; procedures with the same name. ;
;***********************************************************************;
undef("smooth92d")
undef("smooth93d")
undef("hsv2rgb")
undef("tofloat")
undef("tointeger")
undef("stringtoxxx")
undef("lower_case")
undef("get_long_name_units_string")
undef("copy_var_atts")
undef("cat_strings")
undef("get_resources")
undef("set_attr")
undef("check_attr")
undef("get_res_eq_replace")
undef("get_res_eq")
undef("get_res_ne")
undef("get_res_value")
undef("get_res_value_keep")
undef("get_non_missing_pairs")
undef("get_display_mode")
undef("attsetvalues_check")
undef("spread_colors")
undef("check_for_irreg2loglin")
undef("is_data_1d_or_2d")
undef("overlay_irregular")
undef("get_plot_not_loglin")
undef("get_overlay_plot")
undef("get_contour_levels")
undef("get_contour_line_thicknesses")
undef("fix_zero_contour")
undef("set_zero_line_thickness")
undef("set_line_thickness_scale")
undef("set_neg_line_pattern")
undef("maximize_bb")
undef("gsnp_turn_off_tickmarks")
undef("gsnp_point_tickmarks_outward")
undef("gsnp_uniform_tickmark_labels")
undef("gsnp_shape_plot")
undef("gsnp_scale_plot")
undef("check_for_tickmarks_off")
undef("compute_device_coords")
undef("reset_device_coordinates")
undef("maximize_output")
undef("draw_and_frame")
undef("gsn_blank_plot")
undef("create_canvas")
undef("get_bb_res")
undef("gsn_open_ncgm")
undef("gsn_open_x11")
undef("create_labelbar")
undef("gsn_open_ps")
undef("gsn_open_pdf")
undef("gsn_open_image")
undef("gsn_open_wks")
undef("gsn_add_annotation")
undef("gsn_add_primitive")
undef("gsn_primitive")
undef("gsn_polygon")
undef("gsn_add_polygon")
undef("gsn_polygon_ndc")
undef("gsn_polyline")
undef("gsn_add_polyline")
undef("gsn_polyline_ndc")
undef("gsn_polymarker")
undef("gsn_add_polymarker")
undef("gsn_polymarker_ndc")
undef("gsn_create_labelbar_ndc")
undef("gsn_create_labelbar")
undef("gsn_labelbar_ndc")
undef("gsn_create_legend_ndc")
undef("gsn_create_legend")
undef("gsn_legend_ndc")
undef("gsn_create_text_ndc")
undef("gsn_create_text")
undef("gsn_text_ndc")
undef("gsn_text")
undef("gsn_add_text")
undef("draw_bb")
undef("gsn_panel_return")
undef("gsn_panel")
undef("gsn_attach_plots")
undef("get_rgb_values")
undef("gsn_define_colormap")
undef("gsn_retrieve_colormap")
undef("gsn_reverse_colormap")
undef("gsn_merge_colormaps")
undef("scalar_field")
undef("vector_field")
undef("hist_columns")
undef("compute_hist_vals")
undef("gsn_histogram")
undef("gsn_contour")
undef("gsn_contour_map")
undef("gsn_map")
undef("gsn_streamline")
undef("gsn_streamline_map")
undef("gsn_draw_colormap")
undef("gsn_draw_named_colors")
undef("gsn_vector")
undef("gsn_vector_contour")
undef("gsn_streamline_contour")
undef("gsn_vector_contour_map")
undef("gsn_vector_map")
undef("gsn_vector_scalar")
undef("gsn_vector_scalar_map")
undef("gsn_xy")
undef("gsn_y")
;***********************************************************************;
; function : smooth92d ;
; var[*][*]:float ;
; p:float ;
; q:float ;
; ;
; Performs smoothing on a 2-dimensional array. ;
; ;
;***********************************************************************;
function smooth92d(var[*][*]:float,p[1]:float,q[1]:float)
local dims,output,coef,m,n,p4,q4,i
begin
dims = dimsizes(var)
output = new((/dims(0),dims(1)/),float)
coef = 1 - p - q
m = dims(0)
n = dims(1)
p4 = p/4.0
q4 = q/4.0
do i = 1, m -2
output(i,1:n-2) = (p4)*(var( i-1, 1 : n-2 ) + var( i, 2 : n-1) + \
var( i+1, 1 : n-2) + var( i, 0 : n-3)) + \
(q4)*(var(i-1, 0 : n-3 ) + var(i-1, 2 : n-1) + \
var( i+1, 2 : n-1) + var( i+1, 0 : n-3))
end do
output = output + (coef * var)
if(isdimnamed(var,0).and.iscoord(var,var!0)) then
output!0 = var!0
output&$var!0$ = var&$var!0$
end if
if(isdimnamed(var,1).and.iscoord(var,var!1)) then
output!1 = var!1
output&$var!1$ = var&$var!1$
end if
return(output)
end
;***********************************************************************;
; function : smooth93d ;
; var[*][*][*]:float ;
; p:float ;
; q:float ;
; ;
; Performs smoothing on a 3-dimensional array. ;
; ;
;***********************************************************************;
function smooth93d(var[*][*][*]:float,p[1]:float,q[1]:float)
local dims,output,coef,m,n,p4,q4,i
begin
dims = dimsizes(var)
output = new((/dims(0),dims(1),dims(2)/),float)
coef = 1 - p - q
m = dims(1)
n = dims(2)
p4 = p/4.0
q4 = q/4.0
do i = 1, m -2
output(:,i,1:n-2) = (p4)*(var( :,i-1, 1 : n-2 ) + var(:, i, 2 : n-1) + \
var( :,i+1, 1 : n-2) + var(:, i, 0 : n-3)) + \
(q4)*(var( :,i-1, 0 : n-3 ) + var( :,i-1, 2 : n-1) + \
var( :,i+1, 2 : n-1) + var(:, i+1, 0 : n-3))
end do
output = output + (coef * var)
if(isdimnamed(var,0).and.iscoord(var,var!0)) then
output!0 = var!0
output&$var!0$ = var&$var!0$
end if
if(isdimnamed(var,1).and.iscoord(var,var!1)) then
output!1 = var!1
output&$var!1$ = var&$var!1$
end if
if(isdimnamed(var,2).and.iscoord(var,var!2)) then
output!2 = var!2
output&$var!2$ = var&$var!2$
end if
return(output)
end
;***********************************************************************;
; function : hsv2rgb ;
; h:float ;
; s:float ;
; v:float ;
; This function maps values from the HSV color model to the RGB color ;
; model. HSV is a good model for generating smooth color maps. See ;
; (Computer Graphics: Principles and Practice by Foley). The return ;
; value is a 2 dimensional array of rgb color triplets. The return ;
; value from this function can be directly assigned to the "wkColorMap" ;
; resource of a workstation object or to the second argument of ;
; gsn_define_colormap. ;
;***********************************************************************;
function hsv2rgb (h_old[*]:float,s_old[*]:float,v_old[*]:float)
begin
;
; Make a backup copy of the HSV values.
;
h = h_old
s = s_old
v = v_old
;
; This function converts between HSV and RGB color space
; Input: h [0.0-360.0], s [0.0-1.0], v [0.0-1.0]
; Output: r [0.0-1.0], g [0.0-1.0], b [0.0-1.0]
;
r_g_b = new((/3,dimsizes(h)/),float)
r_g_b!0 = "rgb"
r_g_b!1 = "cmap_len"
if (any((s .eq. 0.0).and.(h.eq.0.0.or.h.eq.360))) then
indexs = ind((h.eq.0.0.or.h.eq.360).and.s.eq.0.0)
r_g_b(:,indexs) = (/v(indexs),v(indexs),v(indexs)/)
delete(indexs)
end if
f = new(dimsizes(h),float)
p = new(dimsizes(h),float)
q = new(dimsizes(h),float)
t = new(dimsizes(h),float)
i = new(dimsizes(h),integer)
if any(h.eq.360.0)
h(ind(h.eq.360.0)) = 0.0
end if
h = h/60.0
i = floattoint(floor(h))
f = h - i
p = v*(1.0 - s)
q = v*(1.0 - (s*f))
t = v*(1.0 - (s*(1.0 - f)))
if any(i.eq.0) then
indexs = ind(i.eq.0)
r_g_b(:,indexs) = (/v(indexs),t(indexs),p(indexs)/)
delete(indexs)
end if
if any(i.eq.1) then
indexs = ind(i.eq.1)
r_g_b(:,indexs) = (/q(indexs),v(indexs),p(indexs)/)
delete(indexs)
end if
if any(i.eq.2) then
indexs = ind(i.eq.2)
r_g_b(:,indexs) = (/p(indexs),v(indexs),t(indexs)/)
delete(indexs)
end if
if any(i.eq.3) then
indexs = ind(i.eq.3)
r_g_b(:,indexs) = (/p(indexs),q(indexs),v(indexs)/)
delete(indexs)
end if
if any(i.eq.4) then
indexs = ind(i.eq.4)
r_g_b(:,indexs) = (/t(indexs),p(indexs),v(indexs)/)
delete(indexs)
end if
if any(i.eq.5) then
indexs = ind(i.eq.5)
r_g_b(:,indexs) = (/v(indexs),p(indexs),q(indexs)/)
delete(indexs)
end if
if(any(ismissing(r_g_b)))
print("Warning: hsv2rgb: Some invalid HSV values were passed to hsv2rgb")
end if
return(r_g_b(cmap_len|:,rgb|:))
end
;***********************************************************************;
; function : tofloat ;
; x:numeric ;
; ;
; Convert input to float. ;
; ;
;***********************************************************************;
function tofloat(x:numeric)
local xf
begin
if(typeof(x).eq."double")
xf = doubletofloat(x)
else
if(isatt(x,"_FillValue"))
xf = new(dimsizes(x),float,x@_FillValue)
else
xf = new(dimsizes(x),float)
delete(xf@_FillValue)
end if
xf = x
end if
return(xf)
end
;***********************************************************************;
; function : tointeger ;
; x:numeric ;
; ;
; Convert input to integer. ;
; ;
;***********************************************************************;
function tointeger(x:numeric)
local xi
begin
if(typeof(x).eq."double")
xi = doubletointeger(x)
else
if(typeof(x).eq."float")
xi = floattointeger(x)
else
if(isatt(x,"_FillValue"))
xi = new(dimsizes(x),integer,x@_FillValue)
else
xi = new(dimsizes(x),integer)
delete(xi@_FillValue)
end if
xi = x
end if
end if
return(xi)
end
;***********************************************************************;
; function : stringtoxxx ;
; str : string ;
; type: string ;
; ;
; Convert string to int, float or double, depending on type ;
; ;
;***********************************************************************;
function stringtoxxx(str:string,type:string)
begin
if(type.eq."double")
return(stringtodouble(str))
else
if(type.eq."float")
return(stringtofloat(str))
else
if(type.eq."integer")
return(stringtointeger(str))
end if
end if
end if
return(str)
end
;***********************************************************************;
; Function : lower_case ;
; name : string ;
; ;
; Converts "name" to lowercase. ;
;***********************************************************************;
function lower_case(name:string)
local lower, upper, lowc, upc, namec, i
begin
lower = (/"a","b","c","d","e","f","g","h","i","j","k","l","m", \
"n","o","p","q","r","s","t","u","v","w","x","y","z" /)
upper = (/"A","B","C","D","E","F","G","H","I","J","K","L","M", \
"N","O","P","Q","R","S","T","U","V","W","X","Y","Z" /)
lowc = stringtocharacter(lower)
upc = stringtocharacter(upper)
namec = stringtocharacter(name)
do i = 0, dimsizes(namec)-2
if (any(upc(:,0).eq.namec(i))) then
namec(i) = lowc(ind(upc(:,0).eq.namec(i)),0)
end if
end do
return(charactertostring(namec))
end
;***********************************************************************;
; Function : get_long_name_units_string ;
; data : numeric ;
; ;
; This function checks if the long_name and units attributes exist, and ;
; if so, constructs a string using them. A missing value is returned ;
; otherwise. ;
;***********************************************************************;
function get_long_name_units_string(data)
begin
lu_string = new(1,string)
if(isatt(data,"long_name")) then
lu_string = data_at_long_name
;
; Comment out this code for now, because I'm not sure I want
; the default behavior to change from just a long_name string
; to a long_name (units) string for now. This was added around
; version a031 (Jan 2004).
;
; if(isatt(data,"units").and.data_at_units.ne."") then
; lu_string = lu_string + " (" + data_at_units + ")"
; end if
end if
return(lu_string)
end
;***********************************************************************;
; Procedure : copy_var_atts ;
; var_from ;
; var_to ;
; att_names: string ;
; This is almost identical to D Shea's "copy_VarAtts" routine, except ;
; it allows you to specify which atts to copy. ;
;***********************************************************************;
procedure copy_var_atts(var_from,var_to,att_names)
local i
begin
if(ismissing(att_names).or.att_names.eq."") then
att_names_copy = getvaratts(var_from)
else
att_names_copy = att_names
end if
if(.not.all(ismissing(att_names_copy)))
do i = 0,dimsizes(att_names_copy)-1
if (isatt(var_from,att_names_copy(i)).and.\
.not.isatt(var_to,att_names_copy(i))) then
var_to@$att_names_copy(i)$ = var_from@$att_names_copy(i)$
end if
end do
end if
end
;***********************************************************************;
; Function : cat_strings ;
; strings : string ;
; ;
; Takes an array of strings and cats them into a single string. ;
;***********************************************************************;
function cat_strings(str_array)
local i, slen
begin
slen = dimsizes(str_array)
single_string = "'" + str_array(0) + "'"
do i=1,slen-1
single_string = single_string + " '" + str_array(i) + "'"
end do
return(single_string)
end
;***********************************************************************;
; Function : get_resources ;
; res:logical ;
; ;
; This function takes a logical value and a list of resources, and ;
; assigns them to another variable. If res is False, however, then no ;
; resources are carried over, but res is set to True for future use. ;
; ;
;***********************************************************************;
function get_resources(res:logical)
begin
if(res) then
res2 = res
else
;
; Set res2 to True, but don't carry over any resources.
;
res2 = True
end if
return(res2)
end
;***********************************************************************;
; Procedure : set_attr ;
; res:logical ;
; att_name: string ;
; att_value ;
; ;
; Add resource and its value to a resource list if it isn't already set.;
;***********************************************************************;
procedure set_attr(res:logical,att_name:string,att_value)
begin
res = True
if(.not.isatt(res,att_name))
res@$att_name$ = att_value
end if
return
end
;***********************************************************************;
; Function : check_attr ;
; res : logical ;
; att_name : string ;
; att_value ;
; convert_lower: logical ;
; ;
; Checks if res_at_att_name exists and if it is equal to att_value. ;
;***********************************************************************;
function check_attr(res:logical,att_name:string,att_value, \
convert_lower:logical)
local res2, new_att_value, is_att_value_string, is_att_name_string
begin
res2 = res
if(res2.and.isatt(res2,att_name))
if(typeof(att_value).eq."string") then
is_att_value_string = True
else
is_att_value_string = False
end if
if(typeof(res@$att_name$).eq."string") then
is_att_name_string = True
else
is_att_name_string = False
end if
;
; If one value is a string and the other isn't, then we can't
; compare them, and we just have to return False.
if(is_att_name_string.ne.is_att_value_string) then
return(False)
end if
if(is_att_value_string.and.convert_lower)
new_att_value = lower_case(att_value)
res2@$att_name$ = lower_case(res2@$att_name$)
else
new_att_value = att_value
end if
if(res2@$att_name$.eq.new_att_value)
return(True)
end if
end if
return(False)
end
;***********************************************************************;
; res:logical ;
; prefix: string ;
; rep_prefix: string ;
; ;
; Get a list of resources that start with res_prefix, and replace them ;
; with rep_prefix. ;
;***********************************************************************;
function get_res_eq_replace(res,res_prefix:string,rep_prefix:string)
local i, j, ret_res, res2, attnames, res_index, nres2
begin
ret_res = False
if(res.and..not.any(ismissing(getvaratts(res))))
attnames = getvaratts(res)
do i = 0, dimsizes(attnames)-1
res2 = stringtocharacter(attnames(i))
nres2 = dimsizes(res2)
;
; Loop through the resource prefixes and determine their length
; so that we only check that many characters in the resource name.
;
do j = 0, dimsizes(res_prefix)-1
res_prefix_c = stringtocharacter(res_prefix(j))
rpclen = dimsizes(res_prefix_c)-1 ; Don't count null char
if(nres2.ge.rpclen.and. \
charactertostring(res2(0:rpclen-1)).eq.res_prefix(j))
ret_res = True
;
; Make sure we have enough room in the rest of the resource name to
; replace the current prefix with the rep_prefix. This code will take
; something like "gsnPanelFigureStringsFontHeightF" and replace it with
; "txFontHeightF".
;
if(rep_prefix.ne."".and.nres2.gt.(rpclen+1)) then
resnew_attname = rep_prefix + charactertostring(res2(rpclen:nres2-2))
ret_res@$resnew_attname$ = res@$attnames(i)$
else
ret_res@$attnames(i)$ = res@$attnames(i)$
end if
end if
delete(res_prefix_c)
end do
delete(res2)
end do
delete(attnames)
end if
return(ret_res)
end
;***********************************************************************;
; Function : get_res_eq ;
; res:logical ;
; prefix: string ;
; ;
; Get a list of resources that start with res_prefix. ;
;***********************************************************************;
function get_res_eq(res,res_prefix:string)
local i, j, ret_res, res2, attnames, res_index
begin
return(get_res_eq_replace(res,res_prefix,""))
end
;***********************************************************************;
; Function : get_res_ne ;
; res:logical ;
; prefix: string ;
; ;
; Get a list of resources that don't start with res_prefix. ;
;***********************************************************************;
function get_res_ne(res,res_prefix:string)
local i, j, ret_res, res2, attnames, res_index
begin
ret_res = False
if(res.and..not.any(ismissing(getvaratts(res))))
attnames = getvaratts(res)
do i = 0, dimsizes(attnames)-1
res2 = stringtocharacter(attnames(i))
;
; Loop through the resource prefixes and determine their length
; so that we only check that many characters in the resource name.
;
j = 0
found = False
do while(.not.found.and.j.le.dimsizes(res_prefix)-1)
res_prefix_c = stringtocharacter(res_prefix(j))
rpclen = dimsizes(res_prefix_c)-1 ; Don't count null char
if(dimsizes(res2).ge.rpclen.and.\
charactertostring(res2(0:rpclen-1)).eq.res_prefix(j))
found = True
end if
j = j + 1
delete(res_prefix_c)
end do
if(.not.found) then
ret_res = True
ret_res@$attnames(i)$ = res@$attnames(i)$
end if
delete(res2)
end do
delete(attnames)
end if
return(ret_res)
end
;***********************************************************************;
; Function : get_res_value ;
; res ;
; resname:string ;
; default_val ;
; ;
; This function checks to see if the given resource has been set, and if;
; so, it returns its value and removes it from the resource list. ;
; Otherwise, it returns the default value which is the last argument ;
; passed in. ;
;***********************************************************************;
function get_res_value(res,resname:string,default_val)
local res_value
begin
if(((typeof(res).eq."logical".and.res).or.(typeof(res).ne."logical")).and.\
.not.any(ismissing(getvaratts(res)))) then
if(isatt(res,resname)) then
return_val = res@$resname$
delete(res@$resname$)
else
return_val = default_val
end if
else
return_val = default_val
end if
return(return_val)
end
;***********************************************************************;
; Function : get_res_value_keep ;
; res:logical ;
; resname:string ;
; default_val ;
; ;
; This function checks to see if the given resource has been set, and if;
; so, it returns its value and keeps it from the resource list. ;
; Otherwise, it returns the default value which is the last argument ;
; passed in. ;
; ;
;***********************************************************************;
function get_res_value_keep(res,resname:string,default_val)
local res_value
begin
if(((typeof(res).eq."logical".and.res).or.(typeof(res).ne."logical")).and.\
.not.any(ismissing(getvaratts(res)))) then
if(isatt(res,resname)) then
return_val = res@$resname$
else
return_val = default_val
end if
else
return_val = default_val
end if
return(return_val)
end
;***********************************************************************;
; This function peruses two arrays of the same length and returns pairs ;
; of indices that represent ranges of data values where there are no ;
; missing values. ;
;***********************************************************************;
function get_non_missing_pairs(x[*]:numeric,y[*]:numeric)
local ibeg, iend, indices, ndimx, ndimy, is_missing
begin
ndimx = dimsizes(x)
ndimy = dimsizes(y)
if(ndimx.ne.ndimy)
print("get_non_missing_pairs: x and y must be the same length")
end if
indices = new((/ndimx,2/),integer,-999)
counter = 0
ibeg = -1 ; First non-missing point in a group.
do i = 0,ndimx-1
if(.not.ismissing(x(i)).and..not.ismissing(y(i)))
if(ibeg.lt.0) ; on the first point of the line
ibeg = i
iend = i ; Represents last non-missing point in a group
else
iend = i
end if
is_missing = False
else
is_missing = True
end if
if(ibeg.ge.0.and.(is_missing.or.iend.eq.ndimx-1))
indices(counter,0) = ibeg
indices(counter,1) = iend
ibeg = -1 ; Reinitialize
counter = counter + 1
end if
end do
return(indices)
end
;***********************************************************************;
; Function : get_display_mode ;
; res:logical ;
; name:string ;
; value ;
; ;
; This procedure checks if a DisplayMode resource is set, and returns ;
; an integer value if it's set as a string. ;
;***********************************************************************;
function get_display_mode(res:logical,name:string,value)
local display_mode, new_display_mode
begin
display_mode = get_res_value_keep(res,name,value)
if(typeof(display_mode).ne."string") then
return(display_mode)
else
new_display_mode = -1 ; Default is -1 ("nocreate")
if(lower_case(display_mode).eq."nocreate") then
new_display_mode = -1
end if
if(lower_case(display_mode).eq."never") then
new_display_mode = 0
end if
if(lower_case(display_mode).eq."always") then
new_display_mode = 1
end if
if(lower_case(display_mode).eq."conditional") then
new_display_mode = 2
end if
delete(display_mode)
display_mode = new_display_mode
end if
return(new_display_mode)
end
;***********************************************************************;
; Procedure : attsetvalues_check ;
; plot:graphic ;
; res:logical ;
; ;
; This procedure passes plot and res to attsetvalues only if res is ;
; True and non-empty. ;
;***********************************************************************;
procedure attsetvalues_check(plot:graphic,res:logical)
begin
if(res.and..not.any(ismissing(getvaratts(res))))
attsetvalues(plot,res)
end if
return
end
;***********************************************************************;
; Function : spread_colors ;
; wks:graphic ;
; plot:graphic ;
; min_index:logical ;
; max_index:logical ;
; res:logical ;
; ;
; By default, all of the plotting routines use the first n colors from ;
; a color map, where "n" is the number of contour or vector levels. ;
; If "gsnSpreadColors" is set to True, then the colors are spanned ;
; across the whole color map. The min_index and max_index values are ;
; used for the start and end colors. If either min_index or max_index ;
; is < 0 (but not both), then this indicates to use ncol-i, where "i" ;
; is equal to the negative value. ;
; ;
; If after adjusting for negative index color(s), and ;
; max_index < min_index, then the colors are reversed. ;
; ;
; The "res" is just to check if cnFillColors or vcLevelColors are ;
; already being set, and to issue a warning message (spread_colors will ;
; take precedence over cnFillColors.) ;
;***********************************************************************;
function spread_colors(wks:graphic,plot:graphic,min_index:integer,\
max_index:integer,res:logical)
local ncols, lcount, fcols, icols, minix, maxix, nc, fmin, fmax, class,\
levelcountres
begin
class = NhlClassName(plot)
if(.not.any(class.eq.(/"contourPlotClass","logLinPlotClass",\
"irregularPlotClass","vectorPlotClass"/)))
print("spread_colors: invalid plot: defaulting")
return(ispan(2,255,1))
end if
if (class.eq."contourPlotClass".or.class.eq."logLinPlotClass".or.\
class.eq."irregularPlotClass")
if(isatt(res,"cnFillColors")) then
print("spread_colors: warning: you are setting both cnFillColors and")
print(" gsnSpreadColors. Your cnFillColors resource will")
print(" be ignored. If this is not desired, delete the")
print(" setting of gsnSpreadColors or set it to False.")
end if
levelcountres = "cnLevelCount"
else
levelcountres = "vcLevelCount"
if(isatt(res,"vcLevelolors")) then
print("spread_colors: warning: you are setting both vcLevelColors and")
print(" gsnSpreadColors. Your vcLevelColors resource will")
print(" be ignored. If this is not desired, delete the")
print(" setting of gsnSpreadColors or set it to False.")
end if
end if
getvalues wks
"wkColorMapLen" : ncols
end getvalues
if (class.eq."contourPlotClass".or.class.eq."vectorPlotClass")
getvalues plot
levelcountres : lcount
end getvalues
else
getvalues plot_at_contour
levelcountres : lcount
end getvalues
end if
;
; -1 indicates that min/max_index should be set equal to ncols - 1
; -2 indicates that min/max_index should be set equal to ncols - 2, etc.
;
; If after adjusting for negative indices, and maxix < minix, then
; this implies that the user wants to reverse the colors.
;
if (min_index .lt. 0)
minix = ncols + min_index
else
minix = min_index
end if
if (max_index .lt. 0)
maxix = ncols + max_index
else
maxix = max_index
end if
;
; Make sure indices fall within range of the color map.
;
minix = min((/ncols-1,max((/0,minix/))/))
maxix = min((/ncols-1,max((/0,maxix/))/))
;
; If maxix < minix, then colors are to be reversed.
;
reverse = False
if(maxix.lt.minix)
reverse = True
itmp = maxix
maxix = minix
minix = itmp
end if
fmin = new(1,float)
fmax = new(1,float)
fmin = minix
fmax = maxix
fcols = fspan(fmin,fmax,lcount+1)
if(.not.reverse)
icols = tointeger(fcols + 0.5)
else
icols = tointeger(fcols(::-1) + 0.5)
end if
return(icols)
end
;***********************************************************************;
; Function : get_overlay_plot ;
; plot : graphic ;
; class_name : string ;
; plot_index : integer ;
; ;
; Get a specified overlaid plot id. This function is based on Dennis' ;
; original GetOverlayPlot function. ;
;***********************************************************************;
function get_overlay_plot(plot:graphic,class_name:string,plot_index:integer)
begin
;
; Retrieve objects that have been overlaid on "plot".
;
getvalues plot
"pmOverlaySequenceIds" : overlay_ids
end getvalues
;
; Loop through these objects and check if any of them are a
; match.
;
if(.not.any(ismissing(overlay_ids))) then
num_instances = 0
do i=0,dimsizes(overlay_ids)-1
if(NhlClassName(overlay_ids(i)).eq.class_name)
if(num_instances.eq.plot_index) then
return(overlay_ids(i))
end if
num_instances = num_instances + 1
end if
end do
end if
;
; If no match found, then check the plot itself.
;
if(NhlClassName(plot).eq.class_name) then
return(plot)
end if
;
; No match found, so return a missing object.
;
print("get_overlay_plot: Error: no plot found matching conditions")
print(" Returning a missing value.")
dum = new(1,graphic)
return(dum)
end
;***********************************************************************;
; Function : get_contour_levels ;
; plot: graphic ;
; ;
; Get contour levels associated with "plot". ;
; ;
;***********************************************************************;
function get_contour_levels(plot:graphic)
local overlay_plot
begin
overlay_plot = get_overlay_plot (plot, "contourPlotClass", 0)
if(.not.ismissing(overlay_plot)) then
getvalues overlay_plot
"cnLevels" : levels
"cnLevelFlags" : level_flags
end getvalues
levels_at_flags = level_flags
return(levels)
end if
;
; Return missing if no plot was found.
;
dum = new(1,float)
return(dum)
end
;***********************************************************************;
; Function : get_contour_line_thicknesses ;
; plot: graphic ;
; ;
; Get contour line thicknesses associated with "plot". ;
; ;
;***********************************************************************;
function get_contour_line_thicknesses(plot:graphic)
local overlay_plot
begin
overlay_plot = get_overlay_plot (plot, "contourPlotClass", 0)
if(.not.ismissing(overlay_plot)) then
getvalues overlay_plot
"cnLineThicknesses" : thicknesses
end getvalues
return(thicknesses)
end if
;
; Return missing if no plot was found.
;
dum = new(1,float)
return(dum)
end
;***********************************************************************;
; Function : fix_zero_contour ;
; levels:numeric ;
; ;
; Make sure the 0th contour (if it exists) really is "0" and not ;
; something like "1.00001e-08". But, we also have to make sure we don't;
; have values like 1e-10, 1e-9, etc, where we *do* want "1e-10" label ;
; and not a "0". Don't even bother with checking if the minimum ;
; difference between the levels is less than 1e-5. ;
;***********************************************************************;
function fix_zero_contour(levels)
begin
nlevels = dimsizes(levels)
if(nlevels.gt.1) then
delta_levels = min( levels(1:nlevels-1) - levels(0:nlevels-2) )
if(delta_levels.ge.1e-5)
do n=1,nlevels-2
if(fabs(levels(n)).le.1.e-5.and.levels(n-1).lt.0..and.levels(n+1).gt.0.)
levels(n) = 0.0
end if
end do
end if
end if
return(levels)
end
;***********************************************************************;
; Function : set_zero_line_thickness ;
; plot : graphic ;
; zthickness : numeric ;
; cthickness : numeric ;
; ;
; Make the 0-th contour line the given thickness. ;
; ;
; Note that this function also sets the rest of the line thicknesses to ;
; 1, because it assumes if the user wants to set the thickness of other ;
; lines, he/she can do so with the cnLineThicknesses resource. ;
; ;
; If thickness is equal to 0, then the line is just not drawn. ;
; ;
;***********************************************************************;
function set_zero_line_thickness(plot:graphic,zthickness,cthickness)
begin
levels = get_contour_levels (plot)
nlevels = dimsizes(levels)
if (any(ismissing(levels)).or. nlevels.le.0) then
print ("set_zero_line_thickness: invalid contour levels, returning...")
return (plot)
end if
levels = fix_zero_contour (levels)
thicknesses = new(dimsizes(levels), float)
thicknesses = cthickness
zeroind = ind(levels.eq.0.0) ; Get index where level equals 0.0
if(.not.ismissing(zeroind)) then
if(zthickness.gt.0) then
thicknesses(zeroind) = zthickness
else
thicknesses(zeroind) = 1. ; Make it 1.0, but it doesn't matter
; b/c we are turning off the drawing
; of this line.
levels_at_flags(zeroind) = 0 ; Turn off the zero contour line
end if
end if
overlay_plot = get_overlay_plot (plot, "contourPlotClass", 0)
if(zthickness.gt.0) then
setvalues overlay_plot
"cnMonoLineThickness" : False
"cnLineThicknesses" : thicknesses
end setvalues
else
setvalues overlay_plot
"cnMonoLineThickness" : False
"cnLevelFlags" : levels_at_flags
"cnLineThicknesses" : thicknesses
end setvalues
end if
return (plot)
end
;***********************************************************************;
; Function : set_line_thickness_scale ;
; plot : graphic ;
; scale : numeric ;
; ;
; Scale the line thickness by the given numbers. ;
; ;
;***********************************************************************;
function set_line_thickness_scale(plot:graphic,scale)
begin
thicknesses = get_contour_line_thicknesses (plot)
nthicknesses = dimsizes(thicknesses)
if (any(ismissing(thicknesses)).or. nthicknesses.le.0) then
print ("set_line_thickness_scale: invalid contour line thicknesses, returning...")
return (plot)
end if
thicknesses = scale * thicknesses
overlay_plot = get_overlay_plot (plot, "contourPlotClass", 0)
setvalues overlay_plot
"cnMonoLineThickness" : False
"cnLineThicknesses" : thicknesses
end setvalues
return (plot)
end
;***********************************************************************;
; Function : set_neg_line_pattern ;
; plot : graphic ;
; pattern : numeric ;
; ;
; Set the dash pattern of negative contour lines. ;
; ;
; Note that this function also sets the rest of the line patterns to 0 ;
; because it assumes if the user wants to set the patterns of the other ;
; lines, he/she can do so with the cnLineDashPatterns resource. ;
; ;
;***********************************************************************;
function set_neg_line_pattern(plot:graphic,pattern)
begin
levels = get_contour_levels (plot)
nlevels = dimsizes(levels)
if (any(ismissing(levels)) .or. nlevels.le.0) then
print ("set_neg_line_pattern: invalid contour levels, returning...")
return (plot)
end if
levels = fix_zero_contour (levels)
patterns = new(nlevels,integer)
patterns = 0 ; default to solid line.
if(.not.any(ismissing(patterns))) then
do n=0,nlevels-1
if (levels(n).lt.0.) then
patterns(n) = pattern
end if
end do
end if
overlay_plot = get_overlay_plot (plot, "contourPlotClass", 0)
setvalues overlay_plot
"cnMonoLineDashPattern" : False
"cnLineDashPatterns" : patterns
end setvalues
return (plot)
end
;***********************************************************************;
; Procedure : check_for_irreg2loglin ;
; res:logical ;
; xlinear:logical ;
; ylinear:logical ;
; xlog:logical ;
; ylog:logical ;
; ;
; If any of the sf*Array or vf*Array resources are set, this puts the ;
; plot into "irregular" mode. If you want to make any of your axes log ;
; or linear then, you have to overlay it on a LogLin plot. ;
; ;
; By setting one of the resources gsn{X,Y}AxisIrregular2Linear or ;
; gsnXAxisIrregular2Log to True, the overlay is done for you. This ;
; procedure checks for these resources being set and sets some logical ;
; variables accordingly. ;
;***********************************************************************;
procedure check_for_irreg2loglin(res:logical,xlinear:logical, \
ylinear:logical,\
xlog:logical,ylog:logical)
begin
xlinear = get_res_value(res,"gsnXAxisIrregular2Linear",xlinear)
ylinear = get_res_value(res,"gsnYAxisIrregular2Linear",ylinear)
xlog = get_res_value(res,"gsnXAxisIrregular2Log",xlog)
ylog = get_res_value(res,"gsnYAxisIrregular2Log",ylog)
if(ylog.and.ylinear)
print("Error: You cannot set both gsnYAxisIrregular2Log")
print("and gsnYAxisIrregular2Linear to True.")
exit
end if
if(xlog.and.xlinear)
print("Error: You cannot set both gsnXAxisIrregular2Log")
print("and gsnXAxisIrregular2Linear to True.")
exit
end if
return
end
;***********************************************************************;
; ;
; This function checks if a data array is 1D or 2D and returns False if ;
; is not. ;
; ;
;***********************************************************************;
function is_data_1d_or_2d(data)
begin
dims = dimsizes(data)
rank = dimsizes(dims)
if(rank.eq.1.or.rank.eq.2) then
return(True)
else
return(False)
end if
end
;***********************************************************************;
; Function : overlay_irregular ;
; wks:graphic ;
; wksname: string ;
; overlay_plot_object: graphic ;
; data_object: graphic ;
; xlinear: logical ;
; ylinear: logical ;
; xlog: logical ;
; ylog: logical ;
; type: string ;
; llres: logical ;
; ;
; If xlinear and/or ylinear are set to linear or log, then overlay ;
; plot on an irregularPlotClass so that we can linearize or logize ;
; the appropriate axis. ;
;***********************************************************************;
function overlay_irregular(wks,wksname,overlay_plot_object:graphic,\
data_object:graphic,xlinear:logical, \
ylinear:logical,xlog:logical,ylog:logical,\
type:string,llres:logical)
local xaxistype,yaxistype,trxmin,trymin,trxmax,trymax,Xpts,Ypts,is_tm_mode
begin
if(xlinear) then
xaxistype = "LinearAxis"
else
if(xlog) then
xaxistype = "LogAxis"
else
xaxistype = "IrregularAxis"
end if
end if
if(ylinear) then
yaxistype = "LinearAxis"
else
if(ylog) then
yaxistype = "LogAxis"
else
yaxistype = "IrregularAxis"
end if
end if
;
; Retrieve information about existing plot so we can use these values
; to create new overlay plot object.
;
getvalues overlay_plot_object
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end getvalues
if(type.eq."contour") then
getvalues data_object
"sfXArray" : Xpts
"sfYArray" : Ypts
end getvalues
else
if(type.eq."vector".or.type.eq."streamline") then
getvalues data_object
"vfXArray" : Xpts
"vfYArray" : Ypts
end getvalues
end if
end if
;
; If x/yaxistype is irregular, then we must set trX/YCoordPoints.
; Oherwise, we can't set trX/YCoordPoints, because we'll get an
; error message. So, we have to do all kinds of tests to see which
; axes are irregular, and which ones are log or linear.
;
; Also, if Xpts or Ypts are missing, this means the corresponding
; axis can't be irregular.
;
if(any(ismissing(Xpts)).and.xaxistype.eq."IrregularAxis") then
xaxistype = "LinearAxis"
end if
if(any(ismissing(Ypts)).and.yaxistype.eq."IrregularAxis") then
yaxistype = "LinearAxis"
end if
;
; If both axes at this point are Irregular, then there is no point
; in overlaying it on an irregular plot class. We then have
; three possible cases:
;
; Case 1: Both X and Y axes are either linear or log.
; Case 2: X axis is irregular and Y axis is linear or log.
; Case 3: Y axis is irregular and X axis is linear or log.
;
if(xaxistype.eq."IrregularAxis".and.yaxistype.eq."IrregularAxis") then
return(overlay_plot_object)
else
;
; Case 1
;
; If pmTickMarkDisplayMode is set, we need to set it during the
; create call, and not afterwards. But, we can't assume a default
; default value, because it varies depending on the type of plot
; being created. So, we have to do the kludgy thing of checking
; for it, and only setting it if the user has set it.
;
is_tm_mode = isatt(llres,"pmTickMarkDisplayMode")
if(is_tm_mode) then
tm_mode = get_display_mode(llres,"pmTickMarkDisplayMode","NoCreate")
delete(llres_at_pmTickMarkDisplayMode)
end if
if(xaxistype.ne."IrregularAxis".and. \
yaxistype.ne."IrregularAxis") then
if(is_tm_mode) then
plot_object = create wksname + "_irregular" irregularPlotClass wks
"pmTickMarkDisplayMode" : tm_mode
"trXAxisType" : xaxistype
"trYAxisType" : yaxistype
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
else
plot_object = create wksname + "_irregular" irregularPlotClass wks
"trXAxisType" : xaxistype
"trYAxisType" : yaxistype
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
end if
end if
;
; Case 2
;
if(xaxistype.eq."IrregularAxis".and. \
yaxistype.ne."IrregularAxis") then
if(is_tm_mode) then
plot_object = create wksname + "_irregular" irregularPlotClass wks
"pmTickMarkDisplayMode" : tm_mode
"trXAxisType" : xaxistype
"trYAxisType" : yaxistype
"trXCoordPoints" : Xpts
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
else
plot_object = create wksname + "_irregular" irregularPlotClass wks
"trXAxisType" : xaxistype
"trYAxisType" : yaxistype
"trXCoordPoints" : Xpts
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
end if
end if
;
; Case 3
;
if(yaxistype.eq."IrregularAxis".and. \
xaxistype.ne."IrregularAxis") then
if(is_tm_mode) then
plot_object = create wksname + "_irregular" irregularPlotClass wks
"pmTickMarkDisplayMode" : tm_mode
"trXAxisType" : xaxistype
"trYAxisType" : yaxistype
"trYCoordPoints" : Ypts
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
else
plot_object = create wksname + "_irregular" irregularPlotClass wks
"trXAxisType" : xaxistype
"trYAxisType" : yaxistype
"trYCoordPoints" : Ypts
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
end if
end if
attsetvalues_check(plot_object,llres)
overlay(plot_object,overlay_plot_object)
plot_object@$type$ = overlay_plot_object
end if
return(plot_object)
end
;***********************************************************************;
; function : get_plot_not_loglin ;
; plot:graphic ;
; ;
; Determine what class type "plot" is. If it's a logLinPlotClass, then ;
; It should have an attribute "contour" or "vector" that is the ;
; corresponding contour or vector plot. ;
; ;
;***********************************************************************;
function get_plot_not_loglin(plot:graphic)
local class
begin
new_plot = new(1,graphic)
new_plot_at_plot_type = "unknown"
class = NhlClassName(plot)
if(class(0).ne."contourPlotClass".and.class(0).ne."vectorPlotClass".and. \
class(0).ne."xyPlotClass") then
if(isatt(plot,"contour")) then
new_plot = plot_at_contour
new_plot_at_plot_type = "contour"
else
if(isatt(plot,"vector")) then
new_plot = plot_at_vector
new_plot_at_plot_type = "vector"
else
found = False
getvalues plot
"pmOverlaySequenceIds" : base_ids
end getvalues
if(.not.any(ismissing(base_ids))) then
nbase = dimsizes(base_ids)
i = 0
do while(.not.found.and.i.lt.nbase)
bclass = NhlClassName(base_ids(i))
if(bclass.eq."contourPlotClass") then
new_plot = base_ids(i)
new_plot_at_plot_type = "contour"
found = True
end if
if(bclass.eq."vectorPlotClass") then
new_plot = base_ids(i)
new_plot_at_plot_type = "vector"
found = True
end if
if(bclass.eq."xyPlotClass") then
new_plot = base_ids(i)
new_plot_at_plot_type = "xy"
found = True
end if
i = i + 1
end do
end if
if(.not.found) then
new_plot = plot(0)
end if
end if
end if
else
if(class(0).eq."contourPlotClass") then
new_plot = plot(0)
new_plot_at_plot_type = "contour"
else
if(class(0).eq."vectorPlotClass") then
new_plot = plot(0)
new_plot_at_plot_type = "vector"
else
if(class(0).eq."xyPlotClass") then
new_plot = plot(0)
new_plot_at_plot_type = "xy"
end if
end if
end if
end if
return(new_plot)
end
;**********************************************************************;
; Function : maximize_bb ;
; plot : graphic ;
; res : logical ;
; ;
; This function computes the viewport coordinates needed to optimize ;
; the size of a plot on a page. If the plot is too big for the ;
; viewport, then this function will decrease the plot size. ;
; ;
; plot : plot to maximize on the page. ;
; ;
; res : list of optional resources. Ones accepted include: ;
; ;
; "gsnBoxMargin" - margin to leave around plots (in NDC units, ;
; default is 0.02) ;
; ;
;**********************************************************************;
function maximize_bb(plot[1]:graphic,res:logical)
local coords, top, bot, lft, rgt, width, height, margin
begin
;
; Get resources.
;
margin = get_res_value_keep(res,"gsnBoxMargin",0.02)
;
; Get bounding box of plot.
;
bb = NhlGetBB(plot)
top = bb(0)
bot = bb(1)
lft = bb(2)
rgt = bb(3)
;
; Get height/width of plot in NDC units.
;
uw = rgt - lft
uh = top - bot
;
; Calculate scale factor needed to make plot larger (or smaller, if it's
; outside the viewport).
;
scale = (1 - 2*margin)/max((/uw,uh/))
;
; Get the viewport.
;
getvalues plot
"vpXF" : vpx
"vpYF" : vpy
"vpWidthF" : vpw
"vpHeightF" : vph
end getvalues
dx = scale * (vpx - lft) ; Calculate distance from plot's left position
; to its leftmost annotation
dy = scale * (top - vpy) ; Calculate distance from plot's top position
; to its topmost annotation.
;
; Calculate new viewport coordinates.
;
new_uw = uw * scale
new_uh = uh * scale
new_ux = .5 * (1-new_uw)
new_uy = 1 - .5 * (1-new_uh)
new_vpx = new_ux + dx
new_vpy = new_uy - dy
new_vpw = vpw * scale
new_vph = vph * scale
;
; Return new coordinates
;
return((/new_vpx,new_vpy,new_vpw,new_vph/))
end
;***********************************************************************;
; Procedure : gsnp_turn_off_tickmarks ;
; res:logical ;
; ;
; By default, tickmarks are drawn on all plots that aren't overlaid on ;
; a map. If gsnTickMarksOn is set to False, then this turns off the ;
; drawing of tick marks. This procedure just sets the resources ;
; necessary in order to turn off tick marks. ;
;***********************************************************************;
procedure gsnp_turn_off_tickmarks(res:logical)
begin
set_attr(res,"tmXBBorderOn",False )
set_attr(res,"tmXBOn", False)
set_attr(res,"tmXTBorderOn",False)
set_attr(res,"tmXTOn", False)
set_attr(res,"tmYLBorderOn",False)
set_attr(res,"tmYLOn", False)
set_attr(res,"tmYRBorderOn",False)
set_attr(res,"tmYROn", False)
end
;***********************************************************************;
; Procedure : gsnp_point_tickmarks_outward ;
; plot:object ;
; res:logical ;
; x_major_length:numeric ;
; y_major_length:numeric ;
; x_minor_length:numeric ;
; y_minor_length:numeric ;
; major_length:numeric ;
; minor_length:numeric ;
; ;
; By default, tickmarks are drawn pointing inwards. This procedure ;
; makes them point out. This procedure also sets the major and/or minor ;
; tickmarks on both axes to be the same length if the major and/or minor;
; tickmarks lengths are != 0. ;
;***********************************************************************;
procedure gsnp_point_tickmarks_outward(plot:graphic,res:logical, \
x_major_length, y_major_length, \
x_minor_length, y_minor_length, \
major_length, minor_length,point_outward)
local tmres
begin
if(major_length.lt.0.)
getvalues plot
"tmXBMajorLengthF" : x_major_length
"tmYLMajorLengthF" : y_major_length
end getvalues
major_length = min((/x_major_length,y_major_length/))
if(x_major_length.gt.0..and.y_major_length.gt.0.)
x_major_length = min((/x_major_length,y_major_length/))
y_major_length = x_major_length
end if
else
if(x_major_length.gt.0.)
x_major_length = major_length
end if
if(y_major_length.gt.0.)
y_major_length = major_length
end if
end if
if(minor_length.lt.0.)
getvalues plot
"tmXBMinorLengthF" : x_minor_length
"tmYLMinorLengthF" : y_minor_length
end getvalues
if(x_minor_length.gt.0..and.y_minor_length.gt.0.)
x_minor_length = min((/x_minor_length,y_minor_length/))
y_minor_length = x_minor_length
end if
else
if(x_minor_length.gt.0.)
x_minor_length = minor_length
end if
if(y_minor_length.gt.0.)
y_minor_length = minor_length
end if
end if
tmres = res
tmres = True
set_attr(tmres,"tmXBMajorLengthF" , x_major_length)
set_attr(tmres,"tmXBMinorLengthF" , x_minor_length)
set_attr(tmres,"tmXTMajorLengthF" , x_major_length)
set_attr(tmres,"tmXTMinorLengthF" , x_minor_length)
set_attr(tmres,"tmYLMajorLengthF" , y_major_length)
set_attr(tmres,"tmYLMinorLengthF" , y_minor_length)
set_attr(tmres,"tmYRMajorLengthF" , y_major_length)
set_attr(tmres,"tmYRMinorLengthF" , y_minor_length)
if (point_outward) then
set_attr(tmres,"tmXBMajorOutwardLengthF" , x_major_length)
set_attr(tmres,"tmXBMinorOutwardLengthF" , x_minor_length)
set_attr(tmres,"tmXTMajorOutwardLengthF" , x_major_length)
set_attr(tmres,"tmXTMinorOutwardLengthF" , x_minor_length)
set_attr(tmres,"tmYLMajorOutwardLengthF" , y_major_length)
set_attr(tmres,"tmYLMinorOutwardLengthF" , y_minor_length)
set_attr(tmres,"tmYRMajorOutwardLengthF" , y_major_length)
set_attr(tmres,"tmYRMinorOutwardLengthF" , y_minor_length)
end if
attsetvalues_check(plot,tmres)
return
end
;***********************************************************************;
; Procedure : gsnp_uniform_tickmark_labels ;
; plot:object ;
; res:logical ;
; font_height ;
; ;
; This procedure makes the tickmark labels the same font height on both ;
; axes. If font_height <= 0., then a uniform font height is calculated. ;
;***********************************************************************;
procedure gsnp_uniform_tickmark_labels(plot:graphic,res:logical, \
font_height)
local xbfont, ylfont, tmres
begin
; Get tickmark labels sizes
if(font_height.le.0)
getvalues plot
"tmXBLabelFontHeightF" : xbfont
"tmYLLabelFontHeightF" : ylfont
end getvalues
font_height = min((/xbfont,ylfont/))
end if
; Make tickmark label sizes the same.
tmres = res
tmres = True
set_attr(tmres,"tmXBLabelFontHeightF" , font_height)
set_attr(tmres,"tmYLLabelFontHeightF" , font_height)
set_attr(tmres,"tmXTLabelFontHeightF" , font_height)
set_attr(tmres,"tmYRLabelFontHeightF" , font_height)
attsetvalues_check(plot,tmres)
return
end
;***********************************************************************;
; Procedure : gsnp_shape_plot ;
; plot:graphic ;
; ;
; If gsnShape is set to True, then the plot is scaled such that the X ;
; and Y axes are proportional to each other. ;
;***********************************************************************;
procedure gsnp_shape_plot(plot:graphic)
local xf, yf, width, height, trxmin, trxmax, trymin, trymax, xrange, yrange, \
new_xf, new_yf, new_width, new_height
begin
getvalues plot
"vpXF" : xf
"vpYF" : yf
"vpWidthF" : width
"vpHeightF" : height
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end getvalues
xrange = trxmax - trxmin
yrange = trymax - trymin
if(xrange.lt.yrange)
new_width = width * (xrange/yrange)
new_height = height
new_xf = xf + 0.5*(width-new_width)
new_yf = yf
else
new_height = height * (yrange/xrange)
new_width = width
new_yf = yf - 0.5*(height-new_height)
new_xf = xf
end if
setvalues plot
"vpXF" : new_xf
"vpYF" : new_yf
"vpWidthF" : new_width
"vpHeightF" : new_height
end setvalues
return
end
;***********************************************************************;
; Procedure : gsnp_scale_plot ;
; plot:graphic ;
; ;
; If gsnScale is set to True, then the plot is scaled such the tickmarks;
; and tickmark labels are the same size on both axes. ;
;***********************************************************************;
procedure gsnp_scale_plot(plot:graphic)
local xfont, yfont, xbfont, xlength, xmlength, ylfont, ylength, ymlength
begin
getvalues plot
"tiXAxisFontHeightF" : xfont
"tiYAxisFontHeightF" : yfont
"tmXBLabelFontHeightF" : xbfont
"tmXBMajorLengthF" : xlength
"tmXBMinorLengthF" : xmlength
"tmYLLabelFontHeightF" : ylfont
"tmYLMajorLengthF" : ylength
"tmYLMinorLengthF" : ymlength
end getvalues
if(xlength.ne.0..and.ylength.ne.0.)
major_length = (ylength+xlength)/2.
xlength = major_length
ylength = major_length
end if
if(xmlength.ne.0..and.ymlength.ne.0.)
minor_length = (ymlength+xmlength)/2.
xmlength = minor_length
ymlength = minor_length
end if
setvalues plot
"tiXAxisFontHeightF" : (xfont+yfont)/2.
"tiYAxisFontHeightF" : (xfont+yfont)/2.
"tmXBLabelFontHeightF" : (xbfont+ylfont)/2.
"tmXBMajorLengthF" : xlength
"tmXBMinorLengthF" : xmlength
"tmYLLabelFontHeightF" : (xbfont+ylfont)/2.
"tmYLMajorLengthF" : ylength
"tmYLMinorLengthF" : ymlength
end setvalues
end
;***********************************************************************;
; Procedure : check_for_tickmarks_off ;
; res:logical ;
; ;
; By default, tickmarks are drawn on all plots that aren't overlaid on ;
; a map. If gsnTickMarksOn is set to False, then this turns off the ;
; drawing of tick marks. This procedure checks for the setting of this ;
; resource, and then calls the routine that turns off tickmarks. ;
;***********************************************************************;
procedure check_for_tickmarks_off(res:logical)
local ticks_ons
begin
; Check if turning tickmarks off.
ticks_on = get_res_value(res,"gsnTickMarksOn",True)
if(.not.ticks_on)
gsnp_turn_off_tickmarks(res)
end if
end
;**********************************************************************;
; Function : compute_device_coords ;
; bb(:,4) : float ;
; res : logical ;
; ;
; This function computes the PostScript device coordinates needed to ;
; make a plot fill up the full page. ;
; ;
; bb : bounding box that contains all graphical objects. It should ;
; be a n x 4 float array with values between 0 and 1. ;
; (top,bottom,left,right) ;
; ;
; res : list of optional resources. Ones accepted include: ;
; ;
; "gsnPaperOrientation" - orientation of paper. Can be "landscape", ;
; "portrait", or "auto". Default is "auto". ;
; ;
; "gsnPaperWidth" - width of paper (in inches, default is 8.5) ;
; "gsnPaperHeight" - height of paper (in inches, default is 11.0);
; "gsnPaperMargin" - margin to leave around plots (in inches, ;
; default is 0.5) ;
; ;
;**********************************************************************;
function compute_device_coords(bb,res)
local coords, top, bot, lft, rgt, dpi, dpi_pw, dpi_ph, dpi_margin, \
paper_width, paper_height, paper_margin
begin
;
; Get resources.
;
paper_height = get_res_value_keep(res,"gsnPaperHeight",11.0)
paper_width = get_res_value_keep(res,"gsnPaperWidth",8.5)
paper_margin = get_res_value_keep(res,"gsnPaperMargin",0.5)
paper_orient = get_res_value_keep(res,"gsnPaperOrientation","auto")
is_debug = get_res_value_keep(res,"gsnDebug",False)
;
; Check to see if any panel resources have been set. No defaults
; will be assumed for these. They are only used if they have been
; explicitly set by the user.
;
lft_pnl = isatt(res,"gsnPanelLeft")
rgt_pnl = isatt(res,"gsnPanelRight")
bot_pnl = isatt(res,"gsnPanelBottom")
top_pnl = isatt(res,"gsnPanelTop")
lft_inv_pnl = isatt(res,"gsnPanelInvsblLeft")
rgt_inv_pnl = isatt(res,"gsnPanelInvsblRight")
bot_inv_pnl = isatt(res,"gsnPanelInvsblBottom")
top_inv_pnl = isatt(res,"gsnPanelInvsblTop")
if(typeof(paper_orient).eq."integer")
if(paper_orient.eq.0)
lc_orient = "portrait"
else
lc_orient = "landscape"
end if
else
lc_orient = lower_case(paper_orient)
end if
;
; Get the bounding box that covers all the plots. If gsnPanel
; resources have been added to add white space around plots, then
; count this white space in as well. Note that even though the bounding
; box coordinates should be positive, it *is* possible for them to be
; negative, and we need to keep these negative values in our calculations
; later to preserve the aspect ratio.
;
dimbb = dimsizes(bb)
if(dimsizes(dimbb).eq.1) then
;
; Force newbb to be 2-dimensional so we don't have to have a
; bunch of "if" tests later.
;
newbb = new((/1,4/),float)
newbb(0,:) = bb
else
newbb = bb
end if
if(top_inv_pnl)
top = max((/res_at_gsnPanelInvsblTop,max(newbb(:,0))/))
else
if(top_pnl)
top = max((/1.,max(newbb(:,0))/))
else
top = max(newbb(:,0))
end if
end if
if(bot_inv_pnl)
bot = min((/res_at_gsnPanelInvsblBottom,min(newbb(:,1))/))
else
if(bot_pnl)
bot = min((/0.,min(newbb(:,1))/))
else
bot = min(newbb(:,1))
end if
end if
if(lft_inv_pnl)
lft = min((/res_at_gsnPanelInvsblLeft,min(newbb(:,2))/))
else
if(lft_pnl)
lft = min((/0.,min(newbb(:,2))/))
else
lft = min(newbb(:,2))
end if
end if
if(rgt_inv_pnl)
rgt = max((/res_at_gsnPanelInvsblRight,max(newbb(:,3))/))
else
if(rgt_pnl)
rgt = max((/1.,max(newbb(:,3))/))
else
rgt = max(newbb(:,3))
end if
end if
; if(bot.lt.0.or.bot.gt.1.or.top.lt.0.or.top.gt.1.or. \
; lft.lt.0.or.lft.gt.1.or.rgt.lt.0.or.rgt.gt.1)
; print("compute_device_coords: warning: bounding box values should be between 0 and 1 inclusive. Will continue anyway.")
; end if
if(bot.ge.top.or.lft.ge.rgt)
print("compute_device_coords: bottom must be < top and left < right")
return((/0,0,0,0/))
end if
;
; Debug prints
;
if(is_debug)
print("-------Bounding box values for PostScript-------")
print(" top = " + top + " bot = " + bot + \
" lft = " + lft + " rgt = " + rgt)
end if
;
; Initialization
;
dpi = 72 ; Dots per inch.
dpi_pw = paper_width * dpi
dpi_ph = paper_height * dpi
dpi_margin = paper_margin * dpi
;
; Get paper height/width in dpi units
;
pw = rgt - lft
ph = top - bot
lx = dpi_margin
ly = dpi_margin
ux = dpi_pw - dpi_margin
uy = dpi_ph - dpi_margin
dw = ux - lx
dh = uy - ly
;
; Determine orientation, and then calculate device coordinates based
; on this.
;
if(lc_orient.eq."portrait".or. \
(lc_orient.eq."auto".and.(ph / pw).ge.1.0))
;
; If plot is higher than it is wide, then default to portrait if
; orientation is not specified.
;
lc_orient = "portrait"
if (ph / pw .gt. dh / dw) then
; paper height limits size
ndc2du = dh / ph
else
ndc2du = dw / pw
end if
;
; Compute device coordinates.
;
lx = dpi_margin + 0.5 * ( dw - pw * ndc2du) - lft * ndc2du
ly = dpi_margin + 0.5 * ( dh - ph * ndc2du) - bot * ndc2du
ux = lx + ndc2du
uy = ly + ndc2du
else
;
; If plot is wider than it is high, then default to landscape if
; orientation is not specified.
;
lc_orient = "landscape"
if (pw / ph .gt. dh / dw) then
; paper height limits size
ndc2du = dh / pw
else
ndc2du = dw / ph
end if
;
; Compute device coordinates.
;
ly = dpi_margin + 0.5 * (dh - pw * ndc2du) - (1.0 - rgt) * ndc2du
lx = dpi_margin + 0.5 * (dw - ph * ndc2du) - bot * ndc2du
ux = lx + ndc2du
uy = ly + ndc2du
end if
;
; Return device coordinates and the orientation.
;
coords = tointeger((/lx,ly,ux,uy/))
coords_at_gsnPaperOrientation = lc_orient
;
; Debug prints.
;
if(is_debug)
print("-------Device coordinates for PostScript-------")
print(" wkDeviceLowerX = " + coords(0))
print(" wkDeviceLowerY = " + coords(1))
print(" wkDeviceUpperX = " + coords(2))
print(" wkDeviceUpperY = " + coords(3))
print(" wkOrientation = " + coords_at_gsnPaperOrientation)
end if
return(coords)
end
;***********************************************************************;
; Procedure : reset_device_coordinates ;
; wks:graphic ;
; ;
; This procedure resets the PS/PDF device coordinates back to their ;
; default values. The default values will be whatever ones the user ;
; might have set when they called gsn_open_wks, or the defaults that ;
; NCL uses if none are set. ;
;***********************************************************************;
procedure reset_device_coordinates(wks)
begin
setvalues wks
"wkOrientation" : get_res_value(wks,"wkOrientation", 0)
"wkDeviceLowerX" : get_res_value(wks,"wkDeviceLowerX", 36)
"wkDeviceLowerY" : get_res_value(wks,"wkDeviceLowerY",126)
"wkDeviceUpperX" : get_res_value(wks,"wkDeviceUpperX",576)
"wkDeviceUpperY" : get_res_value(wks,"wkDeviceUpperY",666)
end setvalues
end
;***********************************************************************;
; Procedure : maximize_output ;
; wks:graphic ;
; psres:logical ;
; ;
; This procedure takes a workstation (that supposedly has several plots ;
; drawn on it), calculates the device coordinates needed to maximize ;
; the plots on a PS or PDF workstation, and then sets these device ;
; coordinates back to the workstation. draw and frame happen by default ;
; unless otherwise specified. ;
;***********************************************************************;
procedure maximize_output(wks:graphic,psres:logical)
local bb, calldraw, callframe, class, res2
begin
res2 = psres
;
; Get draw and frame values, if set.
;
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
;
; Only do this type of maximization for PS or PDF workstations.
; The device coordinates mean nothing for NCGM and X11 workstations.
;
max_device = False
class = NhlClassName(wks)
if((class.eq."psWorkstationClass").or. \
(class.eq."pdfWorkstationClass")) then
max_device = True
;
; Get bounding box of everything on the frame.
;
bb = NhlGetBB(wks)
;
; Calculate device coords to maximize these plots on the PDF or PS
; workstation.
;
coords = compute_device_coords(bb,res2)
;
; Using the coordinate values just calculated, set them in the
; workstation (also set the orientation).
;
setvalues wks
"wkDeviceLowerX" : coords(0)
"wkDeviceLowerY" : coords(1)
"wkDeviceUpperX" : coords(2)
"wkDeviceUpperY" : coords(3)
"wkOrientation" : coords_at_gsnPaperOrientation
end setvalues
end if
if(calldraw) then
draw(wks) ; This will draw everything on the workstation.
end if
if(callframe) then
frame(wks)
;
; Only set the device coordinates back if the frame is advanced, because
; if we do it when the frame hasn't been advanced, then anything that
; gets drawn on this plot later will be drawn under the old device
; coordinates.
;
; This means that the user will have to be aware that if he/she decides to
; advance the frame him/herself, then any subsequent plots draw (in which
; the device coordinates are not recalculated), may be drawn incorrectly.
;
if(max_device) then
reset_device_coordinates(wks)
end if
end if
end
;***********************************************************************;
; Procedure : draw_and_frame ;
; wks:graphic ;
; plot:graphic ;
; calldraw:logical ;
; callframe:logical ;
; ispanel: logical ;
; maxbb:logical ;
; ;
; By default, all of the plotting routines will draw the plot and ;
; advance the frame, unless the special resources gsnDraw and/or ;
; gsnFrame are set to False. This procedure checks if these resources ;
; had been set, and calls draw and/or frame accordingly. ;
; If maxbb is True, then the plot is maximized in the NCGM, X11, PS ;
; or PDF window. ;
;***********************************************************************;
procedure draw_and_frame(wks:graphic,plot:graphic,calldraw:logical, \
callframe:logical,ispanel:logical,maxbb:logical)
local nplots, class, coords
begin
max_device = False
if(maxbb) then
;
; If dealing with panel plots, then this means that the viewport
; coordinates have already been calculated to maximize the plots in
; the unit square, so we don't need to do it again here. However, we
; will still need to calculate the optimal device coordinates if the
; output is PDF or PS.
;
if(.not.ispanel) then
;
; First, optimize the plot size in the viewport (unit square). This
; may involve making it bigger or smaller.
;
coords = maximize_bb(plot,maxbb)
setvalues plot
"vpXF" : coords(0)
"vpYF" : coords(1)
"vpWidthF" : coords(2)
"vpHeightF" : coords(3)
end setvalues
end if
class = NhlClassName(wks)
if((class(0).eq."psWorkstationClass").or. \
(class(0).eq."pdfWorkstationClass")) then
;
; Keep track of whether device coordinates were recalculated.
;
max_device = True
;
; Compute device coordinates that will make plot fill the whole page.
;
; NhlGetBB(plot) will work on an array of plots as well.
;
coords = compute_device_coords(NhlGetBB(plot),maxbb)
;
; Set device coordinates to new ones.
;
setvalues wks
"wkOrientation" : coords_at_gsnPaperOrientation
"wkDeviceLowerX" : coords(0)
"wkDeviceLowerY" : coords(1)
"wkDeviceUpperX" : coords(2)
"wkDeviceUpperY" : coords(3)
end setvalues
end if
end if
if(calldraw)
draw(plot)
end if
if(callframe)
frame(wks) ; advance the frame
;
; Only set the device coordinates back if the frame is advanced, because
; if we do it when the frame hasn't been advanced, then anything that
; gets drawn on this plot later will be drawn under the old device
; coordinates.
;
; This means that the user will have to be aware that if he/she decides to
; advance the frame him/herself, then any subsequent plots draw (in which
; the device coordinates are not recalculated), may be drawn incorrectly.
;
if(max_device) then
reset_device_coordinates(wks)
end if
end if
end
;***********************************************************************;
; Function : get_bb_res ;
; res : list of resources ;
; ;
; Get list of resources for use with maximizing the plots within an ;
; X11, NCGM, PS or PDF window. ;
;***********************************************************************;
function get_bb_res(res:logical)
begin
maxbb = get_res_value(res,"gsnMaximize", False)
maxbb_at_gsnPaperMargin = get_res_value(res,"gsnPaperMargin",0.5)
maxbb_at_gsnPaperHeight = get_res_value(res,"gsnPaperHeight",11.0)
maxbb_at_gsnPaperWidth = get_res_value(res,"gsnPaperWidth",8.5)
maxbb_at_gsnBoxMargin = get_res_value(res,"gsnBoxMargin",0.02)
maxbb_at_gsnDebug = get_res_value(res,"gsnDebug",False)
;
; Don't assume a default on this one, because the default will be
; determined by doing a getvalues on the PostScript workstation.
;
if(isatt(res,"gsnPaperOrientation"))
maxbb_at_gsnPaperOrientation = get_res_value(res,"gsnPaperOrientation","")
end if
;
; Indicate here whether the panel resources have been set.
;
if(isatt(res,"gsnPanelLeft"))
maxbb_at_gsnPanelLeft = get_res_value(res,"gsnPanelLeft",0.)
end if
if(isatt(res,"gsnPanelRight"))
maxbb_at_gsnPanelRight = get_res_value(res,"gsnPanelRight",1.)
end if
if(isatt(res,"gsnPanelBottom"))
maxbb_at_gsnPanelBottom = get_res_value(res,"gsnPanelBottom",0.)
end if
if(isatt(res,"gsnPanelTop"))
maxbb_at_gsnPanelTop = get_res_value(res,"gsnPanelTop",1.)
end if
return(maxbb)
end
;***********************************************************************;
; Function : gsn_blank_plot ;
; wks : workstation ;
; res : optional resources ;
; ;
; This function creates a blank tickmark object that can be used for ;
; drawing primitives. ;
; ;
;***********************************************************************;
function gsn_blank_plot(wks:graphic,res:logical)
local res2
begin
res2 = res
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",False)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",False)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
ticks = get_res_value(res2,"pmTickMarkDisplayMode","Always")
title = get_res_value(res2,"pmTitleDisplayMode","Always")
maxbb = get_bb_res(res2)
canvas = create "canvas" logLinPlotClass wks
"pmTickMarkDisplayMode" : ticks
"pmTitleDisplayMode" : title
end create
attsetvalues_check(canvas,res2)
tmres = get_res_eq(res2,"tm")
gsnp_point_tickmarks_outward(canvas,tmres,-1.,-1.,-1.,-1.,-1.,-1.,\
point_outward)
; If gsnShape was set to True, then resize the X or Y axis so that
; the scales are proportionally correct.
if(shape)
gsnp_shape_plot(canvas)
end if
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
if(scale)
gsnp_scale_plot(canvas)
end if
draw_and_frame(wks,canvas,calldraw,callframe,False,maxbb)
return(canvas)
end
;***********************************************************************;
; Function : create_canvas ;
; wks : workstation ;
; ;
; This function creates a blank LogLin plot that can be used for drawing;
; primitives. ;
; ;
;***********************************************************************;
function create_canvas(wks:graphic)
begin
;
; Create a LogLinPlot that covers the entire NDC space
; to use as a drawing canvas
;
canvas = create "canvas" logLinPlotClass wks
"vpXF" : 0.0
"vpYF" : 1.0
"vpWidthF" : 1.0
"vpHeightF" : 1.0
end create
return(canvas)
end
;***********************************************************************;
; Function : gsn_open_ncgm ;
; name : name of output cgm file ;
; ;
; This function opens an NCGM output file called "<name>.ncgm" and ;
; returns the workstation id. If "name" is an empty string, then the ;
; NCGM is given its default name "gmeta". ;
;***********************************************************************;
function gsn_open_ncgm(name[1]:string)
local ncgm, res_file
begin
res_file=get_res_value_keep(name,"res_file","gsnapp")
if(isatt(name,"wkColorMap"))
ncgm = create res_file ncgmWorkstationClass defaultapp
"wkMetaName" : name
"wkColorMap" : name_at_wkColorMap
end create
else
ncgm = create res_file ncgmWorkstationClass defaultapp
"wkMetaName" : name
end create
end if
return(ncgm)
end
;***********************************************************************;
; Function : gsn_open_x11 ;
; name : name of X11 window ;
; ;
; This function opens an X11 output window and returns the workstation ;
; id. ;
;***********************************************************************;
function gsn_open_x11(name[1]:string)
local window
begin
if(isatt(name,"wkColorMap"))
window = create name + "_x11" xWorkstationClass defaultapp
"wkPause" : True
"wkColorMap" : name_at_wkColorMap
end create
else
window = create name + "_x11" xWorkstationClass defaultapp
"wkPause" : True
end create
end if
return(window)
end
;***********************************************************************;
; Function : create_labelbar ;
; wks: graphic ;
; nbox: integer ;
; colors: array ;
; labels: array ;
; lbres: logical ;
; ;
; This function creates a labelbar given a workstation, the number of ;
; boxes, the colors and labels to use, and an optional list of ;
; labelbar resources. By default, lbAutoManage is set to False, the ;
; perimeter is turned off, and the fill patterns are set to solid. ;
;***********************************************************************;
function create_labelbar(wks:graphic, nbox:integer, colors, labels, \
lbres:logical)
local perim_on, mono_fill_pat, label_align, labelbar_object
begin
;
; Set some defaults
;
vpxf = get_res_value(lbres,"vpXF",0.1)
vpyf = get_res_value(lbres,"vpYF",0.1)
vpwidthf = get_res_value(lbres,"vpWidthF",0.8)
vpheightf = get_res_value(lbres,"vpHeightF",0.3)
new_colors = get_res_value(lbres,"lbFillColors",colors)
new_labels = get_res_value(lbres,"lbLabelStrings",labels)
orientation = get_res_value(lbres,"lbOrientation","horizontal")
perim_on = get_res_value(lbres,"lbPerimOn",False)
label_align = get_res_value(lbres,"lbLabelAlignment","InteriorEdges")
font_height = get_res_value(lbres,"lbLabelFontHeightF",0.1)
mono_fill_pat = get_res_value(lbres,"lbMonoFillPattern",True);
labelbar_object = create "labelbar" labelBarClass wks
"vpXF" : vpxf
"vpYF" : vpyf
"vpWidthF" : vpwidthf
"vpHeightF" : vpheightf
"lbBoxCount" : nbox
"lbFillColors" : new_colors
"lbLabelStrings" : new_labels
"lbOrientation" : orientation
"lbPerimOn" : perim_on
"lbLabelAlignment" : label_align
"lbLabelFontHeightF": font_height
"lbMonoFillPattern" : mono_fill_pat
"lbAutoManage" : False
end create
attsetvalues_check(labelbar_object,lbres)
return(labelbar_object)
end
;***********************************************************************;
; Function : gsn_open_ps ;
; name : name of PostScript file ;
; ;
; This function opens a PostScript file called "<name>.ps" and returns ;
; the workstation id. If "name" is an empty string, then the PostScript ;
; file is called "gmeta.ps". ;
;***********************************************************************;
function gsn_open_ps(type:string,name[1]:string)
local ps, res_file, wkres, wkresnew, names, i
begin
;
; If there are resources, copy them over to a logical variable,
; and only grab the ones that start with "wk".
;
if(.not.any(ismissing(getvaratts(type))))
wkres = True
names = getvaratts(type)
do i=0,dimsizes(names)-1
wkres@$names(i)$ = type@$names(i)$
end do
;
; Grab only the ones that start with "wk".
;
wkresnew = get_res_eq(wkres,"wk")
delete(wkres)
delete(names)
else
wkresnew = False
end if
res_file = get_res_value_keep(name,"res_file","gsnapp")
;
; These PS resources are ones that must be set at the time
; the workstation is created. This means that these resources
; will override whatever setting you might have in a resource
; file or your .hluresfile.
;
cmodel = get_res_value(wkresnew,"wkColorModel","rgb")
resltn = get_res_value(wkresnew,"wkPSResolution",1800)
visualt = get_res_value(wkresnew,"wkVisualType","color")
ps = create res_file psWorkstationClass defaultapp
"wkColorModel" : cmodel
"wkPSResolution" : resltn
"wkPSFileName" : name
"wkPSFormat" : type
"wkVisualType" : visualt
end create
;
; Set resources, if any.
;
attsetvalues_check(ps,wkresnew)
delete(wkresnew)
;
; Retrieve the device coordinates and the orientation so we can
; reset them later if necessary.
;
getvalues ps
"wkOrientation" : ps_at_wkOrientation
"wkDeviceLowerX" : ps_at_wkDeviceLowerX
"wkDeviceLowerY" : ps_at_wkDeviceLowerY
"wkDeviceUpperX" : ps_at_wkDeviceUpperX
"wkDeviceUpperY" : ps_at_wkDeviceUpperY
end getvalues
return(ps)
end
;***********************************************************************;
; Function : gsn_open_pdf ;
; name : name of PDF file ;
; ;
; This function opens a PDF file called "<name>.pdf" and returns ;
; the workstation id. If "name" is an empty string, then the PDF file ;
; is called "gmeta.pdf". ;
;***********************************************************************;
function gsn_open_pdf(type:string, name[1]:string)
local pdf, res_file, wkres, wkresnew, names, i
begin
;
; If there are resources, copy them over to a logical variable,
; and only grab the ones that start with "wk".
;
if(.not.any(ismissing(getvaratts(type))))
wkres = True
names = getvaratts(type)
do i=0,dimsizes(names)-1
wkres@$names(i)$ = type@$names(i)$
end do
;
; Grab only the ones that start with "wk".
;
wkresnew = get_res_eq(wkres,"wk")
delete(wkres)
delete(names)
else
wkresnew = False
end if
res_file = get_res_value_keep(name,"res_file","gsnapp")
;
; These PDF resources are ones that must be set at the time
; the workstation is created. This means that these resources
; will override whatever setting you might have in a resource
; file or your .hluresfile.
;
cmodel = get_res_value(wkresnew,"wkColorModel","rgb")
resltn = get_res_value(wkresnew,"wkPDFResolution",1800)
visualt = get_res_value(wkresnew,"wkVisualType","color")
pdf = create res_file pdfWorkstationClass defaultapp
"wkColorModel" : cmodel
"wkPDFResolution" : resltn
"wkPDFFileName" : name
"wkPDFFormat" : type
"wkVisualType" : visualt
end create
;
; Set resources, if any.
;
attsetvalues_check(pdf,wkresnew)
delete(wkresnew)
;
; Retrieve the device coordinates and the orientation so we can
; reset them later if necessary.
;
getvalues pdf
"wkOrientation" : pdf_at_wkOrientation
"wkDeviceLowerX" : pdf_at_wkDeviceLowerX
"wkDeviceLowerY" : pdf_at_wkDeviceLowerY
"wkDeviceUpperX" : pdf_at_wkDeviceUpperX
"wkDeviceUpperY" : pdf_at_wkDeviceUpperY
end getvalues
return(pdf)
end
;***********************************************************************;
; Function : gsn_open_image ;
; type : type of image file ;
; name : name of output image file ;
; ;
; This function opens an image file called "<name>.<type>" and ;
; returns the workstation id. If "name" is an empty string, then the ;
; NCGM is given a default name "gmeta.type". ;
;***********************************************************************;
function gsn_open_image(type:string,name[1]:string)
local image, res_file
begin
res_file = get_res_value_keep(name,"res_file","gsnapp")
wkwidth = get_res_value_keep(type,"wkWidth",512)
wkheight = get_res_value_keep(type,"wkHeight",512)
if(isatt(name,"wkColorMap"))
image = create res_file imageWorkstationClass defaultapp
"wkImageFileName" : name
"wkImageFormat" : type
"wkColorMap" : name_at_wkColorMap
"wkWidth" : wkwidth
"wkHeight" : wkheight
end create
else
image = create res_file imageWorkstationClass defaultapp
"wkImageFileName" : name
"wkImageFormat" : type
"wkWidth" : wkwidth
"wkHeight" : wkheight
end create
end if
return(image)
end
;***********************************************************************;
; Function : gsn_open_wks ;
; type : type of workstation to open ;
; name : name of workstation ;
; ;
; This function opens either an X11 window, an NCGM file, a Postscript ;
; or a PDF file depending on "type", which can be "x11", "ncgm", "ps" ;
; or "pdf". If "type" is a PS or PDF file or an NCGM, then it will be ;
; named <name>.ps or <name>.pdf <name>.ncgm respectively. This function ;
; also looks for a resource file called "name.res". If it exists, then ;
; it loads the resources defined in that file. This function returns ;
; the workstation id. ;
;***********************************************************************;
function gsn_open_wks(type[1]:string,name[1]:string)
local i, wks, appusrdir, name_char, not_found, res_file, res_dir
begin
type2 = type ; Make copy of type and its resources
res_dir = "./" ; Default resource directory.
res_file = "gsnapp" ; Default resource file name.
;
; Parse "name" to get the directory and the file prefix.
;
if(name.ne."") then
name_char = stringtocharacter(name)
name_len = dimsizes(name_char)-1
i = name_len-1 ; Start checking if a directory pathname
not_found = True ; was specified for the resource file.
do while(not_found.and.i.ge.0)
if(name_char(i).eq."/")
res_dir = charactertostring(name_char(0:i))
not_found = False
end if
i = i - 1
end do
res_file = charactertostring(name_char(i+1:name_len-1))
if(isatt(name,"appUsrDir").and.not_found)
res_dir = name_at_appUsrDir ; No directory specified.
end if
end if
appid = create res_file appClass defaultapp
"appDefaultParent" : True
"appUsrDir" : res_dir
end create
;
; If we had a case statement or an "elseif" in NCL, this next
; section would look better!
;
wks = new(1,graphic)
if (lower_case(type2).eq."x11") then
x_file = res_file
if (isatt(type2,"wkColorMap"))
x_file_at_wkColorMap = type2_at_wkColorMap
end if
wks = gsn_open_x11(x_file)
end if
if (lower_case(type2).eq."ps".or.lower_case(type2).eq."eps".or. \
lower_case(type2).eq."epsi") then
ps_file = get_res_value(type2,"wkPSFileName",res_file + "." + type2)
ps_file_at_res_file = res_file
wks = gsn_open_ps(type2,res_dir+ps_file)
end if
if (lower_case(type2).eq."ncgm") then
ncgm_file = get_res_value(type2,"wkMetaName",res_file + ".ncgm")
ncgm_file = res_dir + ncgm_file
ncgm_file_at_res_file = res_file
if (isatt(type2,"wkColorMap"))
ncgm_file_at_wkColorMap = type2_at_wkColorMap
end if
wks = gsn_open_ncgm(ncgm_file)
end if
if (lower_case(type2).eq."pdf") then
pdf_file = get_res_value(type2,"wkPDFFileName", \
res_file + "." + type2)
pdf_file_at_res_file = res_file
wks = gsn_open_pdf(type2, res_dir+pdf_file)
end if
if (lower_case(type2).eq."xwd".or.lower_case(type2).eq."png") then
image_file = get_res_value(type2,"wkImageFileName", res_file)
image_file_at_res_file = res_file
wks = gsn_open_image(type2, res_dir+image_file)
end if
if (ismissing(wks)) then
print("Error: gsn_open_wks: "+ type2 + " is an illegal workstation type.")
exit
end if
;
; Apply other resources.
;
; First create list of resources that we *don't* want applied, as we've
; should have applied them by this point.
;
varatts = getvaratts(type2)
if(.not.any(ismissing(varatts))) then
wks_res = True
res_list = (/"wkColorMap","wkWidth","wkHeight","wkColorModel"/)
do i=0,dimsizes(varatts)-1
if(all(varatts(i).ne.res_list)) then
wks_res@$varatts(i)$ = type2@$varatts(i)$
end if
end do
attsetvalues_check(wks,wks_res)
delete(wks_res)
end if
delete(varatts)
;
; Return workstation and application id.
;
wks_at_name = res_file
wks_at_app = appid
return(wks)
end
;***********************************************************************;
; Function : gsn_add_annotation ;
; plotid : graphic ;
; annoid : graphic ;
; resources : logical ;
; ;
; This function attaches one graphical object to another, for example, ;
; a labelbar to a contour plot. The default is for the annotation to be ;
; added to the center of the plot. You can use the amJust resource ;
; to change the general location of the annotation (top/center, ;
; top/left top/right, bottom/center, bottom/right, etc. You can use ;
; the amOrthogonalPosF and amParallelPosF resources to then move the ;
; annotation perpendicular or parallel to the plot. ;
; ;
; "amJust" is the corner or side of the annotation of which you want to ;
; position using values for "amParallelPosF" and "amOrthogonalPosF". It ;
; can be any one of the four corners, or the center of any edge of the ;
; annotation. ;
; ;
; "amParallelPosF" is the amount to move the annotation to the right or ;
; left, and "amOrthogonalPosF" is the amount to move it up and down. The;
; move is applied to the corner or the side of the annotation that is ;
; indicated by "amJust". ;
; ;
; Here's what various values of amParallelPosF and amOrthogonalPosF ;
; mean for moving the annotation: ;
; ;
; amParallelPosF/amOrthogonalPosF ;
; 0.0/ 0.0 - annotation in dead center of plot ;
; 0.5/ 0.5 - annotation at bottom right of plot ;
; 0.5/-0.5 - annotation at top right of plot ;
; -0.5/-0.5 - annotation at top left of plot ;
; -0.5/ 0.5 - annotation at bottom left of plot ;
; ;
; So, for example, an amJust value of "TopRight" and amParallelPosF, ;
; amOrthogonalPosF values of 0.5 and -0.5 will position the top right ;
; corner of the annotation in the top right corner of the plot. ;
; ;
; Values of just = "TopCenter", para = -0.5, orth = -0.5 will position ;
; the top center of the annotation in the top left corner of the plot, ;
; effectively placing part of the annotation outside the plot. ;
; ;
; Since adding an annotation to a plot can make it bigger, this ;
; function will recognize gsnMaximize if it is set, and resize the plot ;
; if necessary. ;
; ;
;***********************************************************************;
function gsn_add_annotation(plot:graphic, anno:graphic, resources:logical)
local res2, just, para, orth, just, zone, resize, maxbb, tmp_wks
begin
res2 = get_resources(resources)
just = get_res_value(res2,"amJust","CenterCenter")
para = get_res_value(res2,"amParallelPosF",0)
orth = get_res_value(res2,"amOrthogonalPosF",0)
zone = get_res_value(res2,"amZone",0)
resize = get_res_value(res2,"amResizeNotify",True)
maxbb = get_bb_res(res2)
;
; Add annotation to plot.
;
anno_id = NhlAddAnnotation(plot,anno)
;
; Set some resource values.
;
setvalues anno_id
"amZone" : zone
"amJust" : just
"amParallelPosF" : para
"amOrthogonalPosF" : orth
"amResizeNotify" : resize
end setvalues
;
; Apply rest of resources, if any.
;
attsetvalues_check(anno_id,res2)
;
; Remaximize the plot if necessary.
;
tmp_wks = NhlGetParentWorkstation(plot)
draw_and_frame(tmp_wks,plot,False,False,False,maxbb)
;
; Return id
;
return(anno_id)
end
;***********************************************************************;
; Function : gsn_add_primitive ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; isndc: NDC space or not ;
; polytype: type of primitive ;
; resources: optional resources ;
; ;
; This function adds a primitive to the plot "plotid", either in the ;
; same data space as the data in the plot, or in NDC space. ("plotid" ;
; is returned from a previous call to one of the gsn_* plotting ;
; functions), "x" and "y" are the x and y locations of each point in the;
; primitive, and should either be in the same data space as the data ;
; from "plotid" (isndc = False) or should be values from 0 to 1 if in ;
; NDC space (isndc = True). Note that using isndc = True should only ;
; be used internally. It currently only works for NDC coordinates that ;
; actually fall within the plot's boundaries. ;
; ;
; "resources" is an optional list of resources. This function returns ;
; the primitive object created. polytype is the type of primitive to ;
; add (polymarker, polygon, or polyline) ;
; ;
;***********************************************************************;
function gsn_add_primitive(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,isndc:logical,polytype:string, \
resources:logical)
local res2, gsid, gsres, prim_object, dummy
begin
res2 = get_resources(resources)
if(.not.any(polytype.eq.(/"polymarker","polygon","polyline"/)))
print("Warning: gsn_add_primitive: Do not recognize primitive type '"+ polytype + "'.")
return(0)
end if
;
; If in NDC space, make sure X and Y values are in the range 0 to 1 AND
; within the viewport of the polot.
;
if(isndc) then
getvalues plotid
"vpHeightF" : vph
"vpWidthF" : vpw
"vpXF" : vpx
"vpYF" : vpy
end getvalues
;
; This part is commented out because sometimes if values are equal
; to each other, it will incorrectly register as one being greater/less
; than the other value.
;
; if(any(x.lt.vpx.or.x.gt.(vpx+vpw).or.y.gt.vpy.or.y.lt.(vpy-vph))) then
; print("Warning: gsn_add_primitive: The X and Y values must be between the viewport values of the plot if you are in NDC space.")
; return(0)
; end if
;
; Create a canvas to draw on.
;
canvas = create "ndc_canvas" logLinPlotClass wks
"tfDoNDCOverlay" : True
"trXMinF" : vpx
"trXMaxF" : vpx+vpw
"trYMaxF" : vpy
"trYMinF" : vpy-vph
end create
end if
;
; Create a graphic style object. We have to do this instead of using
; the default one, because if we add two primitive objects to a plot
; and assign each one a different color, the two objects will have the
; same color as the last color that was set.
gsid = create "graphic_style" graphicStyleClass wks end create
;
; Set graphic style resources, if any.
;
gsres = get_res_eq(res2,"gs")
gmres = False
attsetvalues_check(gsid,gsres)
if(isatt(gsres,"gsLineColor"))
gmres = True
gmres_at_gsMarkerColor = gsres_at_gsLineColor
end if
if(any(ismissing(x)).or.any(ismissing(y)))
;
; If the primitive is a polymarker or polygon, then just use the
; non-missing values.
;
if(polytype.eq."polygon".or.polytype.eq."polymarker")
inds = ind(.not.ismissing(x).and..not.ismissing(y))
if(.not.any(ismissing(inds)))
x2 = x(inds)
y2 = y(inds)
prim_object = create polytype primitiveClass noparent
"prXArray" : x2
"prYArray" : y2
"prPolyType" : polytype
"prGraphicStyle" : gsid
end create
delete(x2)
delete(y2)
delete(inds)
;
; Add primitive to the plot object. If in NDC space, then add it to the
; canvas, and then add the canvas as an annotation.
;
dummy = new(1,graphic)
if(isndc) then
NhlAddPrimitive(canvas,prim_object,dummy)
overlay(plotid,canvas)
else
NhlAddPrimitive(plotid,prim_object,dummy)
end if
else
prim_object = new(1,graphic)
end if
else
;
; If the primitive is a polyline, then retrieve the pairs of non-missing
; points, and plot them individually.
;
dummy = new(1,graphic)
indices = get_non_missing_pairs(x,y)
i = 0
;
; Get the number of non-missing pairs of lines.
;
nlines = dimsizes(ind(.not.ismissing(indices(:,0))))
if(.not.ismissing(nlines))
prim_object = new(nlines,graphic)
astring = new(nlines,string)
astring = polytype + ispan(0,nlines-1,1)
first_marker = True
do i=0,nlines-1
ibeg = indices(i,0)
iend = indices(i,1)
if(iend.eq.ibeg)
;
; If there's only one point in our line, then indicate it
; with a polymarker.
;
polytype2 = "polymarker"
if(first_marker)
attsetvalues_check(gsid,gmres)
first_marker = False
end if
else
polytype2 = "polyline"
end if
prim_object(i) = create astring(i) primitiveClass noparent
"prXArray" : x(ibeg:iend)
"prYArray" : y(ibeg:iend)
"prPolyType" : polytype2
"prGraphicStyle" : gsid
end create
if(isndc) then
NhlAddPrimitive(canvas,prim_object(i),dummy)
else
NhlAddPrimitive(plotid,prim_object(i),dummy)
end if
end do
;
; If in NDC space, we need to add the canvas as an annotation of
; the plot.
;
if(isndc) then
overlay(plotid,canvas)
end if
else
prim_object = new(1,graphic)
end if
end if
else
;
; No data is missing, so create a primitive object.
;
prim_object = create polytype primitiveClass noparent
"prXArray" : x
"prYArray" : y
"prPolyType" : polytype
"prGraphicStyle" : gsid
end create
;
; Add primitive to the plot object.
;
dummy = new(1,graphic)
if(isndc) then
NhlAddPrimitive(canvas,prim_object,dummy)
overlay(plotid,canvas)
else
NhlAddPrimitive(plotid,prim_object,dummy)
end if
end if
return(prim_object)
end
;***********************************************************************;
; Function : gsn_primitive ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; isndc: NDC space or not ;
; polytype: type of primitive ;
; resources: optional resources ;
; ;
; This function draws a primitive to the plot "plotid", either in the ;
; same data space as the data in the plot, or in NDC space. ("plotid" ;
; is returned from a previous call to one of the gsn_* plotting ;
; functions), "x" and "y" are the x and y locations of each point in the;
; primitive, and should either be in the same data space as the data ;
; from "plotid" (isndc = False) or should be values from 0 to 1 if in ;
; NDC space (isndc = True). Note that using isndc = True should only ;
; be used internally. It currently only works for NDC coordinates that ;
; actually fall within the plot's boundaries. ;
; ;
; "resources" is an optional list of resources. ;
; ;
;***********************************************************************;
procedure gsn_primitive(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,isndc:logical,polytype:string, \
resources:logical)
local res2, gsid, gsres, gmres, canvas, xf, yf, x2, y2
begin
if(.not.any(polytype.eq.(/"polymarker","polygon","polyline"/)))
print("Warning: gsn_primitive: Do not recognize primitive type '"+ polytype + "'.")
return
end if
res2 = get_resources(resources)
; Create graphic style object.
gsid = create "graphic_style" graphicStyleClass wks end create
;
; Create a canvas to draw on, if this is an NDC draw.
;
if(isndc) then
canvas = create_canvas(wks)
end if
gsres = get_res_eq(res2,"gs")
attsetvalues_check(gsid,gsres)
;
; Make sure data is float, since NhlDataPolymarker only takes floats.
;
xf = tofloat(x)
yf = tofloat(y)
;
; Since the NhlData*/NhlNDC* routines don't accept missing values, this
; routine only draws the ones that aren't missing. For polylines, a pen up
; and pen down takes place after each section of missing values. We'll
; handle this later.
;
if(.not.any(ismissing(xf)).and..not.any(ismissing(yf))) then
x2 = xf
y2 = yf
nomsg = True
else
x2 = xf(ind(.not.ismissing(xf).and..not.ismissing(yf)))
y2 = yf(ind(.not.ismissing(xf).and..not.ismissing(yf)))
nomsg = False
end if
if(polytype.eq."polymarker") then
if(isndc) then
NhlNDCPolymarker(canvas,gsid,x2,y2)
else
NhlDataPolymarker(plotid,gsid,x2,y2)
end if
end if
if(polytype.eq."polygon") then
if(isndc) then
NhlNDCPolygon(canvas,gsid,x2,y2)
else
NhlDataPolygon(plotid,gsid,x2,y2)
end if
end if
if(polytype.eq."polyline".and.nomsg) then
if(isndc) then
NhlNDCPolyline(canvas,gsid,x2,y2)
else
NhlDataPolyline(plotid,gsid,x2,y2)
end if
end if
if(polytype.eq."polyline".and..not.nomsg) then
first_marker = True
;
; If we end up with a line with just one point, then we draw it with
; a polymarker. Thus, we need to make sure the marker will be the
; same color as the line.
;
gmres = False
if(isatt(gsres,"gsLineColor"))
gmres = True
gmres_at_gsMarkerColor = gsres_at_gsLineColor
end if
indices = get_non_missing_pairs(xf,yf)
i = 0
do while(.not.ismissing(indices(i,0)).and.i.lt.dimsizes(xf))
ibeg = indices(i,0)
iend = indices(i,1)
if(iend.gt.ibeg)
if(isndc) then
NhlNDCPolyline(canvas,gsid,xf(ibeg:iend),yf(ibeg:iend))
else
NhlDataPolyline(plotid,gsid,xf(ibeg:iend),yf(ibeg:iend))
end if
else ; iend = ibeg --> only one point
if(first_marker)
attsetvalues_check(gsid,gmres)
first_marker = False
end if
if(isndc) then
NhlNDCPolymarker(canvas,gsid,xf(ibeg),yf(ibeg))
else
NhlDataPolymarker(plotid,gsid,xf(ibeg),yf(ibeg))
end if
end if
i = i + 1
end do
delete(indices)
end if
end
;***********************************************************************;
; Procedure : gsn_polygon ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This procedure draws a filled polygon on the workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks") in the same ;
; data space as the data in "plotid" (returned from a previous call to ;
; one of the gsn_* plotting functions). "x" and "y" are the x and y ;
; locations of each point in the polygon, and should be in the same data;
; space as the data from "plotid". "resources" is an optional list of ;
; resources. ;
;***********************************************************************;
procedure gsn_polygon(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,resources:logical)
local res2
begin
res2 = get_resources(resources)
gsn_primitive(wks,plotid,x,y,False,"polygon",res2)
end
;***********************************************************************;
; Function : gsn_add_polygon ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This function adds a polygon to the plot "plotid", in the same data ;
; space as the data in the plot ("plotid" is returned from a previous ;
; call to one of the gsn_* plotting functions). "x" and "y" are the x ;
; and y locations of each point in the polygon, and should be in the ;
; same data space as the data from "plotid". "resources" is an optional ;
; list of resources. This function returns the primitive object ;
; created. ;
; ;
; This function is different from gsn_polygon because it actually ;
; attaches the polygon to the plot. This means that if you resize or ;
; move the plot, the polygon will stay with the plot. ;
;***********************************************************************;
function gsn_add_polygon(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,resources:logical)
begin
res2 = get_resources(resources)
return(gsn_add_primitive(wks,plotid,x,y,False,"polygon",res2))
end
;***********************************************************************;
; Procedure : gsn_polygon_ndc ;
; wks: workstation object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This procedure draws a filled polygon on the workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks") in NDC ;
; space. "x" and "y" are the x and y locations of each point in the ;
; polygon, and "resources" is an optional list of resources. ;
;***********************************************************************;
procedure gsn_polygon_ndc(wks:graphic,x[*]:numeric,y[*]:numeric,\
resources:logical)
local res2, dummy
begin
dummy = new(1,graphic)
res2 = get_resources(resources)
gsn_primitive(wks,dummy,x,y,True,"polygon",res2)
end
;***********************************************************************;
; Procedure : gsn_polyline ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This procedure draws a polyline on the workstation "wks" (the variable;
; returned from a previous call to "gsn_open_wks") in the same data ;
; space as the data in "plotid" (returned from a previous call to one of;
; the gsn_* plotting functions). "x" and "y" are the x and y locations ;
; of each point in the line, and should be in the same data space as the;
; data from "plotid". "resources" is an optional list of resources. ;
;***********************************************************************;
procedure gsn_polyline(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,resources:logical)
local res2
begin
res2 = get_resources(resources)
gsn_primitive(wks,plotid,x,y,False,"polyline",res2)
end
;***********************************************************************;
; Function : gsn_add_polyline ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This function adds a polyline to the plot "plotid", in the same data ;
; space as the data in the plot ("plotid" is returned from a previous ;
; call to one of the gsn_* plotting functions). "x" and "y" are the x ;
; and y locations of each point in the line, and should be in the same ;
; data space as the data from "plotid". "resources" is an optional list ;
; of resources. This function returns the primitive object created. ;
; ;
; This function is different from gsn_polyline because it actually ;
; attaches the line to the plot. This means that if you resize or move ;
; the plot, the line will stay with the plot. ;
;***********************************************************************;
function gsn_add_polyline(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,resources:logical)
local res2
begin
res2 = get_resources(resources)
return(gsn_add_primitive(wks,plotid,x,y,False,"polyline",res2))
end
;***********************************************************************;
; Procedure : gsn_polyline_ndc ;
; wks: workstation object ;
; x: 1-dimensional array of x ndc points ;
; y: 1-dimensional array of y ndc points ;
; resources: optional resources ;
; ;
; This procedure draws a polyline on the workstation "wks" (the variable;
; returned from a previous call to "gsn_open_wks") in NDC space. ;
; "x" and "y" are the x and y locations of each point in the line. ;
; "resources" is an optional list of resources. ;
;***********************************************************************;
procedure gsn_polyline_ndc(wks:graphic,x[*]:numeric,y[*]:numeric,\
resources:logical)
local res2, dummy
begin
dummy = new(1,graphic)
res2 = get_resources(resources)
gsn_primitive(wks,dummy,x,y,True,"polyline",res2)
end
;***********************************************************************;
; Procedure : gsn_polymarker ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This procedure draws polymarkers on the workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks") in the same ;
; data space as the data in "plotid" (returned from a previous call to ;
; one of the gsn_* plotting functions). "x" and "y" are the x and y ;
; locations of each marker, and should be in the same data space as the ;
; data from "plotid". "resources" is an optional list of resources. ;
;***********************************************************************;
procedure gsn_polymarker(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,resources:logical)
local res2
begin
res2 = get_resources(resources)
gsn_primitive(wks,plotid,x,y,False,"polymarker",res2)
end
;***********************************************************************;
; Function : gsn_add_polymarker ;
; wks: workstation object ;
; plotid: plot object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This function adds polymarkers to the plot "plotid", in the same ;
; data space as the data in the plot ("plotid" is returned from a ;
; previous call to one of the gsn_* plotting functions). "x" and "y" are;
; the x and y locations of each marker, and should be in the same data ;
; space as the data from "plotid". "resources" is an optional list of ;
; resources. This function returns the primitive object created. ;
; ;
; This function is different from gsn_polymarker because it actually ;
; attaches the markers to the plot. This means that if you resize or ;
; move the plot, the markers will stay with the plot. ;
;***********************************************************************;
function gsn_add_polymarker(wks:graphic,plotid:graphic,x[*]:numeric,\
y[*]:numeric,resources:logical)
local res2
begin
res2 = get_resources(resources)
return(gsn_add_primitive(wks,plotid,x,y,False,"polymarker",res2))
end
;***********************************************************************;
; Procedure : gsn_polymarker_ndc ;
; wks: workstation object ;
; x: 1-dimensional array of x points ;
; y: 1-dimensional array of y points ;
; resources: optional resources ;
; ;
; This procedure draws polymarkers on the workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks") in NDC ;
; space. "x" and "y" are the x and y locations of each marker in NDC ;
; coordinates. "resources" is an optional list of resources. ;
;***********************************************************************;
procedure gsn_polymarker_ndc(wks:graphic,x[*]:numeric,y[*]:numeric,\
resources:logical)
local res2, dummy
begin
dummy = new(1,graphic)
res2 = get_resources(resources)
gsn_primitive(wks,dummy,x,y,True,"polymarker",res2)
end
;***********************************************************************;
; Function : gsn_create_labelbar_ndc ;
; wks: workstation object ;
; nbox: number of labelbar boxes ;
; labels: labels for boxes ;
; x: X NDC position of labelbar ;
; y: Y NDC position of labelbar ;
; resources: optional resources ;
; ;
; This function is identical to gsn_create_labelbar, except the location;
; of the labelbar is passed in (NDC coordinate values). ;
;***********************************************************************;
function gsn_create_labelbar_ndc(wks:graphic, nbox:integer, labels:string, \
x,y,resources:logical )
local res2, lbres, wksname
begin
res2 = get_resources(resources)
wksname = get_res_value_keep(wks,"name","gsnapp")
;
; If x,y < 0, this is invalid, and hence don't use these values.
; This was a special way to allow gsn_create_labelbar to call this
; routine without needing valid x, y values.
;
if(x.lt.0.or.y.lt.0) then
lbid = create wksname + "_labelbar" labelBarClass wks
"lbBoxCount" : nbox
"lbLabelStrings" : labels
end create
else
lbid = create wksname + "_labelbar" labelBarClass wks
"vpXF" : x
"vpYF" : y
"lbBoxCount" : nbox
"lbLabelStrings" : labels
end create
end if
lbres = get_res_eq(res2,(/"lb","vp"/))
if(lbres.and..not.any(ismissing(getvaratts(lbres))))
; A special test is needed for the resource lbLabelFontHeightF.
; If it is set, then we need to turn off lbAutoManage.
if(isatt(lbres,"lbLabelFontHeightF"))
setvalues lbid
"lbAutoManage" : False
"lbLabelJust" : "CenterCenter"
"lbLabelFontHeightF" : lbres_at_lbLabelFontHeightF
end setvalues
delete(lbres_at_lbLabelFontHeightF)
end if
attsetvalues_check(lbid,lbres)
end if
; Return labelbar.
return(lbid)
end
;***********************************************************************;
; Function : gsn_create_labelbar ;
; wks: workstation object ;
; nbox: number of labelbar boxes ;
; labels: labels for boxes ;
; resources: optional resources ;
; ;
; This function creates and returns a labelbar on the workstation "wks" ;
; (the variable returned from a previous call to "gsn_open_wks"). ;
; "resources" is an optional list of resources. ;
;***********************************************************************;
function gsn_create_labelbar(wks:graphic, nbox:integer, labels:string, \
resources:logical )
begin
x = -1. ; Special values to tip off the routine
y = -1. ; that we don't have X,Y values.
labelbar = gsn_create_labelbar_ndc(wks, nbox, labels, x, y, resources)
return(labelbar)
end
procedure gsn_labelbar_ndc(wks:graphic, nbox:integer, labels:string, \
x,y,resources:logical )
local labelbar
begin
labelbar = gsn_create_labelbar_ndc(wks, nbox, labels, x, y, resources)
draw(labelbar)
delete(labelbar)
end
;***********************************************************************;
; Function : gsn_create_legend_ndc ;
; wks: workstation object ;
; nitems: number of legend items ;
; labels: labels for items ;
; x: X NDC position of legend ;
; y: Y NDC position of legend ;
; resources: optional resources ;
; ;
; This function draws a legend on the workstation "wks" (the variable ;
; returned from a previous call to "gsn_open_wks"). "resources" is an ;
; optional list of resources. ;
;***********************************************************************;
function gsn_create_legend_ndc(wks:graphic, nitems:integer, labels:string, \
x,y,resources:logical )
local i, res2, lgres, wksname, lgres
begin
res2 = get_resources(resources)
wksname = get_res_value_keep(wks,"name","gsnapp")
;
; If x,y < 0, this is invalid, and hence don't use these values.
; This was a special way to allow gsn_create_legend to call this
; routine without needing valid x, y values.
;
if(x.lt.0.or.y.lt.0) then
legend = create wksname + "_legend" legendClass wks
"lgItemCount" : nitems
"lgLabelStrings" : labels
end create
else
legend = create wksname + "_legend" legendClass wks
"vpXF" : x
"vpYF" : y
"lgItemCount" : nitems
"lgLabelStrings" : labels
end create
end if
lgres = get_res_eq(res2,(/"lg","vp"/))
if(lgres.and..not.any(ismissing(getvaratts(lgres))))
; A special test is needed for the resource lgLabelFontHeightF.
; If it is set, then we need to turn off lgAutoManage.
if(isatt(lgres,"lgLabelFontHeightF"))
setvalues legend
"lgAutoManage" : False
"lgLabelFontHeightF" : lgres_at_lgLabelFontHeightF
end setvalues
delete(lgres_at_lgLabelFontHeightF)
end if
attsetvalues_check(legend,lgres)
end if
; Return legend.
return(legend)
end
;***********************************************************************;
; Function : gsn_create_legend ;
; wks: workstation object ;
; nitems: number of legend items ;
; labels: labels for items ;
; resources: optional resources ;
; ;
; This function creates a legend. ;
;***********************************************************************;
function gsn_create_legend(wks:graphic, nitems:integer, labels:string, \
resources:logical )
begin
x = -1. ; Special values to tip off the routine
y = -1. ; that we don't have X,Y values.
legend = gsn_create_legend_ndc(wks, nitems, labels, x, y, resources)
return(legend)
end
;***********************************************************************;
; Procedure : gsn_legend_ndc ;
; wks: workstation object ;
; nitems: number of legend items ;
; labels: labels for items ;
; x: X NDC position of legend ;
; y: Y NDC position of legend ;
; resources: optional resources ;
; ;
; This procedure draws a legend on the workstation "wks" (the variable ;
; returned from a previous call to "gsn_open_wks"). "resources" is an ;
; optional list of resources. ;
;***********************************************************************;
procedure gsn_legend_ndc(wks:graphic, nitems:integer, labels:string, \
x,y,resources:logical )
local legend
begin
legend = gsn_create_legend_ndc(wks,nitems,labels,x,y,resources)
draw(legend)
delete(legend)
end
;***********************************************************************;
; Function : gsn_create_text_ndc ;
; wks: workstation object ;
; text: array of text strings ;
; x: n-dimensional array of x ndc positions ;
; y: n-dimensional array of y ndc positions ;
; resources: optional resources ;
; ;
; This function draws text strings on the workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks"). "x" and ;
; "y" are the x and y locations of each text string, and should be ;
; specified in NDC space. "resources" is an optional list of resources. ;
; This function returns the text string created. ;
;***********************************************************************;
function gsn_create_text_ndc(wks:graphic, texto:string, xo:numeric, \
yo:numeric, resources:logical )
local i, txid, plot_object, res, tx_res_index, x2, y2, res2, \
calldraw, callframe
begin
;
; Any one of xo, yo, and texto can just be one element, but if two or more
; are more than one element, then they must be exactly the same size.
;
xsizes = dimsizes(xo)
ysizes = dimsizes(yo)
tsizes = dimsizes(texto)
xrank = dimsizes(xsizes)
yrank = dimsizes(ysizes)
trank = dimsizes(tsizes)
if(xrank.gt.1.and.yrank.gt.1.and..not.all(xsizes.eq.ysizes)) then
print("Error: gsn_text_ndc: x and y must have the same dimension sizes, or either be a single value.")
dummy = new(1,graphic)
return(dummy)
end if
if(trank.gt.1.and. \
(xrank.gt.1.and..not.all(xsizes.eq.tsizes)) .or. \
(yrank.gt.1.and..not.all(ysizes.eq.tsizes))) then
print("Error: gsn_text_ndc: text must be a single string or the same dimension size as x and/or y.")
dummy = new(1,graphic)
return(dummy)
end if
;
; Convert to 1-dimensional arrays of all the same length.
;
if(xrank.gt.1) then
x = ndtooned(new(xsizes, typeof(xo)))
y = ndtooned(new(xsizes, typeof(yo)))
text = ndtooned(new(xsizes, typeof(texto)))
else
if(yrank.gt.1) then
x = ndtooned(new(ysizes, typeof(xo)))
y = ndtooned(new(ysizes, typeof(yo)))
text = ndtooned(new(ysizes, typeof(texto)))
else
x = new(xsizes > ysizes, typeof(xo))
y = new(xsizes > ysizes, typeof(yo))
text = new(xsizes > ysizes, typeof(texto))
end if
end if
x = ndtooned(xo)
y = ndtooned(yo)
text = ndtooned(texto)
len = dimsizes(x)
res2 = get_resources(resources)
wksname = get_res_value_keep(wks,"name","gsnapp")
calldraw = get_res_value(res2,"gsnDraw", False)
callframe = get_res_value(res2,"gsnFrame",False)
maxbb = get_bb_res(res2)
txres = get_res_eq(res2,"tx") ; Get text resources.
txid = new(len,graphic)
if((res2).and.isatt(res2,"txFuncCode")) then
;
; Special case where we don't have x,y values.
;
if(all(x.lt.0).and.all(y.lt.0)) then
do i=0,len-1
txid(i) = create wksname + "_text_ndc"+i textItemClass wks
"txString" : text(i)
"txFuncCode" : res2_at_txFuncCode
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
draw_and_frame(wks,txid(i),calldraw,callframe,0,maxbb)
end do
else
do i=0,len-1
txid(i) = create wksname + "_text_ndc"+i textItemClass wks
"txString" : text(i)
"txPosXF" : x(i)
"txPosYF" : y(i)
"txFuncCode" : res2_at_txFuncCode
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
draw_and_frame(wks,txid(i),calldraw,callframe,0,maxbb)
end do
end if
else
;
; Special case where we don't have x,y values.
;
if(all(x.lt.0).and.all(y.lt.0)) then
do i=0,len-1
txid(i) = create wksname + "_text_ndc"+i textItemClass wks
"txString" : text(i)
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
draw_and_frame(wks,txid(i),calldraw,callframe,0,maxbb)
end do
else
do i=0,len-1
txid(i) = create wksname + "_text_ndc"+i textItemClass wks
"txString" : text(i)
"txPosXF" : x(i)
"txPosYF" : y(i)
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
draw_and_frame(wks,txid(i),calldraw,callframe,0,maxbb)
end do
end if
end if
if(xrank.gt.1) then
return(onedtond(txid,xsizes))
end if
if(yrank.gt.1) then
return(onedtond(txid,ysizes))
end if
return(txid)
end
;***********************************************************************;
; Function : gsn_create_text ;
; wks: workstation object ;
; text: text strings ;
; resources: optional resources ;
; ;
; This function creates text strings. ;
;***********************************************************************;
function gsn_create_text(wks:graphic, text:string, resources:logical )
local x, y
begin
x = -1. ; Special values to tip off the routine
y = -1. ; that we don't have X,Y values.
txid = gsn_create_text_ndc(wks, text, x, y, resources)
return(txid)
end
;***********************************************************************;
; Procedure : gsn_text_ndc ;
; ;
; This procedure is the same as gsn_text, only it doesn't return ;
; anything. ;
;***********************************************************************;
procedure gsn_text_ndc(wks:graphic, text:string, x:numeric, \
y:numeric, resources:logical )
local txid
begin
if(resources) then
res2 = get_resources(resources)
else
res2 = True
end if
res2_at_gsnDraw = True ; False by default
txid = gsn_create_text_ndc(wks,text,x,y,res2)
end
;***********************************************************************;
; Procedure : gsn_text ;
; wks: workstation object ;
; plotid: plot object ;
; text: array of text strings ;
; x: n-dimensional array of x data positions ;
; y: n-dimensional array of y data positions ;
; resources: optional resources ;
; ;
; This procedure draws text strings on the workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks"). "x" and ;
; "y" are the x and y locations of each text string, and should be ;
; specified in the same data space as the data space of "plotid". ;
; "resources" is an optional list of resources. ;
;***********************************************************************;
procedure gsn_text(wks:graphic,plotid:graphic,texto:string,xo:numeric, \
yo:numeric, resources:logical )
local i, txid, plot_object, res, tx_res_index, x2, y2, xf, yf, \
funccode, res2, calldraw, callframe
begin
;
; Any one of xo, yo, and texto can just be one element, but if two or more
; are more than one element, then they must be exactly the same size.
;
xsizes = dimsizes(xo)
ysizes = dimsizes(yo)
tsizes = dimsizes(texto)
xrank = dimsizes(xsizes)
yrank = dimsizes(ysizes)
trank = dimsizes(tsizes)
if(xrank.gt.1.and.yrank.gt.1.and..not.all(xsizes.eq.ysizes)) then
print("Error: gsn_text: x and y must have the same dimension sizes, or either be a single value.")
return
end if
if(trank.gt.1.and. \
(xrank.gt.1.and..not.all(xsizes.eq.tsizes)) .or. \
(yrank.gt.1.and..not.all(ysizes.eq.tsizes))) then
print("Error: gsn_text: text must be a single string or the same dimension size as x and/or y.")
return
end if
;
; Convert to 1-dimensional arrays of all the same length.
;
if(xrank.gt.1) then
x = ndtooned(new(xsizes, typeof(xo)))
y = ndtooned(new(xsizes, typeof(yo)))
text = ndtooned(new(xsizes, typeof(texto)))
else
if(yrank.gt.1) then
x = ndtooned(new(ysizes, typeof(xo)))
y = ndtooned(new(ysizes, typeof(yo)))
text = ndtooned(new(ysizes, typeof(texto)))
else
x = new(xsizes > ysizes, typeof(xo))
y = new(xsizes > ysizes, typeof(yo))
text = new(xsizes > ysizes, typeof(texto))
end if
end if
x = ndtooned(xo)
y = ndtooned(yo)
text = ndtooned(texto)
len = dimsizes(x)
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",False)
maxbb = get_bb_res(res2)
;
; datatondc can't accept doubles, so have to demote doubles if they
; come in.
;
xf = tofloat(x)
yf = tofloat(y)
x2 = new(dimsizes(x),float)
y2 = new(dimsizes(y),float)
datatondc(plotid,xf,yf,x2,y2)
delete(xf)
delete(yf)
;
; The "txFuncCode" can't be set during a setvalues call. It must be
; set during the creation of the object.
;
wksname = get_res_value_keep(wks,"name","gsnapp")
txid = new(len,graphic)
txres = get_res_eq(res2,"tx") ; Get text resources.
if(res2.and.isatt(res2,"txFuncCode")) then
do i=0,len-1
txid = create wksname + "_text"+i textItemClass wks
"txString" : text(i)
"txPosXF" : x2(i)
"txPosYF" : y2(i)
"txFuncCode" : res2_at_txFuncCode
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
draw_and_frame(wks,txid(i),calldraw,callframe,0,maxbb)
end do
else
do i=0,len-1
txid(i) = create wksname + "_text"+i textItemClass wks
"txString" : text(i)
"txPosXF" : x2(i)
"txPosYF" : y2(i)
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
draw_and_frame(wks,txid(i),calldraw,callframe,0,maxbb)
end do
end if
end
;***********************************************************************;
; Function : gsn_add_text ;
; wks: workstation object ;
; plotid: plot object ;
; text: array of text strings ;
; x: n-dimensional array of x data positions ;
; y: n-dimensional array of y data positions ;
; resources: optional resources ;
; ;
; This function adds text strings to the plot "plotid". "x" and "y" are ;
; the x and y locations of each text string, and should be specified in ;
; the same data space as the data space of "plotid". "resources" is an ;
; optional list of TextItem and AnnoManager resources. ;
; ;
; This function is different from gsn_text because it actually attaches ;
; the text to the plot. This means that if you resize or move the plot, ;
; the text will stay with the plot. ;
;***********************************************************************;
function gsn_add_text(wks:graphic,plotid:graphic,texto:string, \
xo:numeric,yo:numeric, resources:logical )
local txid, txres, amres, just, res2, wksname, am_ids
begin
;
; Any one of xo, yo, and texto can just be one element, but if two or more
; are more than one element, then they must be exactly the same size.
;
xsizes = dimsizes(xo)
ysizes = dimsizes(yo)
tsizes = dimsizes(texto)
xrank = dimsizes(xsizes)
yrank = dimsizes(ysizes)
trank = dimsizes(tsizes)
if(xrank.gt.1.and.yrank.gt.1.and..not.all(xsizes.eq.ysizes)) then
print("Error: gsn_add_text: x and y must have the same dimension sizes, or either be a single value.")
dummy = new(1,graphic)
return(dummy)
end if
if(trank.gt.1.and. \
(xrank.gt.1.and..not.all(xsizes.eq.tsizes)) .or. \
(yrank.gt.1.and..not.all(ysizes.eq.tsizes))) then
print("Error: gsn_add_text: text must be a single string or the same dimension size as x and/or y.")
dummy = new(1,graphic)
return(dummy)
end if
;
; Convert to 1-dimensional arrays of all the same length.
;
if(xrank.gt.1) then
x = ndtooned(new(xsizes, typeof(xo)))
y = ndtooned(new(xsizes, typeof(yo)))
text = ndtooned(new(xsizes, typeof(texto)))
else
if(yrank.gt.1) then
x = ndtooned(new(ysizes, typeof(xo)))
y = ndtooned(new(ysizes, typeof(yo)))
text = ndtooned(new(ysizes, typeof(texto)))
else
x = new(xsizes > ysizes, typeof(xo))
y = new(xsizes > ysizes, typeof(yo))
text = new(xsizes > ysizes, typeof(texto))
end if
end if
x = ndtooned(xo)
y = ndtooned(yo)
text = ndtooned(texto)
len = dimsizes(x)
res2 = get_resources(resources)
;
; The "txFuncCode" can't be set during a setvalues call. It must be
; set during the creation of the object.
;
wksname = get_res_value_keep(wks,"name","gsnapp")
txres = get_res_eq(res2,"tx") ; Get text resources.
txid = new(len,graphic)
if(res2.and.isatt(res2,"txFuncCode")) then
do i=0,len-1
txid(i) = create wksname + "_text"+i textItemClass wks
"txString" : text(i)
"txFuncCode" : res2_at_txFuncCode
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
end do
else
do i=0,len-1
txid(i) = create wksname + "_text"+i textItemClass wks
"txString" : text(i)
end create
attsetvalues_check(txid(i),txres) ; Set text resources.
end do
end if
;
; Get current list of annotations that are already attached to
; the plot.
;
getvalues plotid
"pmAnnoViews" : text_ids
end getvalues
;
; Make sure the next text strings are first in the list.
;
if(.not.any(ismissing(text_ids)))
new_text_ids = new(dimsizes(text_ids)+len,graphic)
new_text_ids(0:len-1) = txid
new_text_ids(len:) = text_ids
else
new_text_ids = txid
end if
;
; Set the old and new annotations, with the new ones being first.
;
setvalues plotid
"pmAnnoViews" : new_text_ids
end setvalues
;
; Retrieve the id of the AnnoManager object created by the PlotManager and
; then set its location in data coordinate space.
;
getvalues plotid
"pmAnnoManagers": am_ids
end getvalues
tmp_just = get_res_value(txres,"txJust","CenterCenter")
just = get_res_value(res2,"amJust",tmp_just)
do i=0,len-1
setvalues am_ids(i)
"amDataXF" : x(i)
"amDataYF" : y(i)
"amResizeNotify" : True
"amTrackData" : True
"amJust" : just
end setvalues
end do
amres = get_res_eq(res2,"am") ; Get annomanager resources.
attsetvalues_check(am_ids(0),amres) ; Set annomanager resources.
if(xrank.gt.1) then
return(onedtond(am_ids(0:len-1),xsizes))
else
return(onedtond(am_ids(0:len-1),ysizes))
end if
end
;***********************************************************************;
; Procedure : draw_bb ;
; plot:graphic ;
; opts:logical ;
; ;
; This procedure draws a box around the bounding box of the given plot ;
; objects. ;
;***********************************************************************;
procedure draw_bb(plot:graphic,opts:logical)
local wks, bb, top, bot, lft, rgt, gsres, drawit, frameit
begin
drawit = isatt(opts,"gsnDraw").and.opts_at_gsnDraw
frameit = isatt(opts,"gsnFrame").and.opts_at_gsnFrame
wks = NhlGetParentWorkstation(plot(0))
dimplot = dimsizes(plot)
if(dimplot.eq.1) then
;
; Force bb to be 2-dimensional so we don't have to have a
; bunch of "if" tests later.
;
bb = new((/1,4/),float)
bb(0,:) = NhlGetBB(plot)
else
bb = NhlGetBB(plot)
end if
gsres = True
; gsres_at_gsLineThicknessF = 5.0
gsres_at_gsLineColor = "red"
do i=0,dimplot-1
top = bb(i,0)
bot = bb(i,1)
lft = bb(i,2)
rgt = bb(i,3)
if(drawit) then
draw(plot(i))
end if
gsn_polyline_ndc(wks,(/lft,rgt,rgt,lft,lft/), \
(/bot,bot,top,top,bot/),gsres)
if(frameit)
frame(wks)
end if
end do
end
;***********************************************************************;
; Procedure : gsn_panel ;
; wks: workstation object ;
; plot : array of plots to put on one page. ;
; dims : a 2-D array indicating number of rows and columns;
; resources: optional resources ;
; ;
; This procedure takes the array of plots and draws them all on one ;
; workstation in the configuration specified by dims. ;
; ;
; For example, if you have six plots and dims is (/2,3/), then the six ;
; plots will be drawn in 2 rows and 3 columns. ;
; ;
; However, if you set gsnPanelRowSpec to True, and dims to an array of ;
; integers, then each integer will represent the number of plots in that;
; row. For example, setting gsnPanelRowSpec = (/2,3,1/) will cause ;
; there to be two plots in the first row, three in the second row, and ;
; one in the third row. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnPanelCenter ;
; gsnPanelLabelBar ;
; gsnPanelRowSpec ;
; gsnPanelXWhiteSpacePercent ;
; gsnPanelYWhiteSpacePercent ;
; gsnPanelBoxes ;
; gsnPanelLeft ;
; gsnPanelRight ;
; gsnPanelBottom ;
; gsnPanelTop ;
; gsnPanelSave ;
; gsnDraw ;
; ;
;***********************************************************************;
function gsn_panel_return(wks:graphic,plot[*]:graphic,dims[*]:integer,\
resources:logical)
local res, nrows, ncols, ddims, is_row_spec, row_spec, npanels, nplots, \
perim_on
begin
res = get_resources(resources) ; Make copy of resources
;
; First check if paneling is to be specified by (#rows x #columns) or
; by #columns per row. The default is rows x columns, unless
; resource gsnPanelRowSpec is set to True
;
is_row_spec = get_res_value(res,"gsnPanelRowSpec",False)
;
; Check to see if we have enough plots to fit panels, and vice versa.
;
ddims = dimsizes(dims)
if(is_row_spec)
row_spec = dims
npanels = 0
nrows = ddims
ncols = max(row_spec)
do i=0,nrows-1
if(row_spec(i).lt.0)
print("Error: gsn_panel: you have specified a negative value for the number of plots in a row.")
exit
end if
npanels = npanels + row_spec(i)
end do
else
if(ddims.ne.2)
print("Error: gsn_panel: for the third argument of gsn_panel, you must either specify # rows by # columns or set gsnPanelRowSpec to True and set the number of plots per row.")
exit
end if
nrows = dims(0)
ncols = dims(1)
npanels = nrows * ncols
row_spec = new(nrows,integer)
row_spec = ncols
end if
nplots = dimsizes(plot) ; Total number of plots.
if(nplots.gt.npanels)
print("Warning: gsn_panel: you have more plots than you have panels.")
print("Only " + npanels + " plots will be drawn.")
nplots = npanels
end if
;
; Check for special resources.
;
panel_save = get_res_value_keep(res,"gsnPanelSave",True)
panel_debug = get_res_value_keep(res,"gsnDebug",False)
panel_center = get_res_value_keep(res,"gsnPanelCenter",True)
panel_labelbar = get_res_value_keep(res,"gsnPanelLabelBar",False)
calldraw = get_res_value_keep(res,"gsnDraw",True)
callframe = get_res_value_keep(res,"gsnFrame",True)
xwsp_perc = get_res_value_keep(res,"gsnPanelXWhiteSpacePercent",1.)
ywsp_perc = get_res_value_keep(res,"gsnPanelYWhiteSpacePercent",1.)
draw_boxes = get_res_value_keep(res,"gsnPanelBoxes",False)
x_lft = get_res_value_keep(res,"gsnPanelLeft",0.)
x_rgt = get_res_value_keep(res,"gsnPanelRight",1.)
y_bot = get_res_value_keep(res,"gsnPanelBottom",0.)
y_top = get_res_value_keep(res,"gsnPanelTop",1.)
main_string = get_res_value_keep(res,"txString","")
maxbb = get_bb_res(res)
lft_pnl = isatt(res,"gsnPanelLeft")
rgt_pnl = isatt(res,"gsnPanelRight")
bot_pnl = isatt(res,"gsnPanelBottom")
top_pnl = isatt(res,"gsnPanelTop")
;
; Check if a main string has been specified. If so, we need to make sure
; we leave some room for it by computing y_top (if the user hasn't set
; it). Also, we have to check if the font height has been set, because
; this could affect the title position.
;
if(main_string.ne."") then
main_string_on = True
main_font_hgt = get_res_value_keep(res,"txFontHeightF",0.02)
;
; By default, we want a distance of 0.01 between top of title and the
; frame, and a distance of 0.03 between the bottom of the title (txPosYF)
; and the top of the panel box (gsnPanelTop).
;
if(y_top.eq.1.) then
if(isatt(res,"txPosYF"))
y_top = min((/1.,res_at_txPosYF - 0.03/))
else
y_top = min((/1.,0.96-main_font_hgt/))
end if
end if
else
main_string_on = False
end if
;
; Calculate number of plot objects that will actually be drawn.
; (Panel plots plus labelbar and main string, if any.)
;
nnewplots = nplots
if(panel_labelbar) then
nnewplots = nnewplots + 1
end if
if(main_string_on) then
nnewplots = nnewplots + 1
end if
newplots = new(nnewplots,graphic) ; Create array to save these plots
; objects.
;
; We only need to set maxbb to True if the plots are being drawn to
; a PostScript or PDF workstation, because the bounding box is already
; maximized for an NCGM/X11 window.
;
if(maxbb) then
class = NhlClassName(wks)
if((class(0).ne."psWorkstationClass").and.(class(0).ne."pdfWorkstationClass")) then
maxbb = False
end if
delete(class)
end if
;
; Get some resources for the figure strings, if they exist.
;
if(isatt(res,"gsnPanelFigureStrings"))
is_figure_strings = True
panel_strings = get_res_value(res,"gsnPanelFigureStrings","")
;
; Get and set resource values for figure strings on the plots.
;
justs = (/"bottomright", "topright", "topleft", "bottomleft"/)
paras = (/ 1.0, 1.0, -1.0, -1.0/)
orths = (/ 1.0, -1.0, -1.0, 1.0/)
amres = get_res_eq(res,"am")
just = lower_case(get_res_value(amres,"amJust","bottomright"))
;
; Look for all resources that start with gsnPanelFigureStrings, and replace
; this with just "tx". This is what allows us to sneak in text resources
; and have them only apply to the figure strings, and not the main string.
;
txres = get_res_eq_replace(res,"gsnPanelFigureStrings","tx")
perim_on = get_res_value(txres,"txPerimOn",True)
bkgrn = get_res_value(txres,"txBackgroundFillColor",0)
else
is_figure_strings = False
end if
;
; Error check the values that the user has entered, to make sure
; they are valid.
;
if(xwsp_perc.lt.0.or.xwsp_perc.ge.100.)
print("Warning: gsn_panel: attribute gsnPanelXWhiteSpacePercent must be >= 0 and < 100.")
print("Defaulting to 1.")
xwsp_perc = 1.
end if
if(ywsp_perc.lt.0.or.ywsp_perc.ge.100.)
print("Warning: gsn_panel: attribute gsnPanelYWhiteSpacePercent must be >= 0 and < 100.")
print("Defaulting to 1.")
ywsp_perc = 1.
end if
if(x_lft.lt.0..or.x_lft.ge.1.)
print("Warning: gsn_panel: attribute gsnPanelLeft must be >= 0.0 and < 1.0")
print("Defaulting to 0.")
x_lft = 0.0
end if
if(x_rgt.le.0..or.x_rgt.gt.1.)
print("Warning: gsn_panel: attribute gsnPanelRight must be > 0.0 and <= 1.0")
print("Defaulting to 1.")
x_rgt = 1.0
end if
if(y_top.le.0..or.y_top.gt.1.)
print("Warning: gsn_panel: attribute gsnPanelTop must be > 0.0 and <= 1.0")
print("Defaulting to 1.")
y_top = 1.0
end if
if(y_bot.lt.0..or.y_bot.ge.1.)
print("Warning: gsn_panel: attribute gsnPanelBottom must be >= 0.0 and < 1.0")
print("Defaulting to 0.")
y_bot = 0.0
end if
if(x_rgt.le.x_lft)
print("Error: gsn_panel: attribute gsnPanelRight ("+x_rgt+") must be greater")
print("than gsnPanelLeft ("+x_lft+").")
exit
end if
if(y_top.le.y_bot)
print("Error: gsn_panel: attribute gsnPanelTop ("+y_top+") must be greater")
print("than gsnPanelBottom ("+y_bot+").")
exit
end if
;
; We assume all plots are the same size, so if we get the size of
; one of them, then this should represent the size of the rest
; of them. Also, count the number of non-missing plots for later.
; Since some of the plots might be missing, grab the first one that
; isn't, and use this one to determine plot size.
;
ind_nomsg = ind(.not.ismissing(plot(0:nplots-1)))
if(.not.any(ismissing(ind_nomsg))) then
valid_plot = ind_nomsg(0)
bb = NhlGetBB(plot(valid_plot)) ; Get bounding box of plot with
top = bb(0) ; all of its annotations.
bottom = bb(1)
left = bb(2)
right = bb(3)
delete(bb)
else
print("Error: ngl_panel: all of the plots passed to gsn_panel appear to be invalid")
exit
end if
nvalid_plots = dimsizes(ind_nomsg)
delete(ind_nomsg)
if(panel_debug) then
print("There are " + nvalid_plots + " valid plots out of " + nplots + " total plots")
end if
;
; Get the type of plots we have. "plot" can be a map, in which case
; the vector or contour plot overlaid on it will be indicated
; by "plot_at_contour" or "plot_at_vector"
;
new_plot = get_plot_not_loglin(plot(valid_plot))
;
; Get the font height.
;
if(is_figure_strings.or.panel_labelbar) then
if(new_plot_at_plot_type.eq."contour") then
getvalues new_plot
"cnInfoLabelFontHeightF" : font_height
"cnFillOn" : fill_on
end getvalues
if(panel_labelbar.and.fill_on) then
getvalues new_plot
"cnFillColors" : colors
"cnFillPatterns" : fill_patterns
"cnFillScales" : fill_scales
"cnMonoFillPattern" : mono_fill_pat
"cnMonoFillScale" : mono_fill_scl
"cnMonoFillColor" : mono_fill_col
"cnLevels" : levels
end getvalues
else
panel_labelbar = False
end if
else
if(new_plot_at_plot_type.eq."vector") then
getvalues new_plot
"vcRefAnnoFontHeightF" : font_height
"vcGlyphStyle" : gstyle
"vcFillArrowsOn" : fill_arrows_on
"vcMonoLineArrowColor" : mono_line_color
"vcMonoFillArrowFillColor" : mono_fill_arrow
end getvalues
if(panel_labelbar) then
;
; 0 = linearrow, 1 = fillarrow, 2 = windbarb, 3 = curlyvector
;
if( (fill_arrows_on .and. .not.mono_fill_arrow) .or. \
(.not.fill_arrows_on .and. .not.mono_line_color) .or. \
(gstyle.eq.1 .and. .not.mono_fill_arrow) .or. \
(gstyle.eq.0 .or. gstyle.eq.3) .and. .not.mono_line_color) then
;
; There are no fill patterns in VectorPlot, only solids.
;
mono_fill_pat = True
mono_fill_scl = True
mono_fill_col = False
getvalues new_plot
"vcLevels" : levels
"vcLevelColors" : colors
end getvalues
else
panel_labelbar = False
end if
end if
else
if(new_plot_at_plot_type.eq."xy") then
getvalues new_plot
"tiXAxisFontHeightF" : font_height
end getvalues
font_height = 0.6*font_height
else
font_height = 0.01
print("Warning: gsn_panel: unrecognized plot type, thus unable to get information for font height.")
print("Defaulting to " + font_height)
end if
end if
end if
;
; Use this font height for the panel strings, if any, unless the user
; has set gsnPanelFigureStringsFontHeightF.
;
pfont_height = get_res_value(res,"gsnPanelFigureStringsFontHeightF",\
font_height)
end if
;
; plot_width : total width of plot with all of its annotations
; plot_height : total height of plot with all of its annotations
; total_width : plot_width plus white space on both sides
; total_height: plot_height plus white space on top and bottom
;
plot_width = right - left ; Calculate total width of plot.
plot_height = top - bottom ; Calculate total height of plot.
xwsp = xwsp_perc/100. * plot_width ; White space is a percentage of total
ywsp = ywsp_perc/100. * plot_height ; width and height.
total_width = 2.*xwsp + plot_width ; Calculate total width and height
total_height = 2.*ywsp + plot_height ; with white space added.
;
; If we are putting a global labelbar at the bottom (right), make
; it 2/10 the height (width) of the plot.
;
lbhor = True
if(panel_labelbar) then
lbres = get_res_eq(res,(/"lb","pmLabelBar","vp"/)) ; Get labelbar resources.
if(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True)) then
lbhor = False
labelbar_width = 0.20 * plot_width + 2.*xwsp
;
; Adjust height depending on whether we have one row or multiple rows.
;
if(nplots.gt.1.and.nrows.gt.1) then
labelbar_height = (nrows-1) * (2.*ywsp + plot_height)
else
labelbar_height = plot_height
end if
else
set_attr(lbres,"lbOrientation","Horizontal")
labelbar_height = 0.20 * plot_height + 2.*ywsp
;
; Adjust width depending on whether we have one column or multiple
; columns.
;
if(nplots.gt.1.and.ncols.gt.1) then
labelbar_width = (ncols-1) * (2.*xwsp + plot_width)
else
labelbar_width = plot_width
end if
end if
else
labelbar_height = 0.
labelbar_width = 0.
end if
;
; We want:
;
; ncols * scale * total_width <= x_rgt - x_lft (the viewport width)
; nrows * scale * total_height <= y_top - y_bot (the viewport height)
; [or scale * (nrows * total_height + labelbar_height) if a labelbar
; is being drawn]
;
; By taking the minimum of these two, we get the scale
; factor that we need to fit all plots on a page.
;
xrange = x_rgt - x_lft
yrange = y_top - y_bot
if(lbhor)
;
; Previously, we used to include xrange and yrange as part of the min
; statement. This seemed to cause problems if you set one of
; gsnPanelTop/Bottom/Right/Left however, so I removed it. Initial
; testing on Sylvia's panel examples seems to indicate this is okay.
;
row_scale = yrange/(nrows*total_height+labelbar_height)
col_scale = xrange/(ncols*total_width)
scale = min((/col_scale,row_scale/))
yrange = yrange - scale * labelbar_height
else
;
; See above comments.
;
row_scale = yrange/(nrows*total_height)
col_scale = xrange/(ncols*total_width+labelbar_width)
scale = min((/col_scale,row_scale/))
xrange = xrange - scale * labelbar_width
end if
new_plot_width = scale*plot_width ; Calculate new width
new_plot_height = scale*plot_height ; and height.
xwsp = xwsp_perc/100. * new_plot_width ; Calculate new white space.
ywsp = ywsp_perc/100. * new_plot_height
new_total_width = 2.*xwsp + new_plot_width ; Calculate new total width
new_total_height = 2.*ywsp + new_plot_height ; and height w/white space.
xsp = xrange - new_total_width*ncols ; Calculate total amt of white space
ysp = yrange - new_total_height*nrows ; left in both X and Y directions.
getvalues plot(valid_plot)
"vpXF" : vpx
"vpYF" : vpy
"vpWidthF" : vpw
"vpHeightF" : vph
end getvalues
dxl = scale * (vpx-left) ; Distance from plot's left
; position to its leftmost annotation
dxr = scale * (right-(vpx+vpw)) ; Distance from plot's right
; position to its rightmost annotation
dyt = scale * (top-vpy) ; Distance from plot's top
; position to its topmost annotation.
dyb = scale * ((vpy-vph)-bottom) ; Distance from plot's bottom
; position to its bottommost annotation.
ypos = y_top - ywsp - dyt -(ysp/2.+new_total_height*ispan(0,nrows-1,1))
delete(top)
delete(bottom)
delete(right)
delete(left)
;
; If we have figure strings, then determine white spacing around
; the text box.
;
if(is_figure_strings) then
fig_index = ind(just.eq.justs)
if(ismissing(fig_index))
fig_index = 0
just = justs(fig_index)
end if
len_pct = 0.025 ; Percentage of width/height of plot
; for white space around text box.
if(vpw .lt. vph) then
wsp_hpct = (len_pct * vpw) / vph
wsp_wpct = len_pct
else
wsp_hpct = len_pct
wsp_wpct = (len_pct * vph) / vpw
end if
para = get_res_value(amres,"amParallelPosF", paras(fig_index) * \
(0.5 - wsp_wpct))
orth = get_res_value(amres,"amOrthogonalPosF", orths(fig_index) * \
(0.5 - wsp_hpct))
end if
;
; Variable to store rightmost location of rightmost plot, and topmost
; location of top plot.
;
max_rgt = 0.
max_top = 0.
;
; Variable to hold original viewport coordinates, and annotations (if
; they exist).
;
old_vp = new((/nplots,4/),float)
anno = new(nplots, graphic)
;
; Loop through each row and create each plot in the new scaled-down
; size. We will draw plots later, outside the loop.
;
num_plots_left = nplots
nplot = 0
nr = 0
do while(num_plots_left.gt.0)
vpy_new = ypos(nr)
new_ncols = min((/num_plots_left,row_spec(nr)/))
if(panel_center)
xsp = xrange - new_total_width*new_ncols ; space before plots.
else
xsp = xrange - new_total_width*ncols ; space before plots.
end if
;
; Calculate new x positions.
;
xpos = x_lft + xwsp + dxl +(xsp/2.+new_total_width*ispan(0,new_ncols-1,1))
do nc = 0,new_ncols-1
vpx_new = xpos(nc)
if(.not.ismissing(plot(nplot)))
pplot = plot(nplot)
getvalues pplot
"vpXF" : old_vp(nplot,0)
"vpYF" : old_vp(nplot,1)
"vpWidthF" : old_vp(nplot,2)
"vpHeightF" : old_vp(nplot,3)
end getvalues
;
; If user setting gsnPanelXF or gsnPanelYF resources, then use these instead.
; They must be set as an array of the same length as you have plots.
; If any of these are negative, then use the calculated values.
;
vpx_new = xpos(nc)
if(isatt(res,"gsnPanelXF").and.dimsizes(res_at_gsnPanelXF).eq.nplots.and.\
res_at_gsnPanelXF(nplot).ge.0.and.res_at_gsnPanelXF(nplot).le.1) then
vpx_new = res_at_gsnPanelXF(nplot)
end if
vpy_new = ypos(nr)
if(isatt(res,"gsnPanelYF").and.dimsizes(res_at_gsnPanelYF).eq.nplots.and.\
res_at_gsnPanelYF(nplot).ge.0.and.res_at_gsnPanelYF(nplot).le.1) then
vpy_new = res_at_gsnPanelYF(nplot)
end if
;
; Print out values used.
;
if(panel_debug) then
print("-------Panel viewport values for each plot-------")
print(" plot #" + nplot)
print(" new x,y = " + vpx_new + "," + vpy_new)
print(" orig wdt,hgt = " + old_vp(nplot,2) + "," + old_vp(nplot,3))
print(" new wdt,hgt = " + scale*old_vp(nplot,2) + "," + scale*old_vp(nplot,3))
end if
setvalues pplot
"vpXF" : vpx_new
"vpYF" : vpy_new
"vpWidthF" : scale*old_vp(nplot,2)
"vpHeightF" : scale*old_vp(nplot,3)
end setvalues
added_anno = False
if(is_figure_strings) then
if(nplot .lt. dimsizes(panel_strings).and. \
panel_strings(nplot).ne."")
text = create "string" textItemClass wks
"txString" : panel_strings(nplot)
"txFontHeightF" : pfont_height
"txPerimOn" : perim_on
"txBackgroundFillColor" : bkgrn
end create
;
; Set some text resources for figure strings, if any.
;
attsetvalues_check(text,txres)
;
; Add annotation to plot.
;
anno(nplot) = NhlAddAnnotation(pplot,text)
added_anno = True
setvalues anno(nplot)
"amZone" : 0
"amJust" : just
"amParallelPosF" : para
"amOrthogonalPosF" : orth
"amResizeNotify" : True
end setvalues
attsetvalues_check(anno(nplot),amres)
delete(text)
end if
end if
;
; Save this plot.
;
newplots(nplot) = pplot
;
; Info for possible labelbar or main_string
;
if(main_string_on.or.panel_labelbar.or.draw_boxes) then
bb = NhlGetBB(pplot) ; Get bounding box of plot.
top = bb(0)
lft = bb(2)
bot = bb(1)
rgt = bb(3)
max_rgt = max((/rgt,max_rgt/))
max_top = max((/top,max_top/))
if(draw_boxes)
draw_bb(pplot,False)
end if
end if
end if ; if(.not.ismissing(plot(nplot)))
;
; Retain the smallest and largest x and y positions.
;
if(nplot.eq.0) then
min_xpos = vpx_new
max_xpos = vpx_new
min_ypos = vpy_new
max_ypos = vpy_new
else
min_xpos = min( (/vpx_new,min_xpos/) )
max_xpos = max( (/vpx_new,max_xpos/) )
min_ypos = min( (/vpy_new,min_ypos/) )
max_ypos = max( (/vpy_new,max_ypos/) )
end if
nplot = nplot + 1 ; Increment plot counter
end do ; end of columns
num_plots_left = nplots - nplot
nr = nr + 1 ; increment rows
delete(xpos)
end do ; end of plots
;
; Print min/max information.
;
if(panel_debug) then
print("-------min/max X,Y positions for plots-------")
print("min/max x position = " + min_xpos + "/" + max_xpos)
print("min/max y position = " + min_ypos + "/" + max_ypos)
end if
;
; Calculate the biggest rescaled widths and heights (technically, they
; should all be the same). These values will be used a few times
; throughout the rest of the code.
;
scaled_width = scale*max(old_vp(:,2))
scaled_height = scale*max(old_vp(:,3))
;
; Check if a labelbar is to be drawn at the bottom.
;
if(panel_labelbar) then
;
; If plot type is unknown or xy, then we can't get labelbar information.
;
if(new_plot_at_plot_type.ne."unknown".and.new_plot_at_plot_type.ne."xy") then
;
; Set labelbar height, width, and font height.
;
labelbar_height = scale * labelbar_height
labelbar_width = scale * labelbar_width
labelbar_font_height = font_height
;
; Set some labelbar resources. If pmLabelBarWidth/Height are set,
; use these no matter what, for the labelbar width and height. Otherwise,
; use vpWidth/Height if they are set.
;
lbres = True
if(isatt(lbres,"pmLabelBarWidthF")) then
lbres_at_vpWidthF = get_res_value(lbres,"pmLabelBarWidthF",labelbar_width)
else
set_attr(lbres,"vpWidthF", labelbar_width)
end if
if(isatt(lbres,"pmLabelBarHeightF")) then
lbres_at_vpHeightF = get_res_value(lbres,"pmLabelBarHeightF",labelbar_height)
else
set_attr(lbres,"vpHeightF",labelbar_height)
end if
;
; Set position of labelbar depending on whether it's horizontal or
; vertical.
;
if(lbhor)
set_attr(lbres,"vpYF",max ((/ywsp+labelbar_height,bot-ywsp/)))
if(ncols.eq.1.and.lbres_at_vpWidthF.le.scaled_width)
set_attr(lbres,"vpXF",min_xpos + (scaled_width-lbres_at_vpWidthF)/2.)
else
tmp_range = x_rgt - x_lft
set_attr(lbres,"vpXF",x_lft + (tmp_range - lbres_at_vpWidthF)/2.)
end if
lbres_at_vpYF = lbres_at_vpYF + get_res_value(lbres,"pmLabelBarOrthogonalPosF",0.)
lbres_at_vpXF = lbres_at_vpXF + get_res_value(lbres,"pmLabelBarParallelPosF",0.)
else
set_attr(lbres,"vpXF",min ((/1.-(xwsp+labelbar_width),max_rgt+xwsp/)))
if(nrows.eq.1.and.lbres_at_vpHeightF.le.scaled_height)
set_attr(lbres,"vpYF",max_ypos-(scaled_height - lbres_at_vpHeightF)/2.)
else
tmp_range = y_top - y_bot
set_attr(lbres,"vpYF",y_top-(tmp_range - lbres_at_vpHeightF)/2.)
end if
lbres_at_vpXF = lbres_at_vpXF + get_res_value(lbres,"pmLabelBarOrthogonalPosF",0.)
lbres_at_vpYF = lbres_at_vpYF + get_res_value(lbres,"pmLabelBarParallelPosF",0.)
end if
set_attr(lbres,"lbLabelFontHeightF",labelbar_font_height)
;
; Check if we want different fill patterns or fill scales. If so, we
; have to pass these on to the labelbar.
;
set_attr(lbres,"lbMonoFillColor",mono_fill_col)
if(.not.mono_fill_pat)
set_attr(lbres,"lbMonoFillPattern", False)
set_attr(lbres,"lbFillPatterns", fill_patterns)
end if
if(.not.mono_fill_scl)
set_attr(lbres,"lbMonoFillScale", False)
set_attr(lbres,"lbFillScales", fill_scales)
end if
;
; Create the labelbar. First check the levels to make sure that a
; contour level with a value like 1e-8 is not really supposed to be
; a value of 0.
;
levels = fix_zero_contour(levels)
newplots(nplot) = create_labelbar(wks,dimsizes(colors),colors, \
levels,lbres)
nplot = nplot + 1
else
print("Warning: gsn_panel: unrecognized plot type for getting labelbar information. Ignoring labelbar request.")
end if
end if
;
; Create the main string, if exists.
;
if(main_string_on) then
y_top = min((/y_top,max_top/))
main_ypos = get_res_value_keep(res,"txPosYF",y_top + 0.03)
main_xpos = get_res_value_keep(res,"txPosXF",0.5)
if(panel_debug)
print("-------Panel title values-------")
print(" title = " + main_string)
print(" top of paneled plots = " + y_top)
print(" y location of title = " + main_ypos)
end if
if((main_ypos+main_font_hgt).gt.1)
print("Warning: gsn_panel: font height (" + main_font_hgt + ") of main string is too large to fit in space provided. Either decrease font size or set gsnPanelTop.")
end if
mntxres = get_res_eq(res,"tx")
mntxres = True
mntxres_at_gsnDraw = False
mntxres_at_gsnFrame = False
mntxres_at_txFontHeightF = main_font_hgt
newplots(nplot) = gsn_create_text_ndc(wks, main_string, main_xpos, \
main_ypos, mntxres)
end if
;
; If some of the paneled plots are missing, we need to take these into
; account so that the maximization will still work properly. For
; example, if we ask for a 2 x 2 configuration, but plots 1 and 3 (the
; rightmost plots) are missing, then we need to set a new resource
; called gsnPanelInvsblRight to whatever approximate X value it
; would have been if those plots weren't missing. Setting just gsnPanelRight
; won't work in this case, because that resource is only used to control
; where the plots are drawn in a 0 to 1 square, and *not* to indicate the
; rightmost location of the rightmost graphic (which could be a vertical
; labelbar.
;
; Not dealing with the case of gsnPanelRowSpec = True yet.
;
if(.not.is_row_spec) then
newbb = new((/dimsizes(newplots),4/),float)
;
; Have to deal with special case of only having one plot.
;
if(dimsizes(newplots).eq.1)
newbb(0,:) = NhlGetBB(newplots) ; Get bounding boxes of plots, plus
; labelbar and text string if they
; exist.
else
newbb = NhlGetBB(newplots) ; Get bounding boxes of plots, plus
; labelbar and text string if they
; exist.
end if
getvalues newplots(valid_plot)
"vpXF" : vpx
"vpYF" : vpy
"vpWidthF" : vpw
"vpHeightF" : vph
end getvalues
dxl = vpx-newbb(valid_plot,2)
dxr = newbb(valid_plot,3)-(vpx+vpw)
dyt = (newbb(valid_plot,0)-vpy)
dyb = (vpy-vph)-newbb(valid_plot,1)
;
; Get largest bounding box that encompasses all non-missing graphical
; objects.
;
newtop = max(newbb(:,0))
newbot = min(newbb(:,1))
newlft = min(newbb(:,2))
newrgt = max(newbb(:,3))
delete(newbb)
;
; This section checks to see if all plots along one side are
; missing, because if they are, we have to pretend like they
; are just invisible (i.e. do the maximization as if the invisible
; plots were really there). This section needs to take
; place even if no plots are missing, because it's possible the
; user specified fewer plots than panels.
;
xlft = min_xpos - dxl
xrgt = max_xpos + vpw + dxr
xtop = max_ypos + dyt
xbot = min_ypos - vph - dyb
if(.not.rgt_pnl.and.xrgt.gt.newrgt) then
maxbb_at_gsnPanelInvsblRight = xrgt
if(panel_debug)
print("gsnPanelInvsblRight = " + maxbb_at_gsnPanelInvsblRight)
end if
end if
if(.not.lft_pnl.and.xlft.lt.newlft) then
maxbb_at_gsnPanelInvsblLeft = xlft
if(panel_debug)
print("gsnPanelInvsblLeft = " + maxbb_at_gsnPanelInvsblLeft)
end if
end if
if(.not.top_pnl.and.xtop.gt.newtop) then
maxbb_at_gsnPanelInvsblTop = xtop
if(panel_debug)
print("gsnPanelInvsblTop = " + maxbb_at_gsnPanelInvsblTop)
end if
end if
if(.not.bot_pnl.and.xbot.lt.newbot) then
maxbb_at_gsnPanelInvsblBottom = xbot
if(panel_debug)
print("gsnPanelInvsblBottom = " + maxbb_at_gsnPanelInvsblBottom)
end if
end if
end if
;
; Draw plots plus labelbar and main title (if they exists). This is
; also where the plots will be maximized for PostScript output,
; if so indicated.
;
if(draw_boxes)
draw_and_frame(wks,newplots,calldraw,False,1,maxbb)
else
draw_and_frame(wks,newplots,calldraw,callframe,1,maxbb)
end if
;
; Draw bounding boxes around each plot object for debugging purposes.
;
if(draw_boxes)
do i=0,dimsizes(newplots)-1
if(.not.ismissing(newplots(i)))
draw_bb(newplots(i),False)
end if
end do
if(callframe) then
frame(wks)
end if
end if
;
; Restore plots to original size.
;
if(.not.panel_save) then
do i=0,nplots-1
if(.not.ismissing(plot(i)))
if(added_anno.and..not.ismissing(anno(i)))
NhlRemoveAnnotation(plot(i),anno(i))
end if
setvalues plot(i)
"vpXF" : old_vp(i,0)
"vpYF" : old_vp(i,1)
"vpWidthF" : old_vp(i,2)
"vpHeightF" : old_vp(i,3)
end setvalues
end if
end do
end if
return(newplots)
end
;***********************************************************************;
; procedure gsn_panel - same as gsn_panel_return, only it doesn't return;
; anything. ;
;***********************************************************************;
procedure gsn_panel(wks:graphic,plot[*]:graphic,dims[*]:integer,\
resources:logical)
local res2
begin
res2 = get_resources(resources)
set_attr(res2,"gsnPanelSave",False )
plots = gsn_panel_return(wks,plot,dims,res2)
end
;***********************************************************************;
; Function : gsn_attach_plots ;
; base : base plot ;
; plots : list of plots to attach ;
; resplot1 : logical ;
; resplot2 : logical ;
; ;
; This function attaches the list of "plots" to the "base" plot, either;
; on the right Y axis or bottom X axis of the base plot. The default is ;
; to attach the plots at the Y axis, unless gsnAttachPlotsXAxis is set ;
; to True. ;
; ;
; By default, the viewport heights of all plots will be made the same, ;
; appropriate tick marks and labels will be turned off, and the aspect ;
; ratio preserved. ;
; ;
; For example, if you have the following plots and you want them ;
; attached at the Y axis: ;
; ;
; ___________ _____ __________ ;
; | | | | | | ;
; | | | | | | ;
; | base | | | | | ;
; | | | | | | ;
; | | | | | | ;
; ----------- ----- ---------- ;
; ;
; you will end up with: ;
; ;
; _________________________ ;
; | | | | ;
; | | | | ;
; | base | | | ;
; | | | | ;
; | | | | ;
; ------------------------- ;
; ;
; Or, if you have the following plots and you want them attached at the ;
; X axis: ;
; ;
; ___________ ___________ ;
; | | | | ;
; | | | | ;
; | base | | | ;
; | | ----------- ;
; | | ;
; ----------- ;
; ;
; you will end up with: ;
; ;
; ___________ ;
; | | ;
; | | ;
; | base | ;
; | | ;
; | | ;
; ----------- ;
; | | ;
; | | ;
; | | ;
; ----------- ;
; ;
; plotres1 and plotres2 are resources changing the default behavior of ;
; this function. ;
; ;
;***********************************************************************;
function gsn_attach_plots(oldbaseplot:graphic,oldplots:graphic, \
plotres1:logical, plotres2:logical)
local anno, width1, width2, height1, height2, font_height1, font_height2, \
mj_length1, mj_length2, mjo_length1, mjo_length2, mno_length1, mno_length2, \
mno_length1, mno_length2, total_width1, total_width2, scale1, scale2, scale
begin
res1 = get_resources(plotres1)
res2 = get_resources(plotres2)
base = oldbaseplot
plots = oldplots
nplots= dimsizes(plots)
attach_y = .not.get_res_value(res1,"gsnAttachPlotsXAxis",False)
attach_y = .not.get_res_value(res2,"gsnAttachPlotsXAxis",.not.attach_y)
border_on = get_res_value(res1,"gsnAttachBorderOn",True)
;
; The plots to be attached may not be regular plots (contour, xy, vector,
; etc), so we won't be able to retrieve tickmark info from them. We have
; to see if they are overlay plots, instead, that have regular plots
; overlaid on them. If so, we can use the overlaid plots for tickmark
; info. If not, then we are in trouble.
;
; Here's the list of "regular" plot types:
;
plot_types = (/"contourPlotClass","xyPlotClass","vectorPlotClass",\
"streamlinePlotClass"/)
;
; First check the base plot for "regular plotness".
;
found_base = False
if(any(NhlClassName(base).eq.plot_types)) then
;
; The base plot is a regular plot.
;
new_base = base
found_base = True
else
;
; The base plot is not a regular plot, so find out if it has a regular
; plot overlaid on it.
;
getvalues base
"pmOverlaySequenceIds" : base_ids
end getvalues
if(.not.ismissing(base_ids(0))) then
j = 0
;
; Loop through the overlaid plots and find a "regular" one. We will
; use the first one we find.
;
do while(j.lt.dimsizes(base_ids).and..not.found_base)
if(any(NhlClassName(base_ids(j)).eq.plot_types)) then
new_base = base_ids(j)
found_base = True
end if
j = j + 1
end do
end if
end if
if(.not.found_base) then
print("Warning: gsn_attach_plots: the base plot is an unrecognized plot type; may get unexpected results.")
new_base = base
end if
;
; Now test the plots to be attached, and see if they are "regular" plots.
;
found_plots = new(nplots,logical)
new_plots = new(nplots,graphic)
found_plots = False
do i=0,nplots-1
if(any(NhlClassName(plots(i)).eq.plot_types)) then
new_plots(i) = plots(i)
found_plots(i) = True
else
getvalues plots(i)
"pmOverlaySequenceIds" : tmp_plot_ids
end getvalues
if(.not.ismissing(tmp_plot_ids(0))) then
j = 0
;
; Loop through the overlaid plots and find a "regular" one. We will
; use the first one we find.
;
do while(j.lt.dimsizes(tmp_plot_ids).and..not.found_plots(i))
if(any(NhlClassName(tmp_plot_ids(j)).eq.plot_types)) then
new_plots(i) = tmp_plot_ids(j)
found_plots(i) = True
end if
j = j + 1
end do
end if
delete(tmp_plot_ids)
end if
if(.not.found_plots(i)) then
print("Warning: gsn_attach_plots: unrecognized plot type, may get unexpected results.")
new_plots(i) = plots(i)
found_plots(i) = False
end if
end do
;
; Retrieve tickmark lengths and font height labels so we can make
; them the same size later.
;
; Also get the viewport widths and heights so we can maintain the
; aspect ratio, but yet make the heights or widths the same.
;
getvalues base
"vpWidthF" : width1
"vpHeightF" : height1
"tiMainFontHeightF" : main_font_height1
end getvalues
widths = new(dimsizes(plots),float)
heights = new(dimsizes(plots),float)
do i=0,nplots-1
getvalues plots(i)
"vpWidthF" : widths(i)
"vpHeightF" : heights(i)
end getvalues
end do
mj_lengths = new(nplots,float)
mjo_lengths = new(nplots,float)
mn_lengths = new(nplots,float)
mno_lengths = new(nplots,float)
font_heights = new(nplots,float)
if(attach_y)
;
; If didn't find a regular base plot, then we can't do anything
; about the tickmarks.
;
if(found_base) then
getvalues new_base
"tmXBMajorLengthF" : mj_length1
"tmXBMajorOutwardLengthF" : mjo_length1
"tmXBMinorLengthF" : mn_length1
"tmXBMinorOutwardLengthF" : mno_length1
"tmXBLabelFontHeightF" : font_height1
end getvalues
end if
do i=0,nplots-1
;
; If didn't find a regular plot, then we can't do anything
; about the tickmarks.
;
if(found_plots(i)) then
getvalues new_plots(i)
"tmXBMajorLengthF" : mj_lengths(i)
"tmXBMajorOutwardLengthF" : mjo_lengths(i)
"tmXBMinorLengthF" : mn_lengths(i)
"tmXBMinorOutwardLengthF" : mno_lengths(i)
"tmXBLabelFontHeightF" : font_heights(i)
end getvalues
end if
end do
else
;
; If didn't find a regular base plot, then we can't do anything
; about the tickmarks.
;
if(found_base) then
getvalues new_base
"tmYLMajorLengthF" : mj_length1
"tmYLMajorOutwardLengthF" : mjo_length1
"tmYLMinorLengthF" : mn_length1
"tmYLMinorOutwardLengthF" : mno_length1
"tmYLLabelFontHeightF" : font_height1
end getvalues
end if
do i=0,nplots-1
if(found_plots(i)) then
getvalues new_plots(i)
"tmYLMajorLengthF" : mj_lengths(i)
"tmYLMajorOutwardLengthF" : mjo_lengths(i)
"tmYLMinorLengthF" : mn_lengths(i)
"tmYLMinorOutwardLengthF" : mno_lengths(i)
"tmYLLabelFontHeightF" : font_heights(i)
end getvalues
end if
end do
end if
;
; Calculate the scale factor needed to make the plots the same
; size in the appropriate axis. If we are attaching plots at the Y axis,
; then we want to make them the same height. Otherwise, we want to make
; them the same width. We do this by keeping the size of the largest
; plot the same, and scaling the rest of the plots to be the same height
; (or width).
;
scales = new(nplots,float)
if(attach_y) then
if(any(height1.lt.heights)) then
scale1 = max(heights)/height1
scales = max(heights)/heights
else
scale1 = 1.
scales = height1/heights
end if
else
if(any(width1.lt.widths)) then
scale1 = max(widths)/width1
scales = max(widths)/widths
else
scale1 = 1.
scales = width1/widths
end if
end if
;
; Because we are attaching plots along an axis, turn off
; tickmarks and labels where appropriate.
;
if(attach_y) then
if(found_base) then
setvalues new_base
"tmYUseLeft" : get_res_value(res1,"tmYUseLeft",False)
"tmYROn" : get_res_value(res1,"tmYROn",False)
"tmYRLabelsOn" : get_res_value(res1,"tmYRLabelsOn",False)
"tmYRBorderOn" : get_res_value(res1,"tmYRBorderOn",border_on)
end setvalues
end if
do i=0,nplots-2
if(found_plots(i)) then
setvalues new_plots(i)
"tmYUseLeft" : get_res_value(res2,"tmYUseLeft",False)
"tmYLOn" : get_res_value(res2,"tmYLOn",False)
"tmYLBorderOn" : get_res_value(res2,"tmYLBorderOn",border_on)
"tmYROn" : get_res_value(res2,"tmYROn",False)
"tmYRLabelsOn" : get_res_value(res2,"tmYRLabelsOn",False)
"tmYRBorderOn" : get_res_value(res2,"tmYRBorderOn",border_on)
"tiYAxisOn" : get_res_value(res2,"tiYAxisOn",False)
end setvalues
end if
end do
if(found_plots(nplots-1)) then
setvalues new_plots(nplots-1)
"tmYUseLeft" : get_res_value(res2,"tmYUseLeft",False)
"tiYAxisOn" : get_res_value(res2,"tiYAxisOn",False)
"tmYLOn" : get_res_value(res2,"tmYLOn",False)
"tmYLBorderOn" : get_res_value(res2,"tmYLBorderOn",border_on)
"tmYLLabelsOn" : get_res_value(res1,"tmYLLabelsOn",False)
end setvalues
end if
else
if(found_base) then
setvalues new_base
"tmXUseBottom" : get_res_value(res1,"tmXUseBottom",False)
"tmXBOn" : get_res_value(res1,"tmXBOn",False)
"tmXBBorderOn" : get_res_value(res1,"tmXBBorderOn",border_on)
"tmXBLabelsOn" : get_res_value(res1,"tmXBLabelsOn",False)
"tiXAxisOn" : get_res_value(res1,"tiXAxisOn",False)
end setvalues
end if
do i=0,nplots-2
if(found_plots(i)) then
setvalues new_plots(i)
"tmXUseBottom" : get_res_value(res2,"tmXUseBottom",False)
"tmXBOn" : get_res_value(res2,"tmXBOn",False)
"tmXBBorderOn" : get_res_value(res2,"tmXBBorderOn",border_on)
"tmXBLabelsOn" : get_res_value(res2,"tmXBLabelsOn",False)
"tmXTOn" : get_res_value(res2,"tmXTOn",False)
"tmXTBorderOn" : get_res_value(res2,"tmXTBorderOn",border_on)
"tmXTLabelsOn" : get_res_value(res2,"tmXTLabelsOn",False)
"tiMainOn" : get_res_value(res2,"tiMainOn",False)
"tiXAxisOn" : get_res_value(res2,"tiXAxisOn",False)
end setvalues
end if
end do
if(found_plots(nplots-1)) then
setvalues new_plots(nplots-1)
"tmXUseBottom" : get_res_value(res2,"tmXUseBottom",False)
"tmXTOn" : get_res_value(res2,"tmXTOn",False)
"tmXTBorderOn" : get_res_value(res2,"tmXTBorderOn",border_on)
"tmXTLabelsOn" : get_res_value(res2,"tmXTLabelsOn",False)
"tiMainOn" : get_res_value(res2,"tiMainOn",False)
end setvalues
end if
end if
;
; Now that we've turned off the tickmark stuff, retrieve the bounding box
; of each plot.
;
; First create arrays to hold bounding box and viewport information.
;
bbs = new((/nplots,4/),float)
vpxs = new((/nplots/),float)
vpys = new((/nplots/),float)
vphs = new((/nplots/),float)
vpws = new((/nplots/),float)
bb1 = NhlGetBB(base) ; Get bounding box of plot
top1 = bb1(0)
bot1 = bb1(1)
lft1 = bb1(2)
rgt1 = bb1(3)
;
; Have to deal with special case of only having one plot.
;
if(nplots.eq.1)
bbs(0,:) = NhlGetBB(plots)
else
bbs = NhlGetBB(plots)
end if
tops = bbs(:,0)
bots = bbs(:,1)
lfts = bbs(:,2)
rgts = bbs(:,3)
;
; Retrieve viewports.
;
; Calculate the largest scale factor possible that will allow us
; to fit all plots on the page, with 0.5% white space on the ends.
;
getvalues base
"vpYF" : vpy1
"vpHeightF" : vph1
"vpXF" : vpx1
"vpWidthF" : vpw1
end getvalues
do i=0,nplots-1
getvalues plots(i)
"vpYF" : vpys(i)
"vpHeightF" : vphs(i)
"vpXF" : vpxs(i)
"vpWidthF" : vpws(i)
end getvalues
end do
if(attach_y) then
total_height1 = top1 - bot1
total_heights = tops - bots
total_width1 = (vpx1+vpw1) - lft1
total_widths = vpws
total_widths(nplots-1) = rgts(nplots-1) - vpxs(nplots-1)
scale_widths = 1. / (1.01 * (scale1*total_width1 + sum(scales*total_widths)))
scale_height1 = 1. / (1.01 * scale1*total_height1)
scale_heights = 1. / (1.01 * scales*total_heights)
scale = min((/scale_height1,min(scale_heights),min(scale_widths)/))
else
total_width1 = rgt1 - lft1
total_widths = rgts - lfts
total_height1 = vph1 + (top1 - vpy1)
total_heights = vphs
total_heights(nplots-1) = vpys(nplots-1)-bots(nplots-1)
scale_heights = 1. / (1.01 * (scale1*total_height1 + sum(scales*total_heights)))
scale_width1 = 1. / (1.01 * scale1*total_width1)
scale_widths = 1. / (1.01 * scales*total_widths)
scale = min((/scale_width1,min(scale_heights),min(scale_widths)/))
end if
;
; Resize all plots with new scale factor, and set sizes of tick marks
; and tick marks labels to be the same.
;
new_scale1 = scale * scale1
new_scales = scale * scales
new_mj_length = (new_scale1*mj_length1 + sum(new_scales*mj_lengths))/(nplots+1)
new_mjo_length = (new_scale1*mjo_length1 + sum(new_scales*mjo_lengths))/(nplots+1)
new_mn_length = (new_scale1*mn_length1 + sum(new_scales*mn_lengths))/(nplots+1)
new_mno_length = (new_scale1*mno_length1 + sum(new_scales*mno_lengths))/(nplots+1)
new_font_height = (new_scale1*font_height1 + sum(new_scales*font_heights))/(nplots+1)
new_main_font_height = new_scale1*main_font_height1
if(attach_y) then
mj_length = get_res_value(res1,"tmXBMajorLengthF",new_mj_length)
mjo_length = get_res_value(res1,"tmXBMajorOutwardLengthF",\
new_mjo_length)
mn_length = get_res_value(res1,"tmXBMinorLengthF",new_mn_length)
mno_length = get_res_value(res1,"tmXBMinorOutwardLengthF",\
new_mno_length)
else
mj_length = get_res_value(res1,"tmYLMajorLengthF",new_mj_length)
mjo_length = get_res_value(res1,"tmYLMajorOutwardLengthF",\
new_mjo_length)
mn_length = get_res_value(res1,"tmYLMinorLengthF",new_mn_length)
mno_length = get_res_value(res1,"tmYLMinorOutwardLengthF",\
new_mno_length)
end if
font_heightxl = get_res_value(res1,"tmXBFontHeight",new_font_height)
font_heightyl = get_res_value(res1,"tmYLFontHeight",new_font_height)
font_heightx = get_res_value(res1,"tiXAxisFontHeightF",new_font_height)
font_heighty = get_res_value(res1,"tiYAxisFontHeightF",new_font_height)
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
max((/new_main_font_height,new_font_height/)))
setvalues base
"vpHeightF" : new_scale1 * height1
"vpWidthF" : new_scale1 * width1
end setvalues
if(found_base) then
setvalues new_base
"tiXAxisFontHeightF" : font_heightx
"tiYAxisFontHeightF" : font_heighty
"tiMainFontHeightF" : main_font_height
"tmYRMajorLengthF" : mj_length
"tmYRMajorOutwardLengthF" : mjo_length
"tmYRMinorLengthF" : mn_length
"tmYRMinorOutwardLengthF" : mno_length
"tmYLMajorLengthF" : mj_length
"tmYLMajorOutwardLengthF" : mjo_length
"tmYLMinorLengthF" : mn_length
"tmYLMinorOutwardLengthF" : mno_length
"tmXBMajorLengthF" : mj_length
"tmXBMajorOutwardLengthF" : mjo_length
"tmXBMinorLengthF" : mn_length
"tmXBMinorOutwardLengthF" : mno_length
"tmXTMajorLengthF" : mj_length
"tmXTMajorOutwardLengthF" : mjo_length
"tmXTMinorLengthF" : mn_length
"tmXTMinorOutwardLengthF" : mno_length
"tmXBLabelFontHeightF" : font_heightx
"tmYLLabelFontHeightF" : font_heighty
end setvalues
end if
if(attach_y) then
mj_length = get_res_value(res2,"tmXBMajorLengthF",new_mj_length)
mjo_length = get_res_value(res2,"tmXBMajorOutwardLengthF",\
new_mjo_length)
mn_length = get_res_value(res2,"tmXBMinorLengthF",new_mn_length)
mno_length = get_res_value(res2,"tmXBMinorOutwardLengthF",\
new_mno_length)
else
mj_length = get_res_value(res2,"tmYLMajorLengthF",new_mj_length)
mjo_length = get_res_value(res2,"tmYLMajorOutwardLengthF",\
new_mjo_length)
mn_length = get_res_value(res2,"tmYLMinorLengthF",new_mn_length)
mno_length = get_res_value(res2,"tmYLMinorOutwardLengthF",\
new_mno_length)
end if
font_heightxl = get_res_value(res2,"tmXBFontHeight",new_font_height)
font_heightyl = get_res_value(res2,"tmYLFontHeight",new_font_height)
font_heightx = get_res_value(res2,"tiXAxisFontHeightF",new_font_height)
font_heighty = get_res_value(res2,"tiYAxisFontHeightF",new_font_height)
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
max((/new_main_font_height,new_font_height/)))
do i=0,nplots-1
setvalues plots(i)
"vpHeightF" : new_scales * heights(i)
"vpWidthF" : new_scales * widths(i)
end setvalues
if(found_plots(i)) then
setvalues new_plots(i)
"tiXAxisFontHeightF" : font_heightx
"tiYAxisFontHeightF" : font_heighty
"tiMainFontHeightF" : main_font_height
"tmYRMajorLengthF" : mj_length
"tmYRMajorOutwardLengthF" : mjo_length
"tmYRMinorLengthF" : mn_length
"tmYRMinorOutwardLengthF" : mno_length
"tmYLMajorLengthF" : mj_length
"tmYLMajorOutwardLengthF" : mjo_length
"tmYLMinorLengthF" : mn_length
"tmYLMinorOutwardLengthF" : mno_length
"tmXBMajorLengthF" : mj_length
"tmXBMajorOutwardLengthF" : mjo_length
"tmXBMinorLengthF" : mn_length
"tmXBMinorOutwardLengthF" : mno_length
"tmXTMajorLengthF" : mj_length
"tmXTMajorOutwardLengthF" : mjo_length
"tmXTMinorLengthF" : mn_length
"tmXTMinorOutwardLengthF" : mno_length
"tmXBLabelFontHeightF" : font_heightx
"tmYLLabelFontHeightF" : font_heighty
end setvalues
end if
end do
;
; Get new bounding boxes and sizes of resized plots, so we can
; figure out where to position the base plot.
;
bb1 = NhlGetBB(base) ; Get bounding box of plot
top1 = bb1(0)
bot1 = bb1(1)
lft1 = bb1(2)
rgt1 = bb1(3)
if(nplots.eq.1)
bbs(0,:) = NhlGetBB(plots)
else
bbs = NhlGetBB(plots)
end if
tops = bbs(:,0)
bots = bbs(:,1)
lfts = bbs(:,2)
rgts = bbs(:,3)
getvalues base
"vpYF" : vpy1
"vpHeightF" : vph1
"vpXF" : vpx1
"vpWidthF" : vpw1
end getvalues
do i=0,nplots-1
getvalues plots(i)
"vpYF" : vpys(i)
"vpHeightF" : vphs(i)
"vpXF" : vpxs(i)
"vpWidthF" : vpws(i)
end getvalues
end do
if(attach_y) then
total_height1 = top1 - bot1
total_heights = tops - bots
total_width1 = (vpx1+vpw1) - lft1
total_widths = vpws
total_widths(nplots-1) = rgts(nplots-1) - vpxs(nplots-1)
total_width_left = max((/0.,1. - (total_width1 + sum(total_widths))/))
total_height_left = max((/1. - max((/total_height1,max(total_heights)/))/))
else
total_width1 = rgt1 - lft1
total_widths = rgts - lfts
total_height1 = vph1 + (top1 - vpy1)
total_heights = vphs
total_heights(nplots-1) = vpys(nplots-1)-bots(nplots-1)
total_height_left = max((/0.,1. - (total_height1 + sum(total_heights))/))
total_width_left = max((/0.,1. - max((/total_width1,max(total_widths)/))/))
end if
new_vpx1 = total_width_left/2. + (vpx1-lft1)
new_vpy1 = 1. - (total_height_left/2. + (top1-vpy1))
setvalues base
"vpYF" : new_vpy1
"vpXF" : new_vpx1
end setvalues
;
; Attach each plot. If attaching them on the X axis, then start with
; the bottommost plot. If attaching on the Y axis, start with the
; rightmost plot.
;
annos = new(nplots,graphic)
zone = get_res_value(res2,"amZone",1)
orth = get_res_value(res2,"amOrthogonalPosF",0.0)
para = get_res_value(res2,"amParallelPosF",0.5)
if(attach_y) then
side = get_res_value(res2,"amSide","Right")
just = get_res_value(res2,"amJust","CenterLeft")
else
side = get_res_value(res2,"amSide","Bottom")
just = get_res_value(res2,"amJust","TopCenter")
end if
do i=nplots-1,0,1
if(i.gt.0) then
annos(i) = NhlAddAnnotation(plots(i-1),plots(i))
else
annos(0) = NhlAddAnnotation(base,plots(0))
end if
setvalues annos(i)
"amZone" : zone
"amJust" : just
"amSide" : side
"amResizeNotify" : True ; Allow resize if plot resized.
"amParallelPosF" : para
"amOrthogonalPosF": orth
end setvalues
end do
;
; Check for maximization. The plot does not get drawn in this
; function!
;
wks = NhlGetParentWorkstation(base)
maxbb = get_bb_res(res1)
if(.not.maxbb) then
maxbb = get_bb_res(res2)
end if
draw_and_frame(wks,base,False,False,0,maxbb)
return(annos)
end
;***********************************************************************;
; Function : get_rgb_values ;
; named_colors: string array of named colors ;
; ;
; This function retrieves the RGB of the list of named colors, if they ;
; exist. If any of the named colors don't exist, then a missing value ;
; is returned. ;
; ;
;***********************************************************************;
function get_rgb_values(named_colors)
begin
;
; Read in rgb.txt file that has named colors and RGB values.
;
rgb_file = "$NCARG_ROOT/lib/ncarg/database/rgb.txt"
rgb_text = asciiread(rgb_file,-1,"string")
do i=0,dimsizes(rgb_text)-1
rgb_text(i) = lower_case(rgb_text(i)) ; convert to lower case
end do
rgb_text_char = stringtocharacter(rgb_text) ; convert to character
;
; Normalize RGB values.
;
red = stringtointeger(charactertostring(rgb_text_char(:,0:2)))/255.
green = stringtointeger(charactertostring(rgb_text_char(:,4:6)))/255.
blue = stringtointeger(charactertostring(rgb_text_char(:,8:10)))/255.
;
; Color names don't start in the same column, so we have to search
; for them. The end of the RGB values is column 10, so start searching
; in column 12 (we know there's a space in column 11).
;
names = new(dimsizes(rgb_text_char(:,0)),string)
do i=0,dimsizes(names)-1
tmp_name = rgb_text_char(i,12:)
j = 0
done = False
do while(j.lt.(dimsizes(tmp_name)-1).and..not.done)
if(tmp_name(j).ne." ".and.tmp_name(j).ne." ") then
names(i) = charactertostring(rgb_text_char(i,12+j:))
done = True
end if
j = j+1
end do
delete(tmp_name)
end do
ncolors = dimsizes(named_colors)
rgb_values = new((/ncolors,3/),float,-999)
do i=0,ncolors-1
index = ind(lower_case(named_colors(i)).eq.names)
if(.not.ismissing(index))
rgb_values(i,0) = red(index)
rgb_values(i,1) = green(index)
rgb_values(i,2) = blue(index)
end if
end do
return(rgb_values)
end
;***********************************************************************;
; Procedure : gsn_define_colormap ;
; wks: workstation object ;
; cmap: Colormap ;
; ;
; This procedure defines a color map for workstation "wks" (the ;
; variable returned from a previous call to "gsn_open_wks") using float ;
; RGB values or a pre-defined color name. ;
;***********************************************************************;
procedure gsn_define_colormap(wks:graphic, cmap)
begin
dim_cmap = dimsizes(cmap)
if((typeof(cmap).eq."float".and.(dimsizes(dim_cmap).ne.2.or.\
dim_cmap(1).ne.3)).or.\
(typeof(cmap).eq."string".and.dimsizes(dim_cmap).ne.1))
print("Warning: gsn_define_colormap: cmap must either be an n x 3 float array,")
print("a single pre-defined colormap name, or a 1-dimensional string array of named colors.")
else
setvalues wks
"wkColorMap" : cmap
end setvalues
end if
end
;***********************************************************************;
; Function : gsn_retrieve_colormap ;
; wks: workstation object ;
; ;
; This function retrieves the current color map in use for workstation ;
; "wks". "wks is the workstation id returned from a call to ;
; gsn_open_wks. The return variable will be an n x 3 array, where n is ;
; the number of colors, and the 3 represents the R, G, and B values. ;
;***********************************************************************;
function gsn_retrieve_colormap(wks:graphic)
begin
getvalues wks
"wkColorMap" : cmap
end getvalues
return(cmap)
end
;***********************************************************************;
; Procedure : gsn_reverse_colormap ;
; wks: workstation object ;
; ;
; This function reverses the current color map in use for workstation ;
; "wks". The foregound/background colors will stay the same. ;
;***********************************************************************;
procedure gsn_reverse_colormap(wks:graphic)
begin
getvalues wks
"wkColorMap" : cmap
end getvalues
cmap(2:,:) = cmap(2::-1,:) ; reverse (exclude fore/back)
gsn_define_colormap (wks, cmap)
return
end
;***********************************************************************;
; Procedure : gsn_merge_colormaps ;
; wks: workstation object ;
; cmap1: colormap ;
; cmap2: colormap ;
; ;
; This procedure two colormaps into one, and then sets the workstaion ;
; to use this new colormap. If the merged colormaps exceed 255 colors, ;
; then only the first 255 colors will be used. ;
; ;
; Both cmaps must either be an n x 3 float array, an array of color ;
; names, or a single string representing a pre-defined colormap name. ;
; Each colormap is assumed to have its own background/foreground color, ;
; so the first two colors of the second color map are not included in ;
; the new color map. ;
;***********************************************************************;
procedure gsn_merge_colormaps(wks:graphic,cmap1,cmap2)
local dim_cmap1, dim_cmap2, new_cmap1, new_cmap2, len_cmap1, len_cmap2
begin
dim_cmap1 = dimsizes(cmap1)
dim_cmap2 = dimsizes(cmap2)
;
; Error checking.
;
if((typeof(cmap1).eq."float".and.(dimsizes(dim_cmap1).ne.2.or.\
dim_cmap1(1).ne.3)).or.\
(typeof(cmap1).eq."string".and.dimsizes(dim_cmap1).ne.1))
print("Warning: gsn_merge_colormaps: cmap1 must either be an n x 3 float array,")
print("a single pre-defined colormap name, or a 1-dimensional string array of named colors.")
end if
if((typeof(cmap2).eq."float".and.(dimsizes(dim_cmap2).ne.2.or.\
dim_cmap2(1).ne.3)).or.\
(typeof(cmap2).eq."string".and.dimsizes(dim_cmap2).ne.1))
print("Warning: gsn_merge_colormaps: cmap2 must either be an n x 3 float array,")
print("a single pre-defined colormap name, or a 1-dimensional string array of named colors.")
end if
;
; Get first colormap in RGB values, and include background and
; foreground colors.
;
if(typeof(cmap1).eq."float") then
new_cmap1 = cmap1
else
gsn_define_colormap(wks,cmap1)
new_cmap1 = gsn_retrieve_colormap(wks)
end if
len_cmap1 = dimsizes(new_cmap1(:,0))
;
; Get second colormap in RGB values, and ignore background and
; foreground colors.
;
if(typeof(cmap2).eq."float") then
len_cmap2 = dimsizes(cmap2(:,0)) - 2
if(len_cmap2.gt.0) then
new_cmap2 = cmap2(2:,:)
else
len_cmap2 = 0
end if
else
;
; Test if the strings are named colors or a color map.
; If it's a color map, then we will drop the foreground/background
; colors and only append colors 2 and on. If it is named colors,
; then we'll append all of the named colors.
;
rgb_values = get_rgb_values(cmap2)
indices = ind(.not.ismissing(rgb_values(:,0)))
if(all(ismissing(indices)))
gsn_define_colormap(wks,cmap2) ; Must be a color map name.
tmp_cmap2 = gsn_retrieve_colormap(wks)
new_cmap2 = tmp_cmap2(2:,:)
else
new_cmap2 = new((/dimsizes(indices),3/),"float")
new_cmap2(:,0) = rgb_values(indices,0) ; Must be named colors.
new_cmap2(:,1) = rgb_values(indices,1)
new_cmap2(:,2) = rgb_values(indices,2)
end if
len_cmap2 = dimsizes(new_cmap2(:,0))
delete(indices)
delete(rgb_values)
end if
;
; Make sure two colormaps don't total more than 256 colors.
;
if(len_cmap1.ge.256) then
len_cmap1 = 256
len_cmap2 = 0
else
if( (len_cmap1+len_cmap2).gt.256 ) then
len_cmap2 = 256-len_cmap1
end if
end if
;
; Create new merged colormap.
;
len_cmap = len_cmap1+len_cmap2
new_cmap = new((/len_cmap,3/),float)
new_cmap(0:len_cmap1-1,:) = new_cmap1(0:len_cmap1-1,:)
if(len_cmap2.gt.0)
new_cmap(len_cmap1:,:) = new_cmap2(0:len_cmap2-1,:)
end if
gsn_define_colormap(wks,new_cmap)
end
;***********************************************************************;
; Function : scalar_field ;
; sfname : string ;
; data : numeric ;
; res : logical ;
; ;
; This function creates a scalarField or meshScalarField object. ;
;***********************************************************************;
function scalar_field(sfname:string,data:numeric,res2:logical)
local dims, rank
begin
;
; Check input data. If it is 2D, then create a scalar field.
; If it is 1D, then it must have coordinate arrays the same length.
;
dims = dimsizes(data)
rank = dimsizes(dims)
if(rank.ne.1.and.rank.ne.2) then
print("Error: scalar_field: The input data must either be 1-dimensional or 2-dimensional")
dum = new(1,graphic)
return(dum)
end if
;
; Get sf resources.
;
if(rank.eq.2) then
; Create the data object; also, check for a missing value and
; set during the create call (if you don't do this, then if the
; user's happens by freak chance to have a constant field of -999,
; it will choke.
if(isatt(data,"_FillValue")) then
;
; We need to check for stride, because if we have a case where
; we are creating a scalar field that will be used with the vector
; field, and we are setting the stride for both via setvalues rather
; than during a create call, then at some point the sizes of the
; vector and scalar fields will be different and you will get a
; warning message:
;
; warning:VectorPlotSetValues: ignoring vcScalarFieldData: size does
; not match vcVectorFieldData
;
if(isatt(res2,"sfXCStride").and.isatt(res2,"sfYCStride")) then
data_object = create sfname scalarFieldClass noparent
"sfMissingValueV" : data@_FillValue
"sfDataArray" : data
"sfXCStride" : get_res_value(res2,"sfXCStride",1)
"sfYCStride" : get_res_value(res2,"sfYCStride",1)
end create
else
data_object = create sfname scalarFieldClass noparent
"sfMissingValueV" : data@_FillValue
"sfDataArray" : data
end create
end if
else
if(isatt(res2,"sfXCStride").and.isatt(res2,"sfYCStride")) then
data_object = create sfname scalarFieldClass noparent
"sfDataArray" : data
"sfXCStride" : get_res_value(res2,"sfXCStride",1)
"sfYCStride" : get_res_value(res2,"sfYCStride",1)
end create
else
data_object = create sfname scalarFieldClass noparent
"sfDataArray" : data
end create
end if
end if
else
;
; Rank is 1. This means we have to use the mesh scalar object.
; Make sure sfXArray and sfYArray have been set.
;
if(isatt(res2,"sfXArray").and.isatt(res2,"sfYArray")) then
;
; Create the data object.
;
if(isatt(data,"_FillValue")) then
data_object = create sfname meshScalarFieldClass noparent
"sfDataArray" : data
"sfMissingValueV" : data@_FillValue
"sfXArray" : get_res_value(res2,"sfXArray",1)
"sfYArray" : get_res_value(res2,"sfYArray",1)
end create
else
data_object = create sfname meshScalarFieldClass noparent
"sfDataArray" : data
"sfXArray" : get_res_value(res2,"sfXArray",1)
"sfYArray" : get_res_value(res2,"sfYArray",1)
end create
end if
else
print("Error: scalar_field: If the input data is 1-dimensional, you must set sfXArray and sfYArray to 1-dimensional arrays of the same length.")
dum = new(1,graphic)
return(dum)
end if
end if
return(data_object)
end
;***********************************************************************;
; Function : vector_field ;
; name : string ;
; u : numeric ;
; v : numeric ;
; res : logical ;
; ;
; This function creates a vectorField object. ;
;***********************************************************************;
function vector_field(vfname:string,u:numeric,v:numeric,res2:logical)
begin
;
; We need to check for stride, because if we have a case where
; we are creating a scalar field that will be used with the vector
; field, and we are setting the stride for both via setvalues rather
; than during a create call, then at some point the sizes of the
; vector and scalar fields will be different and you will get a
; warning message:
;
; warning:VectorPlotSetValues: ignoring vcScalarFieldData: size does
; not match vcVectorFieldData
;
if(isatt(res2,"vfXCStride").and.isatt(res2,"vfYCStride")) then
data_object = create vfname vectorFieldClass noparent
"vfUDataArray" : u
"vfVDataArray" : v
"vfXCStride" : get_res_value(res2,"vfXCStride",1)
"vfYCStride" : get_res_value(res2,"vfYCStride",1)
end create
else
data_object = create vfname vectorFieldClass noparent
"vfUDataArray" : u
"vfVDataArray" : v
end create
end if
; Check for missing values.
if(isatt(u,"_FillValue")) then
setvalues data_object
"vfMissingUValueV" : u@_FillValue
end setvalues
end if
if(isatt(v,"_FillValue")) then
setvalues data_object
"vfMissingVValueV" : v@_FillValue
end setvalues
end if
return(data_object)
end
;***********************************************************************;
; Function : hist_columns ;
; wks: workstation object ;
; xy: graphic ;
; binvalues: numeric ;
; barlocs: numeric ;
; bar2locs: numeric ;
; barwidth: numeric ;
; colors ;
; gsres: logical ;
; ;
; xy - xy plot id to draw columns on ;
; bins - the center of each bin range. ;
; binvalues - the number of values in the corresponding bin ;
; start - the start of the bar in each bin (only for irreg axes) ;
; width - the width of the bar ;
; colors - array of colors to use (ints or color names) ;
; gsres - optional primitive resources ;
; ;
; This function creates the columns for a histogram plot. The Y axis ;
; will represent the number of values in a bin and a percentage. ;
; ;
;***********************************************************************;
function hist_columns(wks[1]:graphic,xy[1]:graphic,binvalues:numeric, \
barlocs[*]:numeric, bar2locs[*]:numeric, \
barwidth[*]:numeric, colors[*], gsres:logical)
local i, nbins, dims, nbinvalues, gsres, xpoints, ypoints, compare
begin
nbars = dimsizes(barlocs)
;
; If binvalues is 2-dimensional, then comparing two fields.
;
dims = dimsizes(binvalues)
if(dimsizes(dims).eq.2.and.dims(0).eq.2)
nbinvalues = dims(1)
compare = True
else
nbinvalues = dims(0)
compare = False
end if
if(nbars.ne.nbinvalues) then
print("Error: hist_columns: Dimension sizes of bins (" + nbars+ ") and binvalues (" + nbinvalues + ") must be the same")
return
end if
;
; Set up arrays to hold polygon points.
;
if(compare)
xpoints = new((/2,nbars,5/),float)
ypoints = new((/2,nbars,5/),float)
polygons0 = new(nbars,graphic)
polygons1 = new(nbars,graphic)
else
xpoints = new((/nbars,5/),float)
ypoints = new((/nbars,5/),float)
polygons = new(nbars,graphic)
end if
;
; Set up variable to hold resources.
;
gsres = True
set_attr(gsres,"gsEdgesOn",True)
;
; Begin assigning polygon points.
;
if(compare)
ypoints(0,:,0) = (/0/)
ypoints(1,:,0) = (/0/)
ypoints(0,:,1) = (/binvalues(0,:)/)
ypoints(1,:,1) = (/binvalues(1,:)/)
ypoints(0,:,2) = (/ypoints(0,:,1)/)
ypoints(1,:,2) = (/ypoints(1,:,1)/)
ypoints(0,:,3) = (/0/)
ypoints(1,:,3) = (/0/)
ypoints(0,:,4) = (/0/)
ypoints(1,:,4) = (/0/)
xpoints(0,:,0) = (/barlocs/)
xpoints(0,:,1) = (/xpoints(0,:,0)/)
xpoints(0,:,2) = (/barlocs + barwidth/)
xpoints(0,:,3) = (/xpoints(0,:,2)/)
xpoints(0,:,4) = (/xpoints(0,:,0)/)
;
xpoints(1,:,0) = (/bar2locs/)
xpoints(1,:,1) = (/xpoints(1,:,0)/)
xpoints(1,:,2) = (/bar2locs + barwidth/)
xpoints(1,:,3) = (/xpoints(1,:,2)/)
xpoints(1,:,4) = (/xpoints(1,:,0)/)
else
ypoints(:,0) = (/0/)
ypoints(:,1) = (/binvalues/)
ypoints(:,2) = (/ypoints(:,1)/)
ypoints(:,3) = (/0/)
ypoints(:,4) = (/0/)
xpoints(:,0) = (/barlocs/)
xpoints(:,1) = (/xpoints(:,0)/)
xpoints(:,2) = (/barlocs + barwidth/)
xpoints(:,3) = (/xpoints(:,2)/)
xpoints(:,4) = (/xpoints(:,0)/)
end if
fillindex = get_res_value(gsres,"gsFillIndex",(/0,6/))
;
; Make sure fill indices are between 0 and 17.
;
fillindex1 = min((/max((/fillindex(0),0/)),17/))
if(dimsizes(fillindex).ge.2)
fillindex2 = min((/max((/fillindex(1),0/)),17/))
else
fillindex2 = fillindex1
end if
ncolors = dimsizes(colors)
do i = 0, nbars - 1
gsres_at_gsFillColor = colors(i % ncolors)
if(compare)
;
; Add the second histogram bars first, so that they will be drawn
; first. The first histogram bars will thus be drawn on top.
;
gsres_at_gsFillIndex = fillindex2
if(binvalues_at_horizontal) then
polygons1(i) = gsn_add_polygon(wks,xy,ypoints(1,i,:), \
xpoints(1,i,:), gsres)
else
polygons1(i) = gsn_add_polygon(wks,xy,xpoints(1,i,:), \
ypoints(1,i,:), gsres)
end if
gsres_at_gsFillIndex = fillindex1
if(binvalues_at_horizontal) then
polygons0(i) = gsn_add_polygon(wks,xy,ypoints(0,i,:), \
xpoints(0,i,:), gsres)
else
polygons0(i) = gsn_add_polygon(wks,xy,xpoints(0,i,:), \
ypoints(0,i,:), gsres)
end if
else
gsres_at_gsFillIndex = fillindex1
if(binvalues_at_horizontal) then
polygons(i) = gsn_add_polygon(wks,xy,ypoints(i,:),xpoints(i,:),gsres)
else
polygons(i) = gsn_add_polygon(wks,xy,xpoints(i,:),ypoints(i,:),gsres)
end if
end if
end do
;
; Return the polygons created as attributes of the XY plot. This is
; necessary, b/c otherwise the polygons will go away when you exit the
; function.
;
if(compare)
var_string0 = unique_string("hpolygons0")
var_string1 = unique_string("hpolygons1")
xy@$var_string0$ = polygons0
xy@$var_string1$ = polygons1
else
var_string = unique_string("hpolygons")
xy@$var_string$ = polygons
end if
return(xy)
end
;***********************************************************************;
; Function : compute_hist_vals ;
; x: numeric or string ;
; binlocs: numeric or string ;
; nbinlocs: integer ;
; bin_width: numeric ;
; setinterval: logical ;
; setdiscrete: integer ;
; minmaxbins: logical ;
; count_msg: logical ;
; isnice: integer ;
; compare: integer ;
; ;
; By default, this routine calculates a nice set of ranges for "binning";
; the given data. The following cases are possible: ;
; ;
; 1. If setinterval is True, then the user has set their own bin ;
; intervals via either the gsnHistogramBinIntervals or the ;
; gsnHistogramClassIntervals resource (stored in binlocs array). ;
; ;
; 2. If setdiscrete is True, then the user has set discrete bin values ;
; via the gsnHistogramDiscreteBinValues resource (stored in ;
; "binlocs" array). ;
; ;
; 3. If neither setinterval or setdiscrete is True, and if the resource ;
; gsnHistogramBinWidth is set, then its value will be used as a bin ;
; width (bin_width). By default, bin_width will only be used as an ;
; approximate value, because it attempts to select "nice" values ;
; based on a width close to bin_width. If the resource ;
; gsnHistogramSelectNiceIntervals (isnice) is set to False, then ;
; you will get a bin width exactly equal to bin_width. ;
; ;
; 4. If neither setinterval or setdiscrete is True, and if the resource ;
; gsnHistogramNumberOfBins is set, then its value (nbinlocs) will be ;
; used to determine the number of bins. By default, nbinlocs is only ;
; used as an approximate value, because it attempts to select "nice" ;
; values based on a number of bins close to nbinlocs. If the ;
; resource gsnHistogramSelectNiceIntervals (isnice) is set to False, ;
; then you will get a number of bins exactly equal to nbinlocs. ;
; ;
; 5. If no special resources are set, then this routine defaults to ;
; calculating approximately 10 "nice" bin intervals, based on the ;
; range of the data. ;
; ;
;***********************************************************************;
function compute_hist_vals(xx,binlocs,nbinlocs[1]:integer, \
bin_width:numeric,setinterval:logical, \
setdiscrete:logical, minmaxbins:logical, \
count_msg:logical,isnice:logical,compare:logical)
local xmin, xmax, new_binlocs, nbars, buckets, x, i
begin
if(isnumeric(xx)) then
xmin = tofloat(min(xx))
xmax = tofloat(max(xx))
end if
;
; If the bins are set, need to determine if you want to have the bins
; represent ranges of values or discrete values.
;
if(setdiscrete) then
new_binlocs = binlocs
nbars = dimsizes(new_binlocs) ; # of bars equals # of binlocs
else
;
; Check if range values have been set by user, or if we need to
; calculate them.
;
if(setinterval) then
new_binlocs = binlocs
else
if(nbinlocs.lt.0) then
if(bin_width.lt.0.) then
nbinlocs = 10 ; Default to 10 bin locations.
else
nbinlocs = floattointeger(((xmax - xmin)/bin_width))
if(nbinlocs.le.0) then
print("Warning: compute_hist_vals: cannot use given bin width. Defaulting...")
nbinlocs = 10
end if
end if
end if
if(.not.setdiscrete) then
if(isnice) then
;
; Based on min and max of data, compute a new min/max/step that will
; give us "nice" bin values.
;
nicevals = nice_mnmxintvl(xmin,xmax,nbinlocs,True)
nvals = floattoint((nicevals(1) - nicevals(0))/nicevals(2) + 1)
new_binlocs = fspan(nicevals(0),nicevals(1),nvals)
else
;
; Don't bother with "nice" values; just span the data.
;
new_binlocs = fspan(xmin,xmax,nbinlocs+1)
end if
end if
end if
nbars = dimsizes(new_binlocs)-1
end if
;
; Count number of values in a particular bin range, or exactly
; equal to a bin value if discrete.
;
if(compare) then
nsets = 2
dims = dimsizes(xx)
npts = dims(1)
x = xx
else
nsets = 1
npts = dimsizes(xx)
x = new((/1,npts/),typeof(xx))
x(0,:) = xx
end if
;
; Set up variable to hold binned values. Binned values can have
; unequal spacing.
;
num_in_bins = new((/nsets,nbars/),integer)
;
; Count the values in each discrete bin.
;
if(setdiscrete) then
do j = 0,nsets-1
do i = 0, nbars-1
num_in_bins(j,i) = num(x(j,:).eq.new_binlocs(i))
end do
end do
else
;
; Count the values in each bin interval. Bin intervals can be
; oaf length 0, meaning an exact count is done.
;
do j = 0,nsets-1
do i = 0, nbars-1
if(new_binlocs(i).eq.new_binlocs(i+1)) then
num_in_bins(j,i) = num(x(j,:).eq.new_binlocs(i))
else
;
; Special tests for last interval are required.
;
if(i.eq.(nbars-1)) then
if(nbars.gt.1.and.new_binlocs(i).eq.new_binlocs(i-1)) then
num_in_bins(j,i) = num(x(j,:).gt.new_binlocs(i).and. \
x(j,:).le.new_binlocs(i+1))
else
num_in_bins(j,i) = num(x(j,:).ge.new_binlocs(i).and. \
x(j,:).le.new_binlocs(i+1))
end if
else
;
; If the previous interval was not really an interval, but an exact
; bin value, then be careful not to count those values in the current
; interval.
;
if(i.gt.0.and.new_binlocs(i).eq.new_binlocs(i-1)) then
num_in_bins(j,i) = num(x(j,:).gt.new_binlocs(i).and. \
x(j,:).lt.new_binlocs(i+1))
else
num_in_bins(j,i) = num(x(j,:).ge.new_binlocs(i).and. \
x(j,:).lt.new_binlocs(i+1))
end if
end if
end if
end do
end do
end if
;
; If minmaxbins is True, then we need to also count the values
; outside the range of our new_binlocs.
;
if(minmaxbins) then
new_num_in_bins = new((/nsets,nbars+2/),integer)
new_num_in_bins(:,1:nbars) = num_in_bins
do j = 0,nsets-1
new_num_in_bins(j,0) = num(x(j,:).lt.new_binlocs(0))
new_num_in_bins(j,nbars+1) = num(x(j,:).gt.new_binlocs(nbars))
end do
delete(num_in_bins)
num_in_bins = new_num_in_bins
delete(new_num_in_bins)
nbars = nbars + 2
end if
;
; Count number of missing values.
;
num_missing = new(nsets,integer)
if(isatt(x,"_FillValue")) then
do j = 0,nsets-1
num_missing(j) = num(ismissing(x(j,:)))
end do
else
num_missing = 0
end if
;
; If count_msg is True, then we need to bin the number of missing values.
;
if(count_msg) then
new_num_in_bins = new((/nsets,nbars+1/),integer)
new_num_in_bins(:,0:nbars-1) = num_in_bins
new_num_in_bins(:,nbars) = num_missing
delete(num_in_bins)
num_in_bins = new_num_in_bins
delete(new_num_in_bins)
nbars = nbars + 1
end if
;
; Calculate percentages, both with and without missing points included.
;
npts_nomiss = npts - num_missing
if(compare) then
percs = (100.*num_in_bins)/tofloat(npts)
percs_nomiss = new((/2,nbars/),float)
percs_nomiss(0,:) = (100.*num_in_bins(0,:))/tofloat(npts_nomiss(0))
percs_nomiss(1,:) = (100.*num_in_bins(1,:))/tofloat(npts_nomiss(1))
else
percs = (100.*num_in_bins(0,:))/tofloat(npts)
percs_nomiss = (100.*num_in_bins(0,:))/tofloat(npts_nomiss)
end if
;
; Return information.
;
num_in_bins_at_NumMissing = num_missing
num_in_bins_at_binlocs = new_binlocs
num_in_bins_at_percentages = percs
num_in_bins_at_percentages_nm = percs_nomiss
delete(x)
if(compare) then
return(num_in_bins)
else
return(num_in_bins(0,:))
end if
end
;***********************************************************************;
; Function : gsn_histogram ;
; wks: workstation object ;
; xdata: numeric or string ;
; res: resources ;
; ;
; This function draws a histogram plot. The user can enter the bin ;
; ranges, discrete bin values, or let this function calculate ones ;
; automatically. This function will also compare two sets of ;
; histograms. If xdata is a string, then you must be using ;
; discrete values, and not ranges. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnHistogramNumberOfBins - Indicates number of bin intervals you ;
; want. The default is around 10. ;
; ;
; gsnHistogramBinWidth - Instead of indicating number of bins, you can ;
; specify a bin width. Depending on whether SelectNiceIntervals ;
; is set to True, you will either get exactly bins of this size, ;
; or approximately this size. ;
; ;
; gsnHistogramBarWidthPercent - This indicates the percentage of the ;
; the bin width that the bar width should be. The default is 66% ;
; for single histograms, and 50% for comparison. ;
; ;
; gsnHistogramSelectNiceIntervals - Indicates whether we want ;
; gsn_histogram to select "nice" range values. Default is True. ;
; ;
; gsnHistogramComputePercentages - If True, then percentage values ;
; will be put on right (top) axis. Default is False. ;
; ;
; gsnHistogramComputePercentagesNoMissing - If True, percentage values ;
; will be put on the right (top) axis, and the number of missing ;
; values will be subtracted from the total number of values ;
; before the percentages are calculated. ;
; ;
; gsnHistogramPercentSign - If True, then a percent sign (%) is used on;
; the percentage axis. ;
; ;
; gsnHistogramClassIntervals - By default, gsn_histogram will pick the ;
; bin class intervals for you. If you set this, then it will use ;
; these values for the bin ranges. ;
; ;
; gsnHistogramBinIntervals - Same as gsnHistogramClassIntervals. ;
; ;
; gsnHistogramMinMaxBinsOn - If this is True, then two extra bins will ;
; be added that count all the values less than the smallest bin, ;
; and greater than the largest bin. This resource can only be ;
; used when BinIntervals or ClassIntervals are set. ;
; ;
; gsnHistogramDiscreteClassValues - By default, gsn_histogram will bin ;
; your data into ranges. If you set this resource, then your data;
; is assumed to already be "binned", and it just counts the number;
; of values exactly equal to the discrete values. ;
; ;
; gsnHistogramDiscreteBinValues - Same as ;
; gsnHistogramDiscreteClassValues. ;
; ;
; gsnHistogramCompare - Compare two fields. ;
; ;
; gsnHistogramHorizontal - Draw horizontal bars. Default is False ;
; ;
; The number of missing values counted is returned as an attribute ;
; called "NumMissing". ;
; ;
; This function does the following: ;
; ;
; 1. Sets/retrieves all of the special "gsn" resource allowed and ;
; checks validity of data. ;
; 2. Calls "compute_hist_vals" to calculate bins (if not specified by ;
; user) and count number of values in each bin range, or equal to ;
; each discrete bin value. ;
; 3. Count number of bin locations and bars. ;
; 4. Calculate width of bins and bars in each bin. ;
; 5. Figure out color indices to use for bar colors. ;
; 6. Calculate axis limits for plot, and create plot. ;
; 7. Set some post-resources for labeling the percentage axis. ;
; 8. Set some post-resources for labeling the other axis. ;
; 9. Set some post-resources for labeling the axis that indicates the ;
; bin ranges or discrete values. ;
;10. Apply resources set by user. ;
;11. Calculate starting locations of each bar. ;
;12. Add a percent label, if there is one. ;
;13. Force tickmarks to point outward. ;
;14. Create histogram. ;
;15. Draw and advance frame. ;
;16. Return histogram information. ;
;***********************************************************************;
function gsn_histogram(wks[1]:graphic,xdata, resources:logical)
local res2, calldraw, callframe, maxbb, ispercent, bins, nbars, \
setdiscrete, setinterval,top, botton, left, right, lenc, tmp, \
colors, locs, lbs, compare
begin
dummy = new(1,graphic) ; Dummy graphic to return if things go wrong.
;
; 1. Retrieve special resources.
;
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
nbins = get_res_value(res2,"gsnHistogramNumberOfBins",-1)
xbin_width = get_res_value(res2,"gsnHistogramBinWidth",-1)
minmaxbins = get_res_value(res2,"gsnHistogramMinMaxBinsOn",False)
count_msg = get_res_value(res2,"gsnHistogramBinMissing",False)
perc_nomiss= get_res_value(res2,"gsnHistogramComputePercentagesNoMissing",False)
ispercent = get_res_value(res2,"gsnHistogramComputePercentages",perc_nomiss)
percentsign= get_res_value(res2,"gsnHistogramPercentSign",False)
isnice = get_res_value(res2,"gsnHistogramSelectNiceIntervals",True)
compare = get_res_value(res2,"gsnHistogramCompare",False)
horizontal = get_res_value(res2,"gsnHistogramHorizontal",False)
setdiscrete= False
setinterval= False
;
; xdata can only be 1D or 2D. If it is 2D, then the first dimension
; must be 2, and this routine kicks into "compare" mode.
;
; Also, if gsnHistogramCompare is already set to True, then
; double-check that data is correct size.
;
dims = dimsizes(xdata)
rank = dimsizes(dims)
if(rank.gt.2.or.(rank.eq.2.and.dims(0).ne.2)) then
print("gsn_histogram: the input data must be 1-dimensional or 2-dimensional. If it is 2-dimensional, then the first dimension size must be 2.")
print("No plot will be drawn.")
return(dummy)
end if
;
; If comparing two fields, then first dimension must be two.
;
if(compare) then
if(dims(0).ne.2.or.rank.eq.1) then
print("Error: gsn_histogram: If comparing two fields, then you must input a 2D array dimensioned 2 x npts.")
print("No plot will be drawn.")
return(dummy)
end if
else
if(rank.eq.2) then
print("gsn_histogram: You input a 2D array dimensioned 2 x npts, so will go into compare mode.")
compare = True
end if
end if
delete(dims)
;
; Calculate the percentage of the bin width that the bar width should
; be.
;
if(compare) then
bar_wdt_perc = 0.5
else
bar_wdt_perc = 0.66667
end if
if(isatt(res2,"gsnHistogramBarWidthPercent")) then
if(res2_at_gsnHistogramBarWidthPercent.le.0.or. \
res2_at_gsnHistogramBarWidthPercent.gt.100.) then
print("gsn_histogram: The bar width percentage must be in the range (0,100.].")
print(" Defaulting to " + bar_wdt_perc)
else
bar_wdt_perc = 0.01*res2_at_gsnHistogramBarWidthPercent
end if
delete(res2_at_gsnHistogramBarWidthPercent)
end if
;
; Check if user explicitly specified bin values. If so, and they represent
; end points, then make sure there are at least two values and sort them.
;
if(isatt(res2,"gsnHistogramClassIntervals").or. \
isatt(res2,"gsnHistogramBinIntervals"))
setinterval = True
if(isatt(res2,"gsnHistogramClassIntervals"))
bins = tofloat(get_res_value(res2,"gsnHistogramClassIntervals",1.))
else
bins = tofloat(get_res_value(res2,"gsnHistogramBinIntervals",1.))
end if
nbins = dimsizes(bins)
if(nbins.lt.2)
print("Error: gsn_histogram: There must be at least two values in the bin intervals. No plot will be drawn.")
return(dummy)
end if
if(max(bins).lt.min(xdata).or.min(bins).gt.max(xdata))
print("Error: gsn_histogram: The bin values you picked are out of range. No plot will be drawn.")
return(dummy)
end if
qsort(bins) ; Sort the bins and put back into "bins" variable.
end if
;
; If setting the mid point values, then you only need at least one value.
; But, you can't be setting both Intervals and Discrete values.
;
if(isatt(res2,"gsnHistogramDiscreteClassValues").or. \
isatt(res2,"gsnHistogramDiscreteBinValues"))
if(setinterval) then
print("warning: gsn_histogram: You already set gsnHistogramClassIntervals,")
print("so ignoring gsnHistogramDiscreteClassValues.")
;
; Delete so they don't get passed on to other routines.
;
if(isatt(res2,"gsnHistogramDiscreteBinValues")) then
delete(res2_at_gsnHistogramDiscreteBinValues)
end if
if(isatt(res2,"gsnHistogramDiscreteClassValues")) then
delete(res2_at_gsnHistogramDiscreteClassValues)
end if
else
setdiscrete = True
if(isnumeric(xdata)) then
if(isatt(res2,"gsnHistogramDiscreteBinValues")) then
bins = tofloat(get_res_value(res2,"gsnHistogramDiscreteBinValues",1))
else
bins = tofloat(get_res_value(res2,"gsnHistogramDiscreteClassValues",1))
end if
if(max(bins).lt.min(xdata).or.min(bins).gt.max(xdata)) then
print("Error: gsn_histogram: The bin values you picked are out of range. No plot will be drawn.")
return(dummy)
end if
else
if(isatt(res2,"gsnHistogramDiscreteBinValues")) then
bins = get_res_value(res2,"gsnHistogramDiscreteBinValues",1)
else
bins = get_res_value(res2,"gsnHistogramDiscreteClassValues",1)
end if
end if
end if
end if
;
; You can only count bin values outside the intervals if the intervals
; were set explicitly by the user.
;
if(.not.setinterval) then
minmaxbins = False
end if
if(.not.setinterval.and..not.setdiscrete) then
bins = 0.
end if
if(setinterval.and..not.isnumeric(xdata)) then
print("Error: gsn_histogram: If you are doing bin intervals,")
print(" your data must be numeric.")
return(dummy)
end if
;
; 2. Get number of values in each bin (num_in_bins) and bin locations
; (num_in_bins_at_binlocs).
;
num_in_bins = compute_hist_vals(xdata,bins,nbins,xbin_width,setinterval, \
setdiscrete,minmaxbins,count_msg, \
isnice,compare)
if(all(ismissing(num_in_bins)))
print("Error: gsn_histogram: Unable to calculate bin values. No plot will be drawn.")
return(dummy)
end if
if(all(num_in_bins.eq.0))
print("Error: gsn_histogram: No data found in selected bins. No plot will be drawn.")
return(dummy)
end if
;
; 3. Count number of bars and bin locations. If minmaxbins is True, then
; later we need to account for two extra bars. Also, if count_msg is
; True, then this adds one extra bar.
;
nbinlocs = dimsizes(num_in_bins_at_binlocs)
if(compare)
dims = dimsizes(num_in_bins)
nbars = dims(1)
delete(dims)
else
nbars = dimsizes(num_in_bins)
end if
;
; 4. Calculate width of histogram bins and bars in each bin. If
; comparing two fields, then the histogram bars must be slightly
; smaller in width to accomodate two bars.
;
; A note about how the bin widths are calculated: the bin locations
; (that is, the bin "tickmarks") will be placed along the X axis such
; that the first bin location is at X = 0, and the last bin location
; is at X = 1.0. When dealing with discrete values, the bin tickmark
; falls in the *middle* of the bar, whereas for intervals, the bin
; tickmarks fall on either side of the bar. The width of each bin,
; then, is [1.0/(the number of bin locations - 1)]. So, for example,
; if you have 2 discrete values, the first bin tickmark is at X=0,
; and the second bin tickmark at X=1.0, giving a bin width of
; 1.0. For the special case where you have only 1 discrete value,
; you essentially don't have a bin width, so "bin_width" will just
; be equal to 1.
;
extra_bins = 0
if(minmaxbins) then
extra_bins = 2
end if
if(count_msg) then
extra_bins = extra_bins + 1
end if
if(nbinlocs.gt.1) then
bin_width = 1./(nbinlocs-1+extra_bins)
else
bin_width = 1.
end if
;
; Calculate the width of the histogram bar. It needs to be smaller
; if we are comparing two histograms.
;
bar_width = bar_wdt_perc * bin_width
if(compare.and.1.3333*bar_width.gt.bin_width) then
print("Warning: gsn_histogram: The bar width percentage selected is too large for this comparison histogram.")
print(" Resetting to " + 1/1.3333 + " for better results")
bar_width = bin_width/1.3333
end if
;
; 5. Get set of color indexes to use for filling bars. Span the full
; color map when color-filling the bins.
;
getvalues wks
"wkColorMapLen" : lenc
end getvalues
if(isatt(res2,"gsFillColor")) then
colors = get_res_value(res2,"gsFillColor",1)
else
tmp = (lenc-2)/nbars
if(tmp .eq. 0 )
print("Warning: gsn_histogram: not enough colors, using single color")
colors = new(nbars,integer)
colors = 2
else
colors = new(nbars,integer)
tmpc = ispan(2,lenc,tmp)
if(dimsizes(tmpc).ne.dimsizes(colors))
colors = tmpc(0:dimsizes(colors)-1)
else
colors = tmpc
end if
delete(tmpc)
end if
delete(tmp)
end if
;
; 6. Calculate axis limits for plot, and create plot.
;
if(horizontal) then
left = 0.
right = max(num_in_bins) * 1.1
if(setdiscrete) then
if(nbars.gt.1) then
bottom = -0.6667 * bin_width
top = 1. + 0.6667 * bin_width
else
bottom = -0.6667
top = 0.6667
end if
else
bottom = 0
top = 1.
end if
else
if(setdiscrete) then
if(nbars.gt.1) then
left = -0.6667 * bin_width
right = 1. + 0.6667 * bin_width
else
left = -0.6667
right = 0.6667
end if
else
left = 0.
right = 1.
end if
bottom = 0.
top = max(num_in_bins) * 1.1
end if
;
; Create plot class with limits.
;
res2_at_trXMinF = get_res_value(res2,"trXMinF",left)
res2_at_trXMaxF = get_res_value(res2,"trXMaxF",right)
res2_at_trYMinF = get_res_value(res2,"trYMinF",bottom)
res2_at_trYMaxF = get_res_value(res2,"trYMaxF",top)
xy = create "xy" logLinPlotClass wks
"pmTickMarkDisplayMode" : "Always"
"pmTitleDisplayMode" : "Always"
"trXMinF" : res2_at_trXMinF
"trXMaxF" : res2_at_trXMaxF
"trYMinF" : res2_at_trYMinF
"trYMaxF" : res2_at_trYMaxF
end create
;
; 7. Set some post-resources for labeling the percentage axis, if desired.
;
; If gsnHistogramComputePercentages is True, then we'll add percentage
; labels to the right (or top) axis.
;
; If we are comparing two sets of data, and we want to have a
; percent calculation on the other axis, then in order for this
; axis to correctly represent both sets of data, they must both
; have the same number of missing values, or no missing values at
; all.
;
if(compare.and.perc_nomiss) then
if(num_in_bins_at_NumMissing(0).ne.num_in_bins_at_NumMissing(1)) then
print("Warning: gsn_histogram: When comparing two sets of data, you must have")
print("the same number of missing values in both sets (or no missing values at")
print("all) in order to display a percentage calculation on the other axis.")
print("gsnHistogramComputePercentages will be set to False.")
ispercent = False
perc_nomiss = False
end if
end if
;
; The default is to include the total number of data points in the
; percentage calculate, even if there are missing values. The user
; must set gsnHistogramComputePercentagesNoMissing to True if he doesn't
; want the missing values included in the calculation.
;
if(ispercent) then
if(compare) then
dims = dimsizes(xdata)
npts = dims(1)
else
npts = dimsizes(xdata) ; Total number of points.
end if
if(perc_nomiss) then
npts = npts - num_in_bins_at_NumMissing(0) ; Don't include missing values
; in calculation.
end if
;
; Compute min, max, and step necessary to later get "nice" values for
; the percentages.
;
xnpts = npts*1.
if(horizontal) then
nicevals = nice_mnmxintvl(res2_at_trXMinF,min((/100., \
100.*(res2_at_trXMaxF/xnpts)/)),7,False)
else
nicevals = nice_mnmxintvl(res2_at_trYMinF,min((/100., \
100.*(res2_at_trYMaxF/xnpts)/)),7,False)
end if
nvals = floattoint((nicevals(1) - nicevals(0))/nicevals(2) + 1)
;
; Generate nice values for minor and major percent tick marks. For
; the minor tick marks, just add one tick between each major.
;
pnice = fspan(nicevals(0),nicevals(1),nvals)
pmnice = fspan(nicevals(0)-nicevals(2)*0.5, \
nicevals(1)+nicevals(2)*0.5, 2*nvals+1)
;
; Calculate the bin values that correspond to these percentages.
; These are the values we'll use for the tick marks.
;
bins_at_pnice = 0.01 * (npts * pnice)
bins_at_pmnice = 0.01 * (npts * pmnice)
;
; Set some resources to control tickmarks.
;
if(horizontal) then
set_attr(res2,"tmXUseBottom", False)
set_attr(res2,"tmXTOn",True)
set_attr(res2,"tmXTLabelsOn",True)
set_attr(res2,"tmXTMode","Explicit")
set_attr(res2,"tmXTValues",bins_at_pnice)
set_attr(res2,"tmXTMinorValues",bins_at_pmnice)
if(percentsign)
set_attr(res2,"tmXTLabels",pnice+"%")
else
set_attr(res2,"tmXTLabels",pnice)
end if
else
set_attr(res2,"tmYUseLeft", False)
set_attr(res2,"tmYROn",True)
set_attr(res2,"tmYRLabelsOn",True)
set_attr(res2,"tmYRMode","Explicit")
set_attr(res2,"tmYRValues",bins_at_pnice)
set_attr(res2,"tmYRMinorValues",bins_at_pmnice)
if(percentsign)
set_attr(res2,"tmYRLabels",pnice+"%")
else
set_attr(res2,"tmYRLabels",pnice)
end if
end if
end if
;
; 8. Set some post-resources for labeling the other axis, if desired.
;
axis_string = get_long_name_units_string(xdata)
if(.not.ismissing(axis_string)) then
if(horizontal) then
set_attr(res2,"tiYAxisString",axis_string)
else
set_attr(res2,"tiXAxisString",axis_string)
end if
else
if(setinterval) then
if(horizontal) then
set_attr(res2,"tiYAxisString","Class Intervals")
else
set_attr(res2,"tiXAxisString","Class Intervals")
end if
end if
end if
;
;
; 9. Set some post-resources for labeling the axis that indicates the
; bin ranges or discrete values. If minmaxbins is True, then we
; need to make sure not to label the end bin locations. Also, if
; count_msg is True, then we need to add a special label for this.
;
if(minmaxbins) then
if(.not.count_msg) then
lbs = new(nbinlocs+2,string)
lbs(0) = ""
lbs(1:nbinlocs) = num_in_bins_at_binlocs
lbs(nbinlocs+1) = ""
else
lbs = new(nbinlocs+3,string)
lbs(0) = ""
lbs(1:nbinlocs) = num_in_bins_at_binlocs
lbs(nbinlocs+1) = ""
lbs(nbinlocs+2) = "# msg"
end if
else
if(.not.count_msg) then
lbs = num_in_bins_at_binlocs
else
lbs = new(nbinlocs+1,string)
lbs(0:nbinlocs-1) = num_in_bins_at_binlocs
lbs(nbinlocs) = "# msg"
end if
end if
;
; Calculate location for tickmarks.
;
nlbs = dimsizes(lbs)
lbs_vals = fspan(0.,1.,nlbs)
if(count_msg.and.setinterval) then
dx = lbs_vals(nlbs-1) - lbs_vals(nlbs-2)
lbs_vals(nlbs-1) = lbs_vals(nlbs-2) + dx/2.
end if
if(horizontal) then
set_attr(res2,"tiXAxisString","Frequency")
set_attr(res2,"tmYROn",False)
set_attr(res2,"tmYLMode","EXPLICIT")
set_attr(res2,"tmYLValues",lbs_vals)
set_attr(res2,"tmYLLabels",lbs)
else
set_attr(res2,"tiYAxisString","Frequency")
set_attr(res2,"tmXTOn",False)
set_attr(res2,"tmXBMode","EXPLICIT")
set_attr(res2,"tmXBValues",lbs_vals)
set_attr(res2,"tmXBLabels",lbs)
end if
;
; 10. Apply resources set by user.
;
xyres = get_res_ne(res2,"gs")
attsetvalues_check(xy,xyres)
;
; 11. Calculate starting locations of each bar.
; If comparing two fields, then the second set of bars will be
; slightly to the right (or above for horizontal bars) of the
; first set of bars.
;
if(setdiscrete) then
bar_locs = -.5*bar_width + bin_width * ispan(0,nbars-1,1)
if(compare) then
bar2_locs = -.166667*bar_width + bin_width * ispan(0,nbars-1,1)
else
bar2_locs = 0
end if
else
if(compare) then
bar_locs = .5*(bin_width-(bar_width+0.3333*bar_width)) + \
bin_width*ispan(0,nbars-1,1)
bar2_locs = bar_locs + 0.3333*bar_width
else
bar_locs = .5*(bin_width-bar_width) + bin_width*ispan(0,nbars-1,1)
bar2_locs = 0
end if
end if
;
; 12. Add a right Y (or top X axis) "Percent" label.
;
if(ispercent.and..not.percentsign)
if(horizontal) then
getvalues xy
"tiXAxisFontHeightF" : font_height
end getvalues
txangle = 0.
txside = "top"
else
getvalues xy
"tiYAxisFontHeightF" : font_height
end getvalues
txangle = 90.
txside = "right"
end if
perc_string = "Percent"
if(perc_nomiss) then
perc_string = perc_string + " (missing values not counted)"
else
if(num_in_bins_at_NumMissing(0).gt.1.or. \
(compare.and.num_in_bins_at_NumMissing(1).gt.1)) then
perc_string = perc_string + " (missing values counted)"
end if
end if
hist_axis_string = create "axis_string" textItemClass wks
"txString" : perc_string
"txFontHeightF" : font_height
"txAngleF" : txangle
end create
anno = NhlAddAnnotation(xy,hist_axis_string)
setvalues anno
"amZone" : 3 ; Just outside plot area
"amJust" : "centercenter"
"amSide" : txside
"amParallelPosF" : 0.5
"amOrthogonalPosF": 0.03
"amResizeNotify" : True ; Resize if plot resized.
end setvalues
end if
;
; 13. Force tickmarks to be the same length, and pointing outward.
;
tmres = get_res_eq(res2,"tm") ; Get tickmark resources
gsnp_point_tickmarks_outward(xy,tmres,-1.,-1.,-1.,-1.,-1.,-1.,True)
gsnp_uniform_tickmark_labels(xy,tmres,0.)
;
; 14. Create (but don't draw) histogram plot.
;
gsres = get_res_eq(res2,"gs") ; Get GraphicStyle resources.
num_in_bins_at_horizontal = horizontal ; horizontal or vertical bars
histogram = hist_columns(wks,xy,num_in_bins,bar_locs,bar2_locs,bar_width, \
colors,gsres)
;
; 15. Draw and advance frame.
;
draw_and_frame(wks,histogram,calldraw,callframe,0,maxbb)
;
; 16. Return histogram and the values.
;
; Return begin, mid, and end point location of each bar.
;
if(compare) then
both_locs = new((/2,dimsizes(bar_locs)/),typeof(bar_locs))
both_locs(0,:) = bar_locs
both_locs(1,:) = bar2_locs
histogram_at_BeginBarLocs = both_locs
histogram_at_MidBarLocs = both_locs + 0.5*bar_width
histogram_at_EndBarLocs = both_locs + bar_width
else
histogram_at_BeginBarLocs = bar_locs
histogram_at_MidBarLocs = bar_locs + 0.5*bar_width
histogram_at_EndBarLocs = bar_locs + bar_width
end if
histogram_at_NumInBins = num_in_bins
histogram_at_NumMissing = num_in_bins_at_NumMissing
histogram_at_Percentages = num_in_bins_at_percentages
histogram_at_PercentagesNoMissing = num_in_bins_at_percentages_nm
return(histogram)
end
;***********************************************************************;
; Function : gsn_contour ;
; wks: workstation object ;
; data: 1 or 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a contour plot to the workstation ;
; "wks" (the variable returned from a previous call to "gsn_open_wks"). ;
; "data" is the 2-dimensional data to be contoured, and "resources" is ;
; an optional list of resources. The id of the contour plot is returned.;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_contour(wks:graphic, data:numeric, resources:logical )
local i, data_object, plot_object, res, sf_res_index, \
datares, cnres, llres, cn_res_index, ll_res_index, calldraw, callframe, \
force_x_linear, force_y_linear, force_x_log, force_y_log, \
trxmin, trxmax, trymin, trymax, res2, scale, shape, sprdcols
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_contour: Fatal: the input data array must be 1D or 2D")
return
end if
cnres = False
llres = False
res2 = get_resources(resources)
force_x_linear = False
force_y_linear = False
force_x_log = False
force_y_log = False
wksname = get_res_value_keep(wks,"name","gsnapp")
data_object = scalar_field(wksname+"_data",data,res2)
sfres = get_res_eq(res2,"sf")
attsetvalues_check(data_object,sfres)
;
; Create plot object. Make sure you set the tension values (if
; any) when you create the plot. This works better than setting
; them later.
;
xtension = get_res_value(res2,"trXTensionF", 2.0)
ytension = get_res_value(res2,"trYTensionF", 2.0)
;
; Temporarily (I hope), I need to check if trGridType is being set.
; If so, it needs to be set during the create call, or otherwise it
; will cause the tickmarks to possibly not appear.
;
if(res2.and.isatt(res2,"trGridType")) then
plot_object = create wksname + "_contour" contourPlotClass wks
"cnScalarFieldData" : data_object
"trXTensionF" : xtension
"trYTensionF" : ytension
"trGridType" : res2_at_trGridType
end create
delete(res2_at_trGridType)
else
plot_object = create wksname + "_contour" contourPlotClass wks
"cnScalarFieldData" : data_object
"trXTensionF" : xtension
"trYTensionF" : ytension
end create
end if
; Check for existence of data_at_long_name and use it in a title it
; it exists.
if(isatt(data,"long_name")) then
set_attr(res2,"tiMainString",data_at_long_name)
end if
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
if(res2.and.isatt(res2,"gsnContourZeroLineThicknessF")) then
zthickness = res2_at_gsnContourZeroLineThicknessF
cthickness = get_res_value(res2,"cnLineThicknessF",1.)
delete(res2_at_gsnContourZeroLineThicknessF)
end if
if(res2.and.isatt(res2,"gsnContourLineThicknessesScale")) then
linescale = res2_at_gsnContourLineThicknessesScale
delete(res2_at_gsnContourLineThicknessesScale)
end if
if(res2.and.isatt(res2,"gsnContourNegLineDashPattern")) then
npattern = res2_at_gsnContourNegLineDashPattern
delete(res2_at_gsnContourNegLineDashPattern)
end if
check_for_irreg2loglin(res2,force_x_linear,force_y_linear,\
force_x_log,force_y_log)
check_for_tickmarks_off(res2)
cnres = get_res_ne(res2,"sf")
;
; Don't let pmTickMarkDisplayMode be set after the fact if we are
; going to overlay this plot later, because you might get an error
; message about warning:PlotManagerSetValues: TickMark annotation
; cannot be added after NhlCreate.
;
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log) then
if(isatt(cnres,"pmTickMarkDisplayMode")) then
delete(cnres_at_pmTickMarkDisplayMode)
end if
llres = get_res_eq(res2,(/"pm","tr","vp"/))
end if
attsetvalues_check(plot_object,cnres)
if(isvar("zthickness")) then
plot_object = set_zero_line_thickness(plot_object,zthickness,cthickness)
delete(zthickness)
end if
if(isvar("linescale")) then
plot_object = set_line_thickness_scale(plot_object,linescale)
delete(linescale)
end if
if(isvar("npattern")) then
plot_object = set_neg_line_pattern(plot_object,npattern)
delete(npattern)
end if
if(sprdcols)
cnres2 = True
set_attr(cnres2,"cnFillColors",\
spread_colors(wks,plot_object,min_index,max_index,res2))
attsetvalues(plot_object,cnres2)
end if
;
; If gsnShape was set to True, then resize the X or Y axis so that
; the scales are proportionally correct.
;
if(shape)
gsnp_shape_plot(plot_object)
end if
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(plot_object)
end if
;
; Check if we need to force the X or Y axis to be linear or log.
;
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
overlay_plot_object = plot_object
delete(plot_object)
plot_object = overlay_irregular(wks,wksname,overlay_plot_object,\
data_object,force_x_linear,\
force_y_linear,force_x_log, \
force_y_log,"contour",llres)
end if
draw_and_frame(wks,plot_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
plot_object_at_data = data_object
return(plot_object)
end
;***********************************************************************;
; Function : gsn_contour_map ;
; wks: workstation object ;
; data: 1 or 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a contour plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "data" is the 2-dimensional data to be contoured, ;
; and "resources" is an optional list of resources. The id of the map ;
; plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_contour_map(wks:graphic,data:numeric,\
resources:logical)
local i, data_object, contour_object, res, sf_res_index, \
cn_res_index, mp_res_index, map_object, res2, scale, shape, sprdcols
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_contour_map: Fatal: the input data array must be 1D or 2D")
return
end if
res2 = get_resources(resources)
wksname = get_res_value_keep(wks,"name","gsnapp")
; Create contour plot.
cnres = get_res_eq(res2,(/"sf","tr"/))
cnres = True
cnres_at_gsnDraw = False
cnres_at_gsnFrame = False
contour_object = gsn_contour(wks,data,cnres)
delete(cnres)
; Check for existence of data_at_long_name and use it in a title it
; it exists.
if(isatt(data,"long_name")) then
set_attr(res2,"tiMainString",data_at_long_name)
end if
; Create map object.
map_object = create wksname + "_map" mapPlotClass wks end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
scale = get_res_value(res2,"gsnScale",False)
shape = get_res_value(res2,"gsnShape",scale)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
mpres = get_res_eq(res2,(/"mp","vp","pmA","pmO","pmT","tm"/))
cnres = get_res_ne(res2,(/"mp","sf","vp"/))
attsetvalues_check(map_object,mpres)
attsetvalues_check(contour_object,cnres)
if(sprdcols)
cnres2 = True
set_attr(cnres2,"cnFillColors",\
spread_colors(wks,contour_object,min_index,max_index,res2))
attsetvalues(contour_object,cnres2)
end if
overlay(map_object,contour_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(contour_object)
end if
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = contour_object_at_data
map_object_at_contour = contour_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_map ;
; wks: workstation object ;
; projection: Map projection ;
; resources: optional resources ;
; ;
; This function creates and draws a map plot to the workstation "wks" ;
; (the variable returned from a previous call to "gsn_open_wks"). ;
; "projection" is one of the ten supported map projections, and ;
; "resources" is an optional list of resources. The id of the map plot ;
; is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; ;
;***********************************************************************;
function gsn_map(wks:graphic, projection:string, resources:logical )
local i, plot_object, res2
begin
res2 = get_resources(resources)
; Create plot object.
wksname = get_res_value_keep(wks,"name","gsnapp")
;
; Check if the user is setting tiMainString. If so, then set
; pmTitleDisplayMode to "Always" (unless the user is also setting
; this himself). Otherwise, just use the default value of "NoCreate".
;
if(res2.and.isatt(res2,"tiMainString")) then
title_display = get_res_value(res2,"pmTitleDisplayMode","Always")
else
title_display = get_res_value(res2,"pmTitleDisplayMode","NoCreate")
end if
plot_object = create wksname + "_map" mapPlotClass wks
"mpProjection" : projection
"pmTitleDisplayMode" : title_display
end create
; Check to see if any resources were set.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
attsetvalues_check(plot_object,res2)
draw_and_frame(wks,plot_object,calldraw,callframe,0,maxbb)
; Return plot object.
return(plot_object)
end
;***********************************************************************;
; Function : gsn_streamline ;
; wks: workstation object ;
; u: 2-dimensional U array ;
; v: 2-dimensional V array ;
; resources: optional resources ;
; ;
; This function creates and draws a streamline plot to the workstation ;
; "wks" (the variable returned from a previous call to "gsn_open_wks"). ;
; "u" and "v" are the 2-dimensional arrays to be streamlined, and ;
; "resources" is an optional list of resources. The id of the streamline;
; plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; ;
;***********************************************************************;
function gsn_streamline(wks:graphic,u[*][*]:numeric,v[*][*]:numeric,\
resources:logical)
local i, data_object,plot_object,res,vf_res_index,st_res_index, \
force_x_linear, force_y_linear, force_x_log, force_y_log, \
trxmin, trxmax, trymin, trymax, ll_res_index, llres, res2, scale, shape
begin
llres = False
res2 = get_resources(resources)
force_x_linear = False
force_y_linear = False
force_x_log = False
force_y_log = False
; Create the data object.
wksname = get_res_value_keep(wks,"name","gsnapp")
data_object = vector_field(wksname+"_data",u,v,res2)
; Create plot object.
plot_object = create wksname + "_stream" streamlinePlotClass wks
"stVectorFieldData" : data_object
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
check_for_irreg2loglin(res2,force_x_linear,force_y_linear,\
force_x_log,force_y_log)
check_for_tickmarks_off(res2)
vfres = get_res_eq(res2,"vf")
stres = get_res_ne(res2,"vf")
attsetvalues_check(data_object,vfres)
attsetvalues_check(plot_object,stres)
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
llres = get_res_eq(res2,(/"tr","vp"/))
end if
;
; If gsnShape was set to True, then resize the X or Y axis so that
; the scales are proportionally correct.
;
if(shape)
gsnp_shape_plot(plot_object)
end if
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(plot_object)
end if
; Check if we need to force the X or Y axis to be linear or log.
; If so, then we have to overlay it on a LogLin Plot.
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
overlay_plot_object = plot_object
delete(plot_object)
plot_object = overlay_irregular(wks,wksname,overlay_plot_object,\
data_object,force_x_linear,\
force_y_linear,force_x_log, \
force_y_log,"streamline",llres)
end if
draw_and_frame(wks,plot_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
plot_object_at_data = data_object
return(plot_object)
end
;***********************************************************************;
; Function : gsn_streamline_map ;
; wks: workstation object ;
; u: 2-dimensional U data ;
; v: 2-dimensional V data ;
; resources: optional resources ;
; ;
; This function creates and draws a streamline plot over a map plot to ;
; the workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u" and "v" are the 2-dimensional arrays to be ;
; streamlined, and "resources" is an optional list of resources. The id ;
; of the map plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; ;
;***********************************************************************;
function gsn_streamline_map(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,resources:logical)
local i, data_object, contour_object, res, vf_res_index, \
st_res_index, mp_res_index, map_object, res2
begin
res2 = get_resources(resources)
; Create the data object.
wksname = get_res_value_keep(wks,"name","gsnapp")
data_object = vector_field(wksname+"_data",u,v,res2)
; Create plot object.
stream_object = create wksname + "_stream" streamlinePlotClass wks
"stVectorFieldData" : data_object
end create
; Create map object.
map_object = create wksname + "_map" mapPlotClass wks
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
vfres = get_res_eq(res2,"vf")
mpres = get_res_eq(res2,(/"mp","vp","pmA","pmO","pmT","tm"/))
stres = get_res_ne(res2,(/"vf","mp","vp"/))
attsetvalues_check(data_object,vfres)
attsetvalues_check(stream_object,stres)
attsetvalues_check(map_object,mpres)
overlay(map_object,stream_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(stream_object)
end if
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = data_object
map_object_at_streamline = stream_object
return(map_object)
end
;***********************************************************************;
; Procedure : gsn_draw_colormap ;
; wks: workstation object ;
; ;
; This procedure retrieves the current colormap and draws it. ;
; wks is a variable returned from a previous call to "gsn_open_wks". ;
;***********************************************************************;
procedure gsn_draw_colormap(wks)
local nrows, ncols, ncolors, maxcols, ntotal, offset, width, height, \
xpos, ypos, xbox, ybox
begin
nrows = 16 ; # of rows of colors per page.
maxcols = 256 ; max # of colors per color table.
getvalues wks
"wkColorMapLen" : ncolors ; Get # of colors in color map.
end getvalues
;
; Figure out ncols such that the columns will span across the page.
; Or, just set ncols to 16, which is big enough to cover the largest
; possible color map.
;
ncols = floattoint(ncolors/nrows)
if(ncols*nrows.lt.ncolors)
ncols = ncols+1
end if
ntotal = nrows * ncols ; # of colors per page.
;
; If the number of colors in our color map is less than the allowed
; maximum, then this gives us room to add a white background and/or a
; black foreground.
;
reset_colormap = False
if(ncolors.lt.maxcols) then
reset_colormap = True
;
; Get current color map.
;
getvalues wks
"wkColorMap" : cmap
end getvalues
if(ncolors.lt.maxcols-1) then
offset = 2
cmapnew = new((/ncolors+2,3/),float)
cmapnew(0,:) = (/1.,1.,1./) ; white background
cmapnew(1,:) = (/0.,0.,0./) ; black background
cmapnew(2:,:) = cmap
else
offset = 1
cmapnew = new((/ncolors+1,3/),float)
cmapnew(0,:) = (/1.,1.,1./) ; white background
cmapnew(1:,:) = cmap
end if
;
; Set new color map.
;
setvalues wks
"wkColorMap" : cmapnew
end setvalues
delete(cmapnew)
else
offset = 0
end if
;
; X and Y positions of text and box in the view port.
;
width = 1./ncols
height = 1./nrows
xpos = fspan(0,1-width,ncols)
ypos = fspan(1-height,0,nrows)
;
; Box coordinates.
;
xbox = (/0,width, width, 0,0/)
ybox = (/0, 0,height,height,0/)
font_height = 0.015
font_space = font_height/2.
gonres = True ; variables to hold list of resources
lineres = True
txres = True
txres_at_txFontHeightF = font_height
txres_at_txFont = "helvetica-bold"
txres_at_txJust = "BottomLeft"
txres_at_txPerimOn = True
txres_at_txPerimColor = "black" ; Or close to black if
txres_at_txFontColor = "black" ; black is not in color map.
txres_at_txBackgroundFillColor = "white" ; Or close to white.
lineres_at_gsLineColor = "black"
;
; ntotal colors per page.
;
do k = 1,ncolors,ntotal
jj = 0
do j=k,min((/k+ntotal-1,ncolors/)),nrows
ii = 0
do i=j,min((/j+nrows-1,ncolors/))
;
; Draw box and fill in the appropriate color.
;
gonres_at_gsFillColor = offset + (i-1)
gsn_polygon_ndc(wks,xbox+xpos(jj),ybox+ypos(ii),gonres) ; Draw box.
;
; Outline box in black.
;
gsn_polyline_ndc(wks,xbox+xpos(jj),ybox+ypos(ii),lineres)
;
; Draw color label.
;
gsn_text_ndc(wks,i-1,font_space+xpos(jj),ypos(ii)+font_space,txres)
ii = ii + 1
end do
jj = jj +1
end do
frame(wks) ; Advance the frame.
end do
if(reset_colormap) then
;
; Put the original color map back.
;
setvalues wks
"wkColorMap" : cmap
end setvalues
delete(cmap)
end if
return
end
;***********************************************************************;
; Procedure : gsn_draw_named_colors ;
; wks: workstation object ;
; colors: colors array ;
; box: array defining number of rows and columns ;
; ;
; This procedure takes a named color array and draws it. ;
; wks is a variable returned from a previous call to "gsn_open_wks". ;
;***********************************************************************;
procedure gsn_draw_named_colors(wks:graphic,colors[*]:string, box[2]:integer)
local ncolors, ntotal, nrows, ncols, offset, width, height, \
xpos, ypos, xbox, ybox
begin
nrows = box(0) ; # of rows of colors per page.
ncols = box(1) ; # of columns of colors per page.
if(typeof(colors).ne."string".or.dimsizes(dimsizes(colors)).ne.1)
print("The input array is not a one dimensional array of named color strings")
exit
end if
if((nrows.gt.16).or.(ncols.gt.8))
print("Number of rows should be less than 16 and Number of columns should be less than 8.")
exit
end if
ncolors = dimsizes(colors) ; # of colors given
getvalues wks
"wkColorMap" : oldcmap ; Get current color map.
end getvalues
;
; Find out the rgb values of each color and put it into
; an array
;
rgb_values = get_rgb_values(colors)
rgb_val = new(ncolors, string)
do l =0, ncolors-1, 1
rgb_val(l) = sprintf("%.2f", rgb_values(l,0)) + "," + \
sprintf("%.2f", rgb_values(l,1)) + "," + \
sprintf("%.2f", rgb_values(l,2))
end do
;
; npages number of frames.
;
ntotal = ncols * nrows
npages = floattoint(ncolors/ntotal)
if(npages*ntotal.lt.ncolors)
npages = npages+1
end if
;
; X and Y positions of text and box in the view port.
;
width = 1./ncols
height = 1./nrows
xpos = fspan(0,1-width,ncols)
ypos = fspan(1-height,0,nrows)
;
; Box coordinates.
;
xbox = (/0,width, width, 0,0/)
ybox = (/0, 0,height,height,0/)
;
; Calculate font height.
;
font_heights = (/.0143, .0143, .0143, .0141, .013, .011, .0093, .0085/)
font_height = font_heights(ncols-1)
font_space = font_height/2.
gonres = True ; variables to hold list of resources
lineres = True
txres = True
txres_at_gsnDraw = True
txres_at_txFontHeightF = font_height
txres_at_txFont = "helvetica-bold"
txres_at_txPerimOn = True
txres_at_txPerimColor = "black" ; Or close to black if
txres_at_txFontColor = "black" ; black is not in color map.
txres_at_txBackgroundFillColor = "white" ; Or close to white.
lineres_at_gsLineColor = "black"
kk = 0
offset = 2
do k = 1,ncolors,ntotal
start = kk*ntotal
colorindex = 0
;
; Set the colormap
;
if(npages.eq.1)
cmapnew = new(ncolors-start+2,string)
cmapnew(0) = "White" ; white background
cmapnew(1) = "Black" ; black background
cmapnew(2:) = colors(start:ncolors-1)
else
cmapnew = new(ntotal+2,string)
cmapnew(0) = "White" ; white background
cmapnew(1) = "Black" ; black background
cmapnew(2:) = colors(start:start+ntotal-1)
end if
setvalues wks
"wkColorMap" : cmapnew
end setvalues
delete(cmapnew)
jj = 0
do j=k,min((/k+ntotal-1,ncolors/)),nrows
ii = 0
do i=j,min((/j+nrows-1,ncolors/))
; Draw box and fill in the appropriate color.
gonres_at_gsFillColor = offset + colorindex
gsn_polygon_ndc(wks,xbox+xpos(jj),ybox+ypos(ii),gonres) ; Draw box.
; Outline box in black.
gsn_polyline_ndc(wks,xbox+xpos(jj),ybox+ypos(ii),lineres)
; Draw color label.
txres_at_txJust = "BottomLeft"
text = gsn_create_text_ndc(wks,colors(i-1),font_space+xpos(jj),\
ypos(ii)+font_space,txres)
txres_at_txJust = "TopLeft"
gsn_text_ndc(wks,rgb_val(i-1),font_space+xpos(jj), \
height+ypos(ii)-font_space,txres)
ii = ii + 1
colorindex = colorindex + 1
end do
jj = jj +1
end do
kk = kk + 1
npages = npages - 1
frame(wks) ; Advance the frame.
end do
;
; Put the original color map back.
;
setvalues wks
"wkColorMap" : oldcmap
end setvalues
delete(oldcmap)
end
;***********************************************************************;
; Function : gsn_vector ;
; wks: workstation object ;
; u: 2-dimensional U array ;
; v: 2-dimensional V array ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot to the workstation "wks";
; (the variable returned from a previous call to "gsn_open_wks"). "u" ;
; and "v" are the 2-dimensional arrays to be vectorized, and "resources";
; is an optional list of resources. The id of the vector plot is ;
; returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_vector(wks:graphic, u[*][*]:numeric, v[*][*]:numeric, \
resources:logical )
local i,data_object,plot_object,res,vf_res_index,vc_res_index, \
force_x_linear, force_y_linear, force_x_log, force_y_log, sprdcols, \
trxmin, trxmax, trymin, trymax, ll_res_index, llres, res2
begin
llres = False
res2 = get_resources(resources)
force_x_linear = False
force_y_linear = False
force_x_log = False
force_y_log = False
; Create the data object.
wksname = get_res_value_keep(wks,"name","gsnapp")
data_object = vector_field(wksname+"_data",u,v,res2)
; Create plot object.
plot_object = create wksname + "_vector" vectorPlotClass wks
"vcVectorFieldData" : data_object
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
check_for_irreg2loglin(res2,force_x_linear,force_y_linear,\
force_x_log,force_y_log)
check_for_tickmarks_off(res2)
vfres = get_res_eq(res2,"vf")
vcres = get_res_ne(res2,"vf")
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
llres = get_res_eq(res2,(/"tr","vp"/))
end if
attsetvalues_check(data_object,vfres)
attsetvalues_check(plot_object,vcres)
if(sprdcols)
vcres2 = True
set_attr(vcres2,"vcLevelColors",\
spread_colors(wks,plot_object,min_index,max_index,res2))
attsetvalues(plot_object,vcres2)
end if
;
; If gsnShape was set to True, then resize the X or Y axis so that
; the scales are proportionally correct.
;
if(shape)
gsnp_shape_plot(plot_object)
end if
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(plot_object)
end if
; Check if we need to force the X or Y axis to be linear or log.
; If so, then we have to overlay it on a LogLin Plot.
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
overlay_plot_object = plot_object
delete(plot_object)
plot_object = overlay_irregular(wks,wksname,overlay_plot_object,\
data_object,force_x_linear,\
force_y_linear,force_x_log, \
force_y_log,"vector",llres)
end if
draw_and_frame(wks,plot_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
plot_object_at_data = data_object
return(plot_object)
end
;***********************************************************************;
; Function : gsn_vector_contour ;
; wks: workstation object ;
; u: 2-dimensional U data ;
; v: 2-dimensional V data ;
; data: 2-dimensional scalar field ;
; resources: optional resources ;
; ;
; This function creates and draws vectors and contours to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u" and "v" are the 2-dimensional arrays to be ;
; vectorized, and "data" is the scalar field to be contoured. ;
; "resources" is an optional list of resources. The id of the vector ;
; plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_vector_contour(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric,\
resources:logical)
local i, vfdata_object, sfdata_object, contour_object, res, \
vf_res_index, vc_res_index, sf_res_index, res2
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_vector_contour: Fatal: the input data array must be 1D or 2D")
return
end if
res2 = get_resources(resources)
;
; Create the scalar and vector field object.
;
wksname = get_res_value_keep(wks,"name","gsnapp")
vfdata_object = vector_field(wksname+"_vfdata",u,v,res2)
sfdata_object = scalar_field(wksname+"_sfdata",data,res2);
; Create vector plot object.
vector_object = create wksname + "_vector" vectorPlotClass wks
"vcVectorFieldData" : vfdata_object
end create
; Create contour plot object.
contour_object = create wksname + "_contour" contourPlotClass wks
"cnScalarFieldData" : sfdata_object
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
if(res2.and.isatt(res2,"gsnContourZeroLineThicknessF")) then
zthickness = res2_at_gsnContourZeroLineThicknessF
cthickness = get_res_value(res2,"cnLineThicknessF",1.)
delete(res2_at_gsnContourZeroLineThicknessF)
end if
if(res2.and.isatt(res2,"gsnContourLineThicknessesScale")) then
linescale = res2_at_gsnContourLineThicknessesScale
delete(res2_at_gsnContourLineThicknessesScale)
end if
if(res2.and.isatt(res2,"gsnContourNegLineDashPattern")) then
npattern = res2_at_gsnContourNegLineDashPattern
delete(res2_at_gsnContourNegLineDashPattern)
end if
vfres = get_res_eq(res2,"vf")
sfres = get_res_eq(res2,"sf")
cnres = get_res_eq(res2,(/"cn","vp","tf"/))
vcres = get_res_ne(res2,(/"vf","sf","cn","vp"/))
attsetvalues_check(vfdata_object,vfres)
attsetvalues_check(sfdata_object,sfres)
attsetvalues_check(contour_object,cnres)
attsetvalues_check(vector_object,vcres)
if(isvar("zthickness")) then
contour_object = set_zero_line_thickness(contour_object,zthickness,cthickness)
delete(zthickness)
end if
if(isvar("linescale")) then
contour_object = set_line_thickness_scale(contour_object,linescale)
delete(linescale)
end if
if(isvar("npattern")) then
contour_object = set_neg_line_pattern(contour_object,npattern)
delete(npattern)
end if
if(sprdcols)
cnres2 = True
vcres2 = True
set_attr(cnres2,"cnFillColors",\
spread_colors(wks,contour_object,min_index,max_index,res2))
set_attr(vcres2,"vcLevelColors",\
spread_colors(wks,vector_object,min_index,max_index,res2))
attsetvalues(contour_object,cnres2)
attsetvalues(vector_object,vcres2)
end if
overlay(vector_object,contour_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(vector_object)
end if
draw_and_frame(wks,vector_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
vector_object_at_vfdata = vfdata_object
vector_object_at_sfdata = sfdata_object
vector_object_at_contour = contour_object
return(vector_object)
end
;***********************************************************************;
; Function : gsn_streamline_contour ;
; wks: workstation object ;
; u: 2-dimensional U data ;
; v: 2-dimensional V data ;
; data: 2-dimensional scalar field ;
; resources: optional resources ;
; ;
; This function creates and draws streamlines and contours to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u" and "v" are the 2-dimensional arrays to be ;
; streamlines, and "data" is the scalar field to be contoured. ;
; "resources" is an optional list of resources. The id of the streamline;
; plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_streamline_contour(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric,\
resources:logical)
local i, vfdata_object, sfdata_object, contour_object, res, \
vf_res_index, st_res_index, sf_res_index, res2
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_streamline_contour: Fatal: the input data array must be 1D or 2D")
return
end if
res2 = get_resources(resources)
;
; Create the vector and scalar fields.
;
wksname = get_res_value_keep(wks,"name","gsnapp")
vfdata_object = vector_field(wksname+"_vfdata",u,v,res2)
sfdata_object = scalar_field(wksname+"_sfdata",data,res2);
; Create streamline plot object.
stream_object = create wksname + "_stream" streamlinePlotClass wks
"stVectorFieldData" : vfdata_object
end create
; Create contour plot object.
contour_object = create wksname + "_contour" contourPlotClass wks
"cnScalarFieldData" : sfdata_object
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
if(res2.and.isatt(res2,"gsnContourZeroLineThicknessF")) then
zthickness = res2_at_gsnContourZeroLineThicknessF
cthickness = get_res_value(res2,"cnLineThicknessF",1.)
delete(res2_at_gsnContourZeroLineThicknessF)
end if
if(res2.and.isatt(res2,"gsnContourLineThicknessesScale")) then
linescale = res2_at_gsnContourLineThicknessesScale
delete(res2_at_gsnContourLineThicknessesScale)
end if
if(res2.and.isatt(res2,"gsnContourNegLineDashPattern")) then
npattern = res2_at_gsnContourNegLineDashPattern
delete(res2_at_gsnContourNegLineDashPattern)
end if
vfres = get_res_eq(res2,"vf")
sfres = get_res_eq(res2,"sf")
cnres = get_res_eq(res2,(/"cn","vp"/))
stres = get_res_ne(res2,(/"vf","sf","cn","vp"/))
attsetvalues_check(vfdata_object,vfres)
attsetvalues_check(sfdata_object,sfres)
attsetvalues_check(contour_object,cnres)
attsetvalues_check(stream_object,stres)
if(isvar("zthickness")) then
contour_object = set_zero_line_thickness(contour_object,zthickness,cthickness)
delete(zthickness)
end if
if(isvar("linescale")) then
contour_object = set_line_thickness_scale(contour_object,linescale)
delete(linescale)
end if
if(isvar("npattern")) then
contour_object = set_neg_line_pattern(contour_object,npattern)
delete(npattern)
end if
if(sprdcols)
cnres2 = True
set_attr(cnres2,"cnFillColors",\
spread_colors(wks,contour_object,min_index,max_index,res2))
attsetvalues(contour_object,cnres2)
end if
overlay(stream_object,contour_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(stream_object)
end if
draw_and_frame(wks,stream_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
stream_object_at_vfdata = vfdata_object
stream_object_at_sfdata = sfdata_object
stream_object_at_contour = contour_object
return(stream_object)
end
;***********************************************************************;
; Function : gsn_vector_contour_map ;
; wks: workstation object ;
; u: 2-dimensional U data ;
; v: 2-dimensional V data ;
; data: 2-dimensional scalar field ;
; resources: optional resources ;
; ;
; This function creates and draws vectors and contours over a map plot ;
; to the workstation "wks" (the variable returned from a previous call ;
; to "gsn_open_wks"). "u" and "v" are the 2-dimensional arrays to be ;
; vectorized, and "data" is the scalar field to be contoured. ;
; "resources" is an optional list of resources. The id of the map plot ;
; is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_vector_contour_map(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric,\
resources:logical)
local i, vfdata_object, sfdata_object, contour_object, res, \
vf_res_index, vc_res_index, sf_res_index, mp_res_index, map_object, res2
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_vector_contour_map: Fatal: the input data array must be 1D or 2D")
return
end if
res2 = get_resources(resources)
;
; Create the vector and scalar field objects.
;
wksname = get_res_value_keep(wks,"name","gsnapp")
vfdata_object = vector_field(wksname+"_vfdata",u,v,res2)
sfdata_object = scalar_field(wksname+"_sfdata",data,res2);
; Create vector plot object.
vector_object = create wksname + "_vector" vectorPlotClass wks
"vcVectorFieldData" : vfdata_object
end create
; Create contour plot object.
contour_object = create wksname + "_contour" contourPlotClass wks
"cnScalarFieldData" : sfdata_object
end create
; Create map object.
map_object = create wksname + "_map" mapPlotClass wks end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
if(res2.and.isatt(res2,"gsnContourZeroLineThicknessF")) then
zthickness = res2_at_gsnContourZeroLineThicknessF
cthickness = get_res_value(res2,"cnLineThicknessF",1.)
delete(res2_at_gsnContourZeroLineThicknessF)
end if
if(res2.and.isatt(res2,"gsnContourLineThicknessesScale")) then
linescale = res2_at_gsnContourLineThicknessesScale
delete(res2_at_gsnContourLineThicknessesScale)
end if
if(res2.and.isatt(res2,"gsnContourNegLineDashPattern")) then
npattern = res2_at_gsnContourNegLineDashPattern
delete(res2_at_gsnContourNegLineDashPattern)
end if
vfres = get_res_eq(res2,"vf")
sfres = get_res_eq(res2,"sf")
cnres = get_res_eq(res2,(/"cn","tf"/))
mpres = get_res_eq(res2,(/"mp","vp","pmA","pmO","pmT","tm"/))
vcres = get_res_ne(res2,(/"cn","mp","sf","vf","vp"/))
attsetvalues_check(vfdata_object,vfres)
attsetvalues_check(sfdata_object,sfres)
attsetvalues_check(map_object,mpres)
attsetvalues_check(contour_object,cnres)
attsetvalues_check(vector_object,vcres)
if(isvar("zthickness")) then
contour_object = set_zero_line_thickness(contour_object,zthickness,cthickness)
delete(zthickness)
end if
if(isvar("linescale")) then
contour_object = set_line_thickness_scale(contour_object,linescale)
delete(linescale)
end if
if(isvar("npattern")) then
contour_object = set_neg_line_pattern(contour_object,npattern)
delete(npattern)
end if
if(sprdcols)
cnres2 = True
vcres2 = True
set_attr(cnres2,"cnFillColors",\
spread_colors(wks,contour_object,min_index,max_index,res2))
set_attr(vcres2,"vcLevelColors",\
spread_colors(wks,vector_object,min_index,max_index,res2))
attsetvalues(contour_object,cnres2)
attsetvalues(vector_object,vcres2)
end if
overlay(map_object,vector_object)
overlay(map_object,contour_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(vector_object)
end if
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = vfdata_object
map_object_at_sfdata = sfdata_object
map_object_at_vector = vector_object
map_object_at_contour = contour_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_vector_map ;
; wks: workstation object ;
; : 2-dimensional U data ;
; v: 2-dimensional V data ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u" and "v" are the 2-dimensional arrays to be ;
; vectorized, and "resources" is an optional list of resources. The id ;
; of the map plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_vector_map(wks:graphic, u[*][*]:numeric, v[*][*]:numeric, \
resources:logical )
local i, data_object, contour_object, res, vf_res_index, \
vc_res_index, mp_res_index, map_object, res2, sprdcols
begin
res2 = get_resources(resources)
; Create the data object.
wksname = get_res_value_keep(wks,"name","gsnapp")
data_object = vector_field(wksname+"_data",u,v,res2)
; Create plot object.
vector_object = create wksname + "_vector" vectorPlotClass wks
"vcVectorFieldData" : data_object
end create
; Create map object.
map_object = create wksname + "_map" mapPlotClass wks
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
vfres = get_res_eq(res2,"vf")
mpres = get_res_eq(res2,(/"mp","vp","pmA","pmO","pmT","tm"/))
vcres = get_res_ne(res2,(/"mp","vf","vp"/))
attsetvalues_check(data_object,vfres)
attsetvalues_check(map_object,mpres)
attsetvalues_check(vector_object,vcres)
if(sprdcols)
vcres2 = True
set_attr(vcres2,"vcLevelColors",\
spread_colors(wks,vector_object,min_index,max_index,res2))
attsetvalues(vector_object,vcres2)
end if
overlay(map_object,vector_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(vector_object)
end if
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = data_object
map_object_at_vector = vector_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_vector_scalar ;
; wks: workstation object ;
; u: 2-dimensional U array ;
; v: 2-dimensional V array ;
; data: 2-dimensional scalar field ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot to the workstation "wks";
; (the variable returned from a previous call to "gsn_open_wks"). "u" ;
; and "v" are the 2-dimensional arrays to be vectorized, and "data" is ;
; the scalar field that the vectors are colored by. "resources" is an ;
; optional list of resources. The id of the vector plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_vector_scalar(wks:graphic,u[*][*]:numeric,v[*][*]:numeric,\
data:numeric, resources:logical )
local i, vfdata_object, sfdata_object, plot_object, res, \
force_x_linear, force_y_linear, force_x_log, force_y_log, \
trxmin, trxmax, trymin, trymax, ll_res_index, llres, vf_res_index, \
vc_res_index, sf_res_index, res2, sprdcols
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_vector_scalar: Fatal: the input data array must be 1D or 2D")
return
end if
llres = False
res2 = get_resources(resources)
force_x_linear = False
force_y_linear = False
force_x_log = False
force_y_log = False
; Create the scalar and vector field data object.
wksname = get_res_value_keep(wks,"name","gsnapp")
vfdata_object = vector_field(wksname+"_vfdata",u,v,res2)
sfdata_object = scalar_field(wksname+"_sfdata",data,res2);
; Create plot object.
plot_object = create wksname + "_vector" vectorPlotClass wks
"vcVectorFieldData" : vfdata_object
"vcScalarFieldData" : sfdata_object
"vcUseScalarArray" : True
"vcMonoLineArrowColor" : False
end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
check_for_irreg2loglin(res2,force_x_linear,force_y_linear,\
force_x_log,force_y_log)
check_for_tickmarks_off(res2)
vfres = get_res_eq(res2,"vf")
sfres = get_res_eq(res2,"sf")
vcres = get_res_ne(res2,(/"sf","vf"/))
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
llres = get_res_eq(res2,(/"tr","vp"/))
end if
attsetvalues_check(vfdata_object,vfres)
attsetvalues_check(sfdata_object,sfres)
attsetvalues_check(plot_object,vcres)
if(sprdcols)
vcres2 = True
set_attr(vcres2,"vcLevelColors",\
spread_colors(wks,plot_object,min_index,max_index,res2))
attsetvalues(plot_object,vcres2)
end if
;
; If gsnShape was set to True, then resize the X or Y axis so that
; the scales are proportionally correct.
;
if(shape)
gsnp_shape_plot(plot_object)
end if
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(plot_object)
end if
; Check if we need to force the X or Y axis to be linear or log.
; If so, then we have to overlay it on a LogLin Plot.
if(force_x_linear.or.force_x_log.or.force_y_linear.or.force_y_log)
overlay_plot_object = plot_object
delete(plot_object)
plot_object = overlay_irregular(wks,wksname,overlay_plot_object,\
data_object,force_x_linear,\
force_y_linear,force_x_log, \
force_y_log,"vector",llres)
end if
draw_and_frame(wks,plot_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
plot_object_at_vfdata = vfdata_object
plot_object_at_sfdata = sfdata_object
return(plot_object)
end
;***********************************************************************;
; Function : gsn_vector_scalar_map ;
; wks: workstation object ;
; u: 2-dimensional U data ;
; v: 2-dimensional V data ;
; data: 2-dimensional scalar field ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u" and "v" are the 2-dimensional arrays to be ;
; vectorized, and "data" is the scalar field that the vectors are ;
; colored by. "resources" is an optional list of resources. The id of ;
; the map plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; gsnSpreadColors ;
; gsnSpreadColorStart ;
; gsnSpreadColorEnd ;
; ;
;***********************************************************************;
function gsn_vector_scalar_map(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric,\
resources:logical)
local i, vfdata_object, sfdata_object, contour_object, res, \
vf_res_index, vc_res_index, sf_res_index, mp_res_index, map_object, res2, \
sprdcols
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_vector_scalar_map: Fatal: the input data array must be 1D or 2D")
return
end if
res2 = get_resources(resources)
;
; Create the vector and scalar field object.
;
wksname = get_res_value_keep(wks,"name","gsnapp")
vfdata_object = vector_field(wksname+"_vfdata",u,v,res2)
sfdata_object = scalar_field(wksname+"_sfdata",data,res2);
; Create plot object.
vector_object = create wksname + "_vector" vectorPlotClass wks
"vcVectorFieldData" : vfdata_object
"vcScalarFieldData" : sfdata_object
"vcUseScalarArray" : True
"vcMonoLineArrowColor" : False
end create
; Create map object.
map_object = create wksname + "_map" mapPlotClass wks end create
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
sprdcols = get_res_value(res2,"gsnSpreadColors",False)
min_index = get_res_value(res2,"gsnSpreadColorStart",2)
max_index = get_res_value(res2,"gsnSpreadColorEnd",-1)
vfres = get_res_eq(res2,"vf")
sfres = get_res_eq(res2,"sf")
mpres = get_res_eq(res2,(/"mp","vp","pmA","pmO","pmT","tm"/))
vcres = get_res_ne(res2,(/"mp","sf","vf","vp"/))
attsetvalues_check(vfdata_object,vfres)
attsetvalues_check(sfdata_object,sfres)
attsetvalues_check(map_object,mpres)
attsetvalues_check(vector_object,vcres)
if(sprdcols)
vcres2 = True
set_attr(vcres2,"vcLevelColors",\
spread_colors(wks,vector_object,min_index,max_index,res2))
attsetvalues(vector_object,vcres2)
end if
overlay(map_object,vector_object)
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(vector_object)
end if
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = vfdata_object
map_object_at_sfdata = sfdata_object
map_object_at_vector = vector_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_xy ;
; wks: workstation object ;
; x: n-dimensional array of X arrays ;
; y: n-dimensional array of Y array ;
; resources: optional resources ;
; ;
; This function creates and draws an xy plot to the workstation "wks" ;
; (the variable returned from a previous call to "gsn_open_wks"). "x" ;
; and "y" are either 1 or 2-dimensional arrays containing the X and Y ;
; data points and "resources" is an optional list of resources. The id ;
; of the xy plot is returned. ;
; ;
; Special resources ("gsn" prefix) allowed: ;
; ;
; gsnDraw ;
; gsnFrame ;
; gsnShape ;
; gsnScale ;
; ;
;***********************************************************************;
function gsn_xy(wks:graphic, x:numeric, y:numeric, resources:logical )
local i, attnames, data_object, plot_object, res, ca_res_index, \
xy_res_index, xydp_res_index, dspec, res2, set_dash
begin
set_dash = True ; Default is to set some dash patterns.
res2 = get_resources(resources)
; Determine if we have multiple lines or just one line.
nxdims = dimsizes(dimsizes(x))
xdims = dimsizes(x)
wksname = get_res_value_keep(wks,"name","gsnapp")
data_object = create wksname + "_data" coordArraysClass noparent
"caXArray" : x
"caYArray" : y
end create
; Check for missing values.
if(isatt(x,"_FillValue")) then
setvalues data_object
"caXMissingV" : x@_FillValue
end setvalues
end if
if(isatt(y,"_FillValue")) then
setvalues data_object
"caYMissingV" : y@_FillValue
end setvalues
end if
; Create plot object.
plot_object = create wksname + "_xy" xyPlotClass wks
"xyCoordData" : data_object
end create
;
; I'm guessing that we can't set the tr* resources when we create
; the XY plot because it probably affects other resources. So, we go ahead
; and create the full plot, and *then* we set the tr* resources, if any.
;
getvalues plot_object
"trXMinF" : trxmin2
"trXMaxF" : trxmax2
"trYMinF" : trymin2
"trYMaxF" : trymax2
end getvalues
trxmin = get_res_value_keep(res2,"trXMinF",trxmin2)
trxmax = get_res_value_keep(res2,"trXMaxF",trxmax2)
trymin = get_res_value_keep(res2,"trYMinF",trymin2)
trymax = get_res_value_keep(res2,"trYMaxF",trymax2)
plot_object = create wksname + "_xy" xyPlotClass wks
"xyCoordData" : data_object
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
end create
; Check for existence of x/y_at_long_name/units and use them to
; label X and Y axes.
xaxis_string = get_long_name_units_string(x)
yaxis_string = get_long_name_units_string(y)
if(.not.ismissing(xaxis_string)) then
set_attr(res2,"tiXAxisString",xaxis_string)
end if
if(.not.ismissing(yaxis_string)) then
set_attr(res2,"tiYAxisString",yaxis_string)
end if
; By default, only solid lines get drawn if there are multiple lines, so
; set some dash patterns to use instead. Also set different marker styles.
getvalues plot_object
"xyCoordDataSpec" : dspec
end getvalues
if(res2.and..not.any(ismissing(getvaratts(res2))))
if(isatt(res2,"xyDashPattern").or.isatt(res2,"xyDashPatterns"))
set_dash = False
end if
end if
if(set_dash)
setvalues dspec
"xyDashPatterns" : (/0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,\
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,\
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16/)
end setvalues
end if
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
shape = get_res_value(res2,"gsnShape",False)
scale = get_res_value(res2,"gsnScale",shape)
check_for_tickmarks_off(res2)
cares = get_res_eq(res2,"ca")
attsetvalues_check(data_object,cares)
if(res2.and..not.any(ismissing(getvaratts(res2))))
; Get list of resources.
attnames = getvaratts(res2)
res = stringtocharacter(attnames(ind(attnames.ne."_FillValue")))
;***********************************************************************;
; Check to see if any xy plot resources were set. There are two kinds ;
; of xy plot resources, the regular kind, and the data spec kind. If ;
; the resource starts with an "xy", it could be either kind, so we need ;
; to have some tests to see which object it belongs to. Any "xy" ;
; resources that start with "xyC", "xyX", or "xyY" are regular ;
; resources (meaning, it belongs to the XyPlot object). The remaining ;
; "xy" resources belong to the data spec object. Any resources that do ;
; not start with "xy" or "ca" are assumed to also go with the XyPlot ;
; object. ;
;***********************************************************************;
if(dimsizes(dimsizes(res)).eq.1)
if((charactertostring(res(0:1)).ne."ca".and.\
charactertostring(res(0:1)).ne."xy").or.\
(charactertostring(res(0:1)).eq."xy".and.\
(charactertostring(res(0:2)).eq."xyC".or.\
charactertostring(res(0:2)).eq."xyX".or.\
charactertostring(res(0:2)).eq."xyY")))
setvalues plot_object
attnames : res2@$attnames$
end setvalues
end if
if(charactertostring(res(0:1)).eq."xy".and.\
(charactertostring(res(0:2)).ne."xyC".and.\
charactertostring(res(0:2)).ne."xyX".and.\
charactertostring(res(0:2)).ne."xyY"))
setvalues dspec
attnames : res2@$attnames$
end setvalues
end if
else
xy_res_index = ind((charactertostring(res(:,0:1)).ne."ca".and.\
charactertostring(res(:,0:1)).ne."xy").or.\
(charactertostring(res(:,0:1)).eq."xy".and.\
(charactertostring(res(:,0:2)).eq."xyC".or.\
charactertostring(res(:,0:2)).eq."xyX".or.\
charactertostring(res(:,0:2)).eq."xyY")))
xydp_res_index = ind(charactertostring(res(:,0:1)).eq."xy".and.\
(charactertostring(res(:,0:2)).ne."xyC".and.\
charactertostring(res(:,0:2)).ne."xyX".and.\
charactertostring(res(:,0:2)).ne."xyY"))
if(.not.all(ismissing(xy_res_index)))
xyres = True
do i = 0,dimsizes(xy_res_index)-1
xyres@$attnames(xy_res_index(i))$ = res2@$attnames(xy_res_index(i))$
end do
attsetvalues_check(plot_object,xyres)
end if
if(.not.all(ismissing(xydp_res_index)))
getvalues plot_object
"xyCoordDataSpec" : dspec
end getvalues
xydpres = True
do i = 0,dimsizes(xydp_res_index)-1
xydpres@$attnames(xydp_res_index(i))$ = res2@$attnames(xydp_res_index(i))$
end do
attsetvalues_check(dspec,xydpres)
end if
end if
end if
;
; If gsnShape was set to True, then resize the X or Y axis so that
; the scales are proportionally correct.
;
if(shape)
gsnp_shape_plot(plot_object)
end if
;
; If gsnScale was set to True, then make sure the X and Y axis labels
; and tick marks are the same size.
;
if(scale)
gsnp_scale_plot(plot_object)
end if
draw_and_frame(wks,plot_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
plot_object_at_data = data_object
plot_object_at_dataspec = dspec
return(plot_object)
end
;***********************************************************************;
; Function : gsn_y ;
; wks: workstation object ;
; y: n-dimensional array of Y array ;
; resources: optional resources ;
; ;
; This function is similar to gsn_xy, except instead of a specific X ;
; array, index values are used. ;
; ;
;***********************************************************************;
function gsn_y(wks:graphic, y:numeric, resources:logical )
local dsizes_y, npts, x, rank_y, xy
begin
res2 = get_resources(resources)
;
; Get dimension sizes of Y array.
;
dsizes_y = dimsizes(y)
rank_y = dimsizes(dsizes_y)
if(rank_y.eq.1) then
npts = dsizes_y
else
if(rank_y.ne.2) then
print("Error: gsn_y: The input Y array must either be 1-dimensional, or 2-dimensional, where the leftmost dimension represents the number of curves and the rightmost dimension the number of points in each curve.")
exit
end if
npts = dsizes_y(1)
end if
;
; Create the indexed X array.
;
x = ispan(0,npts-1,1)
x_at_long_name = ""
;
; Call gsn_xy.
;
xy = gsn_xy(wks,x,y,res2)
return(xy)
end
;
; $Id: gsn_csm.ncl,v 1.207 2006/08/04 21:58:00 haley Exp $
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; ;
; Copyright (C) 1998 ;
; University Corporation for Atmospheric Research ;
; All Rights Reserved ;
; ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;; File: gsn_csm.ncl
;;
;; Author: Mary Haley
;; National Center for Atmospheric Research
;; PO 3000, Boulder, Colorado
;;
;; Date: Tue Feb 11 14:08:49 MST 1999
;;
;; Description: This script contains some specialized plotting functions
;; used by CGD for the CSM processor. To use the functions
;; and procedures in this script, you must have the lines:
;;
;; load "gsn_code.ncl"
;; load "gsn_csm.ncl"
;;
;; at the top of your NCL script, before the begin statement.
;;
;***********************************************************************;
; For every function and procedure defined in this script, undefine it ;
; with a call to "undef" so it doesn't clash with other functions and ;
; procedures with the same name. ;
;***********************************************************************;
undef("xy_ref_interp")
undef("ref_line_interp")
undef("get_bar_widths")
undef("outlined_bars")
undef("filled_bars")
undef("find_cross_xy")
undef("get_valid_long_names")
undef("get_valid_units")
undef("get_valid_long_name_value")
undef("get_valid_units_value")
undef("get_csm_long_name_units_string")
undef("check_for_subtitles")
undef("set_right_subtitle")
undef("set_left_subtitle")
undef("set_axis_string")
undef("set_subtitles_res")
undef("is_valid_coord")
undef("is_valid_latlon2d_attr")
undef("check_for_coord_arrays")
undef("check_class_name")
undef("get_allowed_latnames")
undef("get_allowed_lonnames")
undef("get_allowed_pres_units_mb")
undef("get_allowed_pres_units_pa")
undef("get_allowed_pres_units_hpa")
undef("get_allowed_pres_units")
undef("get_allowed_lat_units")
undef("get_allowed_lon_units")
undef("is_valid_latlon_coord")
undef("gsn_geop_hgt")
undef("check_for_y_lat_coord")
undef("check_for_x_lat_coord")
undef("check_for_lon_coord")
undef("get_polar_type")
undef("add_subtitles")
undef("add_labelbar")
undef("set_pres_hgt_axes")
undef("fill_xy_ref")
undef("fill_xy2")
undef("get_lon_values")
undef("get_lat_values")
undef("get_lon_labels")
undef("get_lat_labels")
undef("add_lon_labels")
undef("add_lat_labels_xaxis")
undef("add_lat_labels_yaxis")
undef("add_latlon_labels")
undef("add_map_tickmarks")
undef("gsn_add_cyclic_point")
undef("pop_tick_locs")
undef("pop_latlon_grid")
undef("mask_lambert_conformal")
undef("gsn_csm_map_ce")
undef("gsn_csm_map_polar")
undef("gsn_csm_map")
undef("gsn_csm_map_other")
undef("gsn_csm_contour_map_polar")
undef("gsn_csm_contour_map_ce")
undef("gsn_csm_contour_map_other")
undef("gsn_csm_vector_map_ce")
undef("gsn_csm_vector_map_polar")
undef("gsn_csm_vector_map_other")
undef("gsn_csm_streamline_map_ce")
undef("gsn_csm_streamline_map_polar")
undef("gsn_csm_streamline_map_other")
undef("gsn_csm_streamline_contour_map_ce")
undef("gsn_csm_streamline_contour_map_polar")
undef("gsn_csm_streamline_contour_map_other")
undef("gsn_csm_vector_scalar")
undef("gsn_csm_vector_scalar_map_ce")
undef("gsn_csm_vector_scalar_map_polar")
undef("gsn_csm_vector_scalar_map_other")
undef("gsn_csm_contour_map")
undef("gsn_csm_streamline_map")
undef("gsn_csm_vector_map")
undef("gsn_csm_vector_scalar_map")
undef("gsn_csm_streamline_contour_map")
undef("gsn_csm_contour_map_overlay")
undef("gsn_csm_xy")
undef("gsn_csm_y")
undef("plot_x2y2")
undef("plot_xy3")
undef("plot_xy2")
undef("plot_x2y")
undef("gsn_csm_xy2")
undef("gsn_csm_x2y")
undef("gsn_csm_x2y2")
undef("gsn_csm_xy3")
undef("gsn_csm_contour")
undef("gsn_csm_hov")
undef("gsn_csm_lat_time")
undef("gsn_csm_time_lat")
undef("gsn_csm_pres_hgt")
undef("gsn_csm_vector")
undef("gsn_csm_pres_hgt_vector")
undef("gsn_csm_streamline")
undef("gsn_csm_pres_hgt_streamline")
;***********************************************************************;
; Function : xy_ref_interp ;
; x1: numeric ;
; x2: numeric ;
; y1: numeric ;
; y2: numeric ;
; ;
; Given two points, (x1,y1) and (x2,y1) and a reference value (ref), ;
; this function interpolates where on the X axis the line from the 1st ;
; point to the 2nd point crosses the line y=ref. ;
; plot to the workstation "wks" (the variable returned from a previous ;
; call to "gsn_open_wks"). "resources" is an optional list of ;
; resources. The Id of the map plot is returned. ;
;***********************************************************************;
function xy_ref_interp(x1:numeric,x2:numeric,y1:numeric,y2:numeric, \
ref:numeric)
begin
return(x2-((y2-ref)*(x2-x1))/(y2-y1))
end
;***********************************************************************;
; Function : ref_line_interp ;
; x: numeric ;
; y: numeric ;
; xinterp: numeric ;
; yinterp: numeric ;
; ref_line: numeric ;
; ;
; Given a set of points represented by x and y, add interpolated values ;
; where the line crosses at y = ref_line. x and y must be the same ;
; length, and ref_line must either be a scalar or the same length as x ;
; and y. ref_line can be an array of reference values, as long as there ;
; is only one X/Y curve. ;
; ;
; The dimension size of each interpolated set of points is returned. ;
;***********************************************************************;
function ref_line_interp(x,y,xinterp,yinterp,ref_line)
local ncurves, nref_lines, nlines, i, j, location, xnew, ynew, npts
begin
; Check for missing values.
xmsg = get_res_value_keep(x,"_FillValue",-999)
ymsg = get_res_value_keep(y,"_FillValue",-999)
;
; Convert x and y into two dimensional arrays so we don't have to
; test for whether we have one line or multiple lines. Convert
; ref_line to a 1-d array (if it isn't already).
;
ndimsy = dimsizes(dimsizes(y))
ndimsx = dimsizes(dimsizes(x))
nref_lines = dimsizes(ref_line)
if(ndimsy.eq.1)
ncurves = 1
nptsy = dimsizes(y)
ynew = onedtond(y,(/nref_lines,nptsy/))
else
ncurves = dimsizes(y(:,0))
nptsy = dimsizes(y(0,:))
ynew = y
end if
nlines = max((/ncurves,nref_lines/))
if(ndimsx.eq.1)
xnew = onedtond(x,(/nlines,nptsy/))
else
xnew = x
end if
refnew = new((/nlines/),typeof(ref_line))
refnew = ref_line
xinterp(:,0) = xnew(:,0)
yinterp(:,0) = ynew(:,0)
npts = new((/nlines/),integer)
; Loop through the rest of the points and find out where the curve crosses
; the reference line. If it does, then do an interpolation.
; Store the location of the previous point (-1 if it is below the reference
; line, 0 if it is on the reference line, and 1 if it is above).
do j=0, nlines-1
num_crosses = 0
do i=1, nptsy-1
xinterp(j,i+num_crosses) = xnew(j,i)
yinterp(j,i+num_crosses) = ynew(j,i)
if(.not.ismissing(ynew(j,i)).and..not.ismissing(xnew(j,i)).and.\
.not.ismissing(ynew(j,i-1)).and..not.ismissing(xnew(j,i-1)))
if((ynew(j,i-1).lt.refnew(j).and.ynew(j,i).gt.refnew(j)).or.\
(ynew(j,i-1).gt.refnew(j).and.ynew(j,i).lt.refnew(j)))
xinterp(j,i+num_crosses) = xy_ref_interp(xnew(j,i-1),xnew(j,i),\
ynew(j,i-1),ynew(j,i),\
refnew(j))
xinterp(j,i+num_crosses+1) = xnew(j,i)
yinterp(j,i+num_crosses) = refnew(j)
yinterp(j,i+num_crosses+1) = ynew(j,i)
num_crosses = num_crosses + 1
end if
end if
end do
npts(j) = nptsy + num_crosses
end do
delete(xnew)
delete(ynew)
delete(refnew)
return(npts)
end
;***********************************************************************;
; Function : get_bar_widths ;
; x: numeric ;
; res2: logical ;
; ;
; Given a set of x points, return a bar width for filled bars later. ;
; ;
;***********************************************************************;
function get_bar_widths(x,ncurves,res2)
local ncurves, npts, bar_widths, dx, nwidths
begin
;
; Get number of curves and points, and the distances between x values.
;
dims = dimsizes(x)
if(dimsizes(dims).eq.1)
npts = dimsizes(x)
dx = min( x(1:npts-1) - x(0:npts-2) )
else
npts = dims(1)
x!0 = "ncurves"
x!1 = "npts"
;
; Get the minimum dx for each set of curves.
;
dx = dim_min(x(:,1:npts-1)-x(:,0:npts-2))
delete(x!0)
delete(x!1)
end if
;
; If bar width is set explicitly, we have to check it first.
;
if(isatt(res2,"gsnXYBarChartBarWidth"))
bar_width = get_res_value(res2,"gsnXYBarChartBarWidth",0.)
nwidths = dimsizes(dimsizes(bar_width))
if(.not.(nwidths.eq.1.or.nwidths.eq.ncurves))
print("get_bar_widths: Fatal: You must either select one constant bar width, or the same number of bar widths as you have curves.")
return
end if
if(any(bar_width.gt.dx))
print("get_bar_widths: Warning: The bar width(s) you selected ("+bar_width+") is larger than the smallest delta x ("+dx+").")
print("Defaulting to " + dx + ".")
if(nwidths.eq.1.and.ncurves.gt.1)
bar_widths = new(ncurves,typeof(dx))
end if
bar_widths = dx
else
;
; Make sure bar_widths is 1D array of length (/ncurves/).
;
if(nwidths.eq.1)
bar_widths = new(ncurves,double)
bar_widths = bar_width
end if
end if
else
bar_widths = new(ncurves,double)
bar_widths = dx ; Bar width is not being set.
end if
return(bar_widths)
end
;***********************************************************************;
; Procedure : outlined_bars ;
; x: numeric ;
; y: numeric ;
; xinterp: numeric ;
; yinterp: numeric ;
; ;
; Given a set of points represented by x and y, represent the y values ;
; with bar outlines. ;
;***********************************************************************;
procedure outlined_bars(x,y,xinterp,yinterp)
local ndimsx, ndimsy, ncurves, dims, npts, nyb, bar_width
begin
;
; Convert x and y into two dimensional arrays so we don't have to
; test for whether we have one line or multiple lines.
;
ndimsx = dimsizes(dimsizes(x))
ndimsy = dimsizes(dimsizes(y))
if(ndimsy.eq.1)
ncurves = 1
npts = dimsizes(y)
ynew = onedtond(y,(/ncurves,npts/))
else
ncurves = dimsizes(y(:,0))
npts = dimsizes(y(0,:))
ynew = y
end if
if(ndimsx.eq.1)
xnew = onedtond(x,(/ncurves,npts/))
else
xnew = x
end if
;
; For each old y point, we need two new y points to represent
; the horizontal line. The new X values will be the width of the bars.
;
nyb = 2 * (npts-1) + 1
yinterp(:,0:nyb-2:2) = ynew(:,:npts-2)
yinterp(:,1:nyb-1:2) = ynew(:,:npts-2)
yinterp(:,nyb-1) = ynew(:,npts-1) ; last point
bar_widths = xnew(:,1:) - xnew(:,:npts-2)
xinterp(:,0:nyb-2:2) = xnew(:,:npts-2)
xinterp(:,1:nyb-2:2) = xnew(:,:npts-2) + bar_widths
xinterp(:,nyb-1) = xnew(:,npts-1) ; last point, no bar
delete(xnew)
delete(ynew)
end
;***********************************************************************;
; procedure : filled_bars ;
; x: numeric ;
; y: numeric ;
; xabove: numeric ;
; yabove: numeric ;
; xbelow: numeric ;
; ybelow: numeric ;
; xequal: numeric ;
; yequal: numeric ;
; nya: integer ;
; nyb: integer ;
; nye: integer ;
; iya: integer ;
; iyb: integer ;
; iye: integer ;
; yref_line: numeric ;
; bar_widths: numeric ;
; ;
; Given a set of points represented by x and y, and y reference values, ;
; represent the y values with bars above, below, and equal to the ;
; reference lines. ;
; ;
; Bars aren't filled in this routine. They are returned as threes sets ;
; of polygons: those above, below, and equal to the reference lines. ;
;***********************************************************************;
procedure filled_bars(x,y,xabove,yabove,xbelow,ybelow,xequal,yequal,\
nya,nyb,nye,iya,iyb,iye,yref_line,bar_widths)
local ndimsx, ndimsy, ncurves, dims, npts
begin
;
; Convert x and y into two dimensional arrays so we don't have to
; test for whether we have one line or multiple lines.
;
ndimsx = dimsizes(dimsizes(x))
ndimsy = dimsizes(dimsizes(y))
if(ndimsy.eq.1)
ncurves = 1
npts = dimsizes(y)
ynew = new((/ncurves,npts/),double)
ynew = onedtond(y,(/ncurves,npts/))
else
ncurves = dimsizes(y(:,0))
npts = dimsizes(y(0,:))
ynew = new(dimsizes(y),double)
ynew = y
end if
if(ndimsx.eq.1)
xnew = new((/ncurves,npts/),double)
xnew = onedtond(x,(/ncurves,npts/))
else
xnew = new(dimsizes(x),double)
xnew = x
end if
;
; Make yref_line a 1D double array of length ncurves.
;
yref_lines = new(ncurves,double)
yref_lines = yref_line
;
; Loop across ncurves.
;
do i=0,ncurves-1
;
; Get the indices where the y curve is above, below, equal to the ref line.
;
ya_ind = ind(ynew(i,:).gt.yref_lines(i))
yb_ind = ind(ynew(i,:).lt.yref_lines(i))
ye_ind = ind(ynew(i,:).eq.yref_lines(i))
;
; Create new array to hold bar charts. For each old y point, we need
; five new y points to represent the closed rectangle.
;
if(.not.any(ismissing(ya_ind)))
nya(i) = 5*dimsizes(ya_ind) ; # values above ref line
iya(i,0:dimsizes(ya_ind)-1) = ya_ind ; indexes above ref line
yabove(i,0:nya(i)-5:5) = yref_lines(i)
yabove(i,1:nya(i)-4:5) = ynew(i,ya_ind)
yabove(i,2:nya(i)-3:5) = ynew(i,ya_ind)
yabove(i,3:nya(i)-2:5) = yref_lines(i)
yabove(i,4:nya(i)-1:5) = yref_lines(i)
xabove(i,0:nya(i)-5:5) = xnew(i,ya_ind) - bar_widths(i)/2.
xabove(i,1:nya(i)-4:5) = xnew(i,ya_ind) - bar_widths(i)/2.
xabove(i,2:nya(i)-3:5) = xnew(i,ya_ind) + bar_widths(i)/2.
xabove(i,3:nya(i)-2:5) = xnew(i,ya_ind) + bar_widths(i)/2.
xabove(i,4:nya(i)-1:5) = xnew(i,ya_ind) - bar_widths(i)/2.
else
nya(i) = 0
end if
if(.not.any(ismissing(yb_ind)))
nyb(i) = 5*dimsizes(yb_ind) ; # values below ref line
iyb(i,0:dimsizes(yb_ind)-1) = yb_ind ; indexes below ref line
ybelow(i,0:nyb(i)-5:5) = yref_lines(i)
ybelow(i,1:nyb(i)-4:5) = ynew(i,yb_ind)
ybelow(i,2:nyb(i)-3:5) = ynew(i,yb_ind)
ybelow(i,3:nyb(i)-2:5) = yref_lines(i)
ybelow(i,4:nyb(i)-1:5) = yref_lines(i)
xbelow(i,0:nyb(i)-5:5) = xnew(i,yb_ind) - bar_widths(i)/2.
xbelow(i,1:nyb(i)-4:5) = xnew(i,yb_ind) - bar_widths(i)/2.
xbelow(i,2:nyb(i)-3:5) = xnew(i,yb_ind) + bar_widths(i)/2.
xbelow(i,3:nyb(i)-2:5) = xnew(i,yb_ind) + bar_widths(i)/2.
xbelow(i,4:nyb(i)-1:5) = xnew(i,yb_ind) - bar_widths(i)/2.
else
nyb(i) = 0
end if
if(.not.any(ismissing(ye_ind)))
nye(i) = 5*dimsizes(ye_ind) ; # values equal ref line
iye(i,0:dimsizes(ye_ind)-1) = ye_ind ; indexes equal ref line
yequal(i,0:nye(i)-1:5) = yref_lines(i)
xequal(i,0:nye(i)-5:5) = xnew(i,ye_ind) - bar_widths(i)/2.
xequal(i,1:nye(i)-4:5) = xnew(i,ye_ind) - bar_widths(i)/2.
xequal(i,2:nye(i)-3:5) = xnew(i,ye_ind) + bar_widths(i)/2.
xequal(i,3:nye(i)-2:5) = xnew(i,ye_ind) + bar_widths(i)/2.
xequal(i,4:nye(i)-1:5) = xnew(i,ye_ind) - bar_widths(i)/2.
else
nye(i) = 0
end if
delete(ya_ind)
delete(yb_ind)
delete(ye_ind)
end do
delete(xnew)
delete(ynew)
end
;***********************************************************************;
; Function : find_cross_xy ;
; x1: numeric ;
; x2: numeric ;
; y11: numeric ;
; y12: numeric ;
; y21: numeric ;
; y22: numeric ;
; ;
; Given two points of two curves: ;
; ;
; (x1,y11) & (x2,y12) and (x1,y21) & (x2,y22) ;
; ;
; compute the point at which the two curves cross. ;
; ;
;***********************************************************************;
function find_cross_xy(x1:double,x2:double,y11:double,y12:double, \
y21:double,y22:double)
begin
if((x2-x1).eq.0.or.(y12-y11+y21-y22).eq.0)
x0 = new(1,double,-9999)
y0 = new(1,double,-9999)
x0 = -9999
y0 = -9999
else
x0 = (x2*y21 - x2*y11 + x1*y12 - x1*y22)/(y12-y11+y21-y22)
y0 = (y11*y22 - y12*y21) / (y11-y12+y22-y21)
; y0 = (x0*(y22-y21)-x1*y22+x2*y21)/(x2-x1)
end if
return((/x0,y0/))
end
;***********************************************************************;
; Function : get_valid_long_names() ;
; ;
; This function returns the list of valid names that can be used in ;
; place of "long_name". Note that these names are in the order that ;
; they should be used. I.e. if both "long_name" and "Description" are ;
; present, then long_name takes precedence over "Description". ;
; ;
;***********************************************************************;
function get_valid_long_names()
begin
return((/"long_name","standard_name","description","DESCRIPTION", \
"DataFieldName"/))
end
;***********************************************************************;
; Function : get_valid_units() ;
; ;
; This function returns the list of valid names that can be used for ;
; "units". ;
; ;
;***********************************************************************;
function get_valid_units()
begin
return((/"units","Units","UNITS","unit","Unit","UNIT"/))
end
;***********************************************************************;
; Function : get_valid_long_name_value() ;
; ;
; This function returns the attribute and the attribute value of the ;
; valid long_name, if it exists, and missing otherwise. ;
;***********************************************************************;
function get_valid_long_name_value(data)
local data_atts, n, found_valid_name, data_atts
begin
data_atts = getvaratts(data)
found_valid_name = False
if(.not.any(ismissing(data_atts))) then
valid_long_names = get_valid_long_names()
n = 0
do while(n.lt.dimsizes(valid_long_names).and..not.found_valid_name)
if (any(valid_long_names(n).eq.data_atts)) then
;
; Return both the attribute name and its value.
;
return((/valid_long_names(n),data@$valid_long_names(n)$/))
end if
n = n + 1
end do
end if
return(new(1,string))
end
;***********************************************************************;
; Function : get_valid_units_value() ;
; ;
; This function returns the attribute and the attribute value of the ;
; valid units, if it exists, and missing otherwise. ;
;***********************************************************************;
function get_valid_units_value(data)
local data_atts, n, found_valid_name, data_atts
begin
data_atts = getvaratts(data)
found_valid_name = False
if(.not.any(ismissing(data_atts))) then
valid_units = get_valid_units()
n = 0
do while(n.lt.dimsizes(valid_units).and..not.found_valid_name)
if (any(valid_units(n).eq.data_atts)) then
;
; Return both the attribute name and its value.
;
return((/valid_units(n),data@$valid_units(n)$/))
end if
n = n + 1
end do
end if
return(new(1,string))
end
;***********************************************************************;
; Function : get_csm_long_name_units_string ;
; data : numeric ;
; ;
; This function checks if a valid long_name and units attributes exist, ;
; and if so, constructs a string using them. A missing value is returned;
; otherwise. ;
;***********************************************************************;
function get_csm_long_name_units_string(data)
local lname, uname
begin
lu_string = new(1,string)
lname = get_valid_long_name_value(data)
uname = get_valid_units_value(data)
if(.not.any(ismissing(lname))) then
lu_string = lname(1)
;
; Comment out this code for now, because I'm not sure I want
; the default behavior to change from just a long_name string
; to a long_name (units) string for now. This was added around
; version a031 (Jan 2004).
;
; if(.not.any(ismissing(uname)).and.uname(1).ne."") then
; lu_string = lu_string + " (" + uname(1) + ")"
; end if
end if
return(lu_string)
end
;***********************************************************************;
; Procedure : check_for_subtitles ;
; res: logical ;
; left: logical ;
; center: logical ;
; right: logical ;
; ;
; This procedure checks if the resources gsnLeftString, gsnCenterString,;
; and/or gsnRightString have been set. These resources provide three ;
; subtitles for the top of a plot. ;
;***********************************************************************;
procedure check_for_subtitles(res:logical,left:logical,center:logical,\
right:logical)
begin
; Initialize
left = False
right = False
center = False
if((res).and..not.any(ismissing(getvaratts(res)))) then
;
; Check for font setting.
;
if(isatt(res,"gsnStringFont")) then
left_at_gsnStringFont = res_at_gsnStringFont
center_at_gsnStringFont = res_at_gsnStringFont
right_at_gsnStringFont = res_at_gsnStringFont
delete(res_at_gsnStringFont)
end if
;
; Check for left string.
;
if(isatt(res,"gsnLeftString")) then
left = True
left_at_sub_string = res_at_gsnLeftString
;
; Check for ParallelPosF/OrthogonalPosF setting.
;
if(isatt(res,"gsnLeftStringParallelPosF")) then
left_at_gsnLeftStringParallelPosF = \
get_res_value(res,"gsnLeftStringParallelPosF",0.0)
end if
if(isatt(res,"gsnLeftStringOrthogonalPosF")) then
;
; 0.0 is just a dummy value. It will not be used.
;
left_at_gsnLeftStringOrthogonalPosF = \
get_res_value(res,"gsnLeftStringOrthogonalPosF",0.0)
end if
;
; Check for font heights.
;
if(isatt(res,"gsnLeftStringFontHeightF")) then
left_at_gsnLeftStringFontHeightF = get_res_value(res, \
"gsnLeftStringFontHeightF",0.0)
else
if(isatt(res,"gsnStringFontHeightF")) then
left_at_gsnLeftStringFontHeightF = get_res_value_keep(res, \
"gsnStringFontHeightF",0.0)
end if
end if
delete(res_at_gsnLeftString)
end if
;
; Check for center string.
;
if(isatt(res,"gsnCenterString"))
center = True
center_at_sub_string = res_at_gsnCenterString
;
; Check for ParallelPosF/OrthogonalPosF setting.
;
if(isatt(res,"gsnCenterStringParallelPosF")) then
center_at_gsnCenterStringParallelPosF = \
get_res_value(res,"gsnCenterStringParallelPosF",0.5)
end if
if(isatt(res,"gsnCenterStringOrthogonalPosF")) then
;
; 0.0 is just a dummy value. It will not be used.
;
center_at_gsnCenterStringOrthogonalPosF = \
get_res_value(res,"gsnCenterStringOrthogonalPosF",0.0)
end if
;
; Check for font heights.
;
if(isatt(res,"gsnCenterStringFontHeightF")) then
center_at_gsnCenterStringFontHeightF = get_res_value(res, \
"gsnCenterStringFontHeightF",0.0)
else
if(isatt(res,"gsnStringFontHeightF")) then
center_at_gsnCenterStringFontHeightF = get_res_value_keep(res, \
"gsnStringFontHeightF",0.0)
end if
end if
delete(res_at_gsnCenterString)
end if
;
; Check for right string.
;
if(isatt(res,"gsnRightString"))
right = True
right_at_sub_string = res_at_gsnRightString
;
; Check for ParallelPosF/OrthogonalPosF setting.
;
if(isatt(res,"gsnRightStringParallelPosF")) then
right_at_gsnRightStringParallelPosF = \
get_res_value(res,"gsnRightStringParallelPosF",1.0)
end if
if(isatt(res,"gsnRightStringOrthogonalPosF")) then
;
; 0.0 is just a dummy value. It will not be used.
;
right_at_gsnRightStringOrthogonalPosF = \
get_res_value(res,"gsnRightStringOrthogonalPosF",0.0)
end if
;
; Check for font heights.
;
if(isatt(res,"gsnRightStringFontHeightF")) then
right_at_gsnRightStringFontHeightF = get_res_value(res, \
"gsnRightStringFontHeightF",0.0)
else
if(isatt(res,"gsnStringFontHeightF")) then
right_at_gsnRightStringFontHeightF = get_res_value_keep(res, \
"gsnStringFontHeightF",0.0)
end if
end if
delete(res_at_gsnRightString)
end if
end if
if(isatt(res,"gsnStringFontHeightF")) then
delete(res_at_gsnStringFontHeightF)
end if
return
end
;***********************************************************************;
; Procedure : set_right_subtitle ;
; data: numeric ;
; res: logical ;
; newres: logical ;
; ;
; This procedure checks if gsnRightString is set. If not, then uses ;
; data_at_units if it exists. ;
;***********************************************************************;
procedure set_right_subtitle(data:numeric,res:logical,newres:logical)
begin
;
; If gsnRightString hasn't been set, then use the valid units
; attribute if it exists.
;
if(isatt(res,"gsnRightString"))
newres = True
newres_at_gsnRightString = res_at_gsnRightString
else
uname = get_valid_units_value(data)
if(.not.any(ismissing(uname)))
newres = True
newres_at_gsnRightString = uname(1)
end if
end if
return
end
;***********************************************************************;
; Procedure : set_left_subtitle ;
; data: numeric ;
; res: logical ;
; newres: logical ;
; ;
; This procedure checks if gsnLeftString is set. If not, then uses ;
; one of the valid "long_name" attributes, if they exist. ;
;***********************************************************************;
procedure set_left_subtitle(data:numeric,res:logical,newres:logical)
begin
;
; If gsnLeftString hasn't been set, then use one of several valid "long
; names" if they exist. Also have to delete the attribute used so it
; doesn't get used in the title by gsn_code.ncl. But, be careful here
; because you don't want to remove the attribute from the actual data.
; Before calling this routine, you should be using a copy of your
; data.
;
lname = get_valid_long_name_value(data)
if(.not.any(ismissing(lname)))
newres = True
newres_at_gsnLeftString = get_res_value_keep(res,"gsnLeftString",lname(1))
;
; Delete so it doesn't get used for main title
;
delete(data@$lname(0)$)
end if
;
; Of course, if gsnLeftString is set, use it. We had to do the test
; above first to make sure the attribute got removed, if it existed,
; so it doesn't get used again for another resource.
;
if(isatt(res,"gsnLeftString"))
newres = True
newres_at_gsnLeftString = res_at_gsnLeftString
end if
return
end
;***********************************************************************;
; Function : is_valid_coord ;
; ;
; Checks if the X or Y coordinate variable exist and if it is ;
; 1-dimensional. ;
; ;
;***********************************************************************;
function is_valid_coord(data:numeric,axis:string)
local dims
begin
dims = -1
if(axis.eq."x") then
if(isdimnamed(data,1).and.iscoord(data,data!1))
dims = dimsizes(dimsizes(data&$data!1$))
end if
else
if(isdimnamed(data,0).and.iscoord(data,data!0))
dims = dimsizes(dimsizes(data&$data!0$))
end if
end if
if(dims.eq.1) then
return(True)
else
return(False)
end if
end
;***********************************************************************;
; Function : is_valid_latlon2d_attr ;
; ;
; Checks for a valid lon2d or lat2d attribute. This special attribute is;
; used by the gsn_csm* scripts for cases where the data is represented ;
; by 2D lat/lon arrays, instead of 1D coordinate arrays. ;
; ;
; The lat2d/lon2d arrays can be one element larger in both dimensions. ;
; This can mean that we are dealing with cell boundaries instead of cell;
; centers. ;
;***********************************************************************;
function is_valid_latlon2d_attr(data:numeric,lstring:string)
local ldims, data_dims
begin
if(isatt(data,lstring)) then
ldims = dimsizes(data@$lstring$)
data_dims = dimsizes(data)
if(all(ldims.eq.data_dims).or.all(ldims.eq.(data_dims+1))) then
return(True)
else
print("is_valid_latlon2d_attr: Warning: The '" + lstring + "' attribute must either be the same dimension sizes as the data, or one element larger in both directions. Your data will most likely not be overlaid on the map correctly.")
end if
end if
return(False)
end
;***********************************************************************;
; Procedure : set_axis_string ;
; res: logical ;
; data: numeric ;
; axis: string ;
; ;
; This procedure sets the tiXAxisString or tiYAxisString resource ;
; depending on current resource and/or attribute settings. ;
;***********************************************************************;
procedure set_axis_string(plot:graphic,res:logical,data:numeric,axis:string)
local title, tires, is_xyplot
begin
tires = get_res_eq(res,(/"ti"/)) ; Get tickmark resources
is_xyplot = get_res_value_keep(res,"gsnXYPlot", False)
valid_coord = is_valid_coord(data,axis)
if(axis.eq."y") then
mode_res = "tmYLMode"
axis_res = "tiYAxisString"
if(valid_coord) then
coord_var = data&$data!0$
end if
else
mode_res = "tmXBMode"
axis_res = "tiXAxisString"
if(valid_coord) then
coord_var = data&$data!1$
end if
end if
;
; If the axis tickmarks are being labeled explicitly by the user,
; then don't put a label on that axis.
;
if(check_attr(res,mode_res,"Explicit",True).or. \
check_attr(res,mode_res,2,True)) then
set_attr(tires,axis_res,"")
else
if(.not.is_xyplot) then
if(valid_coord) then
axis_string = get_csm_long_name_units_string(coord_var)
if(.not.ismissing(axis_string)) then
set_attr(tires,axis_res,axis_string)
end if
end if
else
axis_string = get_csm_long_name_units_string(data)
if(.not.ismissing(axis_string)) then
set_attr(tires,axis_res,axis_string)
end if
end if
end if
attsetvalues_check(plot,tires)
return
end
;***********************************************************************;
; Procedure : set_subtitles_res ;
; res: logical ;
; plotres: logical ;
; ;
; This procedure checks if any of the gsn*String subtitle resources have;
; been set. If so, it adds them to plotres as resources so they can ;
; be passed to another plotting function to be processed. ;
;***********************************************************************;
procedure set_subtitles_res(res:logical,plotres:logical)
local valid_string_res
begin
valid_subttl_res = (/"gsnLeftString","gsnCenterString","gsnRightString",\
"gsnStringFont","gsnStringFontHeightF", \
"gsnLeftStringFontHeightF", \
"gsnCenterStringFontHeightF", \
"gsnRightStringFontHeightF", \
"gsnLeftStringParallelPosF", \
"gsnCenterStringParallelPosF", \
"gsnRightStringParallelPosF", \
"gsnLeftStringOrthogonalPosF", \
"gsnCenterStringOrthogonalPosF", \
"gsnRightStringOrthogonalPosF"/)
if((res).and..not.any(ismissing(getvaratts(res))))
nstrings = dimsizes(valid_subttl_res)
do i=0,nstrings-1,1
if(isatt(res,valid_subttl_res(i)))
plotres = True
plotres@$valid_subttl_res(i)$ = res@$valid_subttl_res(i)$
delete(res@$valid_subttl_res(i)$)
end if
end do
end if
return
end
;***********************************************************************;
; Procedure : check_for_coord_arrays ;
; data: numeric ;
; res: logical ;
; type: string ;
; ;
; This procedure checks if the data contains a coordinate variable in ;
; dimension 0 or 1. If so, then it sets sf/vfX/YArray (depending on if ;
; type equals "contour*" or "vector*" to these coordinate arrays. ;
; ;
; If no coordinate array exists, then this procedure checks for the ;
; special "lat2d"/"lon2d" *attributes*. This is an indicator that we ;
; have "2D coordinate" arrays, and we can set the sf/vfX/YArray ;
; resources to these values. These 2D coords only work if you plan to ;
; overlay the vectors/contours on a map, however. ;
; ;
;***********************************************************************;
procedure check_for_coord_arrays(data:numeric,res:logical,type:string)
local prefix, xstart_name, xend_name, ystart_name, yend_name, \
xarray_name, yarray_name, valid_2dcoord_types
begin
;
; If the data is 1D, no coord arrays should exist.
;
if(dimsizes(dimsizes(data)).eq.1) then
return
end if
if(type.eq."vector".or.type.eq."vector_map")
prefix = "vf"
else
prefix = "sf"
end if
xarray_name = prefix + "XArray"
xstart_name = prefix + "XCStartV"
xend_name = prefix + "XCEndV"
yarray_name = prefix + "YArray"
ystart_name = prefix + "YCStartV"
yend_name = prefix + "YCEndV"
;
; I originally thought that Only plots over maps could have
; 2D lat/lon coordinates, but I don't believe this is the case.
; So, I've commented out the valid_2dcoord_types stuff.
;
; valid_2dcoord_types = (/"contour_map","vector_map"/)
;
; First check if a valid "lon2d" attribute is set and whether we are
; drawing over a map. If both conditions are not met, then
; check for a regular coordinate array. One of these will be used for
; sf/vf/XArray.
;
if(.not.((isatt(res,xstart_name).and.isatt(res,xend_name)).or.\
isatt(res,xarray_name))) then
; if(any(type.eq.valid_2dcoord_types).and. \
; is_valid_latlon2d_attr(data,"lon2d")) then
if(is_valid_latlon2d_attr(data,"lon2d")) then
res@$xarray_name$ = data_at_lon2d
else
if(is_valid_coord(data,"x")) then
res@$xarray_name$ = data&$data!1$
end if
end if
end if
;
; First check if a valid "lat2d" attribute is set. If not set, then
; check for a regular coordinate array. One of these will be used for
; sf/vf/YArray.
;
if(.not.((isatt(res,ystart_name).and.isatt(res,yend_name)).or.\
isatt(res,yarray_name))) then
; if(any(type.eq.valid_2dcoord_types).and. \
; is_valid_latlon2d_attr(data,"lat2d")) then
if(is_valid_latlon2d_attr(data,"lat2d")) then
res@$yarray_name$ = data_at_lat2d
else
if(is_valid_coord(data,"y")) then
res@$yarray_name$ = data&$data!0$
end if
end if
end if
return
end
;***********************************************************************;
; Function : check_class_name ;
; plot: graphic ;
; plot_type: string ;
; ;
; This procedure checks what type "plot" is, and returns the plot from ;
; it (for example, if "plot" is an overlay, and you want the contour ;
; part of it, it will return the contour plot. ;
; ;
;***********************************************************************;
function check_class_name(plot:graphic,plot_type:string)
begin
class_name = NhlClassName(plot)
if(class_name.eq."logLinPlotClass".or.class_name.eq."irregularPlotClass")
new_plot = plot@$plot_type$
else
new_plot = plot
end if
return(new_plot)
end
;***********************************************************************;
; Function : get_allowed_latnames ;
; ;
; Get list of names allowed for a latitude coordinate array. ;
; ;
;***********************************************************************;
function get_allowed_latnames()
begin
return((/"lat","Lat","Latitude","LAT","latitude","LATITUDE","hlat",\
"lat_u","lat_t","lat_98","lat1","lat2","yc"/))
end
;***********************************************************************;
; Function : get_allowed_lonnames ;
; ;
; Get list of names allowed for a longitude coordinate array. ;
; ;
;***********************************************************************;
function get_allowed_lonnames()
begin
return((/"lon","Lon","Longitude","LON","longitude","LONGITUDE","hlon",\
"long","lon_u","lon_t","lon_98","lon1","lon2","xc"/))
end
;***********************************************************************;
; Function : get_allowed_pres_units_pa ;
; ;
; Get list of names allowed for pressure units in pascals. ;
; ;
;***********************************************************************;
function get_allowed_pres_units_pa()
begin
return((/"Pa","pa","PA","Pascals","pascals","PASCALS"/))
end
;***********************************************************************;
; Function : get_allowed_pres_units_hpa ;
; ;
; Get list of names allowed for pressure units in hecto-pascals. ;
; ;
;***********************************************************************;
function get_allowed_pres_units_hpa()
begin
return((/"hpa","hPa","HPA","hecto-pascals","HECTO-PASCALS"/))
end
;***********************************************************************;
; Function : get_allowed_pres_units_mb ;
; ;
; Get list of names allowed for pressure units in millibars. ;
; ;
;***********************************************************************;
function get_allowed_pres_units_mb()
begin
return((/"mb","Mb","MB","millibar","millibars","MILLIBARS", \
"hybrid_sigma_pressure"/))
end
;***********************************************************************;
; Function : get_allowed_pres_units ;
; ;
; Get list of names allowed for pressure units. ;
; ;
;***********************************************************************;
function get_allowed_pres_units()
begin
mb = get_allowed_pres_units_mb()
pa = get_allowed_pres_units_pa()
hpa = get_allowed_pres_units_hpa()
nmb = dimsizes(mb)
npa = dimsizes(pa)
nhpa = dimsizes(hpa)
all_pres = new(nmb+npa+nhpa,string)
all_pres(0:nmb-1) = mb
all_pres(nmb:nmb+npa-1) = pa
all_pres(nmb+npa:) = hpa
return(all_pres)
end
;***********************************************************************;
; Function : get_allowed_lat_units ;
; ;
; Get list of names allowed for the units attribute of a latitude ;
; coordinate array. ;
; ;
;***********************************************************************;
function get_allowed_lat_units()
begin
return((/"degrees_north","degrees-north","degree_north","degrees north",\
"degrees_N","Degrees_north","degree_N","degreeN","degreesN", \
"deg north"/))
end
;***********************************************************************;
; Function : get_allowed_lon_units ;
; ;
; Get list of names allowed for the units attribute of a longitude ;
; coordinate array. ;
; ;
;***********************************************************************;
function get_allowed_lon_units()
begin
return((/"degrees_east","degrees-east","degree_east","degrees east",\
"degrees_E","Degrees_east","degree_E","degreeE","degreesE",\
"deg east"/))
end
;***********************************************************************;
; Function : is_valid_latlon_coord ;
; ;
; Checks if the X or Y coordinate variable contains real a valid lat or ;
; lon coordinate array. It does this just by checking for a valid ;
; "units" attribute. ;
; ;
; It used to be that we checked the name of the coordinate array as well;
; as the units. But, according to D. Shea, it is enough check for just ;
; the units. So, as of Dec 2003, we are now just checking units. ;
; ;
; We don't print out any warning messages in this function, b/c ;
; sometimes the calling routine is just calling it for informational ;
; purposes. It is up to the calling routine to print an error if a False;
; value is returned. ;
;***********************************************************************;
function is_valid_latlon_coord(data:numeric,axis:string,latorlon:string,\
res:logical)
begin
;
; If tfDoNDCOverlay is set to True, then coordinate arrays shouldn't be
; used in the first place, and hence the units don't need to be correct.
; It is up to the user to do the right thing and *not* set coordinate
; arrays. Here, we check for the setting of this resource to True,
; and if so, then the units attribute isn't even checked.
;
if(get_res_value_keep(res,"tfDoNDCOverlay",False)) then
return(False)
end if
if(axis.eq."x") then
if(is_valid_coord(data,"x")) then
if(latorlon.eq."lat") then
if(isatt(data&$data!1$,"units").and. \
any(data&$data!1$@units.eq.get_allowed_lat_units)) then
return(True)
end if
;
; Otherwise, we must be dealing with longitudes.
;
else
if(isatt(data&$data!1$,"units").and.\
any(data&$data!1$@units.eq.get_allowed_lon_units)) then
return(True)
end if
end if
end if
;
; We are dealing with the Y axis.
;
else
if(is_valid_coord(data,"y")) then
if(latorlon.eq."lat") then
if(isatt(data&$data!0$,"units").and.\
any(data&$data!0$@units.eq.get_allowed_lat_units)) then
return(True)
end if
;
; Otherwise, we must be dealing with longitudes.
;
else
if(isatt(data&$data!0$,"units").and.\
any(data&$data!0$@units.eq.get_allowed_lon_units)) then
return(True)
end if
end if
end if
end if
return(False)
end
;***********************************************************************;
; Procedure : gsn_geop_hgt ;
; ;
; Returns geopotential height (in km) given array p (pressure in mb) ;
; p must lie between 1013.25 mb and 2.54e-06 mb. ;
; ;
; Algorithm is simply logarithmic interpolation from Standard ;
; Atmosphere. ;
; Intended to provide an ESTIMATE of geopotential height when ;
; temperature and geopotential data are lacking. ;
; ;
; Values above 85km were obtained from the COSPAR International ;
; Reference Atmosphere: 1986 QB495 .A38 v.10 No.12 [FL] ;
; ;
;***********************************************************************;
function gsn_geop_hgt( p[*]:numeric )
local nsa,psa,zsa,ptmp,npres,found,i,j
begin
if(isatt(p,"units").and.(any(p_at_units.eq.get_allowed_pres_units_pa())))
ptmp = p * 0.01 ; Convert to mb
else
if((.not.isatt(p,"units")).or. \
(isatt(p,"units").and. \
.not.(any(p_at_units.eq.get_allowed_pres_units_hpa()).or. \
any(p_at_units.eq.get_allowed_pres_units_mb()))))
print("gsn_geop_hgt: Warning: The 'units' attribute is either not set, or it is not set")
print("to the recognized names for 'hecto-pascals' or 'millibars', so")
print("assuming pressure values are already converted to millibars.")
end if
ptmp = tofloat(p) ; Assume already converted to mb!
end if
nsa = 53
psa = new( (/nsa/), float, 1.e36 )
zsa = new( (/nsa/), float, 1.e36 )
zsa = (/ -0.3, \ ; km
0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, \
3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, \
7.0, 7.5, 8.0, 8.5, 9.0, 9.5, 10.0, \
11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, \
18.0, 19.0, 20.0, 25.0, 30.0, 35.0, 40.0, 45.0, \
50.0, 60.0, 70.0, 80.0, 84.8, 87.7, 90.6, \
93.3, 96.1, 97.5,100.4,104.9, \
110.0,114.2,116.7,119.7/)
psa = (/ 1050., \ ; mb (hPa)
1013.25, 954.61, 898.76, 845.59, 795.01, 746.91, 701.21, \
657.80, 616.60, 577.52, 540.48, 505.39, 472.17, 440.75, \
411.05, 382.99, 356.51, 331.54, 308.00, 285.84, 264.99, \
226.99, 193.99, 165.79, 141.70, 121.11, 103.52, 88.497, \
75.652, 64.674, 55.293, 25.492, 11.970, 5.746, 2.871, 1.491,\
0.798, 0.220, 0.052, 0.010, 0.00485,0.00294,0.000178, \
0.000108, 0.0000656, 0.0000511, 0.0000310, 0.0000146, \
0.00000691, 0.00000419, 0.00000327, 0.00000254 /)
if ( any(ptmp.lt.min(psa)) .or. any(ptmp.gt.max(psa))) then
print("gsn_geop_hgt: Fatal: The pressure values do not fall between")
print(min(psa) + " mb and " + max(psa) + " mb.")
print("Execution halted.")
exit
end if
npres = dimsizes(ptmp)
gph = new(npres,float)
do i = 0,npres-1
found = False
j = 0
do while(.not.found.and.j.le.nsa-2)
if ( ( ptmp(i) .le. psa(j) ) .and. ( ptmp(i) .ge. psa(j+1) ) ) then
gph(i) = zsa(j) + (zsa(j+1) - zsa(j)) * \
log( psa(j)/ptmp(i) )/log( psa(j)/psa(j+1) )
found = True
end if
j = j + 1
end do
end do
delete(psa)
delete(zsa)
delete(ptmp)
return(gph)
end
;***********************************************************************;
; Procedure : check_for_y_lat_coord ;
; data: numeric ;
; res: logical ;
; type: string ;
; ;
; This procedure checks if the data contains a coordinate variable in ;
; dimension 0 of an allowable list of latnames ;
; ;
; If so, then it sets sf/vfYArray (depending on if type equals ;
; "contour*" or "vector*" to this coordinate array. ;
; ;
;***********************************************************************;
procedure check_for_y_lat_coord(data:numeric,res:logical,type:string)
local latname, char_latname, array_name, start_name, end_name, \
valid_2dcoord_types
begin
;
; If the data is 1D, no coord arrays should exist.
;
if(dimsizes(dimsizes(data)).eq.1) then
return
end if
;
;
; If tfDoNDCOverlay is set to True, then coordinate arrays shouldn't be
; used in the first place. It is up to the user to do the right thing
; and *not* set coordinate arrays. Here, we check for the setting
; of this resource to True, and if so, then no warning messages are
; printed out if no coordinate arrays are set.
;
if(get_res_value_keep(res,"tfDoNDCOverlay",False)) then
return(False)
end if
;
; Determine what kind of plot we need to set the data field resources for.
;
if(type.eq."vector".or.type.eq."vector_map")
array_name = "vfYArray"
start_name = "vfYCStartV"
end_name = "vfYCEndV"
else
array_name = "sfYArray"
start_name = "sfYCStartV"
end_name = "sfYCEndV"
end if
;
; I originally thought that Only plots over maps could have
; 2D lat/lon coordinates, but I don't believe this is the case.
; So, I've commented out the valid_2dcoord_types stuff.
;
; valid_2dcoord_types = (/"contour_map","vector_map"/)
;
; Make sure user is not already setting own *Start* and *End*
; or *Array resources. Then check if a valid "lat2d" attribute
; is set or if a valid coordinate array is set.
;
if(.not.((isatt(res,start_name).and.isatt(res,end_name)).or.\
isatt(res,array_name))) then
; if(any(type.eq.valid_2dcoord_types).and. \
; is_valid_latlon2d_attr(data,"lat2d")) then
if(is_valid_latlon2d_attr(data,"lat2d")) then
res@$array_name$ = data_at_lat2d
return
else
if(is_valid_latlon_coord(data,"y","lat",res))
res@$array_name$ = data&$data!0$
return
else
print("check_for_y_lat_coord: Warning: Data either does not contain a valid latitude coordinate array or doesn't contain one at all.")
print("A valid latitude coordinate array should have a 'units' attribute equal to one of the following values: ")
print(" " + cat_strings(get_allowed_lat_units))
end if
end if
end if
return
end
;***********************************************************************;
; Procedure : check_for_x_lat_coord ;
; data: numeric ;
; res: logical ;
; type: string ;
; ;
; This procedure checks if the data contains a coordinate variable in ;
; dimension 1 of an allowable list of latnames ;
; ;
; If so, then it sets sf/vfYArray (depending on if type equals ;
; "contour*" or "vector*" to this coordinate array. ;
; ;
;***********************************************************************;
procedure check_for_x_lat_coord(data:numeric,res:logical,type:string)
local latname, char_latname, array_name, start_name, end_name, \
valid_2dcoord_types
begin
;
; If the data is 1D, no coord arrays should exist.
;
if(dimsizes(dimsizes(data)).eq.1) then
return
end if
;
; If tfDoNDCOverlay is set to True, then coordinate arrays shouldn't be
; used in the first place. It is up to the user to do the right thing
; and *not* set coordinate arrays. Here, we check for the setting
; of this resource to True, and if so, then no warning messages are
; printed out if no coordinate arrays are set.
;
if(get_res_value_keep(res,"tfDoNDCOverlay",False)) then
return(False)
end if
;
; Determine what kind of plot we need to set the data field resources for.
;
if(type.eq."vector".or.type.eq."vector_map")
array_name = "vfXArray"
start_name = "vfXCStartV"
end_name = "vfXCEndV"
else
array_name = "sfXArray"
start_name = "sfXCStartV"
end_name = "sfXCEndV"
end if
;
; I originally thought that Only plots over maps could have
; 2D lat/lon coordinates, but I don't believe this is the case.
; So, I've commented out the valid_2dcoord_types stuff.
;
; valid_2dcoord_types = (/"contour_map","vector_map"/)
;
; Make sure user is not already setting own *Start* and *End*
; or *Array resources. Then check if a valid "lat2d" attribute
; is set or if a valid coordinate array is set.
;
if(.not.((isatt(res,start_name).and.isatt(res,end_name)).or. \
isatt(res,array_name))) then
; if(any(type.eq.valid_2dcoord_types).and. \
; is_valid_latlon2d_attr(data,"lat2d")) then
if(is_valid_latlon2d_attr(data,"lat2d")) then
res@$array_name$ = data_at_lat2d
return
else
if(is_valid_latlon_coord(data,"x","lat",res))
res@$array_name$ = data&$data!1$
return
else
print("check_for_x_lat_coord: Warning: Data either does not contain a valid latitude coordinate array or doesn't contain one at all.")
print("A valid latitude coordinate array should have a 'units' attribute equal to one of the following values: ")
print(" " + cat_strings(get_allowed_lat_units))
end if
end if
end if
return
end
;***********************************************************************;
; Procedure : check_for_lon_coord ;
; data: numeric ;
; res: logical ;
; type: string ;
; ;
; This procedure checks if the data contains a coordinate variable in ;
; dimension 1 of an allowable list of lonnames ;
; ;
; If so, then it sets sf/vfXArray (depending on if type equals ;
; "contour*" or "vector*" to this coordinate array. ;
; ;
;***********************************************************************;
procedure check_for_lon_coord(data:numeric,res:logical,type:string)
local lonname, char_lonname, array_name, start_name, end_name, \
valid_2dcoord_types
begin
;
; If the data is 1D, no coord arrays should exist.
;
if(dimsizes(dimsizes(data)).eq.1) then
return
end if
;
; If tfDoNDCOverlay is set to True, then coordinate arrays shouldn't be
; used in the first place. It is up to the user to do the right thing
; and *not* set coordinate arrays. Here, we check for the setting
; of this resource to True, and if so, then no warning messages are
; printed out if no coordinate arrays are set.
;
if(get_res_value_keep(res,"tfDoNDCOverlay",False)) then
return(False)
end if
;
; Determine what kind of plot we need to set the data field resources for.
;
if(type.eq."vector".or.type.eq."vector_map")
array_name = "vfXArray"
start_name = "vfXCStartV"
end_name = "vfXCEndV"
else
array_name = "sfXArray"
start_name = "sfXCStartV"
end_name = "sfXCEndV"
end if
;
; I originally thought that Only plots over maps could have
; 2D lat/lon coordinates, but I don't believe this is the case.
; So, I've commented out the valid_2dcoord_types stuff.
;
; valid_2dcoord_types = (/"contour_map","vector_map"/)
;
; Make sure user is not already setting his own *Start* and *End*
; or *Array resources. If not, check for a valid lon2d attribute
; or a valid coordinate array.
;
if(.not.((isatt(res,start_name).and.isatt(res,end_name)).or.\
isatt(res,array_name))) then
; if(any(type.eq.valid_2dcoord_types).and. \
; is_valid_latlon2d_attr(data,"lon2d")) then
if(is_valid_latlon2d_attr(data,"lon2d")) then
res@$array_name$ = data_at_lon2d
return
else
if(is_valid_latlon_coord(data,"x","lon",res))
res@$array_name$ = data&$data!1$
return
else
print("check_for_lon_coord: Warning: Data either does not contain a valid longitude coordinate array or doesn't contain one at all.")
print("A valid longitude coordinate array should have a 'units' attribute equal to one of the following values: ")
print(" " + cat_strings(get_allowed_lon_units))
end if
end if
end if
return
end
;***********************************************************************;
; Function : get_polar_type ;
; res: logical ;
; ;
; This function checks the resource list for gsnPolar, gsnPolarNH, or ;
; gsnPolarSH to and returns what kind of polar plot is desired. ;
; ;
; The default will be northern ("NH") if none is set. ;
;***********************************************************************;
function get_polar_type(res:logical)
local polar_nh, polar_sh
begin
polar_type = get_res_value(res,"gsnPolar","")
polar_nh = get_res_value(res,"gsnPolarNH",False)
polar_sh = get_res_value(res,"gsnPolarSH",False)
if(polar_type.eq."NH".or.polar_type.eq."nh")
return("NH")
end if
if(polar_type.eq."SH".or.polar_type.eq."sh")
return("SH")
end if
if(polar_type.ne."")
print("get_polar_type: Warning: Invalid option for gsnPolar. Defaulting to northern hemisphere.")
return("NH")
end if
;
; Can't have polar_nh and polar_sh both False or both True.
;
if(polar_nh.and.polar_sh)
print("get_polar_type: Fatal: You have indicated you want both northern and southern polar projections.")
print("Only one of them can be selected, so please correct this.")
print("Execution halted.")
exit
end if
if(.not.polar_nh.and..not.polar_sh)
print("get_polar_type: Warning: No polar projection has been selected. Defaulting to northern hemisphere.")
return("NH")
end if
if(polar_nh)
return("NH")
else
return("SH")
end if
end
;***********************************************************************;
; Procedure : add_subtitles ;
; wks: graphic ;
; plot: graphic ;
; left_string: logical ;
; center_string: logical ;
; right_string: logical ;
; res: logical ;
; ;
; This procedure adds one to three subtitles to the top of the plot, ;
; depending on whether the special resources gsnLeftString, ;
; gsnCenterString, and/or gsnRightString had been set. ;
;***********************************************************************;
procedure add_subtitles(wks:graphic,plot:graphic,left_string:logical,\
center_string:logical,right_string:logical,\
res:logical)
local text_object, parallel_pos, anno, just, strings, txres, amres, \
num_res, ablank, chararray, string_len
begin
amres = False ; Annotation resources
txres = False ; Text resources
txres = get_res_eq(res,"tx")
amres = get_res_eq(res,"am")
;
; Get the height, as we use this to calculate distance of strings
; from top of plot.
;
getvalues plot
"vpHeightF" : vph
end getvalues
num_res = 0
parallel_pos = new(3,float)
parallel_pos(0) = get_res_value(left_string, \
"gsnLeftStringParallelPosF", 0.0)
parallel_pos(1) = get_res_value(center_string, \
"gsnCenterStringParallelPosF", 0.5)
parallel_pos(2) = get_res_value(right_string, \
"gsnRightStringParallelPosF", 1.0)
zone = get_res_value(amres,"amZone",3)
orthpos = get_res_value(amres,"amOrthogonalPosF",0.01*vph)
orthogonal_pos = new(3,float)
orthogonal_pos(0) = get_res_value(left_string, \
"gsnLeftStringOrthogonalPosF", orthpos)
orthogonal_pos(1) = get_res_value(center_string, \
"gsnCenterStringOrthogonalPosF",orthpos)
orthogonal_pos(2) = get_res_value(right_string, \
"gsnRightStringOrthogonalPosF", orthpos)
just = (/"left","center","right"/)
fhghts = (/0.,0.,0./)
strings = (/"","",""/)
;
; Set the three strings and their fonts and font heights.
;
if(left_string)
if(isatt(left_string,"gsnStringFont"))
txres_at_txFont = left_string_at_gsnStringFont
end if
strings(0) = left_string_at_sub_string
fhghts(0) = get_res_value_keep(left_string,"gsnLeftStringFontHeightF",\
get_res_value_keep(left_string,"gsnStringFontHeightF",\
get_res_value_keep(txres,"txFontHeightF",0.0)))
end if
if(center_string)
if(isatt(center_string,"gsnStringFont"))
txres_at_txFont = center_string_at_gsnStringFont
end if
strings(1) = center_string_at_sub_string
fhghts(1) = get_res_value_keep(center_string,"gsnCenterStringFontHeightF",\
get_res_value_keep(center_string,"gsnStringFontHeightF",\
get_res_value_keep(txres,"txFontHeightF",0.0)))
end if
if(right_string)
if(isatt(right_string,"gsnStringFont"))
txres_at_txFont = right_string_at_gsnStringFont
end if
strings(2) = right_string_at_sub_string
fhghts(2) = get_res_value_keep(right_string,"gsnRightStringFontHeightF",\
get_res_value_keep(right_string,"gsnStringFontHeightF",\
get_res_value_keep(txres,"txFontHeightF",0.0)))
end if
;
; Remove the text font height, so it doesn't get applied at the end.
;
if(isatt(txres,"txFontHeightF")) then
delete(txres_at_txFontHeightF)
end if
ablank = stringtocharacter(" ")
do i=0,2
if(.not.ismissing(strings(i)).and.strings(i).ne."")
;
; Check to make sure the string doesn't contain only blanks.
;
chararray = stringtocharacter(strings(i))
string_len = dimsizes(chararray)-1
if(any(chararray(0:string_len-1).ne.ablank(0)))
text_object = create just(i)+"string" textItemClass wks
"txString" : strings(i)
"txFontHeightF" : fhghts(i)
end create
attsetvalues_check(text_object,txres) ; Set some text resources.
anno = NhlAddAnnotation(plot,text_object) ; Add annotation to plot.
setvalues anno
"amZone" : zone ; Outside plot area
"amSide" : "top" ; Subtitle at top.
"amParallelPosF" : parallel_pos(i)
"amJust" : "bottom"+just(i)
"amOrthogonalPosF": orthogonal_pos(i) ; Move away from top edge
"amResizeNotify" : True ; Resize subtitle if map resized.
end setvalues
attsetvalues_check(anno,amres) ; Set some annotation resources.
end if
delete(chararray)
end if
end do
return
end
;***********************************************************************;
; Procedure : add_labelbar ;
; wks: graphic ;
; plot: graphic ;
; zone: integer ;
; font_height: numeric ;
; type: string ;
; res: logical ;
; ;
; This procedure adds a labelbar to "plot" (which must be either a ;
; contour or vector plot). The default is to add the labelbar to the ;
; bottom of the plot, unless resources are set to change this. The zone ;
; must be passed in, as well as the font height for the labelbar labels.;
; "type" is the type of plot ("ce", "polar", and so on) so the labelbar ;
; can be positioned differently depending on the plot. ;
;***********************************************************************;
procedure add_labelbar(wks:graphic,plot,zone:integer,font_height:numeric,\
type:string,res:logical)
local anno, num_res, amres, lbres, labelbar_object, lbar_orient, \
lbar_side, lbar_just, fill_patterns, fill_scales, mono_fill_pat, \
mono_fill_scl, mono_fill_col
begin
;
; if lbLabelBarOn is set to False, then don't bother with a labelbar.
;
if(check_attr(res,"lbLabelBarOn",False,False))
return
end if
lbres = True ; hold labelbar resources
amres = True ; hold annomanager resources
parallel = get_res_value(res,"pmLabelBarParallelPosF",0.5)
; Check for annotation/labelbar resources
lbres = get_res_eq(res,(/"lb","vp"/))
amres = get_res_eq(res,"am")
set_attr(amres,"amZone",zone)
set_attr(amres,"amResizeNotify",True)
set_attr(amres,"amParallelPosF",parallel)
set_attr(lbres,"lbLabelFontHeightF",font_height)
; Default is horizontal at the bottom.
lbar_orient = "horizontal"
lbar_side = "bottom"
lbar_just = "bottomcenter"
if(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True)) then
lbar_orient = "vertical"
lbar_side = "right"
lbar_just = "centerright"
end if
set_attr(lbres,"lbOrientation",lbar_orient)
set_attr(amres,"amSide",lbar_side)
set_attr(amres,"amJust",lbar_just)
;
; Determine what the default labelbar width and height should be depending
; on shape of plot (this is for a horizontal labelbar). For example, if
; the plot is square, then make the labelbar the same width as the plot.
; If the plot is 1:2, then make the labelbar .75 * width of the plot.
;
; For a vertical labelbar, make the height the same as the height of the
; plot.
;
getvalues plot
"vpWidthF" : width ; Width of plot
"vpHeightF" : height ; Height of plot
end getvalues
ratio1 = width/height
ratio2 = height/width
ratio = min((/ratio1,ratio2/))
ratios = (/0.50, 0.75, 1.00/) ; viewport ratios
lwscale = (/0.75, 0.90, 1.00/)
wh_ind = ind(ratio.le.ratios)
def_lvpwf = lwscale(wh_ind(0)) ; default width scale for labelbar
amres = get_res_eq(res,"am")
if(lbar_orient.eq."vertical") then
if(type.eq."polar")
orth = get_res_value(res,"pmLabelBarOrthogonalPosF",0.05)
else
orth = get_res_value(res,"pmLabelBarOrthogonalPosF",0.03)
end if
height = get_res_value(res,"pmLabelBarHeightF",height)
width = get_res_value(res,"pmLabelBarWidthF",0.2*width)
else
height = get_res_value(res,"pmLabelBarHeightF",0.3*height)
width = get_res_value(res,"pmLabelBarWidthF",def_lvpwf*width)
if(zone.eq.2)
if(type.eq."polar")
orth = get_res_value(res,"pmLabelBarOrthogonalPosF",0.03)
else
orth = get_res_value(res,"pmLabelBarOrthogonalPosF",0.06)
end if
else
orth = get_res_value(res,"pmLabelBarOrthogonalPosF",0.0)
end if
end if
set_attr(lbres,"vpHeightF",height)
set_attr(lbres,"vpWidthF",width)
set_attr(amres,"amOrthogonalPosF",orth)
class_name = NhlClassName(plot)
if(class_name.eq."logLinPlotClass".or.class_name.eq."irregularPlotClass")
the_plot = plot_at_contour
else
the_plot = plot
end if
if(class_name.eq."contourPlotClass".or.class_name.eq."logLinPlotClass".or.\
class_name.eq."irregularPlotClass")
getvalues the_plot
"cnLevels" : levels
"cnFillDotSizeF" : dot_size
"cnFillColors" : colors
"cnFillPatterns" : fill_patterns
"cnFillPattern" : fill_pattern
"cnFillScales" : fill_scales
"cnFillScaleF" : fill_scale
"cnFillMode" : fill_mode
"cnMonoFillPattern" : mono_fill_pat
"cnMonoFillScale" : mono_fill_scl
"cnMonoFillColor" : mono_fill_col
"lbLabelStrings" : lbstrings
"cnLabelBarEndLabelsOn" : end_labels_on
end getvalues
;
; Check if the fill mode is "RasterFill". If so, be sure to
; set lbRasterFillOn to True
;
if(.not.isatt(lbres,"lbRasterFillOn").and.fill_mode.eq.1)
lbres_at_lbRasterFillOn = True
end if
;
; Check if we want different fill patterns or fill scales. If so, we
; have to pass these on to the labelbar.
;
lbres_at_lbMonoFillColor = mono_fill_col
if(.not.mono_fill_pat)
lbres_at_lbMonoFillPattern = False
lbres_at_lbFillPatterns = fill_patterns
lbres_at_lbFillDotSizeF = dot_size
else
lbres_at_lbFillPattern = fill_pattern
end if
if(.not.mono_fill_scl)
lbres_at_lbMonoFillScale = False
lbres_at_lbFillScales = fill_scales
lbres_at_lbFillDotSizeF = dot_size
else
lbres_at_lbFillScaleF = fill_scale
end if
else
getvalues the_plot
"vcLevels" : levels
"vcLevelColors" : colors
"vcLabelBarEndLabelsOn" : end_labels_on
"lbLabelStrings" : lbstrings
end getvalues
end if
;
; If user set cn/vcLabelBarEndLabelsOn to True, then we need to
; add an additional label at each end.
;
if(end_labels_on) then
nlev = dimsizes(levels)
newlevels = new(nlev+2,typeof(levels))
newlevels(1:nlev) = levels
newlevels(0) = stringtoxxx(lbstrings(0),typeof(newlevels))
newlevels(nlev+1) = stringtoxxx(lbstrings(nlev+1),typeof(newlevels))
delete(levels)
levels = newlevels
delete(newlevels)
set_attr(lbres,"lbLabelAlignment","ExternalEdges")
end if
delete(lbstrings)
levels = fix_zero_contour(levels)
labelbar_object = create_labelbar(wks,dimsizes(colors),colors,levels,lbres)
anno = NhlAddAnnotation(plot,labelbar_object)
attsetvalues_check(anno,amres) ; Set annotation resources.
return
end
;***********************************************************************;
; Procedure : set_pres_hgt_axes ;
; pres: numeric ;
; res: logical ;
; add_hgt: logical ;
; ;
; This procedure sets some resources necessary to label the left and ;
; right Y axis with "nice" pressure and height values. The left axis is ;
; values, and the right for height values. The pressure values are ;
; assumed to be in millibars. ;
;***********************************************************************;
procedure set_pres_hgt_axes(pres:numeric,res:logical,add_hgt:logical)
local hgt, hnice, pnice, ptmp
begin
if(pres(0).lt.pres(dimsizes(pres)-1))
ptmp = tofloat(pres(::-1)) ; reverse values so descending order
else
ptmp = tofloat(pres) ; Make sure values are floating point.
end if
if(.not.(isatt(res,"sfYCStartV").and.isatt(res,"sfYCEndV")))
set_attr(res,"sfYArray",ptmp)
end if
;
; Set up the "nice" pressure values for which to label the left axis.
;
if(.not.isatt(res,"tmYLMode"))
res_at_tmYLMode = "Explicit" ; Define own tick mark labels.
res_at_tmYLValues = (/1000., 850., 700., 500., 400., 300., 250.,\
200., 150., 100., 70., 50., 30., 10./)
res_at_tmYLLabels = (/"1000","850","700","500","400","300","250",\
"200","150","100", "70", "50", "30", "10"/)
res_at_tmYLMinorOn= False ; No minor tick marks.
set_attr(res,"tiYAxisString","Pressure (mb)")
end if
;
; Calculate "nice" height values for which to label the right axis
;
if(.not.isatt(res,"tmYRMode"))
add_hgt = True
hgt = gsn_geop_hgt(ptmp) ; Calculate hgts as a fcn of pres.
hrange = fabs(hgt(0)-hgt(dimsizes(hgt)-1))
if(hrange.le.35) then
step = 4
else
if(hrange.le.70) then
step = 7
else
step = 10
end if
end if
;
; If user has set the resource "tmYRTickSpacingF", then use this for
; the value of the height spacing, instead of our calculated values
; above. This value must be a "nice" value, like 1, 2, 4, etc.
;
step = tointeger(get_res_value(res,"tmYRTickSpacingF",step))
; Set range of "nice" hgt values.
hnice = tofloat(ispan(tointeger(floor(hgt(0))), \
tointeger(ceil(hgt(dimsizes(hgt)-1))),step))
pnice = ftcurv(hgt,ptmp,hnice) ; Get pres vals at nice hgt vals.
use_left = get_res_value_keep(res,"tmYUseLeft",False)
yrvalues = get_res_value_keep(res,"tmYRValues",pnice)
yrlabels = get_res_value_keep(res,"tmYRLabels",hnice)
yron = get_res_value_keep(res,"tmYROn",True)
yrlabelson = get_res_value_keep(res,"tmYRLabelsOn",True )
yrminoron = get_res_value_keep(res,"tmYRMinorOn",False)
;
; At each "nice" pressure value put a "height" value label, unless
; the user has specified own labels. The user has to know what he's
; doing if he specifies own labels, because the values must be in pressure
; units, not height units.
;
if(.not.isatt(res,"tmYRValues")) then
res_at_tmYRValues = yrvalues
end if
if(.not.isatt(res,"tmYRLabels")) then
res_at_tmYRLabels = yrlabels
end if
res_at_tmYRMode = "Explicit"
res_at_tmYUseLeft = use_left
res_at_tmYROn = yron
res_at_tmYRLabelsOn = yrlabelson
res_at_tmYRMinorOn = yrminoron
delete(hnice)
delete(hgt)
delete(pnice)
else
add_hgt = False
end if
delete(ptmp)
return
end
;***********************************************************************;
; Function : fill_xy_ref ;
; wks: graphic ;
; xy: graphic ;
; xin[*]: numeric ;
; yin[*]: numeric ;
; ref: numeric ;
; ref_line_above_color: integer or string or RGB value ;
; ref_line_below_color: integer or string or RGB value ;
; ;
; Take a set of X and Y points, and fill the Y points in one color if ;
; they are above the ref line, and in another color if they are below ;
; the ref line. ;
;***********************************************************************;
function fill_xy_ref(wks:graphic,xy:graphic,xin[*]:numeric,yin[*]:numeric,\
ref:numeric,ref_line_above_color,ref_line_below_color)
local npts, yabove_gon, ybelow_gon, i, gsresa, gsresb, gsresr, \
fill_above, fill_below
begin
npts = dimsizes(yin)
anumgons = 0 ; Count the number of polygons
bnumgons = 0
if(ref_line_above_color.ne.-1)
gsresa = True
gsresa_at_gsFillColor = ref_line_above_color
;
; First count the number of the above-the-y-reference-line polygons we
; need to create.
;
igon = 0
create_gon = False
do i=0,npts-1
if(.not.ismissing(yin(i)).and..not.ismissing(xin(i)))
if(yin(i).ge.ref)
if(igon.eq.0)
igon = 1
else
igon = igon + 1
end if
if(i.eq.npts-1) ; On the last point.
create_gon = True
end if
else
create_gon = True
end if
else
create_gon = True
end if ; not ismissing
if(create_gon)
if(igon.gt.1)
anumgons = anumgons + 1
end if
igon = 0
create_gon = False
end if
end do
end if
if(ref_line_below_color.ne.-1)
gsresb = True
gsresb_at_gsFillColor = ref_line_below_color
;
; First count the number of the above-the-y-reference-line polygons we
; need to create.
;
igon = 0
create_gon = False
do i=0,npts-1
if(.not.ismissing(yin(i)).and..not.ismissing(xin(i)))
if(yin(i).le.ref)
if(igon.eq.0)
igon = 1
else
igon = igon + 1
end if
if(i.eq.npts-1) ; On the last point.
create_gon = True
end if
else
create_gon = True
end if
else
create_gon = True
end if ; not ismissing
if(create_gon)
if(igon.gt.1)
bnumgons = bnumgons + 1
end if
igon = 0
create_gon = False
end if
end do
end if
if(anumgons.gt.0.or.bnumgons.gt.0) then
polygons = new(anumgons+bnumgons,graphic)
else
polygons = new(1,graphic)
end if
;
; Loop through and add above-ref-line polygons.
;
ngons = 0
if(ref_line_above_color.ne.-1.and.anumgons.gt.0)
igon = 0
create_gon = False
do i=0,npts-1
if(.not.ismissing(yin(i)).and..not.ismissing(xin(i)))
if(yin(i).ge.ref)
if(igon.eq.0)
xabove_line = new(npts+2,typeof(xin))
yabove_line = new(npts+2,typeof(yin))
yabove_line(0) = yin(i)
xabove_line(0) = xin(i)
igon = 1
else
xabove_line(igon) = xin(i)
yabove_line(igon) = yin(i)
igon = igon + 1
end if
if(i.eq.npts-1) ; On the last point.
create_gon = True
end if
else
create_gon = True
end if
else
create_gon = True
end if ; not ismissing
if(create_gon)
if(igon.gt.1)
yabove_gon = new((/igon+3/),typeof(yin))
xabove_gon = new((/igon+3/),typeof(xin))
; Close up and draw polygon
if(yabove_line(0).ne.ref)
xabove_gon(0) = xabove_line(0)
yabove_gon(0) = ref
xabove_gon(1:igon) = xabove_line(0:igon-1)
yabove_gon(1:igon) = yabove_line(0:igon-1)
newgon = igon + 1
else
xabove_gon(0:igon-1) = xabove_line(0:igon-1)
yabove_gon(0:igon-1) = yabove_line(0:igon-1)
newgon = igon
end if
if(yabove_line(igon-1).ne.ref)
xabove_gon(newgon) = xabove_line(igon-1)
yabove_gon(newgon) = ref
newgon = newgon + 1
end if
polygons(ngons) = gsn_add_polygon(wks,xy,xabove_gon(0:newgon-1),\
yabove_gon(0:newgon-1),gsresa)
ngons = ngons + 1
; Delete temporary arrays so we can recreate them.
delete(xabove_line)
delete(yabove_line)
delete(xabove_gon)
delete(yabove_gon)
end if
igon = 0
create_gon = False
end if
end do
end if
;
; Loop through and add below-ref-line polygons.
;
if(ref_line_below_color.ne.-1.and.bnumgons.gt.0) then
igon = 0
create_gon = False
do i=0,npts-1
if(.not.ismissing(yin(i)).and..not.ismissing(xin(i)))
if(yin(i).le.ref)
if(igon.eq.0)
xbelow_line = new(npts+2,typeof(xin))
ybelow_line = new(npts+2,typeof(yin))
ybelow_line(0) = yin(i)
xbelow_line(0) = xin(i)
igon = 1
else
xbelow_line(igon) = xin(i)
ybelow_line(igon) = yin(i)
igon = igon + 1
end if
if(i.eq.npts-1) ; On the last point.
create_gon = True
end if
else
create_gon = True
end if
else
create_gon = True
end if ; not ismissing
if(create_gon)
if(igon.gt.1)
ybelow_gon = new((/igon+3/),typeof(yin))
xbelow_gon = new((/igon+3/),typeof(xin))
; Close up and draw polygon
if(ybelow_line(0).ne.ref)
xbelow_gon(0) = xbelow_line(0)
ybelow_gon(0) = ref
xbelow_gon(1:igon) = xbelow_line(0:igon-1)
ybelow_gon(1:igon) = ybelow_line(0:igon-1)
newgon = igon + 1
else
xbelow_gon(0:igon-1) = xbelow_line(0:igon-1)
ybelow_gon(0:igon-1) = ybelow_line(0:igon-1)
newgon = igon
end if
if(ybelow_line(igon-1).ne.ref)
xbelow_gon(newgon) = xbelow_line(igon-1)
ybelow_gon(newgon) = ref
newgon = newgon + 1
end if
polygons(ngons) = gsn_add_polygon(wks,xy,xbelow_gon(0:newgon-1), \
ybelow_gon(0:newgon-1),gsresb)
ngons = ngons + 1
; Delete temporary arrays so we can recreate them.
delete(xbelow_line)
delete(ybelow_line)
delete(xbelow_gon)
delete(ybelow_gon)
end if
igon = 0
create_gon = False
end if
end do
end if
return(polygons)
end
;***********************************************************************;
; Function : fill_xy2 ;
; ;
; This function takes as input two Y curves, defined on the same set ;
; of X points, and fills the area between the two curves with two ;
; different colors, depending on which curve is above the other one. ;
; ;
;***********************************************************************;
function fill_xy2(wks,plot,xi:numeric,yi1:numeric,yi2:numeric,colora,colorb)
local nx, ny1, ny2, y1_gt_y2, i, ab, bpt, ept, x, y1, y2, color, first, last
begin
res = True
;
; Check length of arrays.
;
nx = dimsizes(xi)
ny1 = dimsizes(yi1)
ny2 = dimsizes(yi2)
if(nx.ne.ny1.or.nx.ne.ny2.or.nx.lt.2)
print("fill_xy2: Error: x and y arrays must be the same length and at least two elements")
return
end if
if(any(ismissing(xi)))
print("fill_xy2: Error: The x array cannot contain any missing values")
return
end if
;
; Convert input arrays to double.
;
; If both y arrays are equal to each other, then just return.
;
if(all(yi1.eq.yi2))
return(plot)
end if
;
; Convert input arrays to double.
;
x = new(dimsizes(xi),double)
y1 = new(ny1,double,1.e36)
y2 = new(ny1,double,1.e36)
x = (/xi/)
y1 = (/yi1/)
y2 = (/yi2/)
res_at_gsFillColor = colora ; Color for when first curve is > second curve
;
; Compute a delta that will be used to determine if two points are
; actually the same point.
;
range_y1 = max(y1) - min(y1)
range_y2 = max(y2) - min(y2)
delta_y1 = 0.01 * range_y1
delta_y2 = 0.01 * range_y2
if(delta_y1.eq.0)
delta = delta_y2
else
if(delta_y2.eq.0)
delta = delta_y1
else
delta = min((/delta_y1,delta_y2/))
end if
end if
;
; Create arrays for storing polygon points.
;
first = new(2,double)
last = new(2,double)
polygon_x = new(2*nx+3,double)
polygon_y = new(2*nx+3,double)
npoly = 0 ; Number of polygons
;
; First fill in polygons where y1 is above y2, and then fill in
; polygons where y2 is above y1.
;
do ab = 0,1
if(ab.eq.1)
y1 = (/yi2/)
y2 = (/yi1/)
res_at_gsFillColor = colorb ; Color for when first curve is > second curve
end if
;
; Get areas where y1 > y2.
;
y1_gt_y2 = y1.gt.y2
bpt = -1 ; Index of first point of polygon.
ept = -1 ; Index of last point of polygon.
;
; Loop through points.
;
do i=0,nx-1
if(bpt.lt.0)
if(.not.ismissing(y1_gt_y2(i)).and.y1_gt_y2(i))
bpt = i
ept = i
end if
else
if(.not.ismissing(y1_gt_y2(i)).and.y1_gt_y2(i))
ept = i
end if
if(ismissing(y1_gt_y2(i)).or..not.y1_gt_y2(i).or.ept.eq.(nx-1))
;
; Draw polygon, If bpt is the very first point or ept is the
; very last point, then these are special cases we have to
; handle separately.
;
if(bpt.eq.0.or.(bpt.gt.0.and.(ismissing(y1(bpt-1)).or.\
ismissing(y2(bpt-1)).or.\
ismissing(x(bpt-1)))))
first(0) = x(bpt)
first(1) = y2(bpt)
else
if(fabs(y1(bpt-1)-y2(bpt-1)).le.delta)
;
; If the two points are within delta of each other, then we'll
; consider them to be the same point.
;
first(0) = x(bpt-1)
first(1) = y1(bpt-1)
else
;
; Otherwise, find the intersection where the two curves cross.
;
first = find_cross_xy(x(bpt-1),x(bpt),y1(bpt-1), \
y1(bpt),y2(bpt-1),y2(bpt))
end if
end if
if(ept.eq.(nx-1).or.(ept.lt.(nx-1).and.(ismissing(y1(ept+1)).or.\
ismissing(y2(ept+1)).or.\
ismissing(x(ept+1)))))
last(0) = x(ept)
last(1) = y2(ept)
else
if(fabs(y1(ept+1)-y2(ept+1)).le.delta)
;
; If the two points are within delta of each other, then we'll
; consider them to be the same point.
;
last(0) = x(ept+1)
last(1) = y1(ept+1)
else
;
; Otherwise, find the intersection where the two curves cross.
;
last = find_cross_xy(x(ept),x(ept+1),y1(ept),y1(ept+1), \
y2(ept),y2(ept+1))
end if
end if
;
; Initialize polygon.
;
npts = ept - bpt + 1
npts2 = npts * 2
polygon_x(0) = first(0)
polygon_y(0) = first(1)
polygon_x(1:npts) = x(bpt:ept)
polygon_y(1:npts) = y1(bpt:ept)
polygon_x(npts+1) = last(0)
polygon_y(npts+1) = last(1)
polygon_x(npts+2:npts2+1) = x(ept:bpt)
polygon_y(npts+2:npts2+1) = y2(ept:bpt)
polygon_x(npts2+2) = first(0)
polygon_y(npts2+2) = first(1)
;
; Make sure polygons get drawn *after* the plot gets drawn.
;
if(npoly.eq.0)
setvalues plot
"tfPolyDrawOrder" : "Predraw"
end setvalues
end if
;
; Add polygon to XY plot.
;
var_string = unique_string("fill_polygon"+npoly)
plot@$var_string$ = gsn_add_polygon(wks,plot, \
polygon_x(0:npts2+2), \
polygon_y(0:npts2+2),res)
;
; Advance polygon counter.
;
npoly = npoly + 1
bpt = -1 ; Reinitialize
ept = -1
end if
end if
end do
end do
return(plot)
end
;***********************************************************************;
; Function : get_lon_values ;
; min_lon: numeric ;
; max_lon: numeric ;
; lon_spacing: numeric ;
; mlon_spacing: numeric ;
; ;
; Calculate "nice" longitude values to use for placing longitude labels ;
; an axis. min_lon and max_lon are the min/max longitude values, and ;
; lon_spacing and mlon_spacing are the spacings to use for major and ;
; minor tickmarks. ;
;***********************************************************************;
function get_lon_values(min_lon:numeric,max_lon:numeric,lon_spacing:numeric,\
mlon_spacing:numeric,range_array,lonspacing_array, \
mlonspacing_array)
local lon_range, lcheck_arr, lspcng_arr, mlspcng_arr, lon_spcng, mlon_spcng, \
start_lon, end_lon, xstart_lon, xend_lon
begin
; Initialize
if(all(range_array.eq.0))
lcheck_arr = (/ 20, 40, 60, 360/) ; lon range will determine
; spacing of minor/major ticks
else
lcheck_arr = range_array
end if
if(all(lonspacing_array.eq.0))
lspcng_arr = (/ 5, 10, 20, 30/) ; spacings for major ticks
else
lspcng_arr = lonspacing_array
end if
if(all(mlonspacing_array.eq.0))
mlspcng_arr = (/ 1, 2, 5, 10/) ; spacings for minor ticks
else
mlspcng_arr = mlonspacing_array
end if
; Longitude range, will help determine longitude spacing.
lon_range = max_lon - min_lon ; lat/lon range
if(lon_range.gt.360)
print("get_lon_values: Warning: The range your of longitude values is greater than 360.")
lon_ind = dimsizes(lcheck_arr)-1
else
lon_ind = ind(lon_range.le.lcheck_arr)
end if
if(lon_spacing.le.0)
lon_spcng = lspcng_arr(lon_ind(0)) ; spacing for lon major tickmarks
else
lon_spcng = tointeger(lon_spacing)
end if
if(mlon_spacing.le.0)
mlon_spcng = mlspcng_arr(lon_ind(0)) ; spacing for lon minor tickmarks
else
mlon_spcng = tointeger(mlon_spacing)
end if
delete(lon_ind)
;
; This code will find the first integer value that is divisible
; by the major lon spacing value. This will end up being the first
; labeled longitude value.
;
start_lon = floattointeger(ceil(tofloat(min_lon)))
end_lon = floattointeger(floor(tofloat(max_lon)))
lon = start_lon
found = False
do while(lon.le.end_lon.and..not.found)
if((lon % lon_spcng).eq.0)
start_lon = lon
found = True
end if
lon = lon + 1
end do
; Calculate values for major and minor lon tickmark locations.
lon_values = ispan(start_lon,end_lon,lon_spcng)
lon_values_at_minor = ispan(min(lon_values)-lon_spcng,max(lon_values)+lon_spcng,mlon_spcng)
return(lon_values)
end
;***********************************************************************;
; Function : get_lat_values ;
; min_lat: numeric ;
; max_lat: numeric ;
; lat_spacing: numeric ;
; mlat_spacing: numeric ;
; ;
; Calculate "nice" latitude values to use for placing latitude labels ;
; an axis. min_lat and max_lat are the min/max latitude values, and ;
; lat_spacing and mlat_spacing are the spacings to use for major and ;
; minor tickmarks. ;
;***********************************************************************;
function get_lat_values(min_lat:numeric,max_lat:numeric,lat_spacing:numeric,\
mlat_spacing:numeric)
local lat_range, lcheck_arr, lspcng_arr, mlspcng_arr, lat_spcng, mlat_spcng, \
start_lat, end_lat, lat, found
begin
; Initialize
if(min_lat.lt.-90.or.max_lat.gt.90) then
print("get_lat_values: Warning: Your latitude values do not fall between -90 and 90 inclusive.")
print("You will not get 'nice' latitude labels.")
lat_values = new(1,float,-999)
return(lat_values)
end if
lcheck_arr = (/ 20, 40, 60, 180/) ; lat range will determine
; spacing of minor/major ticks
lspcng_arr = (/ 5, 10, 20, 30/) ; spacings for major ticks
mlspcng_arr = (/ 1, 2, 5, 10/) ; spacings for minor ticks
; Latitude range, will help determine latitude spacing.
lat_range = max_lat - min_lat ; lat/lat range
lat_ind = ind(lat_range.le.lcheck_arr)
if(lat_spacing.le.0)
lat_spcng = lspcng_arr(lat_ind(0)) ; spacing for lat major tickmarks
else
lat_spcng = tointeger(lat_spacing)
end if
if(mlat_spacing.le.0)
mlat_spcng = mlspcng_arr(lat_ind(0)) ; spacing for lat minor tickmarks
else
mlat_spcng = tointeger(mlat_spacing)
end if
delete(lat_ind)
;
; This code will find the first integer value that is divisible
; by the major lat spacing value. This will end up being the first
; labeled latitude value.
;
start_lat = floattointeger(ceil(tofloat(min_lat)))
end_lat = floattointeger(floor(tofloat(max_lat)))
lat = start_lat
found = False
do while(lat.le.end_lat.and..not.found)
if((lat % lat_spcng).eq.0)
start_lat = lat
found = True
end if
lat = lat + 1
end do
; Calculate values for major and minor lat tickmark locations.
lat_values = ispan(start_lat,end_lat,lat_spcng)
lat_values_at_minor = ispan(min(lat_values)-lat_spcng,max(lat_values)+lat_spcng,mlat_spcng)
return(lat_values)
end
;***********************************************************************;
; Function : get_lon_labels ;
; lon_values[*]: numeric ;
; ;
; Return some nice longitude labels given longitude values "lon_values".;
;***********************************************************************;
function get_lon_labels(lon_values:numeric)
local lon_index
begin
lon_labels = new(dimsizes(lon_values),string)
; -180 < lon < 0 (west)
lon_index = ind((lon_values).lt.0)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = fabs(lon_values(lon_index)) + "W" ; west
end if
delete(lon_index)
; 0 < lon < 180 (east)
lon_index = ind(lon_values.gt.0.and.lon_values.lt.180)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = lon_values(lon_index) + "E" ; east
end if
delete(lon_index)
; 180 < lon < 360 (west)
lon_index = ind(lon_values.gt.180.and.lon_values.lt.360)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = 360-lon_values(lon_index) + "W" ; west
end if
delete(lon_index)
; 360 < lon < 540 (east)
lon_index = ind(lon_values.gt.360.and.lon_values.lt.540)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = lon_values(lon_index)-360 + "E" ; east
end if
delete(lon_index)
; 540 < lon < 720 (west)
lon_index = ind(lon_values.gt.540.and.lon_values.lt.720)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = 540-lon_values(lon_index) + "W" ; west
end if
delete(lon_index)
; lon = +/-180 or lon=540 (180)
lon_index = ind(fabs(lon_values).eq.180.or.lon_values.eq.540)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = "180"
end if
delete(lon_index)
; lon=0, lon=360, or lon=720 (0)
lon_index = ind(lon_values.eq.0.or.lon_values.eq.360.or.lon_values.eq.720)
if(.not.all(ismissing(lon_index)))
lon_labels(lon_index) = "0"
end if
delete(lon_index)
return(lon_labels)
end
;***********************************************************************;
; Function : get_lat_labels ;
; lat_values[*]: numeric ;
; ;
; Return some nice latitude labels given latitude values "lat_values". ;
;***********************************************************************;
function get_lat_labels(lat_values:numeric)
local lat_index
begin
; Create labels for latitude tick marks.
lat_labels = new(dimsizes(lat_values),string)
lat_index = ind(lat_values.lt.0)
if(.not.all(ismissing(lat_index)))
lat_labels(lat_index) = fabs(lat_values(lat_index)) + "S" ; south
end if
delete(lat_index)
lat_index = ind(lat_values.gt.0)
if(.not.all(ismissing(lat_index)))
lat_labels(lat_index) = lat_values(lat_index) + "N" ; north
end if
delete(lat_index)
lat_index = ind(lat_values.eq.0)
if(.not.all(ismissing(lat_index)))
lat_labels(lat_index) = lat_values(lat_index) ; equator
end if
delete(lat_index)
return(lat_labels)
end
;***********************************************************************;
; Function : add_lon_labels ;
; plot: graphic ;
; min_lon: numeric ;
; max_lon: numeric ;
; lon_spacing: numeric ;
; mlon_spacing: numeric ;
; res: logical ;
; ;
; Add "nice" longitude labels ("120W", "60E", etc) to the X axis. ;
;***********************************************************************;
procedure add_lon_labels(plot:graphic,min_lon:numeric,max_lon:numeric,\
lon_spacing:numeric,mlon_spacing:numeric,\
range_array,lonspacing_array,mlonspacing_array, \
res:logical)
local tmres, lonvalues, lonlabels
begin
tmres = get_res_eq(res,(/"tm","ti"/)) ; Get tickmark resources
lon_spacing2 = get_res_value(tmres,"tmXBTickSpacingF",lon_spacing)
lonvalues = get_lon_values(min_lon,max_lon,lon_spacing2,mlon_spacing,\
range_array,lonspacing_array,mlonspacing_array)
if(.not.any(ismissing(lonvalues)))
lonlabels = get_lon_labels(lonvalues)
tmres = True
set_attr(tmres,"tmXBMode" , "Explicit")
set_attr(tmres,"tmXBLabels" , lonlabels)
set_attr(tmres,"tmXBValues" , lonvalues)
set_attr(tmres,"tmXBMinorValues" , lonvalues_at_minor)
;
; If the user has set tiXAxisString explicitly, then don't set tiXAxisOn
; to False.
;
if(.not.(isatt(tmres,"tiXAxisString").and.tmres_at_tiXAxisString.ne.""))
set_attr(tmres,"tiXAxisOn" , False)
end if
attsetvalues(plot,tmres)
end if
return
end
;***********************************************************************;
; Procedure : add_lat_labels_xaxis ;
; plot: graphic ;
; min_lat: numeric ;
; max_lat: numeric ;
; lat_spacing: numeric ;
; mlat_spacing: numeric ;
; res: logical ;
; ;
; ;
; Add "nice" latitude labels ("90S", "30N", etc) to the X axis in ;
; "plot". ;
;***********************************************************************;
procedure add_lat_labels_xaxis(plot:graphic,min_lat:numeric,max_lat:numeric,\
lat_spacing:numeric,mlat_spacing:numeric, \
res:logical)
local tmres, latvalues, latlabels
begin
tmres = get_res_eq(res,(/"tm","ti"/)) ; Get tickmark resources
lat_spacing2 = get_res_value(tmres,"tmXBTickSpacingF",lat_spacing)
latvalues = get_lat_values(min_lat,max_lat,lat_spacing2,mlat_spacing)
if(.not.any(ismissing(latvalues)))
latlabels = get_lat_labels(latvalues)
tmres = True
set_attr(tmres,"tmXBMode" , "Explicit")
set_attr(tmres,"tmXBLabels" , latlabels)
set_attr(tmres,"tmXBValues" , latvalues)
set_attr(tmres,"tmXBMinorValues" , latvalues_at_minor)
;
; If the user has set tiXAxisString explicitly, then don't set tiXAxisOn
; to False.
;
if(.not.(isatt(tmres,"tiXAxisString").and.tmres_at_tiXAxisString.ne.""))
set_attr(tmres,"tiXAxisOn" , False)
end if
attsetvalues(plot,tmres)
end if
return
end
;***********************************************************************;
; Procedure : add_lat_labels_yaxis ;
; plot: graphic ;
; min_lat: numeric ;
; max_lat: numeric ;
; lat_spacing: numeric ;
; mlat_spacing: numeric ;
; res: logical ;
; ;
; Add "nice" latitude labels ("90S", "30N", etc) to the Y axis in ;
; "plot". ;
;***********************************************************************;
procedure add_lat_labels_yaxis(plot:graphic,min_lat:numeric,max_lat:numeric,\
lat_spacing:numeric,mlat_spacing:numeric, \)
res:logical)
local tmres, latvalues, latlabels
begin
tmres = get_res_eq(res,(/"tm","ti"/)) ; Get tickmark resources
lat_spacing2 = get_res_value(tmres,"tmYLTickSpacingF",lat_spacing)
latvalues = get_lat_values(min_lat,max_lat,lat_spacing2,mlat_spacing)
if(.not.any(ismissing(latvalues)))
latlabels = get_lat_labels(latvalues)
tmres = True
set_attr(tmres,"tmYLMode" , "Explicit")
set_attr(tmres,"tmYLLabels" , latlabels)
set_attr(tmres,"tmYLValues" , latvalues)
set_attr(tmres,"tmYLMinorValues" , latvalues_at_minor)
;
; If the user has set tiYAxisString explicitly, then don't set tiYAxisOn
; to False.
;
if(.not.(isatt(tmres,"tiYAxisString").and.tmres_at_tiYAxisString.ne.""))
set_attr(tmres,"tiYAxisOn" , False)
end if
attsetvalues(plot,tmres)
end if
return
end
;***********************************************************************;
; Procedure : add_latlon_labels ;
; plot: graphic ;
; data: numeric ;
; res: logical ;
; ;
; Add "nice" latitude/longitude labels ("90S", "30N", etc) to the X/Y ;
; axes if the appropriate lat/lon coordinate arrays exist. ;
; ;
;***********************************************************************;
procedure add_latlon_labels(plot:graphic,data:numeric,res:logical)
local min_lat, max_lat, min_lon, max_lon, lat_spacing
begin
;
; If the plot coming in is an XY plot, then it won't have
; coordinate variables associated with it. Instead, we have
; to determine if it's the X or Y data coming in, and then see
; if the data contains a valid "units" attribute.
;
is_xyplot = get_res_value_keep(res,"gsnXYPlot", False)
is_xaxis = get_res_value_keep(res,"gsnXAxis", False)
is_yaxis = get_res_value_keep(res,"gsnYAxis", False)
if((is_xyplot.and.is_xaxis.and.isatt(data,"units").and. \
any(data_at_units.eq.get_allowed_lat_units)).or. \
(.not.is_xyplot.and.is_valid_latlon_coord(data,"x","lat",res))) then
; Label X axis with nice latitude labels.
getvalues plot
"trXMinF" : min_lat
"trXMaxF" : max_lat
end getvalues
add_lat_labels_xaxis(plot,min_lat,max_lat,0,0,res)
else
if((is_xyplot.and.is_xaxis.and.isatt(data,"units").and. \
any(data_at_units.eq.get_allowed_lon_units)).or. \
(.not.is_xyplot.and.is_valid_latlon_coord(data,"x","lon",res))) then
; Label X axis with nice longitude labels.
getvalues plot
"trXMinF" : min_lon
"trXMaxF" : max_lon
end getvalues
;
; We want different defaults for longitude spacing, so set them up here.
;
lon_range = (/ 20, 40, 60, 180, 360/)
lon_spacing_arr = (/ 10, 20, 30, 45, 60/)
mlon_spacing_arr = (/ 5, 5, 10, 15, 30/)
add_lon_labels(plot,min_lon,max_lon,0,0,lon_range, \
lon_spacing_arr,mlon_spacing_arr,res)
else
;
; Only set a X axis label if it is not a lon axis.
;
if((is_xyplot.and.is_xaxis).or..not.is_xyplot) then
set_axis_string(plot,res,data,"x")
end if
end if
end if
if((is_xyplot.and.is_yaxis.and.isatt(data,"units").and. \
any(data_at_units.eq.get_allowed_lat_units)).or. \
(.not.is_xyplot.and.is_valid_latlon_coord(data,"y","lat",res))) then
; Label Y axis with nice latitude labels.
getvalues plot
"trYMinF" : min_lat
"trYMaxF" : max_lat
end getvalues
add_lat_labels_yaxis(plot,min_lat,max_lat,0,0,res)
else
;
; Only set a Y axis label if it is not a lat axis.
;
if((is_xyplot.and.is_yaxis).or..not.is_xyplot) then
set_axis_string(plot,res,data,"y")
end if
end if
end
;***********************************************************************;
; Procedure : add_map_tickmarks ;
; plot:object ;
; res:logical ;
; font_height:numeric ;
; ;
; This procedure adds tickmarks to a C.E. map projection. ;
;***********************************************************************;
procedure add_map_tickmarks(wks:graphic,map:graphic,tmres:logical, \
lon_spacing,mlon_spacing,lat_spacing,\
mlat_spacing,point_outward)
local vpxf, vpyf, vpwf, vphf, min_lon, max_lon, min_lat, max_lat, \
center_lon, lonvalues, latvalues, lonlabels, latlabels, tickmark
begin
; Retrieve the view port location of the map plot so we know where
; to put lat/lon labels.
getvalues map
"vpXF" : vpxf
"vpYF" : vpyf
"vpWidthF" : vpwf
"vpHeightF" : vphf
"mpLimitMode" : limit_mode
end getvalues
;
; We allow either mpLimitMode to be "LatLon" (1) or "Corners" (5)
;
if(limit_mode.eq.1)
getvalues map
"mpMinLonF" : min_lon
"mpMaxLonF" : max_lon
"mpMinLatF" : min_lat
"mpMaxLatF" : max_lat
"mpCenterLonF" : center_lon
end getvalues
else
if(limit_mode.eq.5)
getvalues map
"mpLeftCornerLonF" : min_lon
"mpRightCornerLonF" : max_lon
"mpLeftCornerLatF" : min_lat
"mpRightCornerLatF" : max_lat
"mpCenterLonF" : center_lon
end getvalues
else
print("add_map_tickmarks: Warning: you cannot use mpLimitMode=" + limit_mode + " with the gsm_csm_map routines")
return
end if
end if
; Create tickmark values for lat/lon labels.
lonvalues = get_lon_values(min_lon,max_lon,lon_spacing,mlon_spacing,0,0,0)
latvalues = get_lat_values(min_lat,max_lat,lat_spacing,mlat_spacing)
; Create labels for lat/lon tick marks.
latlabels = get_lat_labels(latvalues)
lonlabels = get_lon_labels(lonvalues)
; Create a TickMark object to label lat/lon grid.
tickmark = create "tickmarks" tickMarkClass wks
"vpXF" : vpxf ; Set the viewport location of the
"vpYF" : vpyf ; tick marks to be the same as
"vpWidthF" : vpwf ; the map.
"vpHeightF" : vphf
"tmYLDataBottomF" : min_lat ; Use the lat/lon limits
"tmYLDataTopF" : max_lat ; from the coordinate variables.
"tmXBDataLeftF" : min_lon
"tmXBDataRightF" : max_lon
"tmXBMode" : "Explicit" ; Indicate that we want to
"tmXBLabels" : lonlabels ; explicitly label the X axis.
"tmXBValues" : lonvalues
"tmXBMinorValues" : lonvalues_at_minor
"tmYLMode" : "Explicit" ; Indicate that we want to
"tmYLLabels" : latlabels ; explicitly label the Y axis.
"tmYLValues" : latvalues
"tmYLMinorValues" : latvalues_at_minor
end create
attsetvalues_check(tickmark,tmres)
; Point tick marks outward and make labels the same size.
gsnp_point_tickmarks_outward(tickmark,tmres,-1.,-1.,-1.,-1.,-1.,-1.,\
point_outward)
gsnp_uniform_tickmark_labels(tickmark,tmres,0.)
;
; Add the tick mark object as an annotation of the map object, so that
; whenever the map object is drawn the tick mark object will also be
; drawn. It will also be rescaled automatically.
;
anno = NhlAddAnnotation(map,tickmark)
setvalues anno
"amZone" : 0 ; Zone 0 centers tick marks over map.
"amResizeNotify" : True ; Resize tick marks if map resized.
end setvalues
map_at_tickmarks = tickmark
return
end
;***********************************************************************;
; Function : gsn_add_cyclic_point ;
; data : numeric ;
; ;
; Add a cyclic point in "x" to the 2D array "data". ;
; For a lat/lon plot "x" corresponds to "lon" ;
; "ny" corresponds to "nlat" ;
; "mx" corresponds to "mlon" ;
; ;
; If a lat/lon coordinate doesn't exist, then the data is tested to see ;
; if it contains a lat2d/lon2d attribute, and uses this instead. ;
;***********************************************************************;
function gsn_add_cyclic_point(data:numeric)
local dims, newdata, ny, mx, mx1, range, delta, first_val, second_val, \
last_val
begin
;
; If the data is 1D, no cyclic point should be added.
;
dims = dimsizes(data)
if(dimsizes(dims).eq.1) then
return(data)
end if
ny = dims(0)
mx = dims(1)
mx1 = mx+1
newdata = new((/ny, mx1/),typeof(data))
newdata(:,0:mx-1) = data ; pass everything
newdata(:,mx) = (/ data(:,0) /) ; value only
;
; Only check the longitude values if we are dealing with a 1D coordinate
; array. It is possible that if we have a 2D longitudate "coordinate"
; array, it will not be 360 in range, so we don't want to check 2D arrays.
;
res = False
if(is_valid_latlon_coord(newdata,"x","lon",res)) then
first_val = newdata&$newdata!1$(0)
second_val = newdata&$newdata!1$(1)
last_val = newdata&$newdata!1$(mx-1)
delta = second_val - first_val
range = last_val - first_val
if(range.ge.360.)
print("gsn_add_cyclic: Warning: The range of your longitude coordinate array is at least 360.")
print("You may want to set gsnAddCyclic to False to avoid a warning")
print("message from the spline function.")
end if
if(any((range+delta).lt.359.))
print("gsn_add_cyclic: Warning: The range of your longitude data is not 360.")
print("You may want to set gsnAddCyclic to False to avoid a warning")
print("message from the spline function.")
end if
else
if(.not.(isatt(newdata,"lon2d").and.isatt(newdata,"lat2d"))) then
return(newdata)
else
if(.not.all(dimsizes(newdata_at_lon2d).eq.dimsizes(newdata_at_lat2d))) then
print("gsn_add_cyclic: Warning: Your lat2d/lon2d attributes must have the same dimension sizes.")
end if
end if
end if
if(is_valid_latlon_coord(newdata,"x","lon",res)) then
newdata&$newdata!1$(mx) = newdata&$newdata!1$(0) + 360
else
;
; Have to store lat2d/lon2d to a local variable, because NCL
; doesn't let you subscript attributes that are greater than
; one dimension.
;
lon2d = newdata_at_lon2d
lat2d = newdata_at_lat2d
lon_dims = dimsizes(lon2d)
nlat = lon_dims(0)
nlon = lon_dims(1)
nlon1 = nlon+1
new_lon2d = new((/nlat,nlon1/),typeof(lon2d))
new_lat2d = new((/nlat,nlon1/),typeof(lat2d))
new_lon2d(:,0:nlon-1) = lon2d
new_lon2d(:,nlon) = lon2d(:,0)
new_lat2d(:,0:nlon-1) = lat2d
new_lat2d(:,nlon) = (new_lat2d(:,0) + new_lat2d(:,nlon-1))/2.
delete(newdata_at_lon2d)
delete(newdata_at_lat2d)
newdata_at_lon2d = new_lon2d
newdata_at_lat2d = new_lat2d
delete(lon2d)
delete(lat2d)
end if
return(newdata)
end
;***********************************************************************;
; Function : pop_tick_locs ;
; lonorlat : numeric ;
; locs : numeric ;
; ;
; This function calculates tickmark values for placing tick marks on a ;
; plot that has a POP grid overlaid on it. ;
; ;
;***********************************************************************;
function pop_tick_locs(lonorlat,locs)
local ret, i, in, j1, j0
begin
ret = new(dimsizes(locs),typeof(lonorlat))
do i =0 , dimsizes(locs)-1
in = ind(lonorlat.gt.locs(i))
j1 = in(0)
j0 = in(0)-1
delete(in)
ret(i) = j0 + (lonorlat(j1)-locs(i))/(lonorlat(j1) -lonorlat(j0))
end do
return(ret)
end
;***********************************************************************;
; Procedure : pop_latlon_grid ;
; wks: graphic ;
; plot: graphic ;
; popgrid: string ;
; ;
; This procedure overlays a POP grid on a plot. ;
;***********************************************************************;
procedure pop_latlon_grid(wks:graphic,plot:graphic,popgrid:string)
local latlon_res, tmplon, lat_object, lon_object, valid_popgrids, \
popgrid_dir, popgrid_files, i, found
begin
;
; Open POP grid that contains lat/lon information.
;
popgrid_dir = "/fs/cgd/data0/shea/pop/"
valid_popgrids = (/"POP23"/) ; list of valid POP grids
popgrid_files = (/"POP23PCM.nc"/) ; list of corresponding POP files
if(.not.any(popgrid.eq.valid_popgrids))
print("pop_latlon_grid: "+popgrid+" is not a supported POP grid.")
print(" Supported POP grids include: " + valid_popgrids)
print(" No grid will be overlaid.")
return
end if
i = 0
found = False
do while(i.lt.dimsizes(valid_popgrids).and..not.found)
if(popgrid.eq.valid_popgrids(i))
a = addfile(popgrid_dir + popgrid_files(i),"r")
found = True
end if
i = i + 1
end do
;
; Set up list of latitude and longitude resources.
;
latlon_res = True
latlon_res_at_gsnDraw = False
latlon_res_at_gsnFrame = False
latlon_res_at_cnInfoLabelOn = False
latlon_res_at_cnLineLabelsOn = False
latlon_res_at_cnLevelSelectionMode = "ManualLevels"
latlon_res_at_cnMinLevelValF = -90
latlon_res_at_cnMaxLevelValF = 90
latlon_res_at_cnLevelSpacingF = 15
latlon_res_at_cnLineDashPattern = 10
lat_object = gsn_contour(wks,a->LAT,latlon_res)
tmplon = a->LON - 360.0
tmplon(242:,190) = -999.0
tmplon@_FillValue = -999.0
latlon_res_at_cnMinLevelValF = -90
latlon_res_at_cnMaxLevelValF = 270
lon_object = gsn_contour(wks,tmplon,latlon_res)
setvalues plot
"tmXBMode" : "Explicit"
"tmXBValues" : pop_tick_locs((a->LON(0,:)-360.0),\
(/-90,-45,0.0,45,90,135,180,225/))
"tmXBLabels" : (/"90W","45W","0","45E","90E","135E",\
"180E","135W"/)
"tmYLMode" : "EXPLICIT"
"tmYLValues" : pop_tick_locs(a->LAT(:,0),\
(/-75,-60,-45,-30,-15,0,15,30/))
"tmYLLabels" : (/"75S","60S","45S","30S","15S","EQ",\
"15N","30N"/)
"tmXBLabelFontHeightF" : 0.015
"tmYLLabelFontHeightF" : 0.015
"tmXBMajorLengthF" : 0.0001
"tmYLMajorLengthF" : 0.0001
end setvalues
overlay(plot,lat_object) ; Overlay latitude/longitude
overlay(plot,lon_object) ; lines on plot.
return
end
;***********************************************************************;
; Function : mask_lambert_conformal ;
; wks: graphic ;
; maplc: graphic ;
; minlat: numeric ;
; maxlat: numeric ;
; minlon: numeric ;
; maxlon: numeric ;
; maskoutln: logical ;
; res: logical ;
; ;
; Given a lambert conformal projection, and min/max lat/lon coords, ;
; this function will mask the map outside the boundaries defined by ;
; the coords. maskoutln determines whether the area will be outlined ;
; in the foreground color. "res" is an optional list of resources. ;
; ;
; Note, due to the nature of Lambert Conformal plots, lon labels ;
; cannot be automatically drawn on this type of plot. ;
; ;
; Programming Note: The function expects longitude input data to ;
; range from -360:180E. If this is not the case, the function ;
; will alter the min/max to be in that range. ;
; ;
;***********************************************************************;
function mask_lambert_conformal(wks:graphic, maplc:graphic, minlat:numeric,\
maxlat:numeric, minlon:numeric, \
maxlon:numeric, maskoutln, res)
local pres, var_string, maplc, mpres, tmplat, vpx, vpy, vpw, vph, \
xlft, xrgt, ytop, ybot, nscirc, nncirc, nxpoly, nypoly, sxpoly, sypoly, \
var_string, scirc_xndc, scirc_yndc, ncirc_xndc, ncirc_yndc, mask_outline, \
xmnlnmnlt, ymnlnmnlt, xmnlnmxlt, ymnlnmxlt, \
xmxlnmnlt, ymxlnmnlt, xmxlnmxlt, ymxlnmxlt, is_nh
begin
;
; Some error checking.
;
if(maxlat.gt.0.and.minlat.lt.0) then
print("mask_lambert_conformal: warning: you are not authorized to specify.")
print(" a maxlat that is above the equator and a minlat that is below")
print(" the equator. No masking will take place.")
return(maplc)
end if
if (minlon.gt.maxlon) then
print("mask_lambert_conformal: warning: Minimum longitude is greated than")
print(" maximum, subtracting 360 from minumum.")
minlon = minlon - 360
print("minlon = "+minlon+", maxlon = "+maxlon)
end if
if (minlat.gt.maxlat) then
print("mask_lambert_conformal: warning: Minimum latitude is greater than")
print(" maximum, swapping the two.")
tmplat = minlat
minlat = maxlat
maxlat = tmplat
print("minlat = "+minlat+", maxlat = "+maxlat)
end if
if (minlon.ge.180.and.maxlon.gt.180) then
minlon = minlon - 360
maxlon = maxlon - 360
end if
if (minlon.lt.180.and.maxlon.ge.180) then
minlon = minlon - 360
maxlon = maxlon - 360
end if
;
; Set up list of map resources. The user should have already created a
; lambert conformal map, but just in case he/she didn't, it will be done
; here. Some of these resources may have already been set by the user, so
; be sure to use these values.
;
meridian = minlon + (maxlon - minlon)/2.
mpres = True
if(isatt(res,"mpProjection")) then
iproj = res_at_mpProjection
if((typeof(iproj).eq."integer".and.iproj.ne.9).or.\
(typeof(iproj).eq."string".and. \
lower_case(iproj).ne."lambertconformal")) then
print("mask_lambert_conformal: warning: you are using a projection other")
print(" than LambertConformal. Unexpected results will likely occur.")
end if
delete(iproj)
end if
mpres_at_mpProjection = get_res_value_keep(res,"mpProjection", \
"LambertConformal")
if(isatt(res,"mpLimitMode")) then
need_to_set_limits = False
else
need_to_set_limits = True
mpres_at_mpLimitMode = "LatLon"
end if
mpres_at_mpLambertMeridianF = get_res_value_keep(res, \
"mpLambertMeridianF",meridian)
if (minlat.lt.0) then
mpres_at_mpLambertParallel1F = get_res_value_keep(res, \
"mpLambertParallel1F",-0.001)
mpres_at_mpLambertParallel2F = get_res_value_keep(res, \
"mpLambertParallel2F",-89.999 )
else
mpres_at_mpLambertParallel1F = get_res_value_keep(res, \
"mpLambertParallel1F", 0.001)
mpres_at_mpLambertParallel2F = get_res_value_keep(res, \
"mpLambertParallel2F",89.999 )
end if
;
; Determine whether we are in the southern or northern hemisphere.
;
if(minlat.ge.0) then
is_nh = True
else
is_nh = False
end if
;
; If the user hasn't already set the limits of the map, then set them
; here. Make sure there's some space around the area we want to mask.
;
if(need_to_set_limits) then
if(is_nh)
mpres_at_mpMinLatF = max((/minlat-0.5, 0/))
mpres_at_mpMaxLatF = min((/maxlat+0.5, 90/))
else
mpres_at_mpMinLatF = max((/minlat-0.5,-90/))
mpres_at_mpMaxLatF = min((/maxlat+0.5, 0/))
end if
mpres_at_mpMinLonF = minlon-0.5
mpres_at_mpMaxLonF = maxlon+0.5
end if
;
; These draw order resources are necessary to make sure the map
; outlines, lat/lon lines, and perimeter gets drawn *after* the
; masking polygons are drawn.
;
mpres_at_mpOutlineDrawOrder = get_res_value_keep(res, \
"mpOutlineDrawOrder","PostDraw")
mpres_at_mpGridAndLimbDrawOrder = get_res_value_keep(res, \
"mpGridAndLimbDrawOrder","PostDraw")
mpres_at_mpPerimDrawOrder = get_res_value_keep(res, \
"mpPerimDrawOrder","PostDraw")
;
; This section is to get rid of some of the remnants that appear around the
; edges of the plot, even after the masking is done. To accomplish this,
; tickmarks are being turned on, but only the border is being drawn in the
; background color. Since things like streamlines can *still* leave
; remnants, even with this extra code, we have put in a hook to allow the
; user to specify the thickness of the border line.
;
mpres_at_pmTickMarkDisplayMode = "Always"
mpres_at_tmXBLabelsOn = False
mpres_at_tmXTLabelsOn = False
mpres_at_tmYLLabelsOn = False
mpres_at_tmYRLabelsOn = False
mpres_at_tmYLOn = False
mpres_at_tmYROn = False
mpres_at_tmXBOn = False
mpres_at_tmXTOn = False
mpres_at_tmBorderLineColor = "background"
mpres_at_tmBorderThicknessF = get_res_value_keep(res, \
"tmBorderThicknessF",2.0)
;
; Now that we've set all these resources, apply them to the map.
;
attsetvalues(maplc,mpres)
;
; Thus begins the section for creating the two masking polygons.
; The polygons must be drawn in NDC, because trying to draw them in
; lat/lon space is not a good use of time and produces unpredictable
; results.
;
; Get viewport coordinates and calculate NDC positionsd of the
; four corners of the plot.
;
getvalues maplc
"vpXF" : vpx
"vpYF" : vpy
"vpWidthF" : vpw
"vpHeightF" : vph
end getvalues
xlft = vpx
xrgt = vpx + vpw
ytop = vpy
ybot = vpy - vph
;
; Calculate NDC coordinates of four corners of area defined by min/max
; lat/lon coordinates.
;
xmnlnmnlt = new(1,float) ; (minlon,minlat)
ymnlnmnlt = new(1,float)
xmxlnmnlt = new(1,float) ; (maxlon,minlat)
ymxlnmnlt = new(1,float)
xmnlnmxlt = new(1,float) ; (minlon,maxlat)
ymnlnmxlt = new(1,float)
xmxlnmxlt = new(1,float) ; (maxlon,maxlat)
ymxlnmxlt = new(1,float)
datatondc(maplc, tofloat(minlon), tofloat(minlat), xmnlnmnlt, ymnlnmnlt)
datatondc(maplc, tofloat(maxlon), tofloat(minlat), xmxlnmnlt, ymxlnmnlt)
datatondc(maplc, tofloat(minlon), tofloat(maxlat), xmnlnmxlt, ymnlnmxlt)
datatondc(maplc, tofloat(maxlon), tofloat(maxlat), xmxlnmxlt, ymxlnmxlt)
;
; Calculate NDC coordinates of southern hemisphere semi-circle.
;
nscirc = 100
scirc_xndc = new(nscirc,float)
scirc_yndc = new(nscirc,float)
scirc_lon = new(nscirc,float)
scirc_lat = new(nscirc,float)
scirc_lon = fspan(maxlon,minlon,nscirc)
scirc_lat = minlat
datatondc(maplc,scirc_lon,scirc_lat,scirc_xndc,scirc_yndc)
;
; Calculate NDC coordinates of northern hemisphere semi-circle.
;
nncirc = 100
ncirc_xndc = new(nncirc,float)
ncirc_yndc = new(nncirc,float)
ncirc_lon = new(nncirc,float)
ncirc_lat = new(nncirc,float)
ncirc_lon = fspan(maxlon,minlon,nncirc)
ncirc_lat = maxlat
datatondc(maplc,ncirc_lon,ncirc_lat,ncirc_xndc,ncirc_yndc)
;
; Create two polygons in NDC space (northern and southern hemisphere),
; using all the coordinates we gathered above. The two polygons will be
; set differently depending on whether we're in the northern or
; southern hemisphere. Yes, we could do this with one polygon, but it's
; a little cleaner this way, trust me.
;
if(is_nh) then
nxpoly = new(nncirc+7,float)
nypoly = new(nncirc+7,float)
sxpoly = new(nscirc+5,float)
sypoly = new(nscirc+5,float)
else
nxpoly = new(nncirc+5,float)
nypoly = new(nncirc+5,float)
sxpoly = new(nscirc+7,float)
sypoly = new(nscirc+7,float)
end if
;
; Define masking polygons for map that is in the northern hemisphere.
;
if(is_nh) then
nxpoly(0) = xrgt
nypoly(0) = ymxlnmnlt
nxpoly(1) = xmxlnmnlt
nypoly(1) = ymxlnmnlt
nxpoly(2:nncirc+1) = ncirc_xndc
nypoly(2:nncirc+1) = ncirc_yndc
nxpoly(nncirc+2) = xmnlnmnlt
nypoly(nncirc+2) = ymnlnmnlt
nxpoly(nncirc+3) = xlft
nypoly(nncirc+3) = ymnlnmnlt
nxpoly(nncirc+4) = xlft
nypoly(nncirc+4) = ytop
nxpoly(nncirc+5) = xrgt
nypoly(nncirc+5) = ytop
nxpoly(nncirc+6) = xrgt
nypoly(nncirc+6) = ymxlnmnlt
sxpoly(0) = xrgt
sypoly(0) = ymxlnmnlt
sxpoly(1:nscirc) = scirc_xndc
sypoly(1:nscirc) = scirc_yndc
sxpoly(nscirc+1) = xlft
sypoly(nscirc+1) = ymnlnmnlt
sxpoly(nscirc+2) = xlft
sypoly(nscirc+2) = ybot
sxpoly(nscirc+3) = xrgt
sypoly(nscirc+3) = ybot
sxpoly(nscirc+4) = xrgt
sypoly(nscirc+4) = ymxlnmnlt
else
;
; Define masking polygons for plot that is in the southern hemisphere.
;
nxpoly(0) = xrgt
nypoly(0) = ymxlnmxlt
nxpoly(1:nncirc) = ncirc_xndc
nypoly(1:nncirc) = ncirc_yndc
nxpoly(nncirc+1) = xlft
nypoly(nncirc+1) = ymnlnmxlt
nxpoly(nncirc+2) = xlft
nypoly(nncirc+2) = ytop
nxpoly(nncirc+3) = xrgt
nypoly(nncirc+3) = ytop
nxpoly(nncirc+4) = xrgt
nypoly(nncirc+4) = ymxlnmxlt
sxpoly(0) = xrgt
sypoly(0) = ymxlnmxlt
sxpoly(1) = xmxlnmxlt
sypoly(1) = ymxlnmxlt
sxpoly(2:nscirc+1) = scirc_xndc
sypoly(2:nscirc+1) = scirc_yndc
sxpoly(nscirc+2) = xmnlnmxlt
sypoly(nscirc+2) = ymnlnmxlt
sxpoly(nscirc+3) = xlft
sypoly(nscirc+3) = ymnlnmxlt
sxpoly(nscirc+4) = xlft
sypoly(nscirc+4) = ybot
sxpoly(nscirc+5) = xrgt
sypoly(nscirc+5) = ybot
sxpoly(nscirc+6) = xrgt
sypoly(nscirc+6) = ymxlnmxlt
end if
;
; Attach the two polygons (and optionally, the outline polyline)
; to the map. Fill the polygons in the background color.
;
pres = True
pres_at_gsFillColor = "background"
;
; Northern hemisphere polygon
;
var_string = unique_string("lamb_polygon")
maplc@$var_string$ = gsn_add_primitive(wks,maplc,nxpoly,nypoly,True, \
"polygon",pres)
;
; Southern hemisphere polygon
;
var_string = unique_string("lamb_polygon")
maplc@$var_string$ = gsn_add_primitive(wks,maplc,sxpoly,sypoly,True, \
"polygon",pres)
;
; For debugging purposes only. This draws outlines around the two
; polygons, in case you need to see what areas are being masked.
;
; pres_at_gsLineThicknessF = 3.0
; pres_at_gsLineColor = "red"
; var_string = unique_string("lamb_polyline")
; maplc@$var_string$ = gsn_add_primitive(wks,maplc,nxpoly,nypoly,True, \
; "polyline",pres)
; pres_at_gsLineColor = "blue"
; var_string = unique_string("lamb_polyline")
; maplc@$var_string$ = gsn_add_primitive(wks,maplc,sxpoly,sypoly,True, \
; "polyline",pres)
;
;
; Outline the area we are looking at (optional).
;
if(maskoutln) then
pres_at_gsLineColor = "foreground"
pres_at_gsLineThicknessF = 3.0
var_string = unique_string("lamb_polyline")
outline_lon = (/ minlon, maxlon, maxlon, minlon, minlon /)
outline_lat = (/ minlat, minlat, maxlat, maxlat, minlat /)
maplc@$var_string$ = gsn_add_polyline(wks,maplc,outline_lon, \
outline_lat,pres)
end if
return(maplc)
end
;***********************************************************************;
; Function : gsn_csm_map_ce ;
; wks: workstation object ;
; resources: optional resources ;
; ;
; This function creates and draws a labeled cylindrical equidistant map ;
; plot to the workstation "wks" (the variable returned from a previous ;
; call to "gsn_open_wks"). "resources" is an optional list of ;
; resources. The Id of the map plot is returned. ;
; ;
; This function behaves differently from gsn_map in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
;***********************************************************************;
function gsn_csm_map_ce(wks:graphic,resources:logical)
local i, res, map_object, tickmark_object, calldraw, callframe, \
left_string, center_string, right_string, main_zone, min_lat, max_lat, \
min_lon, max_lon, res2, tmres, ticks_on, display_mode
begin
; Initialize.
main_zone = 2 ; Zone for main title (may change later)
res2 = get_resources(resources)
;
; Make sure user is not calling this function, and then trying to
; change the map projection, because this can cause problems later.
;
if(isatt(res2,"mpProjection")) then
iproj = res2_at_mpProjection
if( (typeof(iproj).eq."integer".and.iproj.ne.8).or.\
(typeof(iproj).eq."string".and.lower_case(iproj).ne. \
"cylindricalequidistant")) then
print("gsn_csm_map_ce: Warning: you are calling one of the CE map functions,")
print("but setting the map projection to something other than")
print("'CylindricalEquidistant'. You may get errors or unexpected results.")
end if
end if
; This section tests for more special resources: those that start
; with "gsn."
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",True)
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = 4
end if
;
; Increase title zone if map tickmarks are on.
;
if(check_attr(res2,"pmTickMarkDisplayMode","Always",True).or.\
check_attr(res2,"pmTickMarkDisplayMode",2,False).or.\
check_attr(res2,"pmTickMarkDisplayMode",3,False)) then
main_zone = main_zone + 1
end if
;
; If automatic tick marks are turned on, then turn off gsn_csm generated
; tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
ticks_on = get_res_value(res2,"gsnTickMarksOn",False)
else
ticks_on = get_res_value(res2,"gsnTickMarksOn",True)
end if
lat_spacing = get_res_value(res2,"gsnMajorLatSpacing",0.)
lat_spacing = get_res_value(res2,"tmYLTickSpacingF",lat_spacing)
lon_spacing = get_res_value(res2,"gsnMajorLonSpacing",0.)
lon_spacing = get_res_value(res2,"tmXBTickSpacingF",lon_spacing)
mlat_spacing = get_res_value(res2,"gsnMinorLatSpacing",0.)
mlon_spacing = get_res_value(res2,"gsnMinorLonSpacing",0.)
shape_mode = get_res_value(res2,"mpShapeMode","FixedAspectFitBB")
limit_mode = get_res_value(res2,"mpLimitMode","LatLon")
if((typeof(limit_mode).eq."integer".and.(limit_mode.ne.1.and. \
limit_mode.ne.5)).or. \
(typeof(limit_mode).eq."string").and.(lower_case(limit_mode).ne. \
"latlon".and. \
lower_case(limit_mode).ne. \
"corners"))
print("gsn_csm_map_ce: Warning: you cannot use mpLimitMode=" + limit_mode + " with the gsm_csm_map routines.")
return
end if
;
; If mpCenterLonF is set, but mpMinLonF/mpLeftCornerLonF and/or
; mpMaxLonF/mpRightCornerLonF are not, then we need to set them.
;
if(lower_case(limit_mode).eq."latlon")
min_lon_str = "mpMinLonF"
max_lon_str = "mpMaxLonF"
min_lat_str = "mpMinLatF"
max_lat_str = "mpMaxLatF"
else
if(lower_case(limit_mode).eq."corners")
min_lon_str = "mpLeftCornerLonF"
max_lon_str = "mpRightCornerLonF"
min_lat_str = "mpLeftCornerLatF"
max_lat_str = "mpRightCornerLatF"
end if
end if
if(res2.and.isatt(res2,"mpCenterLonF").and.\
.not.isatt(res2,min_lon_str).and.\
.not.isatt(res2,max_lon_str))
res2@$min_lon_str$ = res2_at_mpCenterLonF - 180
res2@$max_lon_str$ = res2_at_mpCenterLonF + 180
end if
if(res2.and.isatt(res2,"mpCenterLonF").and..not.isatt(res2,min_lon_str))
res2@$min_lon_str$ = res2_at_mpCenterLonF - \
(res2@$max_lon_str$-res2_at_mpCenterLonF)
end if
if(res2.and.isatt(res2,"mpCenterLonF").and..not.isatt(res2,max_lon_str))
res2@$max_lon_str$ = res2_at_mpCenterLonF + \
(res2_at_mpCenterLonF-res2@$min_lon_str$)
end if
min_lon = get_res_value(res2,min_lon_str,-180)
max_lon = get_res_value(res2,max_lon_str, 180)
min_lat = get_res_value(res2,min_lat_str, -90)
max_lat = get_res_value(res2,max_lat_str, 90)
if(min_lon.ge.max_lon)
print("gsn_csm_map_ce: Fatal: The resources mpMinLonF/mpLeftCornerLonF must be less than the resources mpMaxLonF/mpRightCornerLonF.")
print("Execution halted.")
exit
end if
if(min_lat.ge.max_lat)
print("gsn_csm_map_ce: Fatal: The resources mpMinLatF/mpLeftCornerLatF must be less than the resources mpMaxLatF/mpRightCornerF.")
print("Execution halted.")
exit
end if
;
; Determine what the default width and height should be depending
; on shape of plot.
;
lat_range = tofloat(max_lat - min_lat)
lon_range = tofloat(max_lon - min_lon)
ratio1 = lat_range/lon_range
ratio2 = lon_range/lat_range
ratio = min((/ratio1,ratio2/))
ratios = (/0.50, 0.75, 1.00/) ; lat/lon ratios
wharray = (/0.80, 0.70, 0.52/) ; default widths/heights
wh_ind = ind(ratio.le.ratios)
def_vpwf = wharray(wh_ind(0)) ; default width for plot
def_vphf = def_vpwf ; default height for plot
set_attr(res2,"vpWidthF",min((/lon_range/lat_range,1./)) * def_vpwf)
set_attr(res2,"vpHeightF",min((/lat_range/lon_range,1./)) * def_vphf)
set_attr(res2,"vpXF",(1. - res2_at_vpWidthF)/2.)
set_attr(res2,"vpYF",1. - (1. - res2_at_vpHeightF)/2.)
set_attr(res2,"mpGridAndLimbOn", False)
set_attr(res2,"mpFillOn", True)
set_attr(res2,"mpFillColors",(/"background","transparent","LightGray",\
"transparent"/)) ; (default,ocean,land,
; inland water)
;
; By default, mpOutlineOn is False, unless mpFillOn is set to False,
; then it is set back to True.
;
set_attr(res2,"mpOutlineOn",.not.res2_at_mpFillOn)
;
; Create the map object. We have to use this code instead of gsn_map
; because we want to set the size of the map. If we set the size of the
; map later with setvalues, as gsn_map would do, then the size wouldn't
; be correct.
;
if(lower_case(limit_mode).eq."latlon")
map_object = create "map" mapPlotClass wks
"vpXF" : res2_at_vpXF
"vpYF" : res2_at_vpYF
"vpWidthF" : res2_at_vpWidthF
"vpHeightF" : res2_at_vpHeightF
"mpLimitMode" : limit_mode
"mpMinLonF" : min_lon
"mpMaxLonF" : max_lon
"mpMinLatF" : min_lat
"mpMaxLatF" : max_lat
"mpShapeMode" : shape_mode ; must be set when map created
"pmTitleDisplayMode" : "Always"
"pmTitleZone" : main_zone ; Zone for main title
end create
else
if(lower_case(limit_mode).eq."corners")
map_object = create "map" mapPlotClass wks
"vpXF" : res2_at_vpXF
"vpYF" : res2_at_vpYF
"vpWidthF" : res2_at_vpWidthF
"vpHeightF" : res2_at_vpHeightF
"mpLimitMode" : limit_mode
"mpLeftCornerLonF" : min_lon
"mpRightCornerLonF" : max_lon
"mpLeftCornerLatF" : min_lat
"mpRightCornerLatF" : max_lat
"mpShapeMode" : shape_mode ; must be set when map created
"pmTitleDisplayMode" : "Always"
"pmTitleZone" : main_zone ; Zone for main title
end create
end if
end if
delete(min_lon)
delete(max_lon)
delete(min_lat)
delete(max_lat)
delete(lon_range)
delete(lat_range)
; This section tests for regular resources.
tmres = get_res_eq(res2,"tm") ; Get tickmark resources
if(.not.ticks_on)
tmres = True
gsnp_turn_off_tickmarks(tmres)
end if
;
; If user has turned on built-in map tickmarks, then go ahead and
; let the tickmark resources (if any) be passed to the map object.
;
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres = get_res_ne(res2,(/"tx","am"/)) ; Get rest of resources
else
mpres = get_res_ne(res2,(/"tx","am","tm"/)) ; Get rest of resources
end if
;
; Set some map resources
;
attsetvalues_check(map_object,mpres)
;
; Add tickmark object, even if the tickmarks have been turned off, because
; we need to get the size of the X/Y axis labels.
;
add_map_tickmarks(wks,map_object,tmres,lon_spacing,mlon_spacing,\
lat_spacing,mlat_spacing,point_outward)
; Make sure axes labels (if any) are the same size.
getvalues map_object_at_tickmarks
"tmYLLabelFontHeightF" : yfontf
"tmXBLabelFontHeightF" : xfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the tickmark labels.
font_height = 1.25 * font_height ; Make fonts 25% bigger.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value_keep(res2,"tiMainFontHeightF", \
1.3*font_height)
main_font = get_res_value_keep(res2,"tiMainFont","helvetica-bold")
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
"tiMainFont" : main_font ; main title font
end setvalues
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"tx","am"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",font_height)
set_attr(subres,"amOrthogonalPosF",0.05)
add_subtitles(wks,map_object,left_string,center_string,right_string, \
subres)
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and tickmark object.
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_map_polar ;
; wks: workstation object ;
; resources: optional resources ;
; ;
; This function creates and draws a polar stereographic map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The id ;
; of the map plot is returned. ;
; ;
; This function behaves differently from gsn_map in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The longitude lines are labeled. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top of the plot. ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If either of the resources "gsnPolarNH" or "gsnPolarSH" are set ;
; to True then only the northern or southern hemisphere is ;
; displayed. ;
; 4. If gsnPolarLabelSpacing is set, then this spacing will be used ;
; to label the longitude lines. ;
; 5. If gsnPolarLabelDistance is set, then this will be used to ;
; increase/decrease the default position of the labels from the ;
; perimeter of the map. ;
; 6. gsnPolarLabelFont and gsnPolarLabelFontHeightF can be used to ;
; control the label font and heights of the lat/lon labels. ;
;***********************************************************************;
function gsn_csm_map_polar(wks:graphic,resources:logical)
local i, res, res2, map_object, main_zone, \
calldraw, callframe, left_string, center_string, right_string, yoffset, \
min_lat, max_lat, center_lat, main_offset, \
side, just, orth, para, quad1, quad2, quad3, quad4, topbot, xcen, ycen, \
vpxf, vpyf, vphf, vpwf, plon, plat, xndc, yndc, polar_type
begin
; Initialize.
min_lat = 0.0
max_lat = 90.0
center_lat = 0.0
main_zone = 2 ; Zone for main title (may change later)
res2 = get_resources(resources)
; This section tests for special resources: those that start with "gsn."
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
polar_dst = get_res_value(res2,"gsnPolarLabelDistance",1.04)
ticks_on = get_res_value(res2,"gsnTickMarksOn",True)
polar_time = get_res_value(res2,"gsnPolarTime",False)
ut = tofloat(get_res_value(res2,"gsnPolarUT",0.))
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = 4
end if
;
; Check for type of polar plot desired.
;
polar_type = get_polar_type(res2)
if(polar_type.eq."NH")
min_lat = 0
max_lat = 90
center_lat = 90
else
min_lat = -90
max_lat = 0
center_lat = -90
end if
height = get_res_value(res2,"vpHeightF",0.62)
width = get_res_value(res2,"vpWidthF",0.62)
xpos = get_res_value(res2,"vpXF",0.2)
ypos = get_res_value(res2,"vpYF",0.8)
;
; Print a warning if user tries to set mpMinLonF and/or mpMaxLonF,
; since these values should not be messed with in a polar plot (they
; should be -180 and 180.
;
if(isatt(res2,"mpMinLonF").or.isatt(res2,"mpMaxLonF")) then
print("gsn_csm_map_polar: Warning: you should not set the mpMinLonF and/or mpMaxLonF resources.")
print("Setting these resources to something other than -180 and 180 may produce unexpected results.")
end if
;
; Check for other resources that we need to set at the time the
; map is created.
;
limit_mode = get_res_value(res2,"mpLimitMode","LatLon")
shape_mode = get_res_value(res2,"mpShapeMode","FixedAspectFitBB")
; Create a polar stereographic map object.
map_object = create "ezplot1p_map" mapPlotClass wks
"vpHeightF" : height
"vpWidthF" : width
"vpXF" : xpos
"vpYF" : ypos
"mpProjection" : "Stereographic"
"mpEllipticalBoundary" : True
"mpLimitMode" : limit_mode
"mpShapeMode" : shape_mode ; must be set when map created
"mpFillOn" : True
"mpFillColors" : (/"background","transparent","LightGray",\
"transparent"/)
"pmTitleDisplayMode" : "Always"
"pmTitleZone" : main_zone
end create
; Set some map plot resources.
res2 = True
set_attr(res2,"mpMinLatF",min_lat)
set_attr(res2,"mpMaxLatF",max_lat)
set_attr(res2,"mpCenterLatF",center_lat)
set_attr(res2,"mpFillOn",True)
set_attr(res2,"mpGridAndLimbOn",True)
set_attr(res2,"mpGridLineDashPattern",2)
set_attr(res2,"mpGridLonSpacingF",30.)
set_attr(res2,"mpPerimOn",True)
;
; If labeling the polar plot with time values, then we want slt = 0
; to be at the bottom of the plot, so we need to rotate the map
; accordingly, by setting mpCenterLonF.
;
; If slt = ut + lon/15, then at slt=0:
;
; 0 = ut + lon/15 --> lon/15 = -ut --> lon = -ut*15.
;
if(polar_time) then
if(polar_type.eq."NH")
set_attr(res2,"mpCenterLonF",-ut*15)
else
set_attr(res2,"mpCenterLonF",-ut*15+180)
end if
end if
;
; Set the spacing of the polar labels to the same as mpGridLonSpacingF,
; unless user has explicitly set gsnPolarLabelSpacing.
;
label_spacing = get_res_value(res2,"gsnPolarLabelSpacing", \
res2_at_mpGridLonSpacingF)
;
; By default, mpOutlineOn is False, unless mpFillOn is set to False,
; then it is set back to True.
;
set_attr(res2,"mpOutlineOn",.not.res2_at_mpFillOn)
;
; Retrieve the map resources.
;
mpres = get_res_ne(res2,(/"gs","tx","tm"/))
attsetvalues_check(map_object,mpres)
; Retrieve the view port location of the map plot so we know where
; to put titles.
getvalues map_object
"vpXF" : vpxf
"vpYF" : vpyf
"vpWidthF" : vpwf
"vpHeightF" : vphf
"mpMinLatF" : min_lat
"mpMaxLatF" : max_lat
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value_keep(res2,"tiMainFontHeightF", \
2.*font_height)
main_font = get_res_value_keep(res2,"tiMainFont","helvetica-bold")
main_offset = get_res_value_keep(res2,"tiMainOffsetYF",0.02)
setvalues map_object
"tiMainOffsetYF" : main_offset ; main title offset
"tiMainFont" : main_font ; main title font
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
if(ticks_on) then
;
; Create the lat/lon coordinates where you want labels to appear.
;
; In this case, we want the labels to appear at a fixed latitude value
; and at varying longitude values.
;
if(.not.polar_time) then
ngrid = floattoint(360/label_spacing)
plon = fspan(0.,360.-label_spacing,ngrid)
else
;
; If labeling with time, we calculate the longitudes, given nice
; time values of 0, 3, ..., 21.
;
slt = ispan(0,21,3)
plon = 15.*(slt-ut)
ngrid = dimsizes(plon)
end if
;
; The "0.005" addition is to make sure we are within the map perimeter.
; Otherwise,; if we enter points right along the edge of the circle, then
; when they are converted to NDC coords, you might get missing values.
;
if(min((/min_lat,max_lat/)).ge.0.or.polar_type.eq."NH")
plat = fspan(min_lat+.005,min_lat+.005,ngrid)
else
plat = fspan(max_lat-.005,max_lat-.005,ngrid)
end if
; Create arrays to hold the NDC values that we're going to convert
; the lat/lon values to.
xndc = new(dimsizes(plon),float)
yndc = new(dimsizes(plat),float)
; Convert lat/lon cooridinates to NDC coordinates since we are
; drawing the labels in NDC space and NOT in lat/lon space.
datatondc(map_object,plon,plat,xndc,yndc)
;
; Get center of plot in NDC coordinates.
;
xcen = vpxf + vpwf/2. ; X center
ycen = vpyf - vphf/2. ; Y center
;
; Determine if we want longitude labels, or time labels.
;
labels = new(dimsizes(plon),string)
if(.not.polar_time) then
; Define an array of strings to label the longitude values.
indexes = ind(plon.gt.0.and.plon.lt.180)
labels(indexes) = floattoint(plon(indexes)) + "E"
delete(indexes)
indexes = ind(plon.gt.180.and.plon.lt.360)
labels(indexes) = floattoint(360-plon(indexes)) + "W"
delete(indexes)
indexes = ind(plon.eq.0.or.plon.eq.180)
labels(indexes) = floattoint(plon(indexes))
delete(indexes)
else
;
; Define an array of strings to label the time values.
;
labels = slt
end if
num_labels = dimsizes(labels)
text_ids = new(num_labels,graphic)
;
; Check if user setting own font heights. gsnPolarLabelFontHeightF
; takes precedence over txFontHeightF.
;
text_font_height = get_res_value(res2,"gsnPolarLabelFontHeightF", \
get_res_value_keep(res2,"txFontHeightF",\
font_height))
text_font = get_res_value(res2,"gsnPolarLabelFont", \
get_res_value_keep(res2,"txFont","helvetica"))
; Create an array of TextItem objects that we'll use to label the
; lat/lon grid.
do i=0,num_labels-1
text_ids(i) = create "lon_"+labels(i) textItemClass wks
"txString" : labels(i)
"txFont" : text_font
"txFontHeightF" : text_font_height
end create
end do
setvalues map_object
"pmAnnoViews" : text_ids ; Add text items as annotations of map.
end setvalues
getvalues map_object
"pmAnnoManagers" : am_ids ; Retrieve anno managers so we can
; change some stuff.
end getvalues
;
; Determine which quadrant each label is in, and then set values
; for justification, side, orthogonal and parallel positions.
;
quad1 = ind((ycen-yndc).le.0.and.(xcen-xndc).le.0)
quad2 = ind((ycen-yndc).le.0.and.(xcen-xndc).gt.0)
quad3 = ind((ycen-yndc).gt.0.and.(xcen-xndc).gt.0)
quad4 = ind((ycen-yndc).gt.0.and.(xcen-xndc).le.0)
side = new(ngrid,string)
just = new(ngrid,string)
orth = new(ngrid,float)
para = new(ngrid,float)
;
; The zone is being set to 0, so this means all labels will appear in the
; center of the map by default. We set the orthogonal and parallel values
; to move the labels away from the center of the plot. The orth/para values
; are a fraction of the total width of the map, so if you set an orthogonal
; value to 0.5, this will move the label from the center of the plot to the
; edge of the plot.
;
; We increase the orth/para values by 4 percent so that the labels are
; placed outside of the plot.
;
if(.not.all(ismissing(quad1)))
side(quad1) = "Top" ; Position labels in quadrants I and II wrt
orth(quad1) = ((yndc(quad1) - ycen)/vphf) * polar_dst
just(quad1) = "CenterLeft"
end if
if(.not.all(ismissing(quad2)))
side(quad2) = "Top" ; top of plot.
orth(quad2) = ((yndc(quad2) - ycen)/vphf) * polar_dst
just(quad2) = "CenterRight"
end if
if(.not.all(ismissing(quad3)))
side(quad3) = "Bottom" ; Position labels in quadrants III and IV wrt
orth(quad3) = ((ycen - yndc(quad3))/vphf) * polar_dst
just(quad3) = "CenterRight"
end if
if(.not.all(ismissing(quad4)))
side(quad4) = "Bottom" ; bottom of plot.
orth(quad4) = ((ycen - yndc(quad4))/vphf) * polar_dst
just(quad4) = "CenterLeft"
end if
para = ((xndc - xcen)/vpwf) * polar_dst
;
; Labels at the very top or bottom of the map should be centered, not
; right or left justified.
;
topbot = ind(fabs(xndc-xcen).le.1e-5)
if(.not.all(ismissing(topbot)))
just(topbot) = "CenterCenter"
end if
;
; map_object may already have some other annotations added to it,
; so we have to search until we find the lon label annotations. They
; all start with "lon_", so the first occurrence of this string will
; be the consecutive start of the lon label annotations.
;
names = NhlName(am_ids)
found = False
i = 0
do while(i.lt.dimsizes(names).and..not.found)
names_char = stringtocharacter(names)
if(charactertostring(names_char(i,0:3)).eq."lon_")
start = i
found = True
end if
delete(names_char)
i = i + 1
end do
delete(names)
;
; Set the side, justifcation, and position of each longitude label.
;
do i=0,num_labels-1
setvalues am_ids(start+i)
"amTrackData" : False
"amResizeNotify" : True
"amZone" : 0
"amSide" : side(i)
"amJust" : just(i)
"amOrthogonalPosF" : orth(i)
"amParallelPosF" : para(i)
end setvalues
end do
end if
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,"tx") ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",1.2*font_height)
set_attr(subres,"txFont","helvetica")
subres_at_amOrthogonalPosF = 0.06
add_subtitles(wks,map_object,left_string,center_string,right_string, \
subres)
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_map_other ;
; wks: workstation object ;
; resources: optional resources ;
; ;
; This function creates and draws a labeled "other" map (non-polar, ;
; cylindrical equidistant. ;
; ;
; This function behaves differently from gsn_map in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 2. If the special resource "gsnMaskLambertConformal" is set, then ;
; if the resources mpMinLatF, mpMaxLatF, mpMinLonF, and mpMaxLonF ;
; are also set, the lambert conformal map will be masked outside ;
; of these min/max lat/lon boundaries. Note: mpProjection must ;
; be set to "LambertConformal". ;
; 3. If the special resource "gsnMaskLambertConformalOutlineOn" is ;
; set to False, then the lat/lon area of interest will not be ;
; outlined in the foreground color. ;
;***********************************************************************;
function gsn_csm_map_other(wks:graphic,resources:logical)
local i, res, map_object, calldraw, callframe, \
left_string, center_string, right_string, main_zone, res2
begin
; Initialize.
res2 = get_resources(resources)
;
; Need to check what kind of tickmarks are being used so we can set
; the zone appropriately. It may be the case that it's okay to always
; set it to 3, but this makes the title move slightly up, even if there
; are no tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
main_zone = 3
else
main_zone = 2
end if
; This section tests for more special resources: those that start
; with "gsn."
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
masklc = get_res_value(res2,"gsnMaskLambertConformal",False)
maskoutln = get_res_value(res2,"gsnMaskLambertConformalOutlineOn",True)
maxbb = get_bb_res(res2)
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = 4
end if
shape_mode = get_res_value(res2,"mpShapeMode","FixedAspectFitBB")
set_attr(res2,"vpXF", 0.2)
set_attr(res2,"vpYF", 0.8)
set_attr(res2,"vpWidthF", 0.6)
set_attr(res2,"vpHeightF",0.6)
set_attr(res2,"mpGridAndLimbOn", False)
set_attr(res2,"mpPerimOn", .not.masklc)
set_attr(res2,"mpFillOn", True)
set_attr(res2,"mpFillColors",(/"background","transparent","LightGray",\
"transparent"/)) ; (default,ocean,land,
; inland water)
;
; By default, mpOutlineOn is False, unless mpFillOn is set to False,
; then it is set back to True.
;
set_attr(res2,"mpOutlineOn",.not.res2_at_mpFillOn)
; Create the map object. We have to use this code instead of gsn_map
; because we want to set the size of the map. If we set the size of the
; map later with setvalues, as gsn_map would do, then the size wouldn't
; be correct.
map_object = create "map" mapPlotClass wks
"vpXF" : res2_at_vpXF
"vpYF" : res2_at_vpYF
"vpWidthF" : res2_at_vpWidthF
"vpHeightF" : res2_at_vpHeightF
"pmTitleDisplayMode" : "Always"
"pmTitleZone" : main_zone ; Zone for main title
"mpShapeMode" : shape_mode ; must be set when map created
end create
; This section tests for regular resources.
mpres = get_res_ne(res2,(/"tx","tm"/)) ; Get rest of resources
;
; If user wants to mask the lambert conformal map, then to avoid
; the error message:
;
; warning:MapSetTrans: map limits invalid - using maximal area
;
; we must set the lambert parallels here. We also use this opportunity
; to make sure the Min/Max/Lat/LonF resources are set.
;
if(masklc) then
if(isatt(res2,"mpMinLatF").and.isatt(res2,"mpMaxLatF").and. \
isatt(res2,"mpMinLonF").and.isatt(res2,"mpMaxLonF")) then
if (res2_at_mpMinLatF.lt.0) then
mpres_at_mpLambertParallel1F = -0.001
mpres_at_mpLambertParallel2F = -89.999
end if
else
print("gsn_csm_map_other: Warning: one or more of the resources mpMinLatF, mpMaxLatF, mpMinLonF, and mpMaxLonF have not been set.")
print("No masking of the Lambert Conformal map will take place.")
masklc = False
end if
end if
;
; If user has turned on built-in map tickmarks, then go ahead and
; let the tickmark resources (if any) be passed to the map object.
;
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres = get_res_ne(res2,(/"tx","am"/)) ; Get rest of resources
else
mpres = get_res_ne(res2,(/"tx","am","tm"/)) ; Get rest of resources
end if
;
; Set some map resources.
;
attsetvalues_check(map_object,mpres)
;
; If user wants to mask the lambert conformal map, then the four
; mpMin/Max resources must be set. The masking routine will be called,
; and masking polygons will be attached to map_object.
;
if(masklc) then
map_object = mask_lambert_conformal(wks,map_object,res2_at_mpMinLatF, \
res2_at_mpMaxLatF,res2_at_mpMinLonF, \
res2_at_mpMaxLonF,maskoutln,res2)
end if
; Make sure axes labels (if any) are the same size.
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value_keep(res2,"tiMainFontHeightF", \
1.1*font_height)
main_font = get_res_value_keep(res2,"tiMainFont","helvetica-bold")
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
"tiMainFont" : main_font ; main title font
end setvalues
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"tx","am"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",0.8*font_height)
set_attr(subres,"amOrthogonalPosF",0.015)
add_subtitles(wks,map_object,left_string,center_string,right_string, \
subres)
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and tickmark object.
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_map ;
; wks: workstation object ;
; resources: optional resources ;
; ;
; This function calls either gsn_csm_map_ce, gsn_csm_map_other, or ;
; gsn_csm_map_polar depending on if gsnPolar is set, or how ;
; mpProjection is set. ;
;***********************************************************************;
function gsn_csm_map(wks:graphic,resources:logical)
begin
res2 = get_resources(resources)
if(res2.and.(isatt(res2,"gsnPolarNH").or.isatt(res2,"gsnPolarSH").or.\
isatt(res2,"gsnPolar")))
return(gsn_csm_map_polar(wks,res2))
else
if(.not.isatt(res2,"mpProjection").or.\
check_attr(res2,"mpProjection","cylindricalequidistant",True).or.\
check_attr(res2,"mpProjection",8,True))
return(gsn_csm_map_ce(wks,res2))
else
return(gsn_csm_map_other(wks,res2))
end if
end if
end
;***********************************************************************;
; Function : gsn_csm_contour_map_polar ;
; wks: workstation object ;
; data: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a contour plot over a polar ;
; stereographic map plot to the workstation "wks" (the variable ;
; returned from a previous call to "gsn_open_wks"). "data" is the ;
; 2-dimensional data to be contoured, and "resources" is an optional ;
; list of resources. The id of the map plot is returned. ;
; ;
; This function behaves differently from gsn_contour in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. By default, a cyclic point is added. If gsnAddCyclic is set to ;
; False, then the cyclic point is not added. ;
; 2. The longitude lines are labeled. ;
; 3. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top of the plot. ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 4. If the resource "cnFillOn" is set to True, then a labelbar is ;
; drawn and line labels are turned off. ;
; 5. If data has an attribute called "long_name," and "gsnLeftString";
; hasn't explicitly been set, then the value of this attribute ;
; is used for the left string title. ;
; 6. If data has an attribute called "units," and "gsnRightString" ;
; hasn't explicitly been set, then the value of this attribute ;
; is used for the right string title. ;
; 7. If either of the resources "gsnPolarNH" or "gsnPolarSH" are set ;
; to True then only the northern or southern hemisphere is ;
; displayed. ;
;***********************************************************************;
function gsn_csm_contour_map_polar(wks:graphic,data:numeric,resources:logical)
local i, contour_object, map_object, res, lbar_pos, lbar_zone, \
lbar_on, calldraw, callframe, main_offset, datanew, res2, cnres, mpres, \
vpwf, vphf, font_height, levels, colors, zonal_zone, lbres, \
infolabel_on, infolabel_zone, lbar_zone, lbar_height, lbar_width
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_contour_map_polar: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
lbar_on = False ; Labelbar flag
res2 = get_resources(resources) ; Copy of resources
lbar_zone = 3 ; Zone for labelbar (may change later)
mpres = True ; Will hold map resources
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.(isatt(data,"lat2d").and.isatt(data,"lon2d"))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
datanew = gsn_add_cyclic_point(data)
else
datanew = data
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,mpres)
set_left_subtitle(datanew,res2,mpres)
; Check for draw and frame.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Check for type of polar plot and polar labels desired.
;
mpres_at_gsnPolar = get_polar_type(res2)
mpres_at_gsnPolarTime = get_res_value(res2,"gsnPolarTime",False)
mpres_at_gsnPolarUT = get_res_value(res2,"gsnPolarUT",0.)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Tickmarks.
;
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
; Create data object and use coordinate variables if they exist.
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
; Set some more contour plot resources.
set_attr(res2,"cnLineLabelBackgroundColor",-1)
set_attr(res2,"cnInfoLabelOrthogonalPosF",0.06)
set_attr(res2,"cnInfoLabelZone",2)
;
; By default, mpOutlineOn is False, unless cnFillOn is set to True
; or mpFillOn is set to False, then it is set back to True.
;
if(check_attr(res2,"cnFillOn",True,False).or.\
check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
lbres = get_res_eq(res2,(/"lb","pm"/))
mpres = get_res_eq(res2,(/"mp","ti","vp","tx","am","pmA","pmO","pmT",\
"gsnPolar"/))
cnres = get_res_ne(res2,(/"mp","vp","lb","tx","am","gsnPolar"/))
if(cnres)
if(check_attr(cnres,"cnFillOn",True,False))
set_attr(cnres,"cnInfoLabelOn",False)
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
set_attr(cnres,"cnLineLabelsOn",False)
lbar_on = True ; Turn on a labelbar
end if
end if
end if
;
; Compute zone for labelbar if it is supposed to get drawn.
; Zone for labelbar changes only if an info label is not drawn.
;
if(check_attr(cnres,"cnInfoLabelOn",False,False))
lbar_zone = 2
end if
; Before we create the objects, turn off draw and frame for them.
cnres = True
mpres = True
cnres_at_gsnDraw = False
cnres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
contour_object = gsn_contour(wks,datanew,cnres) ; Create contours.
map_object = gsn_csm_map_polar(wks,mpres) ; Create map.
overlay(map_object,contour_object) ; Overlay contour plot
; on map.
;
; Retrieve the view port location of the map plot so we know where
; to put titles and labelbar (if there is one).
;
getvalues map_object
"vpWidthF" : vpwf
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value_keep(res2,"tiMainFontHeightF", \
2.*font_height)
main_font = get_res_value_keep(res2,"tiMainFont","helvetica-bold")
setvalues map_object
"tiMainFont" : main_font ; main title font
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Create a labelbar.
if(lbar_on)
add_labelbar(wks,contour_object,lbar_zone,font_height,"polar",lbres)
end if
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = contour_object_at_data
map_object_at_contour = contour_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_contour_map_ce ;
; wks: workstation object ;
; data: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a contour plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "data" is the 2-dimensional data to be contoured, ;
; and "resources" is an optional list of resources. The Id of the map ;
; plot is returned. ;
; ;
; This function behaves differently from gsn_contour in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If the special GSUN resource "gsnZonalMean" is set to True, ;
; then a zonal mean XY plot is drawn. ;
; 3a. In addition, if "gsnZonalMeanYRefLine" is set, then a vertical ;
; line is drawn at this value. Otherwise, a line is drawn at 0. ;
; 4. If the resource "cnFillOn" is set to True, then a labelbar is ;
; drawn and line labels are turned off. ;
; 5. If data has an attribute called "long_name," and "gsnLeftString";
; hasn't explicitly been set, then the value of this attribute ;
; is used for the left string title. ;
; 6. If data has an attribute called "units," and "gsnRightString" ;
; hasn't explicitly been set, then the value of this attribute ;
; is used for the right string title. ;
;***********************************************************************;
function gsn_csm_contour_map_ce(wks:graphic,data:numeric,resources:logical)
local i, contour_object, labelbar_object, xy_object, map_object, \
calldraw, callframe, lbar_on, zonal_mean_plot, min_lat, max_lat, datanew, \
res, res2, lbres, xy_res, mpres, cnres, levels, colors, \
lbar_zone, lbar_orient, lbar_side, lbar_height, lbar_width, lbar_just, \
map_vpwf, map_vphf, vphf, contour_plot
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_contour_map_ce: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
lbar_on = False ; Default is no labelbar.
mpres = True
infolabel_zone = 2 ; Zone for info label (may change later)
lbar_zone = 2 ; Zone for labelbar (may change later)
zonal_zone = 2 ; Zone for zonal means plot
res2 = get_resources(resources)
;
; Default is no zonal mean plot.
; Also get min and max X values, if any.
;
zonal_mean_plot = get_res_value(res2,"gsnZonalMean",False)
zonal_xmin = isatt(res2,"gsnZonalMeanXMinF")
zonal_xmax = isatt(res2,"gsnZonalMeanXMaxF")
zonal_ref = get_res_value(res2,"gsnZonalMeanYRefLine",0.)
if(zonal_xmin) then
trxmin = get_res_value(res2,"gsnZonalMeanXMinF",1.)
end if
if(zonal_xmax) then
trxmax = get_res_value(res2,"gsnZonalMeanXMaxF",1.)
end if
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes and data is not 1D).
set_cyclic = .not.(isatt(data,"lat2d").and.isatt(data,"lon2d"))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
datanew = gsn_add_cyclic_point(data)
else
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay contour on map.
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
if(.not.(isatt(res2,"sfXArray")))
set_attr(res2,"sfXCStartV",-180.)
set_attr(res2,"sfXCEndV", 180.)
end if
if(.not.(isatt(res2,"sfYArray")))
set_attr(res2,"sfYCStartV",-90.)
set_attr(res2,"sfYCEndV", 90.)
end if
; Check if a zonal mean plot is desired.
if(zonal_mean_plot) then
if(is_valid_latlon_coord(datanew,"y","lat",res2).and. \
is_valid_latlon_coord(datanew,"x","lon",res2)) then
if(isatt(res2,"vpHeightF"))
map_vphf = res2_at_vpHeightF
else
map_vphf = 0.7 ; make sure zonalplot will fit in view port
set_attr(res2,"vpHeightF",0.7)
set_attr(res2, "vpWidthF",0.7)
set_attr(res2, "vpXF",0.1)
set_attr(res2, "vpYF",0.9)
end if
zmeans2 = dim_avg(datanew)
if(min(zmeans2).le.0.or.max(zmeans2).ge.0)
nmeans = dimsizes(zmeans2)
zmeans = new((/2,nmeans/),typeof(zmeans2))
zmeans(0,:) = zmeans2
zmeans(1,:) = fspan(zonal_ref,zonal_ref,nmeans)
else
zmeans = zmeans2
end if
delete(zmeans2)
else
print("gsn_csm_contour_map_ce: Warning: The resource gsnZonalMean can only be set to True")
print("if the data has one of the coordinate variables " + get_allowed_latnames() + "and " + get_allowed_lonnames())
end if
end if
; Create some contour plot resources.
res2 = True
set_attr(res2,"cnLineLabelBackgroundColor", "transparent")
; This section tests for more special resources: those that start
; with "gsn."
if(isatt(res2,"gsnMajorLonSpacing"))
mpres_at_gsnMajorLonSpacing = res2_at_gsnMajorLonSpacing
delete(res2_at_gsnMajorLonSpacing)
end if
if(isatt(res2,"gsnMajorLatSpacing"))
mpres_at_gsnMajorLatSpacing = res2_at_gsnMajorLatSpacing
delete(res2_at_gsnMajorLatSpacing)
end if
if(isatt(res2,"gsnMinorLonSpacing"))
mpres_at_gsnMinorLonSpacing = res2_at_gsnMinorLonSpacing
delete(res2_at_gsnMinorLonSpacing)
end if
if(isatt(res2,"gsnMinorLatSpacing"))
mpres_at_gsnMinorLatSpacing = res2_at_gsnMinorLatSpacing
delete(res2_at_gsnMinorLatSpacing)
end if
mpres_at_gsnTickMarksPointOutward = get_res_value(res2, \
"gsnTickMarksPointOutward",True)
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,mpres)
set_left_subtitle(datanew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",False)
else
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
end if
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; By default, mpOutlineOn is False, unless cnFillOn is set to True
; or mpFillOn is set to False, then it is set back to True.
;
if(check_attr(res2,"cnFillOn",True,False).or.\
check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
lbres = get_res_eq(res2,(/"lb","pm"/))
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT"/))
cnres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm"/))
if(cnres)
if(check_attr(cnres,"cnFillOn",True,False))
set_attr(cnres,"cnInfoLabelOn",False)
if(.not.check_attr(lbres,"lbLabelBarOn",False,False))
set_attr(cnres,"cnLineLabelsOn",False)
lbar_on = True ; Turn on a labelbar
if(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True))
set_attr(mpres, "vpWidthF",0.75) ; Make room for labelbar
set_attr(mpres,"vpHeightF",0.75) ; on the side.
set_attr(mpres, "vpXF",0.08)
set_attr(mpres, "vpYF",0.90)
end if
end if
end if
end if
;
; Compute zones for zonal means plot, info label, and labelbar if
; they are supposed to get drawn.
;
infolabel_on = get_res_value_keep(cnres,"cnInfoLabelOn",True)
if(zonal_mean_plot) then
if(infolabel_on) then
infolabel_zone = zonal_zone + 1
lbar_zone = zonal_zone + 2
else
lbar_zone = zonal_zone + 1
end if
else
if(infolabel_on)
lbar_zone = infolabel_zone + 1
end if
end if
if(infolabel_on)
if(.not.isatt(cnres,"cnInfoLabelOrthogonalPosF").and.infolabel_zone.eq.2)
cnres_at_cnInfoLabelOrthogonalPosF = 0.13
end if
cnres_at_cnInfoLabelZone = infolabel_zone
end if
; Before we create the objects, turn off draw and frame for them.
cnres = True
mpres = True
cnres_at_gsnDraw = False
cnres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
contour_object = gsn_contour(wks,datanew,cnres) ; Create contours.
map_object = gsn_csm_map_ce(wks,mpres) ; Create map.
overlay(map_object,contour_object) ; Overlay contours on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object_at_tickmarks
"tmXBLabelFontHeightF" : xbfontf
"tmXBMajorLengthF" : xlength
"tmXBMinorLengthF" : xmlength
end getvalues
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value_keep(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Set font heights only if they haven't been set explicitly by user.
contour_plot = check_class_name(contour_object,"contour")
if(.not.isatt(cnres,"cnLineLabelFontHeightF"))
setvalues contour_plot
"cnLineLabelFontHeightF" : xbfontf
end setvalues
end if
if(.not.isatt(cnres,"cnInfoLabelFontHeightF"))
setvalues contour_plot
"cnInfoLabelFontHeightF" : xbfontf
end setvalues
end if
; Create a labelbar.
if(lbar_on)
add_labelbar(wks,contour_object,lbar_zone,xbfontf,"ce",lbres)
end if
; Add a zonal mean plot if requested.
if(zonal_mean_plot)
; Retrieve the view port size of the map plot so we know where
; to put zonal means plot (if there is one).
getvalues map_object
"vpHeightF" : vphf
"mpMinLatF" : min_lat
"mpMaxLatF" : max_lat
end getvalues
; Create data object.
if(is_valid_latlon_coord(datanew,"y","lat",res2)) then
data_object = create "data" coordArraysClass noparent
"caXArray" : zmeans
"caYArray" : datanew&$datanew!0$
end create
; Check for missing values.
if(isatt(zmeans,"_FillValue")) then
setvalues data_object
"caXMissingV" :zmeans@_FillValue
end setvalues
end if
; Create zonal means XY plot.
xy_object = create "xyplot" xyPlotClass wks
"xyCoordData" : data_object
"vpHeightF" : vphf
"vpWidthF" : 0.15 * map_vphf
"trYMaxF" : max_lat
"trYMinF" : min_lat
"tmXBLabelFontHeightF" : xbfontf
"tmYLOn" : False
"tmYROn" : False
"tmXBMaxTicks" : 3
"tmXBMinorPerMajor" : 1
"tmXTMinorPerMajor" : 1
"tmXBMajorLengthF" : xlength
"tmXBMinorLengthF" : xmlength
"tmYRMajorLengthF" : xlength
"tmYRMinorLengthF" : xmlength
"tmXBMajorOutwardLengthF": xlength
"tmXBMinorOutwardLengthF": xmlength
"tmYRMajorOutwardLengthF": xlength
"tmYRMinorOutwardLengthF": xmlength
"tiXAxisOn" : False
"tiYAxisOn" : False
end create
;
; Check if user wants to change minimum of X axis.
;
if(zonal_xmin) then
setvalues xy_object
"trXMinF" : trxmin
end setvalues
end if
;
; Check if user wants to change maximum of X axis.
;
if(zonal_xmax) then
setvalues xy_object
"trXMaxF" : trxmax
end setvalues
end if
; Add XY plot as annotation of map plot.
anno = NhlAddAnnotation(map_object,xy_object)
setvalues anno
"amZone" : zonal_zone ; Just outside plot area
"amSide" : "right" ; Plot at right.
"amResizeNotify" : True ; Resize if map resized.
"amParallelPosF" : 0.5 ; 0.5 is center of plot
"amOrthogonalPosF": 0.05 ; Move away from right edge
end setvalues
end if
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = contour_object_at_data
map_object_at_contour = contour_object
if(zonal_mean_plot)
map_object_at_xy = xy_object
end if
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_contour_map_other ;
; wks: workstation object ;
; data: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a contour plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "data" is the 2-dimensional data to be contoured, ;
; and "resources" is an optional list of resources. The Id of the map ;
; plot is returned. ;
; ;
; This function behaves differently from gsn_contour in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If the resource "cnFillOn" is set to True, then a labelbar is ;
; drawn and line labels are turned off. ;
; 4. If data has an attribute called "long_name," and "gsnLeftString";
; hasn't explicitly been set, then the value of this attribute ;
; is used for the left string title. ;
; 5. If data has an attribute called "units," and "gsnRightString" ;
; hasn't explicitly been set, then the value of this attribute ;
; is used for the right string title. ;
;***********************************************************************;
function gsn_csm_contour_map_other(wks:graphic,data:numeric,\
resources:logical)
local i, contour_object, labelbar_object, xy_object, map_object, \
calldraw, callframe, lbar_on, min_lat, max_lat, datanew, \
res, res2, lbres, xy_res, mpres, cnres, levels, colors, \
lbar_zone, lbar_orient, lbar_side, lbar_height, lbar_width, lbar_just, \
map_vpwf, map_vphf, vphf, contour_plot
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_contour_map_other: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
lbar_on = False ; Default is no labelbar.
mpres = True
infolabel_zone = 2 ; Zone for info label (may change later)
lbar_zone = 2 ; Zone for labelbar (may change later)
zonal_zone = 2 ; Zone for zonal means plot
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.(isatt(data,"lat2d").and.isatt(data,"lon2d"))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
datanew = gsn_add_cyclic_point(data)
else
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay contour on map.
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
; Create some contour plot resources.
res2 = True
set_attr(res2,"cnLineLabelBackgroundColor", "transparent")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,mpres)
set_left_subtitle(datanew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; By default, mpOutlineOn is False, unless cnFillOn is set to True
; or mpFillOn is set to False, then it is set back to True.
;
if(check_attr(res2,"cnFillOn",True,False).or.\
check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
lbres = get_res_eq(res2,(/"lb","pm"/))
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT","gsnMask"/))
cnres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm","gsnMask"/))
if(cnres)
if(check_attr(cnres,"cnFillOn",True,False))
set_attr(cnres,"cnInfoLabelOn",False)
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
set_attr(cnres,"cnLineLabelsOn",False)
lbar_on = True ; Turn on a labelbar
if(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True))
set_attr(mpres, "vpWidthF",0.75) ; Make room for labelbar
set_attr(mpres,"vpHeightF",0.75) ; on the side.
set_attr(mpres, "vpXF",0.08)
set_attr(mpres, "vpYF",0.85)
end if
end if
end if
end if
;
; Compute zones for info label and labelbar if
; they are supposed to get drawn.
;
infolabel_on = get_res_value_keep(cnres,"cnInfoLabelOn",True)
if(infolabel_on)
lbar_zone = infolabel_zone + 1
cnres_at_cnInfoLabelZone = infolabel_zone
end if
;
; Increase labelbar zone if map tickmarks are on.
;
if(lbar_on.and.\
check_attr(mpres,"pmTickMarkDisplayMode","Always",True).or.\
check_attr(mpres,"pmTickMarkDisplayMode",2,False).or.\
check_attr(mpres,"pmTickMarkDisplayMode",3,False)) then
lbar_zone = lbar_zone + 1
end if
; Before we create the objects, turn off draw and frame for them.
cnres = True
mpres = True
cnres_at_gsnDraw = False
cnres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
contour_object = gsn_contour(wks,datanew,cnres) ; Create contours.
map_object = gsn_csm_map_other(wks,mpres) ; Create map.
overlay(map_object,contour_object) ; Overlay contours on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.1*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Set font heights only if they haven't been set explicitly by user.
contour_plot = check_class_name(contour_object,"contour")
if(.not.isatt(cnres,"cnLineLabelFontHeightF"))
setvalues contour_plot
"cnLineLabelFontHeightF" : 0.6 * font_height
end setvalues
end if
if(.not.isatt(cnres,"cnInfoLabelFontHeightF"))
setvalues contour_plot
"cnInfoLabelFontHeightF" : 0.6 * font_height
end setvalues
end if
; Create a labelbar.
if(lbar_on)
add_labelbar(wks,contour_object,lbar_zone,0.6 * font_height,"other",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = contour_object_at_data
map_object_at_contour = contour_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_map_ce ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u,v" is the 2-dimensional data to be vectorized, ;
; and "resources" is an optional list of resources. The Id of the map ;
; plot is returned. ;
; ;
; This function behaves differently from gsn_vector in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If data has an attribute called "long_name," and "gsnLeftString";
; hasn't explicitly been set, then the value of this attribute ;
; is used for the left string title. ;
; 4. If data has an attribute called "units," and "gsnRightString" ;
; hasn't explicitly been set, then the value of this attribute ;
; is used for the right string title. ;
; 5. If the resource "vcMonoLineArrowColor" is set to False, then a ;
; labelbar is drawn. ;
;***********************************************************************;
function gsn_csm_vector_map_ce(wks:graphic,u[*][*]:numeric,v[*][*]:numeric,\
resources:logical)
local i, vector_object, map_object, res, res2, calldraw, vcres, \
lbres, map_vpwf, map_vphf, vpwf, vphf, callframe, min_lat, max_lat, \
lbar_on, lbar_zone, unew, vnew
begin
; Initialize.
annolabel_zone = 2 ; Zone for vector anno label
mpres = True
lbar_zone = 2 ; Zone for labelbar (may change later)
lbar_on = False
res2 = get_resources(resources)
if(isatt(res2,"vcRefAnnoOrthogonalPosF")) then
user_set_ref_orth = True
else
user_set_ref_orth = False
end if
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
; Check for coordinate variables. These values will determine where to
; overlay vector on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
if(.not.(isatt(res2,"vfXArray")))
set_attr(res2,"vfXCStartV",-180.)
set_attr(res2,"vfXCEndV", 180.)
end if
if(.not.(isatt(res2,"vfYArray")))
set_attr(res2,"vfYCStartV",-90.)
set_attr(res2,"vfYCEndV", 90.)
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Check for other special resources.
;
if(isatt(res2,"gsnMajorLonSpacing"))
mpres_at_gsnMajorLonSpacing = res2_at_gsnMajorLonSpacing
delete(res2_at_gsnMajorLonSpacing)
end if
if(isatt(res2,"gsnMajorLatSpacing"))
mpres_at_gsnMajorLatSpacing = res2_at_gsnMajorLatSpacing
delete(res2_at_gsnMajorLatSpacing)
end if
if(isatt(res2,"gsnMinorLonSpacing"))
mpres_at_gsnMinorLonSpacing = res2_at_gsnMinorLonSpacing
delete(res2_at_gsnMinorLonSpacing)
end if
if(isatt(res2,"gsnMinorLatSpacing"))
mpres_at_gsnMinorLatSpacing = res2_at_gsnMinorLatSpacing
delete(res2_at_gsnMinorLatSpacing)
end if
;
; Tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",False)
else
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT"/))
vcres = get_res_ne(res2,(/"mp","vp","tm","tx","am","lb","pm"/))
lbres = get_res_eq(res2,(/"lb","pm"/))
if(vcres)
if(check_attr(vcres,"vcMonoLineArrowColor",False,False))
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
lbar_on = True ; Turn on a labelbar
if(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True))
set_attr(mpres, "vpWidthF",0.75) ; Make room for labelbar
set_attr(mpres,"vpHeightF",0.75) ; on the side.
set_attr(mpres, "vpXF",0.08)
set_attr(mpres, "vpYF",0.90)
end if
end if
end if
end if
;
; Default is for the vector reference anno label to be on. To be
; turned off, it has to be explicitly turned off.
;
refanno_on = get_res_value_keep(vcres,"vcRefAnnoOn",True)
if(refanno_on)
;
; If the user is moving the vector annotation around, then
; the labelbar will no longer be in the zone outside the ref anno.
; This is to avoid the problem of the user moving the ref anno into
; the plot, and then having the labelbar follow it up too far, and
; running into the tickmarks.
;
if(user_set_ref_orth) then
lbar_zone = annolabel_zone
else
lbar_zone = annolabel_zone + 1
end if
end if
; Before we create the objects, turn off draw and frame for them.
vcres = True
mpres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
set_attr(vcres,"vcRefAnnoZone",annolabel_zone)
set_attr(vcres,"vcRefAnnoOrthogonalPosF", 0.12)
set_attr(vcres,"vcRefAnnoString2On","False")
vector_object = gsn_vector(wks,unew,vnew,vcres) ; Create vectors
map_object = gsn_csm_map_ce(wks,mpres) ; Create map.
overlay(map_object,vector_object) ; Overlay vectors on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the anno label size the same as the tick mark label size.
getvalues map_object_at_tickmarks
"tmXBLabelFontHeightF" : xbfontf
"tmXBMajorLengthF" : xlength
"tmXBMinorLengthF" : xmlength
end getvalues
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
if(.not.isatt(vcres,"vcRefAnnoFontHeightF"))
setvalues vector_object
"vcRefAnnoFontHeightF" : xbfontf
end setvalues
end if
; Create a labelbar.
if(lbar_on)
add_labelbar(wks,vector_object,lbar_zone,xbfontf,"vector",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = vector_object_at_data
map_object_at_vector = vector_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_map_polar ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot over a polar ;
; stereographic map projection to the workstation "wks" (the variable ;
; returned from a previous call to "gsn_open_wks"). "u,v" is the ;
; 2-dimensional data to be vectorized, and "resources" is an optional ;
; list of resources. The Id of the map plot is returned. ;
; ;
; This function behaves differently from gsn_vector in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The longitude lines are labeled. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top of the plot. ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If either of the resources "gsnPolarNH" or "gsnPolarSH" are set ;
; to True then only the northern or southern hemisphere is ;
; displayed. ;
; 4. If the resource "vcMonoLineArrowColor" is set to False, then a ;
; labelbar is drawn. ;
;***********************************************************************;
function gsn_csm_vector_map_polar(wks:graphic,u[*][*]:numeric, \
v[*][*]:numeric,resources:logical)
local i, vector_object, map_object, res, res2, calldraw, vcres, \
lbres, map_vpwf, map_vphf, vpwf, vphf, callframe, min_lat, max_lat, \
lbar_on, lbar_zone, unew, vnew
begin
; Initialize.
lbar_on = False
annolabel_zone = 2 ; Zone for vector anno label
lbar_zone = 2 ; Zone for labelbar (may change later)
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check for draw and frame.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Check for type of polar plot and polar labels desired.
;
mpres_at_gsnPolar = get_polar_type(res2)
mpres_at_gsnPolarTime = get_res_value(res2,"gsnPolarTime",False)
mpres_at_gsnPolarUT = get_res_value(res2,"gsnPolarUT",0.)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Tickmarks.
;
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
; Create data object and use coordinate variables if they exist.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO", \
"pmT","gsnPolar"/))
vcres = get_res_ne(res2,(/"mp","vp","tm","tx","am","lb","pm","gsnPolar"/))
lbres = get_res_eq(res2,(/"lb","pm"/))
if(vcres)
if(check_attr(vcres,"vcMonoLineArrowColor",False,False))
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
lbar_on = True ; Turn on a labelbar
end if
end if
end if
if(lbar_on)
if(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True))
set_attr(mpres,"vpXF",0.15)
set_attr(vcres,"vcRefAnnoOrthogonalPosF",0.04)
set_attr(lbres,"pmLabelBarOrthogonalPosF",0.1)
else
set_attr(mpres,"vpYF",0.82)
end if
end if
;
; Default is for the vector reference anno label to be on. To be
; turned off, it has to be explicitly turned off.
;
refanno_on = get_res_value_keep(vcres,"vcRefAnnoOn",True)
if(refanno_on)
lbar_zone = annolabel_zone + 1
end if
; Before we create the objects, turn off draw and frame for them.
vcres = True
mpres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
set_attr(vcres,"vcRefAnnoZone",annolabel_zone)
set_attr(vcres,"vcRefAnnoOrthogonalPosF", 0.01)
set_attr(vcres,"vcRefAnnoParallelPosF", 0.8)
set_attr(vcres,"vcRefAnnoString2On","False")
vector_object = gsn_vector(wks,unew,vnew,vcres) ; Create vectors
map_object = gsn_csm_map_polar(wks,mpres) ; Create map.
overlay(map_object,vector_object) ; Overlay vectors on map.
;
; Retrieve the view port location of the map plot so we know where
; to put titles and labelbar (if there is one).
;
getvalues map_object
"vpWidthF" : vpwf
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
2.*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Create a labelbar.
if(lbar_on)
add_labelbar(wks,vector_object,lbar_zone,font_height,"vector",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = vector_object_at_data
map_object_at_vector = vector_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_map_other ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a vector plot over a map plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u"/"v" is the 2-dimensional data to be vectored, ;
; and "resources" is an optional list of resources. The Id of the map ;
; plot is returned. ;
; ;
; This function behaves differently from gsn_vector in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If the resource "vcMonoLineArrowColor" is set to False, then a ;
; labelbar is drawn. ;
;***********************************************************************;
function gsn_csm_vector_map_other(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,resources:logical)
local i, vector_object, labelbar_object, xy_object, map_object, \
calldraw, callframe, lbar_on, min_lat, max_lat, datanew, \
res, res2, lbres, xy_res, mpres, vcres, levels, colors, \
lbar_zone, lbar_orient, lbar_side, lbar_height, lbar_width, lbar_just, \
map_vpwf, map_vphf, vphf
begin
; Initialize.
lbar_on = False ; Default is no labelbar.
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
; Check for coordinate variables. These values will determine where to
; overlay vectors on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; By default, mpOutlineOn is False, unless vcMonoLineArrowColor is set to
; False or mpFillOn is set to False, then it is set back to True.
;
if(check_attr(res2,"vcMonoLineArrowColor",False,False).or.\
check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
lbres = get_res_eq(res2,(/"lb","pm"/))
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT","gsnMask"/))
vcres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm","gsnMask"/))
if(vcres)
if(check_attr(vcres,"vcMonoLineArrowColor",False,False))
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
lbar_on = True ; Turn on a labelbar
end if
end if
end if
; Before we create the objects, turn off draw and frame for them.
vcres = True
mpres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
set_attr(vcres,"vcRefAnnoString2On","False")
vector_object = gsn_vector(wks,unew,vnew,vcres) ; Create vectors.
map_object = gsn_csm_map_other(wks,mpres) ; Create map.
overlay(map_object,vector_object) ; Overlay vectors on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.1*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Set font heights only if they haven't been set explicitly by user.
if(.not.isatt(vcres,"vcRefAnnoFontHeightF"))
setvalues vector_object
"vcRefAnnoFontHeightF" : 0.6 * font_height
end setvalues
end if
; Create a labelbar.
if(lbar_on)
add_labelbar(wks,vector_object,2,0.6 * font_height,"other",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = vector_object_at_data
map_object_at_vector = vector_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_streamline_map_ce ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a streamline plot over a map plot to ;
; the workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u,v" is the 2-dimensional data to be streamlined, ;
; and "resources" is an optional list of resources. The Id of the map ;
; plot is returned. ;
; ;
; This function behaves differently from gsn_streamline in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If data has an attribute called "long_name," and "gsnLeftString";
; hasn't explicitly been set, then the value of this attribute ;
; is used for the left string title. ;
; 4. If data has an attribute called "units," and "gsnRightString" ;
; hasn't explicitly been set, then the value of this attribute ;
; is used for the right string title. ;
;***********************************************************************;
function gsn_csm_streamline_map_ce(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,resources:logical)
local i, stream_object, map_object, stres, calldraw, callframe, \
min_lat, max_lat, unew, vnew, res, res2, map_vpwf, map_vphf, vpwf, vphf
begin
; Initialize.
infolabel_zone = 2 ; Zone for info label (may change later)
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
; Check for coordinate variables. These values will determine where to
; overlay streamline on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
if(.not.(isatt(res2,"vfXArray")))
set_attr(res2,"vfXCStartV",-180.)
set_attr(res2,"vfXCEndV", 180.)
end if
if(.not.(isatt(res2,"vfYArray")))
set_attr(res2,"vfYCStartV",-90.)
set_attr(res2,"vfYCEndV", 90.)
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Check for other special resources.
;
if(isatt(res2,"gsnMajorLonSpacing"))
mpres_at_gsnMajorLonSpacing = res2_at_gsnMajorLonSpacing
delete(res2_at_gsnMajorLonSpacing)
end if
if(isatt(res2,"gsnMajorLatSpacing"))
mpres_at_gsnMajorLatSpacing = res2_at_gsnMajorLatSpacing
delete(res2_at_gsnMajorLatSpacing)
end if
if(isatt(res2,"gsnMinorLonSpacing"))
mpres_at_gsnMinorLonSpacing = res2_at_gsnMinorLonSpacing
delete(res2_at_gsnMinorLonSpacing)
end if
if(isatt(res2,"gsnMinorLatSpacing"))
mpres_at_gsnMinorLatSpacing = res2_at_gsnMinorLatSpacing
delete(res2_at_gsnMinorLatSpacing)
end if
;
; Tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",False)
else
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT"/))
stres = get_res_ne(res2,(/"mp","vp","tm","tx","am"/))
; Before we create the objects, turn off draw and frame for them.
stres = True
mpres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
stream_object = gsn_streamline(wks,unew,vnew,stres) ; Create streamlines
map_object = gsn_csm_map_ce(wks,mpres) ; Create map.
overlay(map_object,stream_object) ; Overlay streamlines on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object_at_tickmarks
"tmXBLabelFontHeightF" : xbfontf
"tmXBMajorLengthF" : xlength
"tmXBMinorLengthF" : xmlength
end getvalues
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = stream_object_at_data
map_object_at_streamline = stream_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_streamline_map_polar ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a streamline plot over a polar ;
; stereographic map projection to the workstation "wks" (the variable ;
; returned from a previous call to "gsn_open_wks"). "u,v" is the ;
; 2-dimensional data to be streamlined, and "resources" is an optional ;
; list of resources. The Id of the map plot is returned. ;
; ;
; This function behaves differently from gsn_streamline in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The longitude lines are labeled. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top of the plot. ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
; 3. If either of the resources "gsnPolarNH" or "gsnPolarSH" are set ;
; to True then only the northern or southern hemisphere is ;
; displayed. ;
;***********************************************************************;
function gsn_csm_streamline_map_polar(wks:graphic,u[*][*]:numeric, \
v[*][*]:numeric,resources:logical)
local i, stream_object, map_object, res, res2, calldraw, stres, \
map_vpwf, map_vphf, vpwf, vphf, callframe, unew, vnew
begin
; Initialize.
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check for draw and frame.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Check for type of polar plot and polar labels desired.
;
mpres_at_gsnPolar = get_polar_type(res2)
mpres_at_gsnPolarTime = get_res_value(res2,"gsnPolarTime",False)
mpres_at_gsnPolarUT = get_res_value(res2,"gsnPolarUT",0.)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Tickmarks.
;
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
; Create data object and use coordinate variables if they exist.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO", \
"pmT","gsnPolar"/))
stres = get_res_ne(res2,(/"mp","vp","tm","tx","am","gsnPolar"/))
; Before we create the objects, turn off draw and frame for them.
stres = True
mpres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
stream_object = gsn_streamline(wks,unew,vnew,stres) ; Create streamlines
map_object = gsn_csm_map_polar(wks,mpres) ; Create map.
overlay(map_object,stream_object) ; Overlay strmlns on map.
;
; Retrieve the view port location of the map plot so we know where
; to put titles.
;
getvalues map_object
"vpWidthF" : vpwf
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
2.*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = stream_object_at_data
map_object_at_streamline = stream_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_streamline_map_other ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a streamline plot over a map plot to ;
; the workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "u"/"v" is the 2-dimensional data to be ;
; streamlined, and "resources" is an optional list of resources. The ;
; id of the map plot is returned. ;
; ;
; This function behaves differently from gsn_streamline in that it will ;
; create a special kind of plot if certain attributes are set. ;
; ;
; 1. The lat/lon grid is labeled with tickmarks. ;
; 2. If any of the special GSUN resources "gsnLeftString," ;
; "gsnCenterString," and/or "gsnRightString" are set, then they ;
; are used to title the top left, center, and right of the plot ;
; (in addition, the regular resource "tiMainString" can be set to ;
; create a regular title). ;
;***********************************************************************;
function gsn_csm_streamline_map_other(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,resources:logical)
local i, stream_object, labelbar_object, xy_object, map_object, \
calldraw, callframe, lbar_on, min_lat, max_lat, datanew, \
res, res2, mpres, stres, map_vpwf, map_vphf, vphf
begin
; Initialize.
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
; Check for coordinate variables. These values will determine where to
; overlay streamlines on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; By default, mpOutlineOn is False, unless mpFillOn is set to False, then
; it is set back to True.
;
if(check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT","gsnMask"/))
stres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","gsnMask"/))
; Before we create the objects, turn off draw and frame for them.
stres = True
mpres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
stream_object = gsn_streamline(wks,unew,vnew,stres) ; Create streamlines.
map_object = gsn_csm_map_other(wks,mpres) ; Create map.
overlay(map_object,stream_object) ; Overlay streamlines on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.1*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_data = stream_object_at_data
map_object_at_streamline = stream_object
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_streamline_contour_map_ce ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_streamline_map_ce except it ;
; overlays contours. ;
;***********************************************************************;
function gsn_csm_streamline_contour_map_ce(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric,resources:logical)
local i, stream_object, map_object, res, res2, \
calldraw, callframe, min_lat, max_lat, unew, vnew, datanew, \
map_vpwf, map_vphf, vpwf, vphf, lbar_on
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_streamline_contour_map_ce: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
infolabel_on = False
lbar_on = True
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay vector on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
if(.not.(isatt(res2,"vfXArray")))
set_attr(res2,"vfXCStartV",-180.)
set_attr(res2,"vfXCEndV", 180.)
end if
if(.not.(isatt(res2,"vfYArray")))
set_attr(res2,"vfYCStartV",-90.)
set_attr(res2,"vfYCEndV", 90.)
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
lbres = get_res_eq(res2,(/"lb","pm"/))
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Check for other special resources.
;
if(isatt(res2,"gsnMajorLonSpacing"))
mpres_at_gsnMajorLonSpacing = res2_at_gsnMajorLonSpacing
delete(res2_at_gsnMajorLonSpacing)
end if
if(isatt(res2,"gsnMajorLatSpacing"))
mpres_at_gsnMajorLatSpacing = res2_at_gsnMajorLatSpacing
delete(res2_at_gsnMajorLatSpacing)
end if
if(isatt(res2,"gsnMinorLonSpacing"))
mpres_at_gsnMinorLonSpacing = res2_at_gsnMinorLonSpacing
delete(res2_at_gsnMinorLonSpacing)
end if
if(isatt(res2,"gsnMinorLatSpacing"))
mpres_at_gsnMinorLatSpacing = res2_at_gsnMinorLatSpacing
delete(res2_at_gsnMinorLatSpacing)
end if
lbar_on = False
; Turn on labelbar if cnFillOn is True and it wasn't explicitly
; turned off.
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnInfoLabelOn",False)
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
set_attr(res2,"cnLineLabelsOn",False)
lbar_on = True ; Turn on a labelbar
end if
end if
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
if(.not.(isatt(res2,"sfXArray")))
set_attr(res2,"sfXCStartV",-180.)
set_attr(res2,"sfXCEndV", 180.)
end if
if(.not.(isatt(res2,"sfYArray")))
set_attr(res2,"sfYCStartV",-90.)
set_attr(res2,"sfYCEndV", 90.)
end if
if(check_attr(res2,"lbLabelBarOn",False,False))
lbar_on = False
end if
; Turn off info label if labelbar is on, unless otherwise specified by user.
if(lbar_on)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
end if
;
; Tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",False)
else
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT"/))
stres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm"/))
; Before we create the objects, turn off draw and frame for them.
stres = True
mpres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
if(lbar_on.and.(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True)))
set_attr(mpres, "vpWidthF",0.75) ; Make room for labelbar
set_attr(mpres,"vpHeightF",0.75) ; on the side.
set_attr(mpres, "vpXF",0.08)
set_attr(mpres, "vpYF",0.90)
end if
set_attr(stres,"cnInfoLabelZone",2)
set_attr(stres,"cnInfoLabelOrthogonalPosF", 0.13)
stream_object = gsn_streamline_contour(wks,unew,vnew,datanew,stres)
map_object = gsn_csm_map_ce(wks,mpres) ; Create map.
overlay(map_object,stream_object) ; Overlay streamlines on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object_at_tickmarks
"tmXBLabelFontHeightF" : xbfontf
end getvalues
getvalues map_object
"vpWidthF" : vpwf
"vpHeightF" : vphf
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Make sure line labels and info labels are same size.
if(.not.isatt(stres,"cnLineLabelFontHeightF"))
setvalues stream_object_at_contour
"cnInfoLabelFontHeightF" : xbfontf
end setvalues
end if
if(.not.isatt(stres,"cnLineLabelFontHeightF"))
setvalues stream_object_at_contour
"cnLineLabelFontHeightF" : xbfontf
end setvalues
end if
; Create a labelbar.
if(lbar_on)
if(.not.infolabel_on)
lbar_zone = 2
else
lbar_zone = 3
end if
add_labelbar(wks,stream_object_at_contour,lbar_zone,xbfontf, \
"vector",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = stream_object_at_vfdata
map_object_at_sfdata = stream_object_at_sfdata
map_object_at_streamline = stream_object
map_object_at_contour = stream_object_at_contour
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_streamline_contour_map_polar ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_streamline_map_polar except it ;
; overlays a contour plot. ;
;***********************************************************************;
function gsn_csm_streamline_contour_map_polar(wks:graphic,u[*][*]:numeric, \
v[*][*]:numeric,data:numeric,
resources:logical)
local i, stream_object, map_object, res, res2, calldraw, vcres, \
lbres, vpwf, vphf, callframe, lbar_on, lbar_zone, unew, vnew
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_streamline_contour_map_polar: Fatal: the input data array must be 1D or 2D")
return
end if
;
; The default is to draw streamlines colored by a scalar field, so this
; means a labelbar should be drawn, and no contour information is
; needed.
;
; Initialize.
res2 = get_resources(resources)
mpres = True
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay streamlines on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check for draw and frame.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Check for type of polar plot and polar labels desired.
;
mpres_at_gsnPolar = get_polar_type(res2)
mpres_at_gsnPolarTime = get_res_value(res2,"gsnPolarTime",False)
mpres_at_gsnPolarUT = get_res_value(res2,"gsnPolarUT",0.)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Determine which annotations (labelbar, info label) should be turned on.
; By default, labelbar is on, and contour info label is off.
;
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnLineLabelsOn",False)
set_attr(res2,"cnLinesOn",False)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
set_attr(res2,"lbLabelBarOn",False)
end if
;
; Check for coordinate variables for scalar field.
;
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
lbar_on = get_res_value_keep(res2,"lbLabelBarOn",True)
lbar_orient = lower_case(get_res_value_keep(res2,"lbOrientation", \
"horizontal"))
infolabel_on = get_res_value_keep(res2,"cnInfoLabelOn",False)
;
; Now that we know what's being drawn for annotations (labelbar,
; info label), we can determine where to put all this
; stuff.
;
if(infolabel_on)
set_attr(res2,"cnInfoLabelZone",2)
set_attr(res2,"cnInfoLabelOrthogonalPosF", 0.1)
set_attr(res2,"cnInfoLabelParallelPosF", 1.0)
set_attr(res2,"cnInfoLabelJust","TopRight")
end if
if(lbar_on)
if(lbar_orient.eq."vertical")
set_attr(res2,"vpXF",0.15)
set_attr(res2,"pmLabelBarOrthogonalPosF",0.1)
else
set_attr(res2,"vpYF",0.82)
end if
end if
;
; Tickmarks.
;
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO", \
"pmT","gsnPolar"/))
stres = get_res_ne(res2,(/"mp","vp","tm","tx","am","lb","pm","gsnPolar"/))
; Before we create the objects, turn off draw and frame for them.
stres = True
mpres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
stream_object = gsn_streamline_contour(wks,unew,vnew,datanew,stres)
map_object = gsn_csm_map_polar(wks,mpres) ; Create map.
overlay(map_object,stream_object) ; Overlay streamlines on map.
; Retrieve plot height so we can compute font height.
getvalues map_object
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Create a labelbar.
if(lbar_on)
if(.not.infolabel_on)
lbar_zone = 2
else
lbar_zone = 3
end if
;
; Get labelbar resources, if any.
;
lbres = get_res_eq(res2,(/"lb","pm"/))
add_labelbar(wks,stream_object_at_contour,lbar_zone,font_height, \
"vector",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = stream_object_at_vfdata
map_object_at_sfdata = stream_object_at_sfdata
map_object_at_streamline = stream_object
map_object_at_contour = stream_object_at_contour
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_streamline_contour_map_other ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_streamline_map_other except ;
; overlays a contour plot. ;
;***********************************************************************;
function gsn_csm_streamline_contour_map_other(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric, \
resources:logical)
local i, stream_object, labelbar_object, map_object, \
calldraw, callframe, lbar_on, min_lat, max_lat, datanew, \
res, res2, lbres, mpres, vcres, levels, colors, \
lbar_zone, lbar_orient, lbar_side, lbar_height, lbar_width, lbar_just, \
map_vpwf, map_vphf, vphf
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_streamline_contour_map_other: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
infolabel_on = False
lbar_on = False ; Default is no labelbar.
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay streamlines on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,mpres)
set_left_subtitle(unew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Determine which annotations (labelbar, info label) should be turned on.
; By default, labelbar is on, and contour info label is off.
;
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnLineLabelsOn",False)
set_attr(res2,"cnLinesOn",False)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
set_attr(res2,"lbLabelBarOn",False)
end if
;
; Check for coordinate variables for scalar field.
;
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
lbar_on = get_res_value_keep(res2,"lbLabelBarOn",True)
lbar_orient = lower_case(get_res_value_keep(res2,"lbOrientation", \
"horizontal"))
infolabel_on = get_res_value_keep(res2,"cnInfoLabelOn",False)
;
; Now that we know what's being drawn for annotations (labelbar,
; info label), we can determine where to put all this
; stuff.
;
if(infolabel_on)
set_attr(res2,"cnInfoLabelZone",2)
set_attr(res2,"cnInfoLabelOrthogonalPosF", 0.1)
set_attr(res2,"cnInfoLabelParallelPosF", 1.0)
set_attr(res2,"cnInfoLabelJust","TopRight")
end if
;
; By default, mpOutlineOn is False, unless mpFillOn is set to False,
; then it is set back to True.
;
if(check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT","gsnMask"/))
stres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm","gsnMask"/))
; Before we create the objects, turn off draw and frame for them.
stres = True
mpres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
stream_object = gsn_streamline_contour(wks,unew,vnew,datanew,stres)
map_object = gsn_csm_map_other(wks,mpres) ; Create map.
overlay(map_object,stream_object) ; Overlay streamlines on map.
; Retrieve plot height so we can compute font height.
getvalues map_object
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
2.*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Create a labelbar.
if(lbar_on)
if(.not.infolabel_on)
lbar_zone = 2
else
lbar_zone = 3
end if
;
; Get labelbar resources, if any.
;
lbres = get_res_eq(res2,(/"lb","pm"/))
add_labelbar(wks,stream_object_at_contour,lbar_zone,font_height, \
"vector",lbres)
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = stream_object_at_vfdata
map_object_at_sfdata = stream_object_at_sfdata
map_object_at_vector = stream_object
map_object_at_contour = stream_object_at_contour
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_scalar ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function colors vectors according to a scalar field. ;
; ;
; There's a special resource associated with this function called ;
; "gsnScalarContour". If it's set to True, then the scalar field will ;
; be drawn as a contour plot. Otherwise, the vectors will be colored ;
; according to the scalar field. This resource defaults to False. ;
;***********************************************************************;
function gsn_csm_vector_scalar(wks:graphic,u[*][*]:numeric,v[*][*]:numeric, \
data:numeric,resources:logical)
local i, vector_object, res, res2, \
calldraw, callframe, unew, vnew, datanew, vpwf, vphf, lbar_on
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_vector_scalar: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
main_zone = 2 ; Zone for main title (may change later)
infolabel_on = False
refanno_on = True
lbar_on = True
res2 = get_resources(resources)
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",True)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,res2)
set_left_subtitle(datanew,res2,res2)
; Check for existence of the left, center, and right subtitles.
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = main_zone+1
end if
; Check if gsnShape set.
if(check_attr(res2,"gsnShape",True,False))
main_zone = main_zone+1 ; Zone for main title
end if
; Use coordinate variables for X and/or Y if they exist.
check_for_coord_arrays(datanew,res2,"contour")
check_for_coord_arrays(unew,res2,"vector")
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for type of scalar field representation.
scalar_contour = get_res_value(res2,"gsnScalarContour",False)
; Get labelbar resources.
lbres = get_res_eq(res2,(/"lb","pm"/))
if(scalar_contour)
lbar_on = False
; Turn on labelbar if cnFillOn is True and it wasn't explicitly
; turned off.
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnInfoLabelOn",False)
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
set_attr(res2,"cnLineLabelsOn",False)
lbar_on = True ; Turn on a labelbar
end if
end if
end if
if(check_attr(res2,"lbLabelBarOn",False,False))
lbar_on = False
end if
; Turn off anno label if specified by user.
if(check_attr(res2,"vcRefAnnoOn",False,False))
refanno_on = False
end if
; Turn off info label if labelbar is on, unless otherwise specified by user.
if(scalar_contour)
if(lbar_on)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
end if
infolabel_on = res2_at_cnInfoLabelOn
end if
if(lbar_on.and.(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True)))
set_attr(res2, "vpWidthF",0.75) ; Make room for labelbar
set_attr(res2,"vpHeightF",0.75) ; on the side.
set_attr(res2, "vpXF",0.08)
set_attr(res2, "vpYF",0.90)
end if
if(scalar_contour.and.infolabel_on)
set_attr(res2,"cnInfoLabelZone",2)
set_attr(res2,"cnInfoLabelOrthogonalPosF", 0.13)
end if
if(refanno_on)
if(infolabel_on)
set_attr(res2,"vcRefAnnoParallelPosF",0.)
set_attr(res2,"vcRefAnnoJust","TopLeft")
end if
set_attr(res2,"vcRefAnnoString2On","False")
set_attr(res2,"vcRefAnnoZone",2)
set_attr(res2,"vcRefAnnoOrthogonalPosF", 0.13)
end if
; Before we create the vector object, turn off draw and frame for it.
vcres = get_res_ne(res2,(/"mp","lb","tx","am","pm"/))
vcres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
if(scalar_contour)
vector_object = gsn_vector_contour(wks,unew,vnew,datanew,vcres)
else
vector_object = gsn_vector_scalar(wks,unew,vnew,datanew,vcres)
end if
; Add lat/lon labels to X/Y axes if appropriate coordinate arrays exist.
add_latlon_labels(vector_object,unew,res2)
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues vector_object
"vpHeightF" : height
"vpWidthF" : width
"tmXBLabelFontHeightF" : xbfontf
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
"tmYLMajorLengthF" : ylength
"tmXBMajorLengthF" : xlength
"tmYLMinorLengthF" : ymlength
"tmXBMinorLengthF" : xmlength
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make subtitle label sizes a
; function of the size of the
; X/Y axis labels.
major_length = min((/ylength,xlength/)) ; New length for major ticks.
minor_length = min((/ymlength,xmlength/)) ; New length for minor ticks.
; If the plot is close to square in size, then make the
; three top titles and the tick marks smaller.
font_scale = (/1.0,0.8,0.8/)
ratios = (/0.5,0.75,1.0/)
ratio = height/width
if(ratio.gt.1)
ratio = 1./ratio
end if
index = ind(ratio.le.ratios)
scale = font_scale(index(0))
font_height = scale * font_height
;
; Make tick marks same length and point outward.
;
major_length = scale * major_length
minor_length = scale * minor_length
tmres = get_res_eq(res2,"tm")
gsnp_point_tickmarks_outward(vector_object,tmres,xlength,ylength,\
xmlength,ymlength,\
major_length,minor_length,point_outward)
; Make sure info labels, line labels, and vector labels are same size.
if(scalar_contour)
if(.not.isatt(res2,"cnLineLabelFontHeightF"))
setvalues vector_object_at_contour
"cnInfoLabelFontHeightF" : xbfontf
end setvalues
end if
if(.not.isatt(res2,"cnLineLabelFontHeightF"))
setvalues vector_object_at_contour
"cnLineLabelFontHeightF" : xbfontf
end setvalues
end if
end if
if(.not.isatt(res2,"vcRefAnnoFontHeightF"))
setvalues vector_object
"vcRefAnnoFontHeightF" : xbfontf
end setvalues
end if
; Create a labelbar.
if(lbar_on)
if(.not.refanno_on.and..not.infolabel_on)
lbar_zone = 2
else
lbar_zone = 3
end if
if(scalar_contour)
add_labelbar(wks,vector_object_at_contour,lbar_zone,xbfontf, \
"vector",lbres)
else
add_labelbar(wks,vector_object,lbar_zone,xbfontf, \
"vector",lbres)
end if
end if
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"tx","am"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",font_height)
add_subtitles(wks,vector_object,left_string,center_string,\
right_string,subres)
; Draw all this stuff: vector/contour plot, subtitles, and tick marks.
draw_and_frame(wks,vector_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
vector_object_at_vfdata = vector_object_at_vfdata
vector_object_at_sfdata = vector_object_at_sfdata
if(scalar_contour)
vector_object_at_contour = vector_object_at_contour
end if
return(vector_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_scalar_map_ce ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_vector_map_ce except it colors the;
; vectors according to a scalar field. ;
; ;
; There's a special resource associated with this function called ;
; "gsnScalarContour". If it's set to True, then the scalar field will ;
; be drawn as a contour plot. Otherwise, the vectors will be colored ;
; according to the scalar field. This resource defaults to False. ;
;***********************************************************************;
function gsn_csm_vector_scalar_map_ce(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric,resources:logical)
local i, vector_object, map_object, res, res2, \
calldraw, callframe, min_lat, max_lat, unew, vnew, datanew, \
map_vpwf, map_vphf, vpwf, vphf, lbar_on
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_vector_scalar_map_ce: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
infolabel_on = False
refanno_on = True
lbar_on = True
mpres = True
res2 = get_resources(resources)
if(isatt(res2,"vcRefAnnoOrthogonalPosF")) then
user_set_ref_orth = True
else
user_set_ref_orth = False
end if
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay vector on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
if(.not.(isatt(res2,"vfXArray")))
set_attr(res2,"vfXCStartV",-180.)
set_attr(res2,"vfXCEndV", 180.)
end if
if(.not.(isatt(res2,"vfYArray")))
set_attr(res2,"vfYCStartV",-90.)
set_attr(res2,"vfYCEndV", 90.)
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,mpres)
set_left_subtitle(datanew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
lbres = get_res_eq(res2,(/"lb","pm"/))
; Check for type of scalar field representation.
scalar_contour = get_res_value(res2,"gsnScalarContour",False)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Check for other special resources.
;
if(isatt(res2,"gsnMajorLonSpacing"))
mpres_at_gsnMajorLonSpacing = res2_at_gsnMajorLonSpacing
delete(res2_at_gsnMajorLonSpacing)
end if
if(isatt(res2,"gsnMajorLatSpacing"))
mpres_at_gsnMajorLatSpacing = res2_at_gsnMajorLatSpacing
delete(res2_at_gsnMajorLatSpacing)
end if
if(isatt(res2,"gsnMinorLonSpacing"))
mpres_at_gsnMinorLonSpacing = res2_at_gsnMinorLonSpacing
delete(res2_at_gsnMinorLonSpacing)
end if
if(isatt(res2,"gsnMinorLatSpacing"))
mpres_at_gsnMinorLatSpacing = res2_at_gsnMinorLatSpacing
delete(res2_at_gsnMinorLatSpacing)
end if
if(scalar_contour)
lbar_on = False
; Turn on labelbar if cnFillOn is True and it wasn't explicitly
; turned off.
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnInfoLabelOn",False)
if(.not.isatt(lbres,"lbLabelBarOn").or.\
check_attr(lbres,"lbLabelBarOn",True,False))
set_attr(res2,"cnLineLabelsOn",False)
lbar_on = True ; Turn on a labelbar
end if
end if
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
if(.not.(isatt(res2,"sfXArray")))
set_attr(res2,"sfXCStartV",-180.)
set_attr(res2,"sfXCEndV", 180.)
end if
if(.not.(isatt(res2,"sfYArray")))
set_attr(res2,"sfYCStartV",-90.)
set_attr(res2,"sfYCEndV", 90.)
end if
end if
if(check_attr(res2,"lbLabelBarOn",False,False))
lbar_on = False
end if
; Turn off anno label if specified by user.
if(check_attr(res2,"vcRefAnnoOn",False,False))
refanno_on = False
end if
; Turn off info label if labelbar is on, unless otherwise specified by user.
if(scalar_contour)
if(lbar_on)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
end if
infolabel_on = res2_at_cnInfoLabelOn
end if
;
; Tickmarks.
;
display_mode = get_display_mode(res2,"pmTickMarkDisplayMode","nocreate")
if(display_mode.eq.1.or.display_mode.eq.2) then
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",False)
else
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT"/))
vcres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm"/))
; Before we create the objects, turn off draw and frame for them.
vcres = True
mpres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
if(lbar_on.and.(check_attr(lbres,"lbOrientation","vertical",True).or.\
check_attr(lbres,"lbOrientation",1,True)))
set_attr(mpres, "vpWidthF",0.75) ; Make room for labelbar
set_attr(mpres,"vpHeightF",0.75) ; on the side.
set_attr(mpres, "vpXF",0.08)
set_attr(mpres, "vpYF",0.90)
end if
if(scalar_contour.and.infolabel_on)
set_attr(vcres,"cnInfoLabelZone",2)
set_attr(vcres,"cnInfoLabelOrthogonalPosF", 0.13)
end if
if(refanno_on)
if(infolabel_on)
set_attr(vcres,"vcRefAnnoParallelPosF",0.)
set_attr(vcres,"vcRefAnnoJust","TopLeft")
end if
set_attr(vcres,"vcRefAnnoString2On","False")
set_attr(vcres,"vcRefAnnoZone",2)
set_attr(vcres,"vcRefAnnoOrthogonalPosF", 0.13)
end if
if(scalar_contour)
vector_object = gsn_vector_contour(wks,unew,vnew,datanew,vcres)
else
vector_object = gsn_vector_scalar(wks,unew,vnew,datanew,vcres)
end if
map_object = gsn_csm_map_ce(wks,mpres) ; Create map.
overlay(map_object,vector_object) ; Overlay vectors on map.
; Retrieve some font heights and make the X/Y axis labels the same
; size, and the info label size the same as the tick mark label size.
getvalues map_object_at_tickmarks
"tmXBLabelFontHeightF" : xbfontf
end getvalues
getvalues map_object
"vpWidthF" : vpwf
"vpHeightF" : vphf
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Make sure info labels, line labels, and vector labels are same size.
if(scalar_contour)
if(.not.isatt(vcres,"cnLineLabelFontHeightF"))
setvalues vector_object_at_contour
"cnInfoLabelFontHeightF" : xbfontf
end setvalues
end if
if(.not.isatt(vcres,"cnLineLabelFontHeightF"))
setvalues vector_object_at_contour
"cnLineLabelFontHeightF" : xbfontf
end setvalues
end if
end if
if(.not.isatt(vcres,"vcRefAnnoFontHeightF"))
setvalues vector_object
"vcRefAnnoFontHeightF" : xbfontf
end setvalues
end if
; Create a labelbar.
if(lbar_on)
if(.not.refanno_on.and..not.infolabel_on)
lbar_zone = 2
else
;
; If the user is moving the vector annotation around, then
; the labelbar will no longer be in the zone outside the ref anno.
; This is to avoid the problem of the user moving the ref anno into
; the plot, and then having the labelbar follow it up too far, and
; running into the tickmarks.
;
if(user_set_ref_orth) then
lbar_zone = 2
else
lbar_zone = 3
end if
end if
if(scalar_contour)
add_labelbar(wks,vector_object_at_contour,lbar_zone,xbfontf, \
"vector",lbres)
else
add_labelbar(wks,vector_object,lbar_zone,xbfontf, \
"vector",lbres)
end if
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = vector_object_at_vfdata
map_object_at_sfdata = vector_object_at_sfdata
if(scalar_contour)
map_object_at_vector = vector_object
map_object_at_contour = vector_object_at_contour
else
map_object_at_vector = vector_object
end if
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_scalar_map_polar ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_vector_map_polar except it either ;
; colors the vectors according to a scalar field, or it overlays a ;
; contour plot. ;
; ;
; There's a special resource associated with this function called ;
; "gsnScalarContour". If it's set to True, then the scalar field will ;
; be drawn as a contour plot. Otherwise, the vectors will be colored ;
; according to the scalar field. This resource defaults to False. ;
;***********************************************************************;
function gsn_csm_vector_scalar_map_polar(wks:graphic,u[*][*]:numeric, \
v[*][*]:numeric,data:numeric,
resources:logical)
local i, vector_object, map_object, res, res2, calldraw, vcres, \
lbres, vpwf, vphf, callframe, lbar_on, lbar_zone, unew, vnew
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_vector_scalar_map_polar: Fatal: the input data array must be 1D or 2D")
return
end if
;
; The default is to draw vectors colored by a scalar field, so this
; means a labelbar should be drawn, and no contour information is
; needed.
;
; Initialize.
res2 = get_resources(resources)
mpres = True
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay vectors on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,mpres)
set_left_subtitle(datanew,res2,mpres)
; Check for draw and frame.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Check for type of polar plot and scalar field representation.
;
mpres_at_gsnPolar = get_polar_type(res2)
mpres_at_gsnPolarTime = get_res_value(res2,"gsnPolarTime",False)
mpres_at_gsnPolarUT = get_res_value(res2,"gsnPolarUT",0.)
scalar_contour = get_res_value(res2,"gsnScalarContour",False)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
;
; Determine which annotations (labelbar, vector reference anno, info label)
; should be turned on. By default, labelbar and vector anno are on, and
; contour info label is off.
;
if(scalar_contour)
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnLineLabelsOn",False)
set_attr(res2,"cnLinesOn",False)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
set_attr(res2,"lbLabelBarOn",False)
end if
;
; Check for coordinate variables for scalar field.
;
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
end if
lbar_on = get_res_value_keep(res2,"lbLabelBarOn",True)
lbar_orient = lower_case(get_res_value_keep(res2,"lbOrientation", \
"horizontal"))
infolabel_on = get_res_value_keep(res2,"cnInfoLabelOn",False)
refanno_on = get_res_value_keep(res2,"vcRefAnnoOn",True)
;
; Now that we know what's being drawn for annotations (labelbar,
; info label, ref anno), we can determine where to put all this
; stuff. If both info label and ref anno are on, put the info label
; on the right, and the ref anno on the left. If only one of them is
; on, put it on the right.
;
if(refanno_on)
set_attr(res2,"vcRefAnnoZone",2)
set_attr(res2,"vcRefAnnoString2On","False")
if(infolabel_on)
set_attr(res2,"vcRefAnnoOrthogonalPosF", 0.1)
set_attr(res2,"vcRefAnnoJust","TopLeft")
set_attr(res2,"vcRefAnnoParallelPosF", 0.0)
else
set_attr(res2,"vcRefAnnoOrthogonalPosF",0.02)
set_attr(res2,"vcRefAnnoParallelPosF",0.8)
end if
end if
if(infolabel_on)
set_attr(res2,"cnInfoLabelZone",2)
set_attr(res2,"cnInfoLabelOrthogonalPosF", 0.1)
set_attr(res2,"cnInfoLabelParallelPosF", 1.0)
set_attr(res2,"cnInfoLabelJust","TopRight")
end if
if(lbar_on)
if(lbar_orient.eq."vertical")
set_attr(res2,"vpXF",0.15)
set_attr(res2,"pmLabelBarOrthogonalPosF",0.1)
else
set_attr(res2,"vpYF",0.82)
end if
end if
;
; Tickmarks.
;
mpres_at_gsnTickMarksOn = get_res_value(res2,"gsnTickMarksOn",True)
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO",\
"pmT","gsnPolar"/))
vcres = get_res_ne(res2,(/"mp","vp","tm","tx","am","lb","pm","gsnPolar"/))
; Before we create the objects, turn off draw and frame for them.
vcres = True
mpres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
if(scalar_contour)
vector_object = gsn_vector_contour(wks,unew,vnew,datanew,vcres)
else
vector_object = gsn_vector_scalar(wks,unew,vnew,datanew,vcres)
end if
map_object = gsn_csm_map_polar(wks,mpres) ; Create map.
overlay(map_object,vector_object) ; Overlay vectors on map.
; Retrieve plot height so we can compute font height.
getvalues map_object
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
1.3*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Create a labelbar.
if(lbar_on)
if(.not.refanno_on.and..not.infolabel_on)
lbar_zone = 2
else
lbar_zone = 3
end if
;
; Get labelbar resources, if any.
;
lbres = get_res_eq(res2,(/"lb","pm"/))
if(scalar_contour)
add_labelbar(wks,vector_object_at_contour,lbar_zone,font_height, \
"vector",lbres)
else
add_labelbar(wks,vector_object,lbar_zone,font_height, \
"vector",lbres)
end if
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = vector_object_at_vfdata
map_object_at_sfdata = vector_object_at_sfdata
if(scalar_contour)
map_object_at_vector = vector_object
map_object_at_contour = vector_object_at_contour
else
map_object_at_vector = vector_object
end if
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_vector_scalar_map_other ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional scalar data ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_vector_map_other except it either ;
; colors the vectors according to a scalar field, or it overlays a ;
; contour plot. ;
; ;
; There's a special resource associated with this function called ;
; "gsnScalarContour". If it's set to True, then the scalar field will ;
; be drawn as a contour plot. Otherwise, the vectors will be colored ;
; according to the scalar field. This resource defaults to False. ;
;***********************************************************************;
function gsn_csm_vector_scalar_map_other(wks:graphic,u[*][*]:numeric,\
v[*][*]:numeric,data:numeric, \
resources:logical)
local i, vector_object, labelbar_object, map_object, \
calldraw, callframe, lbar_on, min_lat, max_lat, datanew, \
res, res2, lbres, mpres, vcres, levels, colors, \
lbar_zone, lbar_orient, lbar_side, lbar_height, lbar_width, lbar_just, \
map_vpwf, map_vphf, vphf
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_vector_scalar_map_other: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
infolabel_on = False
refanno_on = True
lbar_on = False ; Default is no labelbar.
mpres = True
res2 = get_resources(resources)
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.((isatt(u,"lat2d").and.isatt(u,"lon2d")).or.\
(isatt(v,"lat2d").and.isatt(v,"lon2d")).or.\
(isatt(data,"lat2d").and.isatt(data,"lon2d")))
if(get_res_value(res2,"gsnAddCyclic",set_cyclic)) then
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
datanew = gsn_add_cyclic_point(data)
else
unew = u
vnew = v
datanew = data
end if
; Check for coordinate variables. These values will determine where to
; overlay vectors on map.
check_for_y_lat_coord(unew,res2,"vector_map")
check_for_lon_coord(unew,res2,"vector_map")
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,mpres)
set_left_subtitle(datanew,res2,mpres)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for subtitles at top and add to mpres if exist.
set_subtitles_res(res2,mpres)
; Check for type of scalar field representation.
scalar_contour = get_res_value(res2,"gsnScalarContour",False)
;
; Determine which annotations (labelbar, vector reference anno, info label)
; should be turned on. By default, labelbar and vector anno are on, and
; contour info label is off.
;
if(scalar_contour)
if(check_attr(res2,"cnFillOn",True,False))
set_attr(res2,"cnFillDrawOrder","Predraw")
set_attr(res2,"cnLineLabelsOn",False)
set_attr(res2,"cnLinesOn",False)
set_attr(res2,"cnInfoLabelOn",False)
else
set_attr(res2,"cnInfoLabelOn",True)
set_attr(res2,"lbLabelBarOn",False)
end if
;
; Check for coordinate variables for scalar field.
;
check_for_y_lat_coord(datanew,res2,"contour_map")
check_for_lon_coord(datanew,res2,"contour_map")
end if
lbar_on = get_res_value_keep(res2,"lbLabelBarOn",True)
lbar_orient = lower_case(get_res_value_keep(res2,"lbOrientation", \
"horizontal"))
infolabel_on = get_res_value_keep(res2,"cnInfoLabelOn",False)
refanno_on = get_res_value_keep(res2,"vcRefAnnoOn",True)
;
; Now that we know what's being drawn for annotations (labelbar,
; info label, ref anno), we can determine where to put all this
; stuff. If both info label and ref anno are on, put the info label
; on the right, and the ref anno on the left. If only one of them is
; on, put it on the right.
;
if(refanno_on)
set_attr(res2,"vcRefAnnoZone",2)
set_attr(res2,"vcRefAnnoString2On","False")
if(infolabel_on)
set_attr(res2,"vcRefAnnoOrthogonalPosF", 0.1)
set_attr(res2,"vcRefAnnoJust","TopLeft")
set_attr(res2,"vcRefAnnoParallelPosF", 0.0)
else
set_attr(res2,"vcRefAnnoOrthogonalPosF",0.02)
set_attr(res2,"vcRefAnnoParallelPosF",0.8)
end if
end if
if(infolabel_on)
set_attr(res2,"cnInfoLabelZone",2)
set_attr(res2,"cnInfoLabelOrthogonalPosF", 0.1)
set_attr(res2,"cnInfoLabelParallelPosF", 1.0)
set_attr(res2,"cnInfoLabelJust","TopRight")
end if
;
; By default, mpOutlineOn is False, unless vcMonoLineArrowColor is set to
; False or mpFillOn is set to False, then it is set back to True.
;
if(check_attr(res2,"vcMonoLineArrowColor",False,False).or.\
check_attr(res2,"mpFillOn",False,False))
set_attr(res2,"mpOutlineOn",True)
end if
; This section tests for regular resources.
mpres = get_res_eq(res2,(/"mp","vp","tm","ti","tx","am","pmA","pmO","pmT","gsnMask"/))
vcres = get_res_ne(res2,(/"mp","vp","tm","lb","tx","am","pm","gsnMask"/))
; Before we create the objects, turn off draw and frame for them.
vcres = True
mpres = True
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
mpres_at_gsnDraw = False
mpres_at_gsnFrame = False
if(scalar_contour)
vector_object = gsn_vector_contour(wks,unew,vnew,datanew,vcres)
else
vector_object = gsn_vector_scalar(wks,unew,vnew,datanew,vcres)
end if
map_object = gsn_csm_map_other(wks,mpres) ; Create map.
overlay(map_object,vector_object) ; Overlay vectors on map.
; Retrieve plot height so we can compute font height.
getvalues map_object
"vpHeightF" : vphf
end getvalues
; Make sure axes labels are the same size.
font_height = 0.02 * vphf ; Make various label sizes a function
; of the height of the viewport.
;
; Check if user setting own font heights.
;
main_font_height = get_res_value(res2,"tiMainFontHeightF", \
2.*font_height)
setvalues map_object
"tiMainFontHeightF" : main_font_height ; main title size
end setvalues
; Set font heights only if they haven't been set explicitly by user.
if(.not.isatt(vcres,"vcRefAnnoFontHeightF"))
setvalues vector_object
"vcRefAnnoFontHeightF" : font_height
end setvalues
end if
; Create a labelbar.
if(lbar_on)
if(.not.refanno_on.and..not.infolabel_on)
lbar_zone = 2
else
lbar_zone = 3
end if
;
; Get labelbar resources, if any.
;
lbres = get_res_eq(res2,(/"lb","pm"/))
if(scalar_contour)
add_labelbar(wks,vector_object_at_contour,lbar_zone,font_height, \
"vector",lbres)
else
add_labelbar(wks,vector_object,lbar_zone,font_height, \
"vector",lbres)
end if
end if
; Draw all this stuff: map plot, subtitles, and tick marks.
draw_and_frame(wks,map_object,calldraw,callframe,0,maxbb)
; Return plot object and data object (as attribute of plot object).
map_object_at_vfdata = vector_object_at_vfdata
map_object_at_sfdata = vector_object_at_sfdata
if(scalar_contour)
map_object_at_vector = vector_object
map_object_at_contour = vector_object_at_contour
else
map_object_at_vector = vector_object
end if
return(map_object)
end
;***********************************************************************;
; Function : gsn_csm_contour_map ;
; wks: workstation object ;
; data: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function calls either gsn_csm_contour_map_ce, ;
; gsn_csm_contour_map_polar or gsn_csm_contour_map_polar depending on ;
; the map projection selected. ;
;***********************************************************************;
function gsn_csm_contour_map(wks:graphic,data:numeric,resources:logical)
local res
begin
res = get_resources(resources)
if(res.and.(isatt(res,"gsnPolarNH").or.isatt(res,"gsnPolarSH").or.\
isatt(res,"gsnPolar")))
return(gsn_csm_contour_map_polar(wks,data,res))
else
if((check_attr(res,"mpProjection","CylindricalEquidistant",True).or.\
check_attr(res,"mpProjection",8,True)).or.\
.not.isatt(res,"mpProjection"))
return(gsn_csm_contour_map_ce(wks,data,res))
else
return(gsn_csm_contour_map_other(wks,data,res))
end if
end if
end
;***********************************************************************;
; Function : gsn_csm_streamline_map ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function calls either gsn_csm_streamline_map_ce, ;
; gsn_csm_streamline_map_polar or gsn_csm_streamline_map_other ;
; depending on the map projection selected. ;
;***********************************************************************;
function gsn_csm_streamline_map(wks:graphic,u[*][*]:numeric,v[*][*]:numeric,\
resources:logical)
local res
begin
res = get_resources(resources)
if(res.and.(isatt(res,"gsnPolarNH").or.isatt(res,"gsnPolarSH").or.\
isatt(res,"gsnPolar")))
return(gsn_csm_streamline_map_polar(wks,u,v,res))
else
if((check_attr(res,"mpProjection","CylindricalEquidistant",True).or.\
check_attr(res,"mpProjection",8,True)).or.\
.not.isatt(res,"mpProjection"))
return(gsn_csm_streamline_map_ce(wks,u,v,res))
else
return(gsn_csm_streamline_map_other(wks,u,v,res))
end if
end if
end
;***********************************************************************;
; Function : gsn_csm_vector_map ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function calls either gsn_csm_vector_map_ce, ;
; gsn_csm_vector_map_polar or gsn_csm_vector_map_polar depending on the ;
; map projection selected. ;
;***********************************************************************;
function gsn_csm_vector_map(wks:graphic,u[*][*]:numeric,v[*][*]:numeric,\
resources:logical)
local res
begin
res = get_resources(resources)
if(res.and.(isatt(res,"gsnPolarNH").or.isatt(res,"gsnPolarSH").or.\
isatt(res,"gsnPolar")))
return(gsn_csm_vector_map_polar(wks,u,v,res))
else
if((check_attr(res,"mpProjection","CylindricalEquidistant",True).or.\
check_attr(res,"mpProjection",8,True)).or.\
.not.isatt(res,"mpProjection"))
return(gsn_csm_vector_map_ce(wks,u,v,res))
else
return(gsn_csm_vector_map_other(wks,u,v,res))
end if
end if
end
;***********************************************************************;
; Function : gsn_csm_vector_scalar_map ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function calls either gsn_csm_vector_scalar_map_ce, ;
; gsn_csm_vector_scalar_map_polar or gsn_csm_vector_scalar_map_other ;
; depending on the map projection selected. ;
;***********************************************************************;
function gsn_csm_vector_scalar_map(wks:graphic,u[*][*]:numeric, \
v[*][*]:numeric,data:numeric, \
resources:logical)
local res
begin
res = get_resources(resources)
if(res.and.(isatt(res,"gsnPolarNH").or.isatt(res,"gsnPolarSH").or.\
isatt(res,"gsnPolar")))
return(gsn_csm_vector_scalar_map_polar(wks,u,v,data,res))
else
if((check_attr(res,"mpProjection","CylindricalEquidistant",True).or.\
check_attr(res,"mpProjection",8,True)).or.\
.not.isatt(res,"mpProjection"))
return(gsn_csm_vector_scalar_map_ce(wks,u,v,data,res))
else
return(gsn_csm_vector_scalar_map_other(wks,u,v,data,res))
end if
end if
end
;***********************************************************************;
; Function : gsn_csm_streamline_contour_map ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; data: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function calls either gsn_csm_streamline_contour_map_ce, ;
; gsn_csm_streamline_contour_map_polar, or ;
; gsn_csm_streamline_contour_map_other depending on the map projection ;
; selected. ;
;***********************************************************************;
function gsn_csm_streamline_contour_map(wks:graphic,u[*][*]:numeric, \
v[*][*]:numeric,data:numeric, \
resources:logical)
local res
begin
res = get_resources(resources)
if(res.and.(isatt(res,"gsnPolarNH").or.isatt(res,"gsnPolarSH").or.\
isatt(res,"gsnPolar")))
return(gsn_csm_streamline_contour_map_polar(wks,u,v,data,res))
else
if((check_attr(res,"mpProjection","CylindricalEquidistant",True).or.\
check_attr(res,"mpProjection",8,True)).or.\
.not.isatt(res,"mpProjection"))
return(gsn_csm_streamline_contour_map_ce(wks,u,v,data,res))
else
return(gsn_csm_streamline_contour_map_other(wks,u,v,data,res))
end if
end if
end
;***********************************************************************;
; Function : gsn_csm_contour_map_overlay ;
; wks: workstation object ;
; data1: 2-dimensional data ;
; data2: 2-dimensional data ;
; res1: optional resources ;
; res2: optional resources ;
; ;
; This is similar to gsn_csm_contour_map, only it overlays an ;
; additional contour plot. ;
; ;
;***********************************************************************;
function gsn_csm_contour_map_overlay(wks:graphic,data1[*][*]:numeric,\
data2[*][*]:numeric,res1:logical, \
res2:logical)
local calldraw, callframe, res1_tmp, res2_tmp
begin
res1_tmp = get_resources(res1) ; Transfer attributes
res2_tmp = get_resources(res2) ; Transfer attributes
res1_tmp = True
res2_tmp = True
calldraw = get_res_value(res1_tmp,"gsnDraw", True)
callframe = get_res_value(res1_tmp,"gsnFrame",True)
maxbb = get_bb_res(res1_tmp)
res1_tmp_at_gsnDraw = False
res1_tmp_at_gsnFrame = False
; Default for first plot is to turn fill on and turn off lines and line
; labels.
if(.not.isatt(res1_tmp,"cnFillOn"))
res1_tmp_at_cnFillOn = True
set_attr(res1_tmp,"cnInfoLabelOn",False)
end if
set_attr(res1_tmp,"cnLinesOn",False)
set_attr(res1_tmp,"cnLineLabelsOn",False)
contour1 = gsn_csm_contour_map(wks,data1,res1_tmp)
res2_tmp_at_gsnDraw = False
res2_tmp_at_gsnFrame = False
; Check for cyclic point (default is True if we are not setting both
; lon2d/lat2d attributes).
set_cyclic = .not.(isatt(data2,"lat2d").and.isatt(data2,"lon2d"))
if(get_res_value(res2_tmp,"gsnAddCyclic",set_cyclic)) then
datanew = gsn_add_cyclic_point(data2)
else
datanew = data2
end if
check_for_y_lat_coord(datanew,res2_tmp,"contour_map")
check_for_lon_coord(datanew,res2_tmp,"contour_map")
; Default for second plot is to draw line labels, but make background
; label box transparent. Also, move the info label around depending on
; whether the labelbar from the first plot is on the side or the bottom.
set_attr(res2_tmp,"cnLineLabelBackgroundColor",-1)
if(.not.isatt(res2_tmp,"cnInfoLabelOrthogonalPosF"))
if(res1_tmp_at_cnFillOn)
if(check_attr(res1_tmp,"lbOrientation","horizontal",True).or.\
check_attr(res1_tmp,"lbOrientation",0,True))
set_attr(res2_tmp,"cnInfoLabelOrthogonalPosF",-0.01)
else
set_attr(res2_tmp,"cnInfoLabelOrthogonalPosF",0.12)
end if
else
set_attr(res2_tmp,"cnInfoLabelOrthogonalPosF",0.12)
end if
end if
contour2 = gsn_contour(wks,datanew,res2_tmp)
overlay(contour1,contour2)
; Draw all this stuff: contour plots and subtitles.
draw_and_frame(wks,contour1,calldraw,callframe,0,maxbb)
; Return contour plot object.
contour1_at_contour2 = contour2
return(contour1)
end
;***********************************************************************;
; Function : gsn_csm_xy ;
; wks: workstation object ;
; x: X values ;
; y: X values ;
; resources: optional resources ;
; ;
; This function creates and draws a titled XY plot to the workstation ;
; "wks" (the variable returned from a previous call to "gsn_open_wks"). ;
; "resources" is an optional list of resources. The Id of the map plot ;
; is returned. ;
; ;
; This function behaves differently from gsn_xy in that it will ;
; add additional titles to the top of the plot if any of the special ;
; GSUN resources "gsnLeftString," "gsnCenterString," and/or ;
; "gsnRightString" are set, They are used to title the top left, center,;
; and right of the plot (in addition, the regular resource ;
; "tiMainString" can be set to create a regular title). ;
; ;
; If gsnYRefLine is set to some value(s), then reference line(s) will be;
; drawn at this value(s). In addition, if gsnAboveYRefLineColor and/or ;
; gsnBelowYRefLineColor is set, the polygons above and below the ;
; reference line will be filled in these colors. ;
; ;
; If gsnXRefLine is set to some value, then a reference line will be ;
; drawn at this value. ;
; ;
; If gsnXYBarChart is set to True, then a bar chart will be drawn ;
; instead of a line plot. You need to also set gsnYRefLine in order to ;
; use this resource. ;
; ;
; The resource gsnXYBarChartColors can be used to specify an array of ;
; bar colors. This resource was not implemented very smartly. These ;
; colors will apply independently to both the above ref line bars, and ;
; the below ref line bars. So, if you give this resource the colors ;
; "red", "green", and "blue", then all the colors above the ref line ;
; will cycle b/w these three colors, and independently, the colors below;
; the ref line will cycle b/w these colors. If you want to have one ;
; resource that specifies the color for each bar, not caring whether it ;
; is above or below the ref line, use the "gsnXYBarChartColors2" ;
; resource. ;
; ;
; Same for the gsnXYBarChartPatterns/gsnXYBarChartPatterns2 resource. ;
; ;
; The resource gsnXYBarChartBarWidth can be used to specify the width ;
; of each bar. The smallest dx is used by default. ;
; ;
; The resource gsnAbove/BelowYRefLineBarColors can be used to specify ;
; an array of bar colors. ;
; ;
; Tick marks will be made to point outwards. ;
; ;
; If the user sets lgLabelFontHeightF to change the size of the legend ;
; labels, then lgAutoManage will be set to False (unless it is being ;
; set explicitly by the user. ;
; ;
;***********************************************************************;
function gsn_csm_xy(wks:graphic,x:numeric,y:numeric,resources:logical)
local res, xy_object, res2, xfontf, yfontf, font_height, calldraw, nlines, \
callframe, left_string, center_string, right_string, main_zone, ncurves, \
yabove, ybelow, ya_ind, yb_ind, xinterp, yinterp, bar_chart
begin
; Initialize.
main_zone = 2 ; Zone for main title (may change later)
xref_line_on = False ; X reference line flag
yref_line_on = False ; Y reference line flag
yref_fill_on = False ; Whether to fill above/below Y ref line.
res2 = get_resources(resources)
left_string = False
center_string = False
right_string = False
bar_chart = False
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",True)
; Check if frame and/or draw are not supposed to be called.
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Calculate number of Y points.
ndimsy = dimsizes(dimsizes(y))
ndimsx = dimsizes(dimsizes(x))
if(ndimsy.eq.1)
ncurves = 1
npts = dimsizes(y)
else
ncurves = dimsizes(y(:,0))
npts = dimsizes(y(0,:))
end if
if(ndimsx.eq.1)
nptsx = dimsizes(x)
else
nptsx = dimsizes(x(0,:))
end if
;
; Test dimensions. They must both either be the same, or have the
; same rightmost dimension.
;
if( (ndimsx.gt.1.and.ndimsy.gt.1.and.(ndimsx.ne.ndimsy.or. \
.not.all(dimsizes(x).eq.dimsizes(y)))).or.\
((ndimsx.eq.1.or.ndimsy.eq.1).and.nptsx.ne.npts))
print("gsn_csm_xy: Fatal: X and Y must have the same dimensions sizes, or one must be one-dimensional and both have the same rightmost dimension.")
end if
; This section tests for more special resources: those that start
; with "gsn."
if((res2).and..not.any(ismissing(getvaratts(res2))))
;
; Check if gsnShape set.
;
if(isatt(res2,"gsnShape").and.res2_at_gsnShape)
main_zone = main_zone+1 ; Zone for main title
end if
; Check if gsnYRefLine set.
if(isatt(res2,"gsnYRefLine"))
yref_line_on = True
yref_line = res2_at_gsnYRefLine
nyref = dimsizes(yref_line)
delete(res2_at_gsnYRefLine)
;
; Determine color of fill above reference line(s).
;
if(isatt(res2,"gsnAboveYRefLineColor"))
if(.not.(dimsizes(res2_at_gsnAboveYRefLineColor).eq.nyref.or.\
dimsizes(res2_at_gsnAboveYRefLineColor).eq.1))
print("gsn_csm_xy: Fatal: there must either be an above-line fill color for every reference line, or one global above-line fill color specified")
return
end if
yref_line_above = res2_at_gsnAboveYRefLineColor
yref_fill_on = True
delete(res2_at_gsnAboveYRefLineColor)
else
if(any(isatt(res2,(/"gsnXYBarChartPatterns", \
"gsnXYBarChartPatterns2", \
"gsnAboveYRefLineBarPatterns"/)))) then
yref_line_above = 1 ; defaults to foreground.
else
yref_line_above = -1 ; defaults to no fill.
end if
end if
;
; Determine color of fill below reference line(s).
;
if(isatt(res2,"gsnBelowYRefLineColor"))
if(.not.(dimsizes(res2_at_gsnBelowYRefLineColor).eq.nyref.or.\
dimsizes(res2_at_gsnBelowYRefLineColor).eq.1))
print("gsn_csm_xy: Fatal: there must either be an below-line fill color for every reference line, or one global below-line fill color specified ")
return
end if
yref_line_below = get_res_value(res2,"gsnBelowYRefLineColor",1)
yref_fill_on = True
else
if(any(isatt(res2,(/"gsnXYBarChartPatterns", \
"gsnXYBarChartPatterns2", \
"gsnBelowYRefLineBarPatterns"/)))) then
yref_line_below = 1 ; defaults to foreground.
else
yref_line_below = -1 ; defaults to no fill.
end if
end if
;
; If yref_fill_on is True, and we have more than one curve, then there
; should be the same number of reference lines as curves.
;
if(yref_fill_on.and.ncurves.gt.1.and.ncurves.ne.nyref.and.nyref.ne.1)
print("gsn_csm_xy: Fatal: if you plan to fill above and/or below reference lines, then the number of reference lines must either equal the number")
print("of curves, or be one.")
return
end if
;
; Determine color of Y reference line(s).
;
set_yref_line_color = False
if(isatt(res2,"gsnYRefLineColors"))
yref_line_color = get_res_value(res2,"gsnYRefLineColors","foreground")
set_yref_line_color = True
else
if(isatt(res2,"gsnYRefLineColor"))
yref_line_color = get_res_value(res2,"gsnYRefLineColor","foreground")
set_yref_line_color = True
else
yref_line_color = "foreground"
end if
end if
if(set_yref_line_color) then
if(.not.(dimsizes(yref_line_color).eq.nyref.or.\
dimsizes(yref_line_color).eq.1))
print("gsn_csm_xy: Warning: you must specify either one Y reference line color")
print("or the same number of colors as there are reference lines.")
print("Will use the foreground color.")
yref_line_color = "foreground"
end if
end if
;
; Determine dash pattern of Y reference line(s).
;
if(isatt(res2,"gsnYRefLineDashPattern"))
yref_line_pattern = res2_at_gsnYRefLineDashPattern(0)
delete(res2_at_gsnYRefLineDashPattern)
else
if(isatt(res2,"gsnYRefLineDashPatterns"))
yref_line_pattern = res2_at_gsnYRefLineDashPatterns
delete(res2_at_gsnYRefLineDashPatterns)
if(.not.(dimsizes(yref_line_pattern).eq.nyref.or.\
dimsizes(yref_line_pattern).eq.1))
print("gsn_csm_xy: Warning: you must specify either one Y reference line dash pattern")
print("or the same number of dash patterns as there are reference lines.")
print("Will use a solid line.")
yref_line_pattern = 0 ; defaults to solid
end if
else
yref_line_pattern = 0 ; defaults to solid
end if
end if
;
; Determine thickness of Y reference line(s).
;
if(isatt(res2,"gsnYRefLineThicknessF"))
yref_line_thickness = res2_at_gsnYRefLineThicknessF(0)
delete(res2_at_gsnYRefLineThicknessF)
else
if(isatt(res2,"gsnYRefLineThicknesses"))
yref_line_thickness = res2_at_gsnYRefLineThicknesses
delete(res2_at_gsnYRefLineThicknesses)
if(.not.(dimsizes(yref_line_thickness).eq.nyref.or.\
dimsizes(yref_line_thickness).eq.1))
print("gsn_csm_xy: Warning: you must specify either one Y reference line thickness")
print("or the same number of line thicknesses as there are reference lines.")
print("Will use a thickness of 1.")
yref_line_thickness = 1.0
end if
else
yref_line_thickness = 1.0
end if
end if
end if ; Check if gsnYRefLine set.
;
; Check if we want a bar chart.
;
bar_chart = get_res_value(res2,"gsnXYBarChart",False)
bar_outline_only = get_res_value(res2,"gsnXYBarChartOutlineOnly",False)
if(bar_chart.and..not.bar_outline_only)
if(.not.yref_line_on) then
;
; If no ref line specified, but bar fill is on, then set the reference
; line to the minimum y value.
;
yref_line = get_res_value_keep(res2,"trYMinF",min(y))
nyref = 1
yref_line_on = True
yref_line_color = "foreground"
yref_line_pattern = 0
yref_line_thickness = 1.
else
if((ncurves.gt.1.and.nyref.gt.1.and.ncurves.ne.nyref).or. \
(ncurves.eq.1.and.nyref.ne.1))
print("gsn_csm_xy: Fatal: if you plan to draw a bar chart with values above")
print("and/or below reference lines, then the number of reference lines")
print("must either equal the number of curves, or be one.")
return
end if
end if ; Check for Y ref line.
end if ; Check for bar chart settage.
; Check if gsnXRefLine set.
if(isatt(res2,"gsnXRefLine"))
xref_line_on = True
xref_line = get_res_value(res2,"gsnXRefLine",0.)
nxref = dimsizes(xref_line)
xref_line_color = get_res_value(res2,"gsnXRefLineColor","foreground")
xref_line_pattern = get_res_value(res2,"gsnXRefLineDashPattern",0)
xref_line_thickness = get_res_value(res2,"gsnXRefLineThicknessF",1.)
end if
; Check for existence of the left, center, and right subtitles.
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = main_zone+1
end if
end if ; Done checking special resources.
res2 = True
res2_at_gsnDraw = False ; Internally, don't draw plot or advance
res2_at_gsnFrame = False ; frame since we take care of that later.
res2_at_gsnScale = True ; force labels and ticks to be same.
; If user explicitly sets X or Y tick marks, then don't label the X
; or Y axis automatically.
if(check_attr(res2,"tmXBMode","Explicit",True).or.\
check_attr(res2,"tmXBMode",2,True))
set_attr(res2,"tiXAxisString","")
end if
if(check_attr(res2,"tmYLMode","Explicit",True).or.\
check_attr(res2,"tmYLMode",2,True))
set_attr(res2,"tiYAxisString","")
end if
; Check if we want fill above or below Y reference value, and whether we
; want to do bar charts or regular curves.
if(yref_fill_on.and..not.bar_chart) then
;
; Create new X and Y arrays to hold new data values. Wherever the curve
; crosses the reference line, an interpolation needs to be done to create
; a point *on* that reference line.
;
xinterp = new((/nyref,2*npts/),double,1e36)
yinterp = new((/nyref,2*npts/),double,1e36)
copy_var_atts(x,xinterp,"")
copy_var_atts(y,yinterp,"")
new_npts = ref_line_interp(x,y,xinterp,yinterp,yref_line)
else
if(bar_chart) then
;
; Figure out if we want filled bars or outlined bars.
;
if(bar_outline_only)
;
; For each old y point, we need two new y points to represent
; the horizontal line.
;
nyb = 2 * (npts-1) + 1
yinterp = new((/ncurves,nyb/),double,1e36)
xinterp = new((/ncurves,nyb/),double,1e36)
copy_var_atts(x,xinterp,"")
copy_var_atts(y,yinterp,"")
outlined_bars(x,y,xinterp,yinterp)
else
;
; Filled bars are desired.
;
; Get bar widths. They are either set by user via a resource, or
; from the smallest dx.
;
bar_widths = get_bar_widths(x,ncurves,res2)
if(any(ismissing(bar_widths)).or.any(bar_widths.le.0))
print("gsn_csm_xy: Fatal: The x array is not monotonically increasing.")
print("Cannot draw a bar chart.")
return
end if
;
; Figure out if we want to fill bars. Three resources can be used to
; specify fill colors, in this order:
;
; gsnAbove/BelowYRefLineBarColors gsnAbove/BelowYRefLineBarPatterns
; gsnXYBarChartColors gsnXYBarChartPatterns
; gsnXYBarChartColors2 gsnXYBarChartPatterns2
;
mlt_above_bar_colors = False
mlt_below_bar_colors = False
mlt_above_bar_pttrns = False
mlt_below_bar_pttrns = False
colors2 = False ; Flag to indicate whether the
pttrns2 = False ; 3rd resource is being used.
;
; First check for above reference line bar fill colors.
;
if(isatt(res2,"gsnAboveYRefLineBarColors")) then
yref_fill_on = True
mlt_above_bar_colors = True
bar_colors_above = get_res_value(res2,"gsnAboveYRefLineBarColors",1)
;
; If gsnXYBarChartColors or gsnXYBarChartColors2 are set, then
; delete them.
;
if(isatt(res2,"gsnXYBarChartColors")) then
delete(res2_at_gsnXYBarChartColors)
end if
if(isatt(res2,"gsnXYBarChartColors2")) then
delete(res2_at_gsnXYBarChartColors2)
end if
end if
;
; Now check for below reference line bar fill colors.
;
if(isatt(res2,"gsnBelowYRefLineBarColors")) then
yref_fill_on = True
mlt_below_bar_colors = True
bar_colors_below = get_res_value(res2,"gsnBelowYRefLineBarColors",1)
;
; If gsnXYBarChartColors and/or gsnXYBarChartColors2 are set,
; then delete them.
;
if(isatt(res2,"gsnXYBarChartColors")) then
delete(res2_at_gsnXYBarChartColors)
end if
if(isatt(res2,"gsnXYBarChartColors2")) then
delete(res2_at_gsnXYBarChartColors2)
end if
end if
;
; If neither gsnBelow/AboveYRefLineBarColors were set, then the
; second choice is to check for gsnXYBarChartColors.
;
if(isatt(res2,"gsnXYBarChartColors")) then
yref_fill_on = True
mlt_above_bar_colors = True
mlt_below_bar_colors = True
bar_colors_above = get_res_value(res2,"gsnXYBarChartColors",1)
bar_colors_below = bar_colors_above
;
; If gsnXYBarChartColors2 is set, then delete it.
;
if(isatt(res2,"gsnXYBarChartColors2")) then
delete(res2_at_gsnXYBarChartColors2)
end if
end if
;
; If none of gsnBelow/AboveYRefLineBarColors/gsnXYBarChartColors were
; set, then the third choice is to use gsnXYBarChartColors2.
;
if(isatt(res2,"gsnXYBarChartColors2")) then
colors2 = True
yref_fill_on = True
mlt_above_bar_colors = True
mlt_below_bar_colors = True
bar_colors_above = get_res_value(res2,"gsnXYBarChartColors2",1)
bar_colors_below = bar_colors_above
end if
;
; Now that we've exhausted all the possible ways that bar colors can
; be set for the above ref line, check that the array is a valid size.
;
if(mlt_above_bar_colors) then
bac_rank = dimsizes(dimsizes(bar_colors_above))
if(bac_rank.gt.2.or. \
(bac_rank.eq.2.and.dimsizes(bar_colors_above(:,0)).ne.nyref)) then
print("gsn_csm_xy: Fatal: The resource for specifying bar colors must either be 1D, or 2D where the first dimension is equal to the number of Y reference lines or curves.")
print("Will not fill your bar chart.")
mlt_above_bar_colors = False
end if
end if
if(mlt_below_bar_colors) then
bbc_rank = dimsizes(dimsizes(bar_colors_below))
if(bbc_rank.gt.2.or. \
(bbc_rank.eq.2.and.dimsizes(bar_colors_below(:,0)).ne.nyref)) then
print("gsn_csm_xy: Fatal: The resource for specifying bar colors must either be 1D, or 2D where the first dimension is equal to the number of Y reference lines or curves.")
print("Will not fill your bar chart.")
mlt_below_bar_colors = False
end if
end if
;
; Check for above reference line fill patterns.
;
if(isatt(res2,"gsnAboveYRefLineBarPatterns")) then
yref_fill_on = True
mlt_above_bar_pttrns = True
bar_pttrns_above = get_res_value(res2,"gsnAboveYRefLineBarPatterns",1)
;
; If gsnXYBarChartPatterns or gsnXYBarChartPatterns2 are set,
; then delete them.
;
if(isatt(res2,"gsnXYBarChartPatterns")) then
delete(res2_at_gsnXYBarChartPatterns)
end if
if(isatt(res2,"gsnXYBarChartPatterns2")) then
delete(res2_at_gsnXYBarChartPatterns2)
end if
end if
;
; Now check for below reference line fill patterns.
;
if(isatt(res2,"gsnBelowYRefLineBarPatterns")) then
yref_fill_on = True
mlt_below_bar_pttrns = True
bar_pttrns_below = get_res_value(res2,"gsnBelowYRefLineBarPatterns",1)
;
; If gsnXYBarChartPatterns or gsnXYBarChartPatterns2 are set,
; then delete them.
;
if(isatt(res2,"gsnXYBarChartPatterns")) then
delete(res2_at_gsnXYBarChartPatterns)
end if
if(isatt(res2,"gsnXYBarChartPatterns2")) then
delete(res2_at_gsnXYBarChartPatterns2)
end if
end if
;
; If the gsnAbove/BelowYRefLineBarPatterns resources are not set, then
; the second choice is to use gsnXYBarChartPatterns.
;
if(isatt(res2,"gsnXYBarChartPatterns")) then
yref_fill_on = True
mlt_above_bar_pttrns = True
mlt_below_bar_pttrns = True
bar_pttrns_above = get_res_value(res2,"gsnXYBarChartPatterns",1)
bar_pttrns_below = bar_pttrns_above
;
; If gsnXYBarChartPatterns2 is set, then delete it.
;
if(isatt(res2,"gsnXYBarChartPatterns2")) then
delete(res2_at_gsnXYBarChartPatterns2)
end if
end if
;
; If gsnAbove/BelowYRefLineBarPatterns and gsnXYBarChartPatterns are
; not set, then the third choice is to use gsnXYBarChartPatterns2.
;
if(isatt(res2,"gsnXYBarChartPatterns2")) then
pttrns2 = True
yref_fill_on = True
mlt_above_bar_pttrns = True
mlt_below_bar_pttrns = True
bar_pttrns_above = get_res_value(res2,"gsnXYBarChartPatterns2",1)
bar_pttrns_below = bar_pttrns_above
end if
;
; Now that we've exhausted all the possible ways that bar patterns can
; be set for the above ref line, check that the array is a valid size.
;
if(mlt_above_bar_pttrns) then
bap_rank = dimsizes(dimsizes(bar_pttrns_above))
if(bap_rank.gt.2.or. \
(bap_rank.eq.2.and.dimsizes(bar_pttrns_above(:,0)).ne.nyref)) then
print("gsn_csm_xy: Fatal: The resource for specifying bar patterns must either be 1D, or 2D where the first dimension is equal to the number of Y reference lines or curves.")
print("Will not fill your bar chart.")
mlt_above_bar_pttrns = False
end if
end if
if(mlt_below_bar_pttrns) then
bbp_rank = dimsizes(dimsizes(bar_pttrns_below))
if(bbp_rank.gt.2.or. \
(bbp_rank.eq.2.and.dimsizes(bar_pttrns_below(:,0)).ne.nyref)) then
print("gsn_csm_xy: Fatal: The resource for specifying bar patterns must either be 1D, or 2D where the first dimension is equal to the number of Y reference lines or curves.")
print("Will not fill your bar chart.")
mlt_below_bar_pttrns = False
end if
end if
;
; Loop across curves and figure out which points are above, below,
; and equal to the references lines. First create arrays to hold points
; above, below, and equal to reference lines.
;
xabove = new((/ncurves,5*npts/),double,1e36)
yabove = new((/ncurves,5*npts/),double,1e36)
xbelow = new((/ncurves,5*npts/),double,1e36)
ybelow = new((/ncurves,5*npts/),double,1e36)
xequal = new((/ncurves,5*npts/),double,1e36)
yequal = new((/ncurves,5*npts/),double,1e36)
;
; Arrays to hold number of points in each set of above/below points,
; and the index values where points fall above, below, and equal
; to the Y ref value.
;
nabove = new(ncurves,integer)
nbelow = new(ncurves,integer)
nequal = new(ncurves,integer)
indabove = new((/ncurves,npts/),integer)
indbelow = new((/ncurves,npts/),integer)
indequal = new((/ncurves,npts/),integer)
;
; Fill in values for filled bars (that will be filled later).
;
filled_bars(x,y,xabove,yabove,xbelow,ybelow,xequal,yequal, \
nabove,nbelow,nequal,indabove,indbelow,indequal, \
yref_line,bar_widths)
;
; Combine the above/below/equal arrays into one X/Y array so that we can
; pass to gsn_xy routine. Make the 5th point missing, since the 5th point
; closes the polygon, and we only want an outline here.
;
na_max = max(nabove)
nb_max = max(nbelow)
ne_max = max(nequal)
nabe_max = na_max + nb_max + ne_max
if(na_max.le.0.and.nb_max.le.0)
print("gsn_csm_xy: Fatal: There are no values above or below the chosen reference line.")
print("Cannot draw a bar chart.")
xinterp = x
yinterp = y
else
ncurves3 = 3*ncurves
xinterp = new((/ncurves3,nabe_max/),double,xabove@_FillValue)
yinterp = new((/ncurves3,nabe_max/),double,yabove@_FillValue)
copy_var_atts(x,xinterp,"")
copy_var_atts(y,yinterp,"")
if(na_max.gt.0)
xinterp(0:ncurves3-1:3,0:na_max-1) = xabove(:,0:na_max-1)
yinterp(0:ncurves3-1:3,0:na_max-1) = yabove(:,0:na_max-1)
yinterp(0:ncurves3-1:3,4:na_max-1:5) = yinterp@_FillValue
end if
if(nb_max.gt.0)
xinterp(1:ncurves3-1:3,0:nb_max-1) = xbelow(:,0:nb_max-1)
yinterp(1:ncurves3-1:3,0:nb_max-1) = ybelow(:,0:nb_max-1)
yinterp(1:ncurves3-1:3,4:nb_max-1:5) = yinterp@_FillValue
end if
if(ne_max.gt.0)
xinterp(2:ncurves3-1:3,0:ne_max-1) = xequal(:,0:ne_max-1)
yinterp(2:ncurves3-1:3,0:ne_max-1) = yequal(:,0:ne_max-1)
yinterp(2:ncurves3-1:3,4:ne_max-1:5) = yinterp@_FillValue
end if
;
; Make sure all lines are solid, and not dashed as is the default
; with the second curve drawn.
;
res2_at_xyDashPatterns = get_res_value(res2,"xyDashPatterns",0)
end if
end if
else
xinterp = x
yinterp = y
end if
end if
if(xref_line_on)
set_attr(res2,"trYMinF",min(yinterp))
set_attr(res2,"trYMaxF",max(yinterp))
end if
if(yref_line_on)
set_attr(res2,"trXMinF",min(xinterp))
set_attr(res2,"trXMaxF",max(xinterp))
end if
;
; If user sets lgLabelFontHeightF, then lgAutoManage needs to
; be False in order for this resource to have any affect.
;
if(isatt(res2,"lgLabelFontHeightF"))
set_attr(res2,"lgAutoManage",False)
end if
; Create XY plot
xyres = get_res_ne(res2,(/"tx"/))
xy_object = gsn_xy(wks,xinterp,yinterp,xyres)
; Add lat/lon labels to X/Y axes if appropriate units exist.
res2_at_gsnXYPlot = True
res2_at_gsnXAxis = True
add_latlon_labels(xy_object,x,res2)
delete(res2_at_gsnXAxis)
res2_at_gsnYAxis = True
add_latlon_labels(xy_object,y,res2)
delete(res2_at_gsnYAxis)
delete(res2_at_gsnXYPlot)
; Fill above/below Y reference line.
if(yref_fill_on.and..not.bar_chart)
;
; Make sure polygons get filled before xy plot is drawn. This way,
; any lines will be drawn *after* the fill. This makes the filled
; polygons look better if the lines are drawn thicker.
;
xyres_tmp = True
xyres_tmp_at_tfPolyDrawOrder = "Predraw"
attsetvalues_check(xy_object,xyres_tmp)
delete(xyres_tmp)
fill_above = yref_line_above(0)
fill_below = yref_line_below(0)
do i=0,max((/ncurves,nyref/))-1
if(dimsizes(yref_line_above).gt.1)
fill_above = yref_line_above(i)
end if
if(dimsizes(yref_line_below).gt.1)
fill_below = yref_line_below(i)
end if
var_string = unique_string("polygons"+i)
xy_object@$var_string$=fill_xy_ref(wks,xy_object, \
xinterp(i,0:new_npts(i)-1), \
yinterp(i,0:new_npts(i)-1),\
yref_line(i),fill_above,fill_below)
end do
end if
; Fill bars with either a single color for above and below, or with
; individual colors.
if(yref_fill_on.and.bar_chart.and..not.bar_outline_only)
gsres = True
do i=0,ncurves-1
var_string = unique_string("polygons"+i)
;
; Fill above reference line.
;
if(nabove(i).gt.0)
;
; Single bar color for each above and below bars.
;
if(.not.mlt_above_bar_colors)
gsres_at_gsFillColor = yref_line_above(0)
if(dimsizes(yref_line_above).gt.1)
gsres_at_gsFillColor = yref_line_above(i)
end if
end if
;
; Multiple bar colors and/or patterns.
;
if(mlt_above_bar_colors.or.mlt_above_bar_pttrns) then
if(mlt_above_bar_colors) then
if(bac_rank.eq.1) then
nca = dimsizes(bar_colors_above)
else
nca = dimsizes(bar_colors_above(0,:))
end if
end if
if(mlt_above_bar_pttrns) then
if(bap_rank.eq.1) then
npa = dimsizes(bar_pttrns_above)
else
npa = dimsizes(bar_pttrns_above(0,:))
end if
end if
do ii = 0,nabove(i)/5-1
var_string2 = var_string + "above" + ii
if(mlt_above_bar_colors) then
if(colors2) then
ci = indabove(i,ii) % nca
else
ci = ii % nca
end if
if(bac_rank.eq.1) then
gsres_at_gsFillColor = bar_colors_above(ci)
else
gsres_at_gsFillColor = bar_colors_above(i,ci)
end if
end if
if(mlt_above_bar_pttrns) then
if(pttrns2) then
pi = indabove(i,ii) % npa
else
pi = ii % npa
end if
if(bap_rank.eq.1) then
gsres_at_gsFillIndex = bar_pttrns_above(pi)
else
gsres_at_gsFillIndex = bar_pttrns_above(i,pi)
end if
end if
xy_object@$var_string2$ = gsn_add_polygon(wks,xy_object, \
xabove(i,ii*5:ii*5+4), \
yabove(i,ii*5:ii*5+4), \
gsres)
end do
else
var_string2 = var_string + "above"
xy_object@$var_string2$ = gsn_add_polygon(wks,xy_object, \
xabove(i,:), \
yabove(i,:),gsres)
end if
end if
;
; Fill below reference line.
;
if(nbelow(i).gt.0)
if(.not.mlt_below_bar_colors) then
gsres_at_gsFillColor = yref_line_below(0)
if(dimsizes(yref_line_below).gt.1)
gsres_at_gsFillColor = yref_line_below(i)
end if
end if
;
; Multiple bar colors and/or patterns.
;
if(mlt_below_bar_colors.or.mlt_below_bar_pttrns) then
if(mlt_below_bar_colors) then
if(bbc_rank.eq.1) then
ncb = dimsizes(bar_colors_below)
else
ncb = dimsizes(bar_colors_below(0,:))
end if
end if
if(mlt_below_bar_pttrns) then
if(bbp_rank.eq.1) then
npb = dimsizes(bar_pttrns_below)
else
npb = dimsizes(bar_pttrns_below(0,:))
end if
end if
do ii = 0,nbelow(i)/5-1
var_string2 = var_string + "below" + ii
if(mlt_below_bar_colors) then
if(colors2) then
ci = indbelow(i,ii) % ncb
else
ci = ii % ncb
end if
if(bbc_rank.eq.1) then
gsres_at_gsFillColor = bar_colors_below(ci)
else
gsres_at_gsFillColor = bar_colors_below(i,ci)
end if
end if
if(mlt_below_bar_pttrns) then
if(pttrns2) then
pi = indbelow(i,ii) % npb
else
pi = ii % npb
end if
if(bbp_rank.eq.1) then
gsres_at_gsFillIndex = bar_pttrns_below(pi)
else
gsres_at_gsFillIndex = bar_pttrns_below(i,pi)
end if
end if
xy_object@$var_string2$ = gsn_add_polygon(wks,xy_object, \
xbelow(i,ii*5:ii*5+4), \
ybelow(i,ii*5:ii*5+4), \
gsres)
end do
else
var_string2 = var_string + "below"
xy_object@$var_string2$ = gsn_add_polygon(wks,xy_object, \
xbelow(i,:), \
ybelow(i,:), gsres)
end if
end if
end do
;
; Make sure polygons get drawn first, so that XY lines are drawn on top.
;
setvalues xy_object
"tfPolyDrawOrder" : "Predraw"
end setvalues
delete(gsres)
end if
; Draw X reference line.
if(xref_line_on)
getvalues xy_object
"trYMinF" : ymin
"trYMaxF" : ymax
end getvalues
gsres = True
yline = (/ymin,ymax/)
gsres_at_gsLineColor = xref_line_color(0)
gsres_at_gsLineDashPattern = xref_line_pattern(0)
gsres_at_gsLineThicknessF = xref_line_thickness(0)
do i=0,nxref-1
if(dimsizes(xref_line_color).gt.1)
gsres_at_gsLineColor = xref_line_color(i)
end if
xline = fspan(xref_line(i),xref_line(i),2)
var_string = unique_string("xpolyline"+i)
xy_object@$var_string$ = gsn_add_polyline(wks,xy_object,xline,yline, \
gsres)
end do
delete(xline)
delete(yline)
end if
; Draw Y reference line.
if(yref_line_on)
getvalues xy_object
"trXMinF" : xmin
"trXMaxF" : xmax
end getvalues
gsres = True
xline = (/xmin,xmax/)
gsres_at_gsLineColor = yref_line_color(0)
gsres_at_gsLineDashPattern = yref_line_pattern(0)
gsres_at_gsLineThicknessF = yref_line_thickness(0)
do i=0,nyref-1
if(dimsizes(yref_line_color).gt.1)
gsres_at_gsLineColor = yref_line_color(i)
end if
if(dimsizes(yref_line_pattern).gt.1)
gsres_at_gsLineDashPattern = yref_line_pattern(i)
end if
if(dimsizes(yref_line_thickness).gt.1)
gsres_at_gsLineThicknessF = yref_line_thickness(i)
end if
yline = fspan(tofloat(yref_line(i)),tofloat(yref_line(i)),2)
var_string = unique_string("ypolyline"+i)
xy_object@$var_string$ = gsn_add_polyline(wks,xy_object,xline, \
yline,gsres)
end do
delete(xline)
delete(yline)
end if
; Get title label sizes and tickmark lengths.
getvalues xy_object
"vpWidthF" : width
"vpHeightF" : height
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
"tmYLMajorLengthF" : ylength
"tmXBMajorLengthF" : xlength
"tmYLMinorLengthF" : ymlength
"tmXBMinorLengthF" : xmlength
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
; the size of the X/Y axis labels.
major_length = min((/ylength,xlength/))
minor_length = min((/ymlength,xmlength/))
; If the plot is close to square in size, then make the
; three top titles and the tick marks smaller.
ratio = height/width
if(ratio.gt.1)
ratio = 1./ratio
end if
if(ratio.gt.0.5)
font_height = 0.75 * font_height
major_length = 0.75 * major_length
minor_length = 0.75 * minor_length
end if
; Make tick marks same length and point outward.
tmres = get_res_eq(res2,"tm")
gsnp_point_tickmarks_outward(xy_object,tmres,xlength,ylength,xmlength, \
ymlength,major_length,minor_length, \
point_outward)
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"tx","am"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",font_height)
add_subtitles(wks,xy_object,left_string,center_string,right_string, \
subres)
; Draw all this stuff: XY plot and subtitles.
draw_and_frame(wks,xy_object,calldraw,callframe,0,maxbb)
; Return XY plot object.
return(xy_object)
end
;***********************************************************************;
; Function : gsn_csm_y ;
; wks: workstation object ;
; y: n-dimensional array of Y array ;
; resources: optional resources ;
; ;
; This function is similar to gsn_csm_xy, except instead of a specific ;
; X array, index values are used. ;
; ;
;***********************************************************************;
function gsn_csm_y(wks:graphic, y:numeric, resources:logical )
local dsizes_y, npts, x, rank_y, xy
begin
res2 = get_resources(resources)
;
; Get dimension sizes of Y array.
;
dsizes_y = dimsizes(y)
rank_y = dimsizes(dsizes_y)
if(rank_y.eq.1) then
npts = dsizes_y
else
if(rank_y.ne.2) then
print("Error: gsn_csm_y: The input Y array must either be 1-dimensional, or 2-dimensional, where the leftmost dimension represents the number of curves and the rightmost dimension the number of points in each curve.")
exit
end if
npts = dsizes_y(1)
end if
;
; Create the indexed X array.
;
x = ispan(0,npts-1,1)
x_at_long_name = ""
;
; Call gsn_csm_xy.
;
xy = gsn_csm_xy(wks,x,y,res2)
return(xy)
end
;***********************************************************************;
; Function : plot_x2y2 ;
; wks: workstation object ;
; x1: X values, representing the bottom axis ;
; x2: second set of X values (opt'l) ;
; representing the top axis ;
; y1: Y values, representing the left axis ;
; y2: second set of Y values (opt'l) ;
; representing the right axis ;
; res1: opt'l resources, to apply to first plot ;
; axes used are bottom/left. ;
; res2: opt'l resources, to apply to second plot ;
; axes used are top/right. ;
; axis: which axis has the multiple curves ("x" means ;
; the X axes has the multiple curves, "y" is for the ;
; Y axes, and "xy" for both axes) ;
; plot_type: whether we're doing generic gsn, or gsn_csm ;
; ;
; Originally created by Dennis Shea to allow two Y curves with two ;
; separate Y axes to reside on the same plot and share the same X axis. ;
; The Y axes are labeled both on the left and right to indicate the two ;
; different axes. ;
; ;
; Modified by Mary Haley and made more generic so it can handle the X ;
; or Y axis or both axes having multiple curves. ;
;***********************************************************************;
function plot_x2y2 (wks:graphic, x1:numeric, x2:numeric, \
y1:numeric, y2:numeric, \
res1:logical, res2:logical, \
axis:string, plot_type:string)
local locRes1, locRes2, Atts1, Atts2, xy1, xy2, calldraw, callframe, maxbb
begin
;
; Make copy of local resources.
;
if (res2) then
locRes2 = res2
end if
if (res1) then
locRes1 = get_res_ne(res1,"tiMain")
locRes2 = get_res_eq(res1,"tiMain")
end if
locRes1 = True
locRes2 = True
;
; Retain draw, frame, and maximize settings for later.
;
calldraw = get_res_value(locRes1,"gsnDraw", True)
callframe = get_res_value(locRes1,"gsnFrame",True)
maxbb = get_bb_res(locRes1)
;
; Check for subtitles. We don't want to add the subtitles until all
; the plot stuff is done, in case some zones need to be adjusted.
;
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(locRes1,left_string,center_string,right_string)
;
; Set some zone information for the subtitles and main string.
;
if(axis.eq."x".or.axis.eq."xy") then
mainzone = 5
amzone = 4
else
mainzone = 6
amzone = 5
end if
locRes2_at_pmTitleZone = mainzone
;
; For first plot, don't auto advance the frame or draw or maximize
; the plot.
;
locRes1_at_gsnFrame = False
locRes1_at_gsnDraw = False
locRes1_at_gsnMaximize = False
;
; If drawing a multiple axis plot, make sure you turn off the
; tickmarks on the other side, since they will later be defined
; by the second set of data.
;
if(axis.eq."y".or.axis.eq."xy") then
locRes1_at_tmYROn = False ; Turn off right tick marks.
locRes1_at_tmYRMinorOn = False ; Turn off right minor tick marks.
locRes1_at_tmYUseLeft = False ; Keep independent of right.
end if
if(axis.eq."x".or.axis.eq."xy") then
locRes1_at_tmXTOn = False ; Turn off top tick marks.
locRes1_at_tmXTMinorOn = False ; Turn off top minor tick marks.
locRes1_at_tmXUseBottom = False ; Keep independent of top.
end if
;
; Create first plot.
;
if(plot_type.eq."csm") then
xy1 = gsn_csm_xy (wks,x1,y1,locRes1)
else
xy1 = gsn_xy (wks,x1,y1,locRes1)
end if
;
; Get viewport coordinates, tickmark lengths, and font heights of
; first plot to use for second plot.
;
getvalues xy1
"vpHeightF" : vph ; Get assorted info from previous
"vpWidthF" : vpw ; plot for use on second plot.
"vpXF" : vpx
"vpYF" : vpy
; Bottom X axis stuff
"trXMinF" : trxmin
"trXMaxF" : trxmax
"trYMinF" : trymin
"trYMaxF" : trymax
"tiXAxisFontHeightF" : xfonth
"tmXBLabelFontHeightF" : xbfonth
"tmXBMajorLengthF" : xmjlength
"tmXBMinorLengthF" : xmnlength
"tmXBMajorOutwardLengthF" : xmjolength
"tmXBMinorOutwardLengthF" : xmnolength
; Left Y axis stuff
"tiYAxisFontHeightF" : yfonth
"tmYLLabelFontHeightF" : ylfonth
"tmYLMajorLengthF" : ymjlength
"tmYLMinorLengthF" : ymnlength
"tmYLMajorOutwardLengthF" : ymjolength
"tmYLMinorOutwardLengthF" : ymnolength
end getvalues
;
; If the user is setting any of these, then use these settings and
; not the ones we just retrieved.
;
; For second plot, don't auto advance the frame or draw or maximize
; the plot.
;
locRes2_at_gsnFrame = False
locRes2_at_gsnDraw = False
locRes2_at_gsnMaximize = False
;
; Set resources that are common for second plot, regardless of what
; kind of axes situation we have.
;
locRes2_at_gsnFrame = False
locRes2_at_gsnDraw = False
locRes2_at_gsnMaximize = False
locRes2_at_vpHeightF = vph ; set to same size as first plot
locRes2_at_vpWidthF = vpw
locRes2_at_vpXF = vpx
locRes2_at_vpYF = vpy
locRes2_at_tmXBLabelsOn = False ; Turn off bottom x axis labels
locRes2_at_tmXBMinorOn = False ; and tick marks.
locRes2_at_tmXBOn = False
locRes2_at_tmYLLabelsOn = False ; Turn off left y axis labels
locRes2_at_tmYLMinorOn = False ; and tick marks.
locRes2_at_tmYLOn = False
;
; Set some resources that will apply if you have two Y axes.
;
if(axis.eq."y".or.axis.eq."xy") then
locRes2_at_tmYRLabelsOn = get_res_value_keep(locRes2, \
"tmYRLabelsOn",True) ; rgt axis labels
locRes2_at_tmYROn = get_res_value_keep(locRes2, \
"tmYROn",True) ; rgt tick marks on
locRes2_at_tmYUseLeft = False
locRes2_at_tiYAxisSide = "Right"; put title on right scale
locRes2_at_tiYAxisFontHeightF = get_res_value_keep(locRes2, \
"tiYAxisFontHeightF",yfonth)
locRes2_at_tmYRLabelFontHeightF = get_res_value_keep(locRes2, \
"tmYLLabelFontHeightF",ylfonth)
locRes2_at_tmYRMajorLengthF = get_res_value_keep(locRes2, \
"tmYLMajorLengthF",ymjlength)
locRes2_at_tmYRMinorLengthF = get_res_value_keep(locRes2, \
"tmYLMinorLengthF",ymnlength)
locRes2_at_tmYRMajorOutwardLengthF = get_res_value_keep(locRes2, \
"tmYLMajorOutwardLengthF",ymjolength)
locRes2_at_tmYRMinorOutwardLengthF = get_res_value_keep(locRes2, \
"tmYLMinorOutwardLengthF",ymnolength)
end if
;
; Set resources specific only to having two Y axes and one X axis.
;
if(axis.eq."y") then
locRes2_at_trXMinF = get_res_value_keep(locRes2,"trXMinF",trxmin)
locRes2_at_trXMaxF = get_res_value_keep(locRes2,"trXMaxF",trxmax)
locRes2_at_tiXAxisString = "" ; already done
locRes2_at_tmXTLabelsOn = False ; Turn off top x axis labels
locRes2_at_tmXTMinorOn = False ; and tick marks.
locRes2_at_tmXTOn = False
;
; Create second plot, but only for the case of two Y axes and one X axis.
;
if(plot_type.eq."csm") then
xy2 = gsn_csm_xy(wks,x1,y2,locRes2)
else
xy2 = gsn_xy(wks,x1,y2,locRes2)
end if
end if
;
; Set some resources that will apply if you have two X axes.
; Note that normally, the x axis will use "long_name" for a title.
; However, this causes clutter if you try to put this title at
; the top of the plot, so for now, we are disabling an x axis string
; for the top, unless it is explicitly set by the user.
;
if(axis.eq."x".or.axis.eq."xy") then
locRes2_at_tmXTLabelsOn = get_res_value_keep(locRes2, \
"tmXTLabelsOn",True) ; top axis labels
locRes2_at_tmXTOn = get_res_value_keep(locRes2, \
"tmXTOn",True) ; top tick marks on
locRes2_at_tmXUseBottom = False
if(isatt(locRes2,"tiXAxisString")) then
locRes2_at_tiXAxisSide = "Top"; put title on Top scale
else
locRes2_at_tiXAxisOn = False
end if
locRes2_at_tiXAxisFontHeightF = get_res_value_keep(locRes2, \
"tiXAxisFontHeightF",xfonth)
locRes2_at_tmXTLabelFontHeightF = get_res_value_keep(locRes2,\
"tmXBLabelFontHeightF",xbfonth)
locRes2_at_tmXTMajorLengthF = get_res_value_keep(locRes2, \
"tmXBMajorLengthF",xmjlength)
locRes2_at_tmXTMinorLengthF = get_res_value_keep(locRes2, \
"tmXBMinorLengthF",xmnlength)
locRes2_at_tmXTMajorOutwardLengthF = get_res_value_keep(locRes2, \
"tmXBMajorOutwardLengthF",xmjolength)
locRes2_at_tmXTMinorOutwardLengthF = get_res_value_keep(locRes2, \
"tmXBMinorOutwardLengthF",xmnolength)
end if
;
; Set resources specific only to having two X axes and one Y axis.
;
if(axis.eq."x") then
locRes2_at_trYMinF = get_res_value_keep(locRes2,"trYMinF",trymin)
locRes2_at_trYMaxF = get_res_value_keep(locRes2,"trYMaxF",trymax)
locRes2_at_tiYAxisString = "" ; already done
locRes2_at_tmYRLabelsOn = False ; Turn off right y axis labels
locRes2_at_tmYRMinorOn = False ; and tick marks.
locRes2_at_tmYROn = False
if(plot_type.eq."csm") then
xy2 = gsn_csm_xy(wks,x2,y1,locRes2)
else
xy2 = gsn_xy(wks,x2,y1,locRes2)
end if
end if
;
; Create a second plot for the case of two Y axes and two X axes.
;
if(axis.eq."xy") then
if(plot_type.eq."csm") then
xy2 = gsn_csm_xy(wks,x2,y2,locRes2)
else
xy2 = gsn_xy(wks,x2,y2,locRes2)
end if
end if
;
; Set up three subtitles at top, if they exist. Note that we are
; attaching the subtitles to the second plot. This is because the
; second plot is the one that might have tickmarks and labels
; coming out the top, and we need to make sure these gsn strings stay
; outside of them. This is also true for the main title, which we
; already handled above.
;
getvalues xy2
"vpHeightF" : height
"vpWidthF" : width
"tiYAxisFontHeightF" : yfontf
"tiXAxisFontHeightF" : xfontf
end getvalues
; If the plot is close to square in size, then make the
; three top titles and the tick marks smaller.
font_height = min((/xfontf,yfontf/)) ; Make label sizes a function of
ratio = height/width
if(ratio.gt.1)
ratio = 1./ratio
end if
if(ratio.gt.0.5)
font_height = 0.75 * font_height
end if
subres = True
subres = get_res_eq(locRes1,"tx") ; Get textitem resources
set_attr(subres,"txFontHeightF",font_height)
set_attr(subres,"txFont","helvetica")
set_attr(subres,"amZone",amzone)
subres_at_amOrthogonalPosF = 0.06
add_subtitles(wks,xy2,left_string,center_string,right_string,subres)
;
; Add second plot as annotation of 1st plot.
;
anno = NhlAddAnnotation(xy1,xy2)
setvalues anno
"amZone" : 0 ; Zone 0 centers tick marks over map.
"amResizeNotify" : True ; Resize tick marks if map resized.
end setvalues
draw_and_frame(wks,xy1,calldraw,callframe,0,maxbb)
xy1_at_xy2 = xy2
return (xy1)
end
;***********************************************************************;
; Function : plot_xy3 ;
; wks: workstation object ;
; x1 : X values ;
; y1 : First set of Y values ;
; y2 : Second set of Y values ;
; y3 : Third set of Y values ;
; res1 : opt'l resources, to apply to first curve ;
; res2 : opt'l resources, to apply to second curve ;
; res3 : opt'l resources, to apply to third curve ;
; plot_type : whether we're doing generic gsn, or gsn_csm ;
; ;
; This function calls plot_x2y2 with a single set of X values, and two ;
; sets of Y values, each with their own Y axis, and puts them on the ;
; same plot. The left axis is labeled according to the y1 values, and ;
; the right axis is labeled according to the y2 values. ;
; ;
;***********************************************************************;
function plot_xy3 (wks:graphic, x1:numeric, y1:numeric, y2:numeric, \
y3:numeric, res1:logical, res2:logical, res3:logical, \
plot_type:string)
begin
;
; Make a copy of the resources
;
if(res1) then
res1_new = res1
end if
if(res2) then
res2_new = res2
end if
if(res3) then
res3_new = get_res_ne(res3,(/"am"/))
end if
;
; Make sure these are True
;
res1_new = True
res2_new = True
res3_new = True
;
; Retain draw, frame, and maximize settings for later.
;
calldraw = get_res_value(res1_new,"gsnDraw", True)
callframe = get_res_value(res1_new,"gsnFrame",True)
maxbb = get_bb_res(res1_new)
;
; Create some dummy variables.
;
x2 = new(1,typeof(x1))
;
; Call plot_x2y2 function.
;
res1_new_at_gsnDraw = False
res1_new_at_gsnFrame = False
res1_new_at_gsnMaximize = False ; Don't need to maximize yet.
res2_new_at_gsnDraw = False
res2_new_at_gsnFrame = False
res2_new_at_gsnMaximize = False ; Don't need to maximize yet.
xy12 = plot_x2y2 (wks, x1, x2, y1, y2, res1_new, res2_new, "y", plot_type)
delete(x2)
;
; Get the size and X limits of this plot, and use them for the third plot.
;
getvalues xy12
"vpHeightF" : vph
"vpWidthF" : vpw
"vpXF" : vpx
"vpYF" : vpy
"trXMinF" : xmin
"trXMaxF" : xmax
"tiXAxisFontHeightF" : xaxis_fh
"tiYAxisFontHeightF" : yaxis_fh
"tmXBLabelFontHeightF" : xlab_fh
"tmYLLabelFontHeightF" : ylab_fh
end getvalues
;
; Set up some resources so we can add the third Y curve to the
; previous plot in the same location as the first two curves,
; but without any tickmarks.
;
; Notice that we are allowing the user to override some of these
; settings, but the user really shouldn't be doing this in the
; first place.
;
res3_new_at_gsnFrame = False
res3_new_at_gsnDraw = False
res3_new_at_gsnMaximize = False
res3_new_at_vpHeightF = get_res_value_keep(res3, "vpHeightF",vph)
res3_new_at_vpWidthF = get_res_value_keep(res3, "vpWidthF", vpw)
res3_new_at_vpXF = get_res_value_keep(res3, "vpXF", vpx)
res3_new_at_vpYF = get_res_value_keep(res3, "vpYF", vpy)
res3_new_at_trXMinF = get_res_value_keep(res3, "trXMinF", xmin)
res3_new_at_trXMaxF = get_res_value_keep(res3, "trXMaxF", xmax)
res3_new_at_tmXTOn = get_res_value_keep(res3, "tmXTOn", False)
res3_new_at_tmXBOn = get_res_value_keep(res3, "tmXBOn", False)
res3_new_at_tmYROn = get_res_value_keep(res3, "tmYROn", False)
res3_new_at_tmYLOn = get_res_value_keep(res3, "tmYLOn", False)
res3_new_at_tiYAxisOn = get_res_value_keep(res3,"tiYAxisOn",False)
res3_new_at_tiXAxisOn = get_res_value_keep(res3,"tiXAxisOn",False)
if(plot_type.eq."csm") then
xy3 = gsn_csm_xy(wks, (/x1/), (/y3/), res3_new)
else
xy3 = gsn_xy(wks, (/x1/), (/y3/), res3_new)
end if
delete(res3_new)
;
; Add this third curve as annotation of the xy12 plot.
;
anno1 = NhlAddAnnotation(xy12,xy3)
setvalues anno1
"amZone" : 0 ; Zone 0 centers tick marks over map.
"amResizeNotify" : True ; Resize tick marks if map resized.
end setvalues
;
; Last step is to attach a single vertical line that will
; represent the Y axis for the third curve. Make the width
; of this plot basically 0, so we can then use the amZone
; resource to attach the left edge of this plot to right side
; of the previous plot, outside of the tickmarks and labels.
;
if(res3) then
res3_new = get_res_ne(res3,(/"am"/))
end if
res3_new = True ; Make sure this is True.
res3_new_at_gsnFrame = False
res3_new_at_gsnDraw = False
res3_new_at_vpHeightF = vph
res3_new_at_vpWidthF = 0.0001
res3_new_at_vpXF = vpx
res3_new_at_vpYF = vpy
res3_new_at_trXMinF = xmin
res3_new_at_trXMaxF = xmax
;
; Pick some "nice" values for this single vertical axis, and
; use them if the user hasn't already set their own.
;
mnmxint = nice_mnmxintvl(min(y3), max(y3), 10, True)
res3_new_at_trYMinF = get_res_value(res3_new,"trYMinF",mnmxint(0))
res3_new_at_trYMaxF = get_res_value(res3_new,"trYMaxF",mnmxint(1))
res3_new_at_tmXBOn = get_res_value(res3_new,"tmXBOn",False)
res3_new_at_tmXBBorderOn = get_res_value(res3_new,"tmXBBorderOn",False)
res3_new_at_tmXTOn = get_res_value(res3_new,"tmXTOn",False)
res3_new_at_tmXTBorderOn = get_res_value(res3_new,"tmXTBorderOn",False)
res3_new_at_tmYLOn = get_res_value(res3_new,"tmYLOn",False)
res3_new_at_tmYROn = get_res_value(res3_new,"tmYROn",True)
;
; Turn on right axis labels; they are off by default.
;
res3_new_at_tmYRLabelsOn = get_res_value(res3_new,"tmYRLabelsOn",True)
res3_new_at_tmYUseLeft = get_res_value(res3_new,"tmYUseLeft",False)
res3_new_at_tiYAxisSide = get_res_value(res3_new,"tiYAxisSide","Right")
res3_new_at_tiXAxisFontHeightF = get_res_value(res3_new, \
"tiXAxisFontHeightF",xaxis_fh)
res3_new_at_tiYAxisFontHeightF = get_res_value(res3_new, \
"tiYAxisFontHeightF",yaxis_fh)
res3_new_at_tmXBLabelFontHeightF = get_res_value(res3_new, \
"tmXBFontHeightF",xlab_fh)
res3_new_at_tmYLLabelFontHeightF = get_res_value(res3_new, \
"tmYLFontHeightF",ylab_fh)
;
; Generate some dummy data for our plot.
;
xdummy = new( 2, double) ; Make it double so it can handle
ydummy = new( 2, double)
if (isatt(y3,"long_name")) then
ydummy_at_long_name = y3_at_long_name
end if
ydummy(0) = res3_new_at_trYMinF ; dummy for vertical line
ydummy(1) = res3_new_at_trYMaxF
xdummy(0) = xmax
xdummy(1) = xmax
;
; Create the vertical line.
;
if(plot_type.eq."csm") then
line = gsn_csm_xy(wks,xdummy,ydummy,res3_new)
else
line = gsn_xy(wks,xdummy,ydummy,res3_new)
end if
;
; Right now we are using 0.7 for an orthgonal distance for the
; single vertical axis to be positioned with respect to the
; previous plot. The real way to do this is to figure out the
; distance from the outermost right edge of the xy3
; plot to the plot border. Then, figure out what fraction of the
; width of the plot this is. This fraction is how much we need to
; move the vertical line to the right. The problem is that if we
; do an NhlGetBB on the plot, it won't include the annotation that
; was added, and hence the outermost edge of the plot space is the
; same as the edge of the plot itself.
;
; At least let the user change this value if he/she wants to.
;
anno2 = NhlAddAnnotation(xy12,line)
amres = get_res_eq(res3,(/"am"/))
setvalues anno2
"amZone" : 0 ; Zone 2 is outside the tickmarks
"amResizeNotify" : True ; Resize tick marks if plot resized.
"amJust" : "CenterLeft"
"amOrthogonalPosF" : get_res_value(res3,"amOrthgonalPosF",0.7)
"amSide" : "Right"
end setvalues
attsetvalues_check(anno2,amres)
;
; Maximize plot, draw and advance the frame, if so desired.
;
draw_and_frame(wks,xy12,calldraw,callframe,0,maxbb)
xy12_at_xy3 = xy3
return (xy12)
end
;***********************************************************************;
; Function : plot_xy2 ;
; wks: workstation object ;
; x1: X values ;
; y1: First set of Y values ;
; y2: Second set of Y values ;
; res1: opt'l resources, to apply to first plot ;
; res2: opt'l resources, to apply to second plot ;;
; ;
; This function calls plot_x2y2 with a single set of X values, and two ;
; sets of Y values, each with their own Y axis, and puts them on the ;
; same plot. The left axis is labeled according to the y1 values, and ;
; the right axis is labeled according to the y2 values. ;
; ;
; "gsn_xy" is the underlying XY plotting routine called to generate ;
; the XY plots. ;
; ;
; Note: the reason I didn't call this routine "gsn_xy2" is two-fold: ;
; ;
; 1. I would have had to put a version of "plot_x2y2" in both ;
; gsn_code.ncl and gsn_csm.ncl. ;
; 2. It's not a widely used routine, so I didn't think people would ;
; miss it. They can just call "plot_xy2". ;
;***********************************************************************;
function plot_xy2 (wks:graphic, x1:numeric, y1:numeric, y2:numeric, \
res1:logical, res2:logical)
begin
;
; Create some dummy variables.
;
x2 = new(1,typeof(x1))
;
; Call plot_x2y2 function.
;
xy = plot_x2y2 (wks, x1, x2, y1, y2, res1, res2, "y", "gsun")
delete(x2)
return(xy)
end
;***********************************************************************;
; Function : plot_x2y ;
; wks: workstation object ;
; x1: First set of X values ;
; x2: Second set of X values ;
; y1: Y values ;
; res1: opt'l resources, to apply to first plot ;
; res2: opt'l resources, to apply to second plot ;
; ;
; This function calls plot_x2y2 with a single set of Y values, and two ;
; sets of X values, each with their own X axis, and puts them on the ;
; same plot. The bottom axis is labeled according to the x1 values, and ;
; the top axis is labeled according to the x2 values. ;
; ;
; "gsn_xy" is the underlying XY plotting routine called to generate ;
; the XY plots. ;
; ;
; Note: the reason I didn't call this routine "gsn_x2y" is two-fold: ;
; ;
; 1. I would have had to put a version of "plot_x2y2" in both ;
; gsn_code.ncl and gsn_csm.ncl. ;
; 2. It's not a widely used routine, so I didn't think people would ;
; miss it. They can just call "plot_x2y". ;
;***********************************************************************;
function plot_x2y (wks:graphic, x1:numeric, x2:numeric, y1:numeric, \
res1:logical, res2:logical)
begin
;
; Create some dummy variables.
;
y2 = new(1,typeof(y1))
;
; Call plot_x2y2 function.
;
xy = plot_x2y2 (wks, x1, x2, y1, y2, res1, res2, "x", "gsun")
delete(y2)
return(xy)
end
;***********************************************************************;;
; Function : gsn_csm_xy2 ;
; wks: workstation object ;
; x1: X values ;
; y1: First set of Y values ;
; y2: Second set of Y values ;
; res1: opt'l resources, to apply to first plot ;
; res2: opt'l resources, to apply to second plot ;
; ;
; This function calls plot_x2y2 with a single set of X values, and two ;
; sets of Y values, each with their own Y axis, and puts them on the ;
; same plot. The left axis is labeled according to the y1 values, and ;
; the right axis is labeled according to the y2 values. ;
; ;
; "gsn_csm_xy" is the underlying XY plotting routine called to generate ;
; the XY plots. ;
;***********************************************************************;
function gsn_csm_xy2 (wks:graphic, x1:numeric, y1:numeric, y2:numeric, \
res1:logical, res2:logical)
begin
;
; Create some dummy variables.
;
x2 = new(1,typeof(x1))
;
; Call plot_x2y2 function.
;
xy = plot_x2y2 (wks, x1, x2, y1, y2, res1, res2, "y", "csm")
delete(x2)
return(xy)
end
;***********************************************************************;
; Function : gsn_csm_x2y ;
; wks: workstation object ;
; x1: First set of X values ;
; x2: Second set of X values ;
; y1: Y values ;
; res1: opt'l resources, to apply to first plot ;
; res2: opt'l resources, to apply to second plot ;
; ;
; This function calls plot_x2y2 with a single set of Y values, and two ;
; sets of X values, each with their own X axis, and puts them on the ;
; same plot. The bottom axis is labeled according to the x1 values, and ;
; the top axis is labeled according to the x2 values. ;
; ;
; "gsn_csm_xy" is the underlying XY plotting routine called to generate ;
; the XY plots. ;
;***********************************************************************;
function gsn_csm_x2y (wks:graphic, x1:numeric, x2:numeric, y1:numeric, \
res1:logical, res2:logical)
begin
;
; Create some dummy variables.
;
y2 = new(1,typeof(y1))
;
; Call plot_x2y2 function.
;
xy = plot_x2y2 (wks, x1, x2, y1, y2, res1, res2, "x", "csm")
delete(y2)
return(xy)
end
;***********************************************************************;
; Function : gsn_csm_x2y2 ;
; wks: workstation object ;
; x1: First set of Y values ;
; x2: First set of Y values ;
; y1: First set of X values ;
; y2: Second set of X values ;
; res1: optl resources, to apply to first plot ;
; res2: optl resources, to apply to second plot ;
; ;
; This function calls plot_x2y2 with a two sets of X *and* Y values, ;
; and puts them on the same plot. ;
; ;
; "gsn_csm_xy" is the underlying XY plotting routine called to generate ;
; the XY plots. ;
;***********************************************************************;
function gsn_csm_x2y2 (wks:graphic, x1:numeric, x2:numeric, \
y1:numeric, y2:numeric, res1:logical, res2:logical)
begin
;
; Call plot_x2y2 function.
;
xy = plot_x2y2 (wks, x1, x2, y1, y2, res1, res2, "xy", "csm")
return(xy)
end
;***********************************************************************;;
; Function : gsn_csm_xy3 ;
; wks: workstation object ;
; x1 : X values ;
; y1 : First set of Y values ;
; y2 : Second set of Y values ;
; y3 : Third set of Y values ;
; res1 : opt'l resources, to apply to first curve ;
; res2 : opt'l resources, to apply to second curve ;
; res3 : opt'l resources, to apply to third curve ;
; ;
; This function calls plot_xy3 with a plot_type of "csm". ;
;***********************************************************************;
function gsn_csm_xy3 (wks:graphic, x1:numeric, y1:numeric, y2:numeric, \
y3:numeric, res1:logical, res2:logical, res3:logical)
begin
;
; Call plot_xy3 function.
;
xy = plot_xy3 (wks, x1, y1, y2, y3, res1, res2, res3, "csm")
return(xy)
end
;***********************************************************************;
; Function : gsn_csm_contour ;
; wks: workstation object ;
; data: data to contour ;
; resources: optional resources ;
; ;
; This function creates and draws a titled contour plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the contour plot is returned. ;
; ;
; This function behaves differently from gsn_contour in that it will ;
; add additional titles to the top of the plot if any of the special ;
; GSUN resources "gsnLeftString," "gsnCenterString," and/or ;
; "gsnRightString" are set, They are used to title the top left, center,;
; and right of the plot (in addition, the regular resource ;
; "tiMainString" can be set to create a regular title). ;
; ;
; If cnFillOn is True, then a labelbar will be added, and the info label;
; will be removed.
; ;
; Tick marks will be made to point outwards. ;
; ;
;***********************************************************************;
function gsn_csm_contour(wks:graphic,data:numeric,resources:logical)
local res, contour_object, res2, xfontf, yfontf, font_height, lbar_on, \
calldraw, callframe, left_string, center_string, right_string, \
main_zone, datanew, popgrid, contour_plot
begin
;
; Make sure input data is 1D or 2D
;
if(.not.is_data_1d_or_2d(data)) then
print("gsn_csm_contour: Fatal: the input data array must be 1D or 2D")
return
end if
; Initialize.
lbar_on = False ; Labelbar flag
main_zone = 2 ; Zone for main title (may change later)
res2 = get_resources(resources)
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",True)
; This section tests for more special resources: those that start
; with "gsn."
; The default is to not add a cyclic point.
if(get_res_value(res2,"gsnAddCyclic",False))
datanew = gsn_add_cyclic_point(data)
else
datanew = data
end if
;
; Check if frame and/or draw are not supposed to be called.
;
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
;
; Check if a POP grid is to be overlaid.
;
popgrid = get_res_value(res2,"gsnPopGrid","")
;
; If adding a POP grid, then don't label the X and Y axis since the
; axes will have lat/lon labels.
;
if(popgrid.ne."")
set_attr(res2,"tiXAxisString","")
set_attr(res2,"tiYAxisString","")
end if
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(datanew,res2,res2)
set_left_subtitle(datanew,res2,res2)
; Check for existence of the left, center, and right subtitles.
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = main_zone+1
end if
; Check if gsnShape set.
if(check_attr(res2,"gsnShape",True,False))
main_zone = main_zone+1 ; Zone for main title
end if
; Use coordinate variables for X and/or Y if they exist.
check_for_coord_arrays(datanew,res2,"contour")
;
; Turn on a labelbar if fill is True and if the labelbar is not
; explicitly being turned off.
;
if(check_attr(res2,"cnFillOn",True,False).and. \
(.not.isatt(res2,"lbLabelBarOn").or.\
.not.check_attr(res2,"lbLabelBarOn",False,False)))
lbar_on = True
set_attr(res2,"cnLineLabelsOn",False)
set_attr(res2,"cnInfoLabelOn",False)
end if
if(isatt(res2,"lbLabelBarOn"))
delete(res2_at_lbLabelBarOn)
end if
res2 = True
res2_at_gsnDraw = False ; Internally, don't draw plot or advance
res2_at_gsnFrame = False ; frame since we take care of that later.
res2_at_gsnScale = True ; force labels and ticks to be same.
cnres = get_res_ne(res2,(/"tx","am"/))
contour_object = gsn_contour(wks,datanew,cnres)
; Get some information from contour plot that was created.
contour_plot = check_class_name(contour_object,"contour")
; Add lat/lon labels to X/Y axes if appropriate coordinate arrays exist.
add_latlon_labels(contour_plot,datanew,res2)
getvalues contour_plot
"vpWidthF" : width
"vpHeightF" : height
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
"tmYLMajorLengthF" : ylength
"tmXBMajorLengthF" : xlength
"tmYLMinorLengthF" : ymlength
"tmXBMinorLengthF" : xmlength
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make subtitle label sizes a
; function of the size of the
; X/Y axis labels.
; If the plot is close to square in size, then make the
; three top titles and the tick marks smaller.
font_scale = (/1.0,0.8,0.8/)
ratios = (/0.5,0.75,1.0/)
ratio = height/width
if(ratio.gt.1)
ratio = 1./ratio
end if
index = ind(ratio.le.ratios)
scale = font_scale(index(0))
font_height = scale * font_height
if(popgrid.ne."") then
pop_latlon_grid(wks,contour_object,popgrid) ; Add a POP grid.
else
;
; Make tick marks same length and point outward.
;
major_length = scale * min((/ylength,xlength/))
minor_length = scale * min((/ymlength,xmlength/))
tmres = get_res_eq(res2,"tm")
gsnp_point_tickmarks_outward(contour_plot,tmres,xlength,ylength,\
xmlength,ymlength,\
major_length,minor_length,point_outward)
end if
; Create a labelbar.
if (lbar_on)
lbres = get_res_eq(res2,(/"lb","pm"/))
add_labelbar(wks,contour_object,3,font_height,"contour",lbres)
end if
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"tx","am"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",font_height)
add_subtitles(wks,contour_object,left_string,center_string,\
right_string,subres)
; Draw all this stuff: contour plot and subtitles.
draw_and_frame(wks,contour_object,calldraw,callframe,0,maxbb)
; Return contour plot object.
return(contour_object)
end
;***********************************************************************;
; Function : gsn_csm_hov ;
; wks: workstation object ;
; data: data to be contoured ;
; resources: optional resources ;
; ;
; This function creates and draws a titled Hovmueller plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the contour plot is returned. ;
; ;
; This function behaves differently from gsn_csm_contour in that it ;
; draws a specially-labelled longitude X axis. ;
; ;
;***********************************************************************;
function gsn_csm_hov(wks:graphic,data[*][*]:numeric,resources:logical)
local res, contour_object, res2, font_height, calldraw, callframe, \
datanew, lon_spacing, contour_plot
begin
; Initialize.
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
lon_spacing = get_res_value(res2,"gsnMajorLonSpacing",0)
mlon_spacing = get_res_value(res2,"gsnMinorLonSpacing",0)
if(is_valid_latlon_coord(data,"x","lat",res2).or.\
is_valid_latlon_coord(data,"x","lon",res2))
set_attr(res2,"tiXAxisString","")
end if
; Use coordinate variable for X if it exists.
if(is_valid_coord(data,"x").and..not.(isatt(res2,"sfXCStartV").and. \
isatt(res2,"sfXCEndV")))
set_attr(res2,"sfXArray",data&$data!1$)
end if
res2 = True
res2_at_gsnDraw = False
res2_at_gsnFrame = False
contour_object = gsn_csm_contour(wks,data,res2) ; Create a contour plot.
; Check if we should label X axis with nice longitude labels.
if(is_valid_latlon_coord(data,"x","lon",res2)) then
; Get min and max X axis values (longitude units)
contour_plot = check_class_name(contour_object,"contour")
getvalues contour_plot
"trXMinF" : min_lon
"trXMaxF" : max_lon
end getvalues
;
; We want different defaults for longitude spacing, so set them up here.
;
lon_range = (/ 20, 40, 60, 180, 360/)
lon_spacing_arr = (/ 10, 20, 30, 45, 60/)
mlon_spacing_arr = (/ 5, 5, 10, 15, 30/)
add_lon_labels(contour_plot,min_lon,max_lon,lon_spacing,mlon_spacing,\
lon_range,lon_spacing_arr,mlon_spacing_arr,res2)
end if
; Draw all this stuff: contour plot and subtitles.
draw_and_frame(wks,contour_object,calldraw,callframe,0,maxbb)
; Return contour plot object.
return(contour_object)
end
;***********************************************************************;
; Function : gsn_csm_lat_time ;
; wks: workstation object ;
; data: data to be contoured ;
; resources: optional resources ;
; ;
; This function creates and draws a titled Lat/time plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the contour plot is returned. ;
; ;
; This function behaves differently from gsn_csm_contour in that it ;
; draws a specially-labelled latitude Y axis. ;
; ;
; ;
;***********************************************************************;
function gsn_csm_lat_time(wks:graphic,data[*][*]:numeric,resources:logical)
local res, contour_object, res2, font_height, calldraw, callframe, \
datanew, lat_spacing
begin
; Initialize.
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
lat_spacing = get_res_value(res2,"gsnMajorLatSpacing",0)
mlat_spacing = get_res_value(res2,"gsnMinorLatSpacing",0)
if((res2).and..not.any(ismissing(getvaratts(res2))))
set_attr(res2,"tiYAxisString","")
end if
; Use coordinate variable for Y if it exists.
check_for_y_lat_coord(data,res2,"contour")
res2 = True
res2_at_gsnDraw = False
res2_at_gsnFrame = False
contour_object = gsn_csm_contour(wks,data,res2) ; Create a contour plot.
; Get min and max Y axis values (latitude units)
contour_plot = check_class_name(contour_object,"contour")
getvalues contour_plot
"trYMinF" : min_lat
"trYMaxF" : max_lat
end getvalues
add_lat_labels_yaxis(contour_plot,min_lat,max_lat,\
lat_spacing,mlat_spacing,res2)
; Draw all this stuff: contour plot and subtitles.
draw_and_frame(wks,contour_object,calldraw,callframe,0,maxbb)
; Return contour plot object.
return(contour_object)
end
;***********************************************************************;
; Function : gsn_csm_time_lat ;
; wks: workstation object ;
; data: data to be contoured ;
; resources: optional resources ;
; ;
; This function creates and draws a titled time/lat plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the contour plot is returned. ;
; ;
; This function behaves differently from gsn_csm_contour in that it ;
; draws a specially-labeled latitude X axis. ;
; ;
;***********************************************************************;
function gsn_csm_time_lat(wks:graphic,data[*][*]:numeric,resources:logical)
local res, contour_object, res2, font_height, calldraw, callframe, \
datanew, lat_spacing
begin
; Initialize.
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
lat_spacing = get_res_value(res2,"gsnMajorLatSpacing",15)
mlat_spacing = get_res_value(res2,"gsnMinorLatSpacing",5)
if((res2).and..not.any(ismissing(getvaratts(res2))))
set_attr(res2,"tiXAxisString","")
end if
; Use coordinate variable for X if it exists.
check_for_x_lat_coord(data,res2,"contour")
res2 = True
res2_at_gsnDraw = False
res2_at_gsnFrame = False
contour_object = gsn_csm_contour(wks,data,res2) ; Create a contour plot.
; Get min and max X axis values (latitude units)
contour_plot = check_class_name(contour_object,"contour")
getvalues contour_plot
"trXMinF" : min_lat
"trXMaxF" : max_lat
end getvalues
add_lat_labels_xaxis(contour_plot,min_lat,max_lat,lat_spacing,\
mlat_spacing,res2)
; Draw all this stuff: contour plot and subtitles.
draw_and_frame(wks,contour_object,calldraw,callframe,0,maxbb)
; Return contour plot object.
return(contour_object)
end
;***********************************************************************;
; Function : gsn_csm_pres_hgt ;
; wks: workstation object ;
; data: data to be contoured ;
; resources: optional resources ;
; ;
; This function creates and draws a titled contour plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the contour plot is returned. ;
; ;
; This function behaves differently from gsn_csm_contour in that it ;
; draws a specially-labelled pressure axis on one side and a height axis;
; on the other side. It also labels the longitude X axis, if one ;
; exists. ;
; ;
;***********************************************************************;
function gsn_csm_pres_hgt(wks:graphic,data[*][*]:numeric,resources:logical)
local res, contour_object, res2, xfontf, yfontf, font_height, \
calldraw, callframe, add_hgt, contour_plot
begin
; Initialize.
add_hgt = False
pres_reverse = True ; Default is to assume pressure values
; already reversed.
res2 = get_resources(resources)
add_hgt_label = get_res_value(res2,"gsnPresHgtHeightLabelOn",True)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
lat_spacing = get_res_value(res2,"gsnMajorLatSpacing",0)
mlat_spacing = get_res_value(res2,"gsnMinorLatSpacing",0)
if(is_valid_coord(data,"y"))
title = get_csm_long_name_units_string(data&$data!0$)
if(.not.ismissing(title)) then
set_attr(res2,"tiYAxisString",title)
end if
end if
;
; If this is a pressure/hgt plot, then do stuff to the pressure values.
;
if(is_valid_coord(data,"y"))
npres = dimsizes(data&$data!0$)
;
; Check for pressure values. If they are not in descending order, then
; reverse 'em.
;
if(data&$data!0$(0).lt.data&$data!0$(npres-1))
pres = tofloat(data&$data!0$(::-1)) ; reverse the values
pres_reverse = False ; pres values weren't already reversed
else
pres = tofloat(data&$data!0$)
end if
;
; Check the units.
;
if(isatt(data&$data!0$,"units").and.\
any(data&$data!0$@units.eq.get_allowed_pres_units()))
;
; If pressure values are Pascals, convert them to millibars.
;
if(any(data&$data!0$@units.eq.get_allowed_pres_units_pa()))
pres = tofloat(data&$data!0$) * 0.01 ; convert to mb
pres_at_units = "mb"
end if
else
print("gsn_csm_pres_hgt: Fatal: The coordinate array for the first dimension of the input data must be in Pascals, Hecto-pascals, or millibars")
print("and it must contain the attribute 'units' set to one of the following strings (depending on your units):")
print(" " + cat_strings(get_allowed_pres_units))
print("Cannot create plot.")
return
end if
set_pres_hgt_axes(pres,res2,add_hgt)
else
print("gsn_csm_pres_hgt: Fatal: The first dimension of the input data must")
print("have a coordinate variable called 'lev.'")
print("Cannot create plot.")
return
end if
log_y = get_res_value(res2,"trYLog",True) ; Check if Y axis to stay linear.
res2 = True
res2_at_gsnDraw = False
res2_at_gsnFrame = False
if(pres_reverse)
contour_object = gsn_csm_hov(wks,data,res2) ; Create a contour plot.
else
contour_object = gsn_csm_hov(wks,data(::-1,:),res2) ; reverse Y
end if
; Retrieve some values from the contour plot so we can create a LogLin
; plot with the same information.
contour_plot = check_class_name(contour_object,"contour")
getvalues contour_plot
"vpXF" : xvp
"vpYF" : yvp
"vpWidthF" : widthvp
"vpHeightF" : heightvp
"trXMinF" : xmin
"trXMaxF" : xmax
"trYMinF" : ymin
"trYMaxF" : ymax
"tiYAxisFontHeightF" : yaxis_font_height
"tmYLLabelFontHeightF" : yaxis_label_height
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make subtitles sizes a function of
; the size of the X/Y axis labels.
setvalues contour_plot
"tmYLLabelFontHeightF" : yaxis_label_height * 0.8
"tmYRLabelFontHeightF" : yaxis_label_height * 0.8
"tmXBLabelFontHeightF" : yaxis_label_height * 0.8
end setvalues
; Check if we should label X axis with nice latitude labels.
if(is_valid_latlon_coord(data,"x","lat",res2)) then
add_lat_labels_xaxis(contour_plot,xmin,xmax,lat_spacing, \
mlat_spacing,res2)
end if
;
; Add a right Y axis "height" label.
;
if(add_hgt.and.add_hgt_label)
rightaxis_string = create "right_axis" textItemClass wks
"txString" : "Height (km)"
"txFontHeightF" : yaxis_font_height
"txAngleF" : 90.
end create
anno = NhlAddAnnotation(contour_object,rightaxis_string)
setvalues anno
"amZone" : 3 ; Just outside plot area
"amJust" : "centercenter"
"amSide" : "right"
"amParallelPosF" : 0.5
"amOrthogonalPosF": 0.03
"amResizeNotify" : True ; Resize if plot resized.
end setvalues
end if
wksname = get_res_value_keep(wks,"name","gsnapp")
loglin_object = create wksname + "_loglin" logLinPlotClass wks
"vpXF" : xvp
"vpYF" : yvp
"vpWidthF" : widthvp
"vpHeightF" : heightvp
"trYReverse" : True
"trXMinF" : xmin
"trXMaxF" : xmax
"trYMinF" : ymin
"trYMaxF" : ymax
"trYLog" : log_y
end create
;
; Check for transformation resources and apply them to loglin plot.
; Not all transformation resources can be applied to the loglin plot.
; For example, you can't apply IrregularTransformation resources. So,
; we have to explicitly test for these.
;
trres = get_res_eq(res2,"tr")
irreg_res = (/"trXAxisType","trXCoordPoints","trXInterPoints", \
"trXTensionF","trXSamples","trYAxisType","trYCoordPoints",\
"trYInterPoints","trYTensionF","trYSamples"/)
do i = 0, dimsizes(irreg_res)-1
if(isatt(trres,irreg_res(i))) then
delete(trres@$irreg_res(i)$) ; Remove irreg trans resource.
end if
end do
attsetvalues_check(loglin_object,trres)
; Overlay this on a LogLin plot so we can get a logarithmic Y axis.
overlay(loglin_object,contour_object)
; Draw all this stuff: contour plot and subtitles.
draw_and_frame(wks,loglin_object,calldraw,callframe,0,maxbb)
; Return loglin plot with contour plot object as an attribute.
loglin_object_at_contour = contour_object
loglin_object_at_data = contour_object_at_data
return(loglin_object)
end
;***********************************************************************;
; Function : gsn_csm_vector ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a titled vector plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the vector plot is returned. ;
; ;
; This function behaves differently from gsn_vector in that it will ;
; add additional titles to the top of the plot if any of the special ;
; GSUN resources "gsnLeftString," "gsnCenterString," and/or ;
; "gsnRightString" are set, They are used to title the top left, center,;
; and right of the plot (in addition, the regular resource ;
; "tiMainString" can be set to create a regular title). ;
; ;
; Tick marks will be made to point outwards. ;
; ;
;***********************************************************************;
function gsn_csm_vector(wks:graphic,u[*][*]:numeric,v[*][*],resources:logical)
local res, vector_object, res2, xfontf, yfontf, font_height, lbar_on, \
calldraw, callframe, left_string, center_string, right_string, \
main_zone, unew, vnew
begin
; Initialize.
lbar_on = False ; Labelbar flag
main_zone = 2 ; Zone for main title (may change later)
res2 = get_resources(resources)
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",True)
; This section tests for more special resources: those that start
; with "gsn."
; The default is to not add a cyclic point.
if(get_res_value(res2,"gsnAddCyclic",False))
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
;
; Check if frame and/or draw are not supposed to be called.
;
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,res2)
set_left_subtitle(unew,res2,res2)
; Check for existence of the left, center, and right subtitles.
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = main_zone+1
end if
; Check if gsnShape set.
if(check_attr(res2,"gsnShape",True,False))
main_zone = main_zone+1 ; Zone for main title
end if
; Use coordinate variables for X and/or Y if they exist.
check_for_coord_arrays(unew,res2,"vector")
;
; Turn on a labelbar if fill is True and if the labelbar is not
; explicitly being turned off.
;
if(check_attr(res2,"vcMonoLineArrowColor",False,False).and.\
(.not.isatt(res2,"lbLabelBarOn").or.\
check_attr(res2,"lbLabelBarOn",True,False)))
lbar_on = True
end if
if(isatt(res2,"lbLabelBarOn"))
delete(res2_at_lbLabelBarOn)
end if
res2 = True
res2_at_gsnDraw = False ; Internally, don't draw plot or advance
res2_at_gsnFrame = False ; frame since we take care of that later.
res2_at_gsnScale = True ; force labels and ticks to be same.
vcres = get_res_ne(res2,(/"tx"/))
vector_object = gsn_vector(wks,unew,vnew,vcres)
; Get some information from vector plot that was created.
vector_plot = check_class_name(vector_object,"vector")
; Add lat/lon labels to X/Y axes if appropriate coordinate arrays exist.
add_latlon_labels(vector_plot,unew,res2)
getvalues vector_plot
"vpWidthF" : width
"vpHeightF" : height
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
"tmYLMajorLengthF" : ylength
"tmXBMajorLengthF" : xlength
"tmYLMinorLengthF" : ymlength
"tmXBMinorLengthF" : xmlength
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make subtitle label sizes a
; function of the size of the
; X/Y axis labels.
major_length = min((/ylength,xlength/)) ; New length for major ticks.
minor_length = min((/ymlength,xmlength/)) ; New length for minor ticks.
; If the plot is close to square in size, then make the
; three top titles and the tick marks smaller.
font_scale = (/1.0,0.8,0.8/)
ratios = (/0.5,0.75,1.0/)
ratio = height/width
if(ratio.gt.1)
ratio = 1./ratio
end if
index = ind(ratio.le.ratios)
scale = font_scale(index(0))
font_height = scale * font_height
;
; Make tick marks same length and point outward.
;
major_length = scale * major_length
minor_length = scale * minor_length
tmres = get_res_eq(res2,"tm")
gsnp_point_tickmarks_outward(vector_plot,tmres,xlength,ylength,\
xmlength,ymlength,\
major_length,minor_length,point_outward)
; Create a labelbar.
if (lbar_on)
lbres = get_res_eq(res2,(/"lb","pm"/))
add_labelbar(wks,vector_object,3,font_height,"vector",lbres)
end if
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"am","tx"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",font_height)
add_subtitles(wks,vector_object,left_string,center_string,\
right_string,subres)
; Draw all this stuff: vector plot and subtitles.
draw_and_frame(wks,vector_object,calldraw,callframe,0,maxbb)
; Return vector plot object.
return(vector_object)
end
;***********************************************************************;
; Function : gsn_csm_pres_hgt_vector ;
; wks: workstation object ;
; data: data to be contoured ;
; u: u component of vectors ;
; v: u component of vectors ;
; resources: optional resources ;
; ;
; This function behaves like gsn_csm_pres_hgt, only it overlays a ;
; vector plot as well. ;
;***********************************************************************;
function gsn_csm_pres_hgt_vector(wks:graphic,data[*][*]:numeric, \
u[*][*]:numeric, v[*][*]:numeric, \
resources:logical)
local res2, cnres, vcres, calldraw, callframe, npres, lbar_zone, anno_zone
begin
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
anno_zone = get_res_value(res2,"vcRefAnnoZone",3)
ypos = get_res_value(res2,"vpYF",0.87)
info_para = get_res_value(res2,"cnInfoLabelParallelPosF",0.)
info_just = get_res_value(res2,"cnInfoLabelJust","TopLeft")
refanno_on= get_res_value_keep(res2,"vcRefAnnoOn",True)
if(refanno_on)
lbar_zone = get_res_value(res2,"pmLabelBarZone",4)
lbar_orth = get_res_value(res2,"pmLabelBarOrthogonalPosF",0.05)
else
lbar_zone = get_res_value(res2,"pmLabelBarZone",3)
lbar_orth = get_res_value(res2,"pmLabelBarOrthogonalPosF",0.0)
end if
cnres = get_res_ne(res2,(/"vc","vf","pm"/))
vcres = get_res_eq(res2,(/"vc","vf","tr"/))
;
; Set some contour resources.
;
cnres = True
cnres_at_gsnDraw = False
cnres_at_gsnFrame = False
cnres_at_vpYF = ypos
cnres_at_cnInfoLabelParallelPosF = info_para ; Change locations of info
cnres_at_cnInfoLabelJust = info_just ; label and label bar so
cnres_at_pmLabelBarZone = lbar_zone ; they don't run into vector
cnres_at_pmLabelBarOrthogonalPosF = lbar_orth ; reference anno.
;
; Create contour pressure/height plot.
;
contour = gsn_csm_pres_hgt(wks,data,cnres)
;
; Set some vector resources.
;
vcres = True
vcres_at_vcRefAnnoZone = anno_zone ; change zones so ref anno and
; labelbar don't run into each other
vcres_at_gsnDraw = False
vcres_at_gsnFrame = False
vcres_at_gsnRightString = "" ; Use gsnRightString and gsnLeftString
vcres_at_gsnLeftString = "" ; from contour plot.
;
; Create vector plot. We have to check the pressure values. If they
; are not in descending order, then reverse 'em.
;
if(is_valid_coord(u,"y"))
npres = dimsizes(u&$u!0$)
if(u&$u!0$(0).lt.u&$u!0$(npres-1))
vector = gsn_csm_vector(wks,u(::-1,:),v(::-1,:),vcres)
else
vector = gsn_csm_vector(wks,u,v,vcres)
end if
else
vector = gsn_csm_vector(wks,u,v,vcres)
end if
;
; Overlay the vectors on the contour plot.
;
overlay(contour,vector)
; Draw all this stuff: vector over contour plot.
draw_and_frame(wks,contour,calldraw,callframe,0,maxbb)
; Return contour/vector plot with data objects as attributes.
contour_at_sfdata = contour_at_data
contour_at_vcdata = vector_at_data
return(contour)
end
;***********************************************************************;
; Function : gsn_csm_streamline ;
; wks: workstation object ;
; u: 2-dimensional data ;
; v: 2-dimensional data ;
; resources: optional resources ;
; ;
; This function creates and draws a titled streamline plot to the ;
; workstation "wks" (the variable returned from a previous call to ;
; "gsn_open_wks"). "resources" is an optional list of resources. The ;
; Id of the streamline plot is returned. ;
; ;
; This function behaves differently from gsn_streamline in that it will ;
; add additional titles to the top of the plot if any of the special ;
; GSUN resources "gsnLeftString," "gsnCenterString," and/or ;
; "gsnRightString" are set, They are used to title the top left, center,;
; and right of the plot (in addition, the regular resource ;
; "tiMainString" can be set to create a regular title). ;
; ;
; Tick marks will be made to point outwards. ;
; ;
;***********************************************************************;
function gsn_csm_streamline(wks:graphic,u[*][*]:numeric,v[*][*],\
resources:logical)
local res, stream_object, res2, xfontf, yfontf, font_height, \
calldraw, callframe, left_string, center_string, right_string, \
main_zone, unew, vnew
begin
; Initialize.
main_zone = 2 ; Zone for main title (may change later)
res2 = get_resources(resources)
point_outward = get_res_value(res2,"gsnTickMarksPointOutward",True)
; This section tests for more special resources: those that start
; with "gsn."
; The default is to not add a cyclic point.
if(get_res_value(res2,"gsnAddCyclic",False))
unew = gsn_add_cyclic_point(u)
vnew = gsn_add_cyclic_point(v)
else
unew = u
vnew = v
end if
;
; Check if frame and/or draw are not supposed to be called.
;
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
; Check for left/right titles at top. Use valid "long_name" type attributes
; and "units" if they exist.
set_right_subtitle(unew,res2,res2)
set_left_subtitle(unew,res2,res2)
; Check for existence of the left, center, and right subtitles.
left_string = new(1,logical)
center_string = new(1,logical)
right_string = new(1,logical)
check_for_subtitles(res2,left_string,center_string,right_string)
if(left_string.or.center_string.or.right_string)
main_zone = main_zone+1
end if
if(check_attr(res2,"gsnShape",True,False))
main_zone = main_zone+1 ; Zone for main title
end if
; Use coordinate variables for X and/or Y if they exist.
check_for_coord_arrays(unew,res2,"vector")
res2 = True
res2_at_gsnDraw = False ; Internally, don't draw plot or advance
res2_at_gsnFrame = False ; frame since we take care of that later.
res2_at_gsnScale = True ; force labels and ticks to be same.
stres = get_res_ne(res2,(/"tx"/))
stream_object = gsn_streamline(wks,unew,vnew,stres)
; Get some information from streamline plot that was created.
streamline_plot = check_class_name(stream_object,"streamline")
; Add lat/lon labels to X/Y axes if appropriate coordinate arrays exist.
add_latlon_labels(streamline_plot,unew,res2)
; Get some information from streamline plot that was created.
getvalues streamline_plot
"vpWidthF" : width
"vpHeightF" : height
"tiXAxisFontHeightF" : xfontf
"tiYAxisFontHeightF" : yfontf
"tmYLMajorLengthF" : ylength
"tmXBMajorLengthF" : xlength
"tmYLMinorLengthF" : ymlength
"tmXBMinorLengthF" : xmlength
end getvalues
font_height = min((/xfontf,yfontf/)) ; Make subtitle label sizes a
; function of the size of the
; X/Y axis labels.
major_length = min((/ylength,xlength/)) ; New length for major ticks.
minor_length = min((/ymlength,xmlength/)) ; New length for minor ticks.
; If the plot is close to square in size, then make the
; three top titles and the tick marks smaller.
font_scale = (/1.0,0.8,0.8/)
ratios = (/0.5,0.75,1.0/)
ratio = height/width
if(ratio.gt.1)
ratio = 1./ratio
end if
index = ind(ratio.le.ratios)
scale = font_scale(index(0))
font_height = scale * font_height
;
; Make tick marks same length and point outward.
;
major_length = scale * major_length
minor_length = scale * minor_length
tmres = get_res_eq(res2,"tm")
gsnp_point_tickmarks_outward(streamline_plot,tmres,xlength,ylength,\
xmlength,ymlength,\
major_length,minor_length,point_outward)
; Set up three subtitles at top, if they exist.
subres = get_res_eq(res2,(/"am","tx"/)) ; Get textitem resources
subres = True
set_attr(subres,"txFontHeightF",font_height)
add_subtitles(wks,stream_object,left_string,center_string,\
right_string,subres)
; Draw all this stuff: streamline plot and subtitles.
draw_and_frame(wks,stream_object,calldraw,callframe,0,maxbb)
; Return streamline plot object.
return(stream_object)
end
;***********************************************************************;
; Function : gsn_csm_pres_hgt_streamline ;
; wks: workstation object ;
; data: data to be contoured ;
; u: u component of streamlines ;
; v: u component of streamlines ;
; resources: optional resources ;
; ;
; This function behaves like gsn_csm_pres_hgt, only it overlays a ;
; streamline plot as well. ;
;***********************************************************************;
function gsn_csm_pres_hgt_streamline(wks:graphic,data[*][*]:numeric, \
u[*][*]:numeric, v[*][*]:numeric, \
resources:logical)
local res2, cnres, stres, calldraw, callframe, npres
begin
res2 = get_resources(resources)
calldraw = get_res_value(res2,"gsnDraw", True)
callframe = get_res_value(res2,"gsnFrame",True)
maxbb = get_bb_res(res2)
cnres = get_res_ne(res2,(/"st","vf","pm"/))
stres = get_res_eq(res2,(/"st","vf"/))
;
; Set some contour resources.
;
cnres = True
cnres_at_gsnDraw = False
cnres_at_gsnFrame = False
;
; Create contour pressure/height plot.
;
contour = gsn_csm_pres_hgt(wks,data,cnres)
;
; Set some streamline resources.
;
stres = True
stres_at_gsnDraw = False
stres_at_gsnFrame = False
stres_at_gsnRightString = "" ; Use gsnRightString and gsnLeftString
stres_at_gsnLeftString = "" ; from contour plot.
;
; Create streamline plot. We have to check the pressure values. If they
; are not in descending order, then reverse 'em.
;
if(is_valid_coord(u,"y"))
npres = dimsizes(u&$u!0$)
if(u&$u!0$(0).lt.u&$u!0$(npres-1))
streamline = gsn_csm_streamline(wks,u(::-1,:),v(::-1,:),stres)
else
streamline = gsn_csm_streamline(wks,u,v,stres)
end if
else
streamline = gsn_csm_streamline(wks,u,v,stres)
end if
;
; Overlay the streamlines on the contour plot.
;
overlay(contour,streamline)
; Draw all this stuff: streamline over contour plot.
draw_and_frame(wks,contour,calldraw,callframe,0,maxbb)
; Return contour/streamline plot with data objects as attributes.
contour_at_sfdata = contour_at_data
contour_at_vcdata = streamline_at_data
return(contour)
end
_______________________________________________
ncl-talk mailing list
ncl-talk_at_ucar.edu
http://mailman.ucar.edu/mailman/listinfo/ncl-talk
Received on Mon Mar 05 2007 - 12:16:19 MST
This archive was generated by hypermail 2.2.0 : Tue Mar 06 2007 - 18:06:25 MST