ギャラリー

あくまでも公開メモという位置づけです. 自分以外に優しくない書き方をしていると思いますが ご容赦ください.

自分の計算結果の図表作成スクリプト (Ruby) に関する 覚書やテンプレートを置いています. 気が向いたらライブラリ化していくかもしれません.

描画以外でよく使うコード

最初の部分

#!/usr/bin/env ruby

require "pp"
require 'optparse'
require "numru/ggraph"
include NumRu

require "../load_config"   # 設定を読み込む. 自作.
require "../utils"         # ユーティリティを読み込む. 自作.

DCL::gllset('LMISS', true) # 欠損値処理を行う

デフォルト値

wsn = 4
clrmap = 1
val_min = ...
val_max = ...
time_start = 1000
time_start = 2000

コマンドライン引数処理

# commandline option
opt = OptionParser.new

opt.on('--wsn VAL') {|v| wsn = v.to_i }
opt.on('--int VAL') {|v| interval = v.to_f }
opt.on('--clrmap VAL') {|v| clrmap = v.to_i }
opt.on('--range VAL') {|v|
  ary = v.split(":")
  if ary.size == 2 and ary[0] < ary[1] then
    val_min = ary[0].to_f
    val_max = ary[1].to_f
  else
    raise "ERROR: #{v} is invalid range."
  end
  if interval == nil then
    interval = (val_max - val_min) / 40.0
  end
}

opt.parse!(ARGV)

if ARGV.size > 0
  raise "ERROR: invalid option: #{ARGV[0]}"
end

netCDF ファイルの読み込み (準備)

以下の記述はまだ不十分.

var = 'U'
path = File.join(exp_dirs[omegas[0]], var+'.nc')

lat = GPhys::IO.open(path, 'lat')
na_lat_weight = GPhys::IO.open(path, 'lat_weight').val
nlat = lat.val.size
na_sig_weight = GPhys::IO.open(path, 'sig_weight').val
nsig = na_sig_weight.size

netCDF ファイルの読み込み (本番)

よくループで回すのでこのような構造にしている.

# input
var = 'U'
path = File.join(dir, var+'.nc')
gp_u = GPhys::IO.open(path, var).cut('time'=>time_start..time_end)

余白を削って eps ファイルとして出力

ここでは必要なコマンドにパスが通っているかの確認は行なっていない.

# remove extra space of ps file
  if wsn == 2 then
    if File.exist?(TMPFILE) then
      puts("MESSAGE: after processing ... #{epsfn} will be generate.")
      `dclpsrmcm #{TMPFILE} | dclpsrot | dclpsmargin > #{epsfn}`
    end
  end

Gphys オブジェクトの使い回し

このあたりは整理中.

def gp2axis(gp)
  data = gp.data
  va = VArray.new( gp.val,
                   {"long_name"=>data.long_name,
                     "units"=>data.units.to_s },
                   data.name )
  gp2axis = Axis.new.set_pos(va)
end

def gpdata_reuse_va(nary, gp)
  gpdata_reuse_va = VArray.new( nary,
                                {
                                  "long_name"=>gp.data.long_name,
                                  "units"=>gp.data.units.to_s},
                                gp.data.name )
end

axis_lat = gp2axis(lat)
grid = Grid.new(axis_x, axis_lat)  
gp = GPhys.new( grid, gpdata_reuse_va(na_x, gp_x) )

描画 (GGraph)

描画準備

DCL.sgscmn(clrmap||1)   # colormap

DCL.gropn(wsn)
GGraph.set_fig('viewport'=>[0.15,0.85,0.2,0.55])
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

描画終了

DCL.grcls

折れ線 (GGraph.line)

マーク (GGraph.mark)

MARK_SIZE = 0.015
MARK_LINE_THICKNESS = 7
MARK_TYPE = 4   # circle
MARK_INDEX = 1  # black

(略)

opt_draw = {
  'max'=>val_max, 'min'=>val_min,
  'size'=>MARK_SIZE,
  'legend'=>false, 'annotate'=>false,
  'title'=>TITLE,
  'type'=> MARK_TYPE,
  'index'=> 10 * MARK_INDEX + MARK_LINE_THICKNESS
}

GGraph.mark( gp, true, opt_draw )

トーン, コンター (GGraph.tone, GGraph.contour)

