[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[dennou-ruby:002127] gpview fix
- To: dennou-ruby@xxxxxxxxxxx
- Subject: [dennou-ruby:002127] gpview fix
- From: tsukahara daisuke <daktu32@xxxxxxxxxxxxxxxxxxxx>
- Date: Thu, 10 Feb 2005 22:46:18 +0900 (JST)
塚原です.
gpview を fix しました. 具体的には
  1. オプションパーサ取り替え
     + getopts から getoptlong ヘ
  2. --map, --m オプション追加
     + 地図投影(--itr 1-4 では無効.)
  3. --reverse, --Gr オプション追加
     + アニメーション時, 逆回しにパラパラする
です. CVS に反映しましたが, メール末尾に添付させていただき
ます.
アニメーションの方向を指定する機能は, 以前のバージョンでは
変数の範囲の指定の仕方で決めてましたが, 値の大きい座標が配
列の先頭に入っていない場合にうまく作用しない等不具合があり,
やや複雑なコードになっていたので陽に指定することにしました.
--dump オプションの処置については, 中野さんに相談しつつ考え
てみたのですが, 人によって dump に求める挙動が異なるようです
ので, ここはむしろ gtview 同様に DCL の swpack の内部変数
を直接設定するオプションを用意するほうがいいように思います.
そのほうがコードも読みやすくなりそうですし. 更に手を加えた
い方は個々人で gpview を叩き台にカスタムしてもらえればと思
います. よって --dump なるオプションは用意しないことにしよ
うと思います. (中野さんには同意をいただきました)
--------------------------------------
北海道大学院理学研究科 地球惑星科学専攻
地球流体力学研究室  M2  塚原大輔
email::daktu32@xxxxxxxxxxxxxxxxxxxx
--------------------------------------
#!/usr/bin/env ruby
##################################################
=begin
=gpview
 quick viewer for the values of a variable specified by
 a gtool4-type URL. 
 (1) for 1-dimensional variable, make line plot.
 (2) for 2-dimensional variable, make contour/tone plot.
 (3) for 3/more-dimensional variable, make contour/tone 
      plot, select first 2D. possible to make animation.
    
==USAGE
     % gpview [options] url
 where the format of the url is
     path@varname[,dimname=pos1[:pos2[:thinning_intv]][,dimname=...]]
==OPTIONS
 if you want to know more description, please read
    http://www.gfd-dennou.org/arch/gtool4/gtool4-1.0/doc/gtview.htm
===GLOBAL OPTIONS
   --wsn [1-4]           : set work staion number. each number represent 
                           output device:
                           1 : X window.
                           2 : PS file. (named dcl.ps) 
                           3 : Tcl/Tk file.
                           4 : GTK Windows (depend on dcl-5.3)
   --itr [1-4,5-7,10-15,20-23,30-33]
		         : set axis scale. default is 1.
                           1 : linear scale for x/y axis 
                           2 : linear scale for x , log scale for y axis
                           3 : log scale for x , linear scale for y axis
                           4 : log scale for x/y axis
   --similar [simfac,vxoff,vyoff]
                         : (for 5<=itr<=7) set similarity parameters
                            which are fed in DCL.grssim. 
   --map_axis [uxc,uyc,rot]
                         : (for 10<=itr<=33) set mapping parameters
                           which are fed in DCL.umpcnt. 
   --title               : set title of figure
   --aspect <aspect>     : set aspect ratio of Viewport. default is 2.0.
   --animate/anim <dim>  : plot animation along <dim>. 
                           <dim> must be name of dimension. 
   --alternate, --Ga     : enable to backing store.
   --nowait, --Gw        : not wait for any actions if animate 
   --reverse, --Gr       : plot animation reversible if animate
   --smooth, --Gaw       : equal to --anlternate && --nowait
   --exch                : exchange(transpose) x/y axis.
   --mean <dim>          : mean along axis <dim>. 
   --m, --map <map_type> : plot map. itr number must be set. 
                           this option is neglect if itr number is 1-4.
                           abailable map type is
                           coast_world, border_world, plate_world, state_usa,
                           coast_japan, pref_japan  
===LINE OPTIONS
   --line                : make line plot forced. (about first 1D)
   --index               : set DCL line index, which set the color/thickness
                           of the line primitive. please see DCL documents. 
   --type                : set line type.
===CONTOUR/TONE OPTIONS
   --shade               : make contour and tone plot.
   --noshade             : make contour plot, without tone.
   --nocont              : make tone plot, without contour.
   --range [min:max]     : set min/max value for contour/tone plot.
                           min or max must be set.
   --crange              : set min/max value for contour plot. this is more
                           dominant than --range
   --srange              : set min/max value for tone plot. this is more
                           dominant than --interval/int
   --interval,--int [num]: set interval value for contour/tone plot.    
                           set the number of lines if you set negative value.
   --cint                : set interval value for contour plot. this is more 
                           dominant than --interval/int
   --sint                : set interval value for tone plot. this is more
                           dominant than --interval/int.
==EXAMPLES
    % gpview data.nc@temp
    % gpview data.nc@temp,lon=130:150,lat=0:90:2
    % gpview --nocont data.nc@temp,lon=130:150,lat=0    
    % gpview --noshade data.nc@temp,lon=130:150,lat=0    
    % gpview --mean lon data.nc@temp,lon=130:150,lat=0
    % gpview --exch data.nc@temp,lon=130:150,lat=0
    % gpview --animate lon data.nc@temp,lon=130:150
    % gpview --animate lon --alternate data.nc@temp
    % gpview --smooth lon data.nc@temp,lon=130:150    
==HISTORY
   2004/12/14  D Tsukahara && T Horinouti(parse_gturl)
   2005/01/08  D Tsukahara (add option --exch and able to invalid value)
   2005/01/09  D Tsukahara (add option --animate, smooth, alternate, index )
   2005/01/10  D Tsukahara (transpose axis with attr "positive:down" ,
                            abailable loopsense_flag. )
   2005/01/10  D Tsukahara (implement GGraph::color_bar, and margin_info, 
                            which file name, date, and toolname. )
   2005/01/11  D Tsukahara ( 1. write document about OPTIONS. 
                             2. add many options. more info please see document. )
   2005/01/23  S Takehiro  (add option --similar, map_axis)
   2005/02/09  D Tsukahara && M Nakano (add option --reverse, --Gr, --map)
   2005/02/10  D Tsukahara (change option parser (getopts => getoptlong))
=end
#################################################
require "getoptlong"        # for option_parse
require "numru/ggraph"   # ggraph library
include NumRu
#####################################################
## Default param.
VIEWPORT = [0.15,0.85,0.2,0.55]
URLfmt = "path@varname[,dimname=pos1[:pos2[:thinning_intv]][,dimname=...]]"
#####################################################
## -- parse gturl --
def parse_gturl(gturl)
  if /(.*)@(.*)/ =~ gturl
    file = $1
    var = $2
  else
    raise "invalid URL: '@' between path & variable is not found" +
           "URL format: " + URLfmt
  end
  if /,/ =~ var
    slice = Hash.new
    thinning = Hash.new
    var_descr = var.split(/,/)
    var = var_descr.shift
    var_descr.each do |s|
      if /(.*)=(.*)/ =~ s
        dimname = $1
        subset = $2
        case subset
        when /(.*):(.*):(.*)/
          slice[dimname] = ($1.to_f)..($2.to_f)
          thinning[dimname] = {0..-1,$3.to_i}
        when /(.*):(.*)/
          slice[dimname] = ($1.to_f)..($2.to_f)
        else
          slice[dimname] = subset.to_f
        end
      else
        raise "invalid URL: variable subset specification error\n\n"
           "URL format: " + URLfmt
      end
    end
    thinning = nil if thinning.length == 0
  else
    slice = nil
    thinning = nil
  end
  [file, var, slice, thinning]
end
def GGraph::annotate(str_ary)
  lnum = 0
  str_ary.each{ |str|lnum += 1 }
    charsize = 0.7 * DCL.uzpget('rsizec1')
  dvx = 0.01
  dvy = charsize*1.5
  raise TypeError,"Array expected" if ! str_ary.is_a?(Array)
  vxmin,vxmax,vymin,vymax = DCL.sgqvpt
  vx = 0.70
  vy = 0.045 + (lnum-1)*dvy
  str_ary.each{|str|
    DCL::sgtxzv(vx,vy,str,charsize,0,-1,1)
    vy -= dvy
  }
  nil
end
def each_along_dims(gphys, loopdim)
  raise ArgumentError,"1st argument must be an GPhys." if !gphys.is_a?(GPhys)
  if loopdim.is_a?(String)
    dimname = loopdim
  elsif
    if loopdim < 0 
      dimname = gphys.coord(gphys.rank + loopdim).name
    else
      dimname = gphys.coord(loopdim).name
    end
  else
    raise ArgumentError,"loopdims must consist of Integer and/or String"
  end
  loopdim_na = gphys.coord(dimname).val                      # get coord ary
  loopdim_na = loopdim_na[-1..0] if $OPT_reverse || $OPT_Gr  # reverse  
  loopdim_na.each { |x|
    yield( gphys.cut(dimname=>x) )
  }
end
def draw_setup(gp)
  # set missing value
  DCLExt.gl_set_params('lmiss'=>true, 
                       'rmiss'=>gp.data.get_att('missing_value')[0]
                       ) if gp.data.get_att('missing_value')
  # fontsize
  DCL.sgpset('lcntl', false)
  DCL.uzfact(0.7)
  DCL.sgpset('lfull', true)               # use full area in the window
  DCL.sgpset('lfprop',true)               # use proportional font
  DCL.uscset('cyspos', 'B' )              # move unit y axis
  
  # viewport size
  GGraph.set_fig('viewport'=>$VIEWPORT)
  GGraph.set_fig( 'itr'=>($OPT_itr == nil) ? 1 : $OPT_itr.to_i )
  GGraph.set_fig("xrev"=>"units:mb,units:hPa,units:millibar,positive:down",  
                 "yrev"=>"units:mb,units:hPa,units:millibar,positive:down") 
  # set options
  min_range,  max_range  = __split_range($OPT_srange)
  min_crange, max_crange = __split_range($OPT_crange)
  min_srange, max_srange = __split_range($OPT_range)
  GGraph.set_linear_contour_options(
                                    'int' => ( $OPT_cint   || $OPT_interval ),
                                    'min' => ( min_crange  || min_range ),
                                    'max' => ( max_crange  || max_range )
                                    )
  GGraph.set_linear_tone_options(
                                    'int' => ( $OPT_sint   || $OPT_interval ),
                                    'min' => ( min_srange  || min_range ),
                                    'max' => ( max_srange  || max_range )
                                 )
  # judge draw kind
  gp_rank = gp.rank
  gp_rank = gp_rank - 1 if ( $OPT_animate || $OPT_anim )
  if ($OPT_line || gp_rank == 1) 
    draw_flag = "line"
  elsif (!$OPT_line && gp_rank >= 2) && !$OPT_noshade && $OPT_nocont 
    draw_flag = "nocont"
  elsif (!$OPT_line && gp_rank >= 2) && $OPT_noshade && !$OPT_nocont 
    draw_flag = "noshade"
  elsif (!$OPT_line && gp_rank >= 2) && !$OPT_noshade && !$OPT_nocont
    draw_flag = "full"
  end  
  # similar projection
  if ($OPT_similar)
    if /([\d\-.]*),([\d\-.]*),([\d\-.]*)/ =~ $OPT_similar
      similar=[$1.to_f,$2.to_f,$3.to_f]
    elsif /([\d\-.]*),([\d\-.]*)/ =~ $OPT_similar
      similar=[$1.to_f,$2.to_f,0]
    elsif /([\d\-.]*)/ =~ $OPT_similar
      similar=[$1.to_f,0,0]
    end
    GGraph.set_fig('similar'=>similar)
  end
  # similar projection
  if ($OPT_map_axis)
    if /([\d\-.]*),([\d\-.]*),([\d\-.]*)/ =~ $OPT_map_axis
      map_axis=[$1.to_f,$2.to_f,$3.to_f]
    elsif /([\d\-.]*),([\d\-.]*)/ =~ $OPT_map_axis
      map_axis=[$1.to_f,$2.to_f,0]
    elsif /([\d\-.]*)/ =~ $OPT_similar
      map_axis=[$1.to_f,0,0]
    end
    GGraph.set_fig('map_axis'=>map_axis)
  end
  # map
  if ( $OPT_m || $OPT_map)
    map_type = "coast_world"     if $OPT_m
    map_type = $OPT_map          if $OPT_map
    GGraph::set_map(map_type=>true)
  end
  return draw_flag
end
def draw(gp, draw_flag)
  # draw hontai
  case draw_flag
  when "line"
    GGraph.line(gp, 
                true,
                "title"=>$OPT_title,
                "index"=>($OPT_index||1),
                "type" =>($OPT_type ||1),
                "exchange"=>$OPT_exch
                )
  when "full"
    GGraph.tone(gp,
                true, 
                "title"=>$OPT_title,
                "transpose"=>$OPT_exch
                )
    GGraph.contour(gp, false, "transpose"=>$OPT_exch)
  when "nocont"
    GGraph.tone(gp,
                true, 
                "title"=>$OPT_title,
                "transpose"=>$OPT_exch
                )
  when "noshade"
    mj = DCL.udpget('indxmj')
    mn = DCL.udpget('indxmn')
    GGraph.contour(gp, 
                   true, 
                   "title"    =>$OPT_title,
                   "label"    =>true,
		   "transpose"=>$OPT_exch
                   )
  end
  # color bar
  if  ( draw_flag == "full") || ( draw_flag == "nocont")
    GGraph::color_bar(
                      "left"      => true,
                      "landscape" => true
                      )
  end
end
def set_vpsize( default_vp, aspect=2.0 )
  raise "#{aspect} must be a positive Numeric" if (aspect.to_f <= 0.0)
  aspect = aspect.to_f
  # default viewport
  x0 = default_vp[0]; x1 = default_vp[1]
  y0 = default_vp[2]; y1 = default_vp[3]
  # viewport size
  hlength =   x1 - x0
  vlength =   y1 - y0
  # center grid of viewport
  cen_of_vp = [ x0 + hlength/2.0, y0 + vlength/2.0  ] 
  if aspect <= 2.0
    hlength = vlength * aspect
    x0 = cen_of_vp[0] - hlength/2.0
    x1 = cen_of_vp[0] + hlength/2.0
  else
    vlength = hlength / aspect     
    y0 = cen_of_vp[1] - vlength/2.0
    y1 = cen_of_vp[1] + vlength/2.0
  end  
  return [ x0, x1, y0, y1 ]
end
def __split_range(range)
  if /(.*):(.*)/ =~ range
    if $1 == ""
      min = nil
    else
      min = $1.to_f
    end
    if $2 == ""
      max = nil
    else
      max = $2.to_f
    end
  elsif range == nil
    min = max = nil
  else
    raise "invalid range: variable subset specification error. split range with ':'\n\n"
  end
  
  return min, max
end
#####################################################
###++++++           Main Routine            ++++++###
## parse options
parser = GetoptLong.new
parser.set_options(
                   ###    global option   ###
                   ['--wsn',                      GetoptLong::REQUIRED_ARGUMENT],
                   ['--itr',                      GetoptLong::REQUIRED_ARGUMENT],
                   ['--similar',                  GetoptLong::REQUIRED_ARGUMENT],
                   ['--map_axis',                 GetoptLong::REQUIRED_ARGUMENT],
                   ['--aspect',                   GetoptLong::REQUIRED_ARGUMENT],
                   ['--animate',                  GetoptLong::REQUIRED_ARGUMENT],
                   ['--anim',                     GetoptLong::REQUIRED_ARGUMENT],
                   ['--alternate',                GetoptLong::NO_ARGUMENT],
                   ['--Ga',                       GetoptLong::NO_ARGUMENT],
                   ['--nowait',                   GetoptLong::NO_ARGUMENT],
                   ['--Gw',                       GetoptLong::NO_ARGUMENT],
                   ['--smooth',                   GetoptLong::NO_ARGUMENT],
                   ['--Gaw',                      GetoptLong::NO_ARGUMENT],
                   ['--exch',                     GetoptLong::NO_ARGUMENT],
                   ['--reverse',                  GetoptLong::NO_ARGUMENT],
                   ['--Gr',                       GetoptLong::NO_ARGUMENT],
                   ['--mean',                     GetoptLong::REQUIRED_ARGUMENT],
                   ['--map',                      GetoptLong::REQUIRED_ARGUMENT],
                   ['--m',                        GetoptLong::NO_ARGUMENT],
                   ###     line option    ###
                   ['--line',                     GetoptLong::NO_ARGUMENT],
                   ['--index',                    GetoptLong::REQUIRED_ARGUMENT],
                   ['--type',                     GetoptLong::REQUIRED_ARGUMENT],
                   ### tone or cont option ###
                   ['--nocont',                   GetoptLong::NO_ARGUMENT],
                   ['--noshade',                  GetoptLong::NO_ARGUMENT],
                   ['--range',                    GetoptLong::REQUIRED_ARGUMENT],
                   ['--crange',                   GetoptLong::REQUIRED_ARGUMENT],
                   ['--srange',                   GetoptLong::REQUIRED_ARGUMENT],
                   ['--interval',                 GetoptLong::REQUIRED_ARGUMENT],
                   ['--int',                      GetoptLong::REQUIRED_ARGUMENT],
                   ['--cint',                     GetoptLong::REQUIRED_ARGUMENT],
                   ['--sint',                     GetoptLong::REQUIRED_ARGUMENT]
#                   ['--help',                     GetoptLong::NO_ARGUMENT], # to be defined
#                   ['--version',                  GetoptLong::NO_ARGUMENT]  # to be defined
                   )
begin
  parser.each_option do |name, arg|
    eval "$OPT_#{name.sub(/^--/, '').gsub(/-/, '_')} = '#{arg}'"  # strage option value to $OPT_val
  end
rescue
  exit(1)
end
## open netcdf variable
gturl = ARGV[0]
file, var, slice,thinning = parse_gturl(gturl)
gp = GPhys::IO.open(file,var)
gp = gp.cut(slice) if slice
gp = gp[thinning]  if thinning
## mean along any axis
if ($OPT_mean)
  dims = ($OPT_mean).split(/\s*,\s*/)
  dims.each{|dim|
    dim = dim.to_i if dim.to_i.to_s == dim
    gp = gp.mean(dim)
  }
end
## set some figure option
DCL::swlset('lwait', false) if ($OPT_nowait    || $OPT_Gw || $OPT_smooth || $OPT_Gaw)
                                         # set wait or nowait
DCL::swlset('lalt',  true)  if ($OPT_alternate || $OPT_Ga || $OPT_smooth || $OPT_Gaw)
                                         # set backing store option
## decide VIEWPORT
$VIEWPORT = set_vpsize( VIEWPORT, ($OPT_aspect||2.0) )
## draw figure
loopdim   = ( $OPT_animate || $OPT_anim ) 
loopdim = loopdim.to_i if loopdim.to_i.to_s == loopdim
DCL.gropn($OPT_wsn||1)                   # open work station
GGraph.margin_info($0, gturl)            # draw margin infomation
kind_of_fig = draw_setup(gp)             # determine figure kind
if loopdim           # animation
  each_along_dims(gp, loopdim){|gp_subset|
    draw(gp_subset, kind_of_fig)
  }
else
  draw( gp, kind_of_fig )                # single figure
end
DCL.grcls