opt_draw = {
  'max'=>val_max, 'min'=>val_min,
  'interval'=>interval,
  'title'=>TITLE,
#  'legend'=>false, 'annotate'=>false,
}

GGraph.tone( gp_flux, true, opt_draw )
GGraph.contour( gp_flux, false, opt_draw )
GGraph.color_bar

ベクトル (GGraph.vector)

# ベクトルの描画間隔 (単位は格子点数)
xintv = 6
yintv = 2

# ベクトルの倍率
xfact1 = 1.0
yfact1 = 1.0

# 凡例の単位ベクトルの長さ
uxunit = 0.03
uyunit = 0.03

(略)

#DCL.sgpset('lcntl', false) ; DCL.uzfact(0.7)
DCL.sgpset('lcntl', false) ; DCL.uzfact(1.0)

# 球の時
#GGraph.set_fig 'itr'=>ITR, 'viewport'=>[0.15,0.95,0.2,0.8], 'map_axis'=>[LON_CNT, 0, 0]
GGraph.set_fig 'viewport'=>[0.15,0.95,0.2,0.8]

DCL.ugpset('LNRMAL', false)  # scale vector automatically

DCL.ugpset('XFACT1', xfact1)
DCL.ugpset('YFACT1', yfact1)

DCL.ugpset('UXUNIT', uxunit) # size of unit vector by dimentional value
DCL.ugpset('UYUNIT', uyunit)

DCL::ugrset('VXUNIT', 0.1)  # size of unit vector
DCL::ugrset('VYUNIT', 0.1)

DCL::uxmttl('T', '', 0.0)  # title (large character)

DCL.ugpset('LMSG', false)   # no message

opt_vector = {
  'xintv'=>xintv, 'yintv'=>yintv,
  'flow_vect'=>false, 'annotate'=>false, 'unit_vect'=>true
}

GGraph.vector( gp_u, gp_v, true, opt_vector)

散布図 (GGraph.scatter)

TITLE = 'OLR'
YNAME = 'OLR'
#YUNIT = '10^15 W'

TIME_START = 1000
TIME_END = 2000

XMIN = 170
XMAX = 340
YMIN = 100
YMAX = 450

(略)

# 2 次元以上のデータを 1 次元配列に落とす (GGraph.scatter 対策)
def flatten_gphys(gp)
  na_dat = gp.val.flatten
  n = na_dat.size
  axis = dummy_axis(n)
  data = VArray.new( na_dat,
                     {"long_name"=>gp.data.long_name, 
                       "units"=>gp.data.units.to_s},
                     gp.data.name )
  gp = GPhys.new( Grid.new(axis), data )
end

# ダミーの gphys を作成 (GGraph.scatter での図の範囲指定のため)
def dummy_gphys(na)
  n = na.size
  axis = dummy_axis(n)
  data = VArray.new( na,
                     {"long_name"=>"dummy", 
                       "units"=>"1"},
                     "dummy" )
  gp = GPhys.new( Grid.new(axis), data )
end

def dummy_axis(n)
  axis_a = VArray.new( NArray.sfloat(n).indgen,
                       {"long_name"=>"dummy","units"=>"1"},
                       "dummy" )
  axis = Axis.new.set_pos(axis_a)
end

(略)

# 範囲指定のためのダミーデータ
  na_xrange = NArray.to_na([XMIN, XMAX])
  na_yrange = NArray.to_na([YMIN, YMAX])
  gp_xrange = dummy_gphys(na_xrange)
  gp_yrange = dummy_gphys(na_yrange)
  gp_xrange.data.long_name = gp_Tg.data.long_name
  gp_yrange.data.long_name = gp_OLR.data.long_name
  gp_xrange.data.units = gp_Tg.data.units
  gp_yrange.data.units = gp_OLR.data.units

# 図の範囲を指定する方法が分からないのでダミーの点を打つ
  GGraph.scatter( gp_xrange, gp_yrange, true, 'type'=>1)

  opt = {
    'annotate'=>false,
    'title'=>TITLE,
    'index'=>1
  }


# draw
  opt['type'] = 1
  GGraph.scatter( flatten_gphys( gp_Tg.cut('lon'=>0..179.99) ),
                  flatten_gphys( gp_OLR.cut('lon'=>0..179.99) ), 
                  false, opt)