[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[dennou-ruby:002690] GGraph: lon/lat axes



神代です.

GGraph で緯度・経度の軸を描いたとき,ラベルを 90N..EQ..90S とか
0..90E..180..90W..0 とかにしたいことがよくあるので,作ってみました.

ggraph.rb の中に DCLExt::lon_ax, DCLExt::lat_ax という名前で追加して,
GGraph::axes からは,これらを xmaplabel, ymaplabel というオプションで
呼べるようにしました.
dclext_datetime_ax.rb を参考に作りました.DCL.us[xy]axs のソースを見て
真似をして,オートスケーリングできるようにしてます.

最新のCVS版に対するパッチを添付します(先日の map_fit/map_axes に関する
パッチとは別にしてます).

テストスクリプトも添付します.gphys/sample/map_projection.rb を改変し
たものです.gphys/sample に置いて実行できます.

# 作った直接の動機は,先日メールした GPhysの地図投影の改良で,少し困っ
# たことがあったからです.これを使うと,データをいじらずに軸つき地図の
# 描画範囲を自由に変えられて便利なのですが,ウィンドウのとりかたによっ
# ては,たとえば
# GGraph.next_fig("itr"=>10, "map_fit"=>false, "map_axis"=>[210,0,0], "map_window"=>[-180,180,-90,90])
# とすると,横軸のラベルは 30..390 になってしまって,経度の値としては
# うれしくないです.なので,こういうのがほしくなりました.

--- ggraph.rb_orig	2006-08-16 12:19:01.932785000 +0900
+++ ggraph.rb	2006-08-18 21:06:09.111918007 +0900
@@ -327,6 +327,12 @@
                              #                 (if nil, internally determined)
        "ylabelint"   nil     # Interval of y axis label
                              #                 (if nil, internally determined)
+       "xmaplabel"   false   # If "lon"("lat"), use
+                             # DCLExt::lon_ax(DCLExt::lat_ax) to draw xaxes;
+                             # otherwise, DCL::usxaxs is used.
+       "ymaplabel"   false   # If "lon"("lat"), use
+                             # DCLExt::lon_ax(DCLExt::lat_ax) to draw yaxes;
+                             # otherwise, DCL::usyaxs is used.
        "help"        false   # show help message if true
 
     RETURN VALUE
@@ -1035,6 +1041,45 @@
 
 ==Original methods:
 
+===Longitude/Latitude Axes
+---lon_ax( options=nil )
+
+    Draw longitude axis. (label format: degrees + 'E' or 'W')
+
+    ARGUMENTS
+    * options (Hash) : options to change the default behavior if specified.
+      It is a Hash with option names (String) as keys and their values.
+      Options are interpreted by a NumRu::Misc::KeywordOptAutoHelp,
+      so you can shorten the keys (by omitting tails) as long as it is
+      unambiguous.
+       option name   default value   # description:
+       "yax"         false   # true => draw y-axis, false => draw x-axis
+       "cside"       nil     # "b", "t", "l", "r",
+                             # nil (=>left/bottom), or false (=>right/top)
+       "dtick1"      nil     # Interval of small tickmark
+                             #             (if nil, internally determined)
+       "dtick2"      nil     # Interval of large tickmark with labels
+                             #             (if nil, internally determined)
+
+---lat_ax( options=nil )
+
+    Draw latitude axis. (label format: degrees + 'N' or 'S')
+
+    ARGUMENTS
+    * options (Hash) : options to change the default behavior if specified.
+      It is a Hash with option names (String) as keys and their values.
+      Options are interpreted by a NumRu::Misc::KeywordOptAutoHelp,
+      so you can shorten the keys (by omitting tails) as long as it is
+      unambiguous.
+       option name   default value   # description:
+       "xax"         false   # true => draw x-axis, false => draw y-axis
+       "cside"       nil     # "b", "t", "l", "r",
+                             # nil (=>left/bottom), or false (=>right/top)
+       "dtick1"      nil     # Interval of small tickmark
+                             #             (if nil, internally determined)
+       "dtick2"      nil     # Interval of large tickmark with labels
+                             #             (if nil, internally determined)
+
 ===Vectors
 ---unit_vect( vxfxratio, vyfyratio, fxunit=nil, fyunit=nil, options=nil )
 
@@ -1421,6 +1466,245 @@
     # RELATIVELY INDEPENDENT OF DCL SUBLIBRARIES
     ############################################################
 
+    # <<< longitude/latitude axes package >>>
+
+    @@lon_ax_options = Misc::KeywordOptAutoHelp.new(
+      ['yax', false, 'true => y-axis, false => x-axis'],
+      ['cside', nil, '"b", "t", "l", "r", nil (=>left/bottom), or false (=>right/top)'],
+      ['dtick1', nil, 'Interval of small tickmark (if nil, internally determined)'],
+      ['dtick2', nil, 'Interval of large tickmark with labels (if nil, internally determined)']
+    )
+
+    def lon_ax(options=nil)
+      opt = @@lon_ax_options.interpret(options)
+
+      yax = opt['yax']
+      xax = !yax
+      if xax
+        xy='x'
+      else
+        xy='y'
+      end
+
+      if opt['cside']
+        cside = opt['cside']
+      elsif opt['cside'].nil?
+        if xax
+          cside='b'
+        else
+          cside='l'
+        end
+      else
+        if xax
+          cside='t'
+        else
+          cside='r'
+        end
+      end
+
+      vxmin, vxmax, vymin, vymax = DCL.sgqvpt
+      uxmin, uxmax, uymin, uymax = DCL.sgqwnd
+      if xax
+        vmin, vmax = [vxmin,vxmax].min, [vxmin,vxmax].max
+        umin, umax = [uxmin,uxmax].min, [uxmin,uxmax].max
+      else
+        vmin, vmax = [vymin,vymax].min, [vymin,vymax].max
+        umin, umax = [uymin,uymax].min, [uymin,uymax].max
+      end
+
+      # get dtick1 & dtick2
+      dtick1 = opt['dtick1']
+      dtick2 = opt['dtick2']
+      unless dtick1 && dtick2
+        irota = DCL.uzpget("irotl#{xy}#{cside}")
+       irota += 1 if yax
+        mode = irota.modulo(2)
+        DCL.ususcu(xy.capitalize,umin,umax,vmin,vmax,mode)
+        dtick1 = DCL.uspget("d#{xy}t") unless dtick1
+        dtick2 = DCL.uspget("d#{xy}l") unless dtick2
+      end
+
+      lepsl = DCL.glpget('lepsl')
+      repsl = DCL.glpget('repsl')
+      DCL.glpset('lepsl',true)
+
+      # generate numbers for small tickmarks
+      nn = 0
+      rx = DCL.irle(umin/dtick1)*dtick1
+      if DCL.lreq(umin,rx)
+        x = rx
+      else
+        x = rx + dtick1
+      end
+      u1 = []
+      while DCL.lrle(x,umax)
+        if x.abs < dtick1*repsl*nn
+          x = 0.0
+        end
+        u1[nn] = x
+        nn = nn + 1
+        x = x + dtick1
+      end
+
+      # generate numbers for large tickmarks and labels
+      nn = 0
+      rx = DCL.irle(umin/dtick2)*dtick2
+      if DCL.lreq(umin,rx)
+        x = rx
+      else
+        x = rx + dtick2
+      end
+      u2 = []
+      while DCL.lrle(x,umax)
+        if x.abs < dtick2*repsl*nn
+          x = 0
+        end
+        u2[nn] = x
+        nn = nn + 1
+        x = x + dtick2
+      end
+
+      # generate labels
+      c2 = NArray.to_na(u2)
+      c2[c2.gt(180)] -= 360.0
+      c2[c2.lt(-180)] += 360.0
+      c2[c2.eq(-180)] = 180.0
+      c2 = c2.to_a.collect do |c|
+        if c == 0 || c == 180
+          c.to_i.to_s
+        elsif c > 0
+          c.to_i.to_s + 'E'
+        else
+          c.abs.to_i.to_s + 'W'
+        end
+      end
+      nc = c2.collect{|c| c.size}.max
+
+      # call DCL.u[xy]axlb
+      if xax
+       DCL.uxaxlb(cside,u1,u2,c2,nc)
+      else
+       DCL.uyaxlb(cside,u1,u2,c2,nc)
+      end
+    end
+
+    @@lat_ax_options = Misc::KeywordOptAutoHelp.new(
+      ['xax', false, 'true => x-axis, false => y-axis'],
+      ['cside', nil, '"b", "t", "l", "r", nil (=>left/bottom), or false (=>right/top)'],
+      ['dtick1', nil, 'Interval of small tickmark (if nil, internally determined)'],
+      ['dtick2', nil, 'Interval of large tickmark with labels (if nil, internally determined)']
+    )
+
+    def lat_ax(options=nil)
+      opt = @@lat_ax_options.interpret(options)
+
+      xax = opt['xax']
+      yax = !xax
+      if xax
+        xy='x'
+      else
+        xy='y'
+      end
+
+      if opt['cside']
+        cside = opt['cside']
+      elsif opt['cside'].nil?
+        if xax
+          cside='b'
+        else
+          cside='l'
+        end
+      else
+        if xax
+          cside='t'
+        else
+          cside='r'
+        end
+      end
+
+      vxmin, vxmax, vymin, vymax = DCL.sgqvpt
+      uxmin, uxmax, uymin, uymax = DCL.sgqwnd
+      if xax
+        vmin, vmax = [vxmin,vxmax].min, [vxmin,vxmax].max
+        umin, umax = [uxmin,uxmax].min, [uxmin,uxmax].max
+      else
+        vmin, vmax = [vymin,vymax].min, [vymin,vymax].max
+        umin, umax = [uymin,uymax].min, [uymin,uymax].max
+      end
+
+      # get dtick1 & dtick2
+      dtick1 = opt['dtick1']
+      dtick2 = opt['dtick2']
+      unless dtick1 && dtick2
+        irota = DCL.uzpget("irotl#{xy}#{cside}")
+        irota += 1 if yax
+        mode = irota.modulo(2)
+        DCL.ususcu(xy.capitalize,umin,umax,vmin,vmax,mode)
+        dtick1 = DCL.uspget("d#{xy}t") unless dtick1
+        dtick2 = DCL.uspget("d#{xy}l") unless dtick2
+      end
+
+      lepsl = DCL.glpget('lepsl')
+      repsl = DCL.glpget('repsl')
+      DCL.glpset('lepsl',true)
+
+      # generate numbers for small tickmarks
+      nn = 0
+      rx = DCL.irle(umin/dtick1)*dtick1
+      if DCL.lreq(umin,rx)
+        x = rx
+      else
+        x = rx + dtick1
+      end
+      u1 = []
+      while DCL.lrle(x,umax)
+        if x.abs < dtick1*repsl*nn
+          x = 0.0
+        end
+        u1[nn] = x
+        nn = nn + 1
+        x = x + dtick1
+      end
+
+      # generate numbers for large tickmarks and labels
+      nn = 0
+      rx = DCL.irle(umin/dtick2)*dtick2
+      if DCL.lreq(umin,rx)
+        x = rx
+      else
+        x = rx + dtick2
+      end
+      u2 = []
+      while DCL.lrle(x,umax)
+        if x.abs < dtick2*repsl*nn
+          x = 0
+        end
+        u2[nn] = x
+        nn = nn + 1
+        x = x + dtick2
+      end
+
+      # generate labels
+      c2 = NArray.to_na(u2)
+      c2 = c2.to_a.collect do |c|
+        if c == 0
+          'EQ'
+        elsif c > 0
+          c.to_i.to_s + 'N'
+        else
+          c.abs.to_i.to_s + 'S'
+        end
+      end
+      nc = c2.collect{|c| c.size}.max
+
+      # call DCL.u[xy]axlb
+      if xax
+        DCL.uxaxlb(cside,u1,u2,c2,nc)
+      else
+        DCL.uyaxlb(cside,u1,u2,c2,nc)
+      end
+    end
+
     # <<< flow vector package >>>
 
     def __truncate(float, order=2)
@@ -2436,7 +2720,11 @@
       ['xlabelint',  nil,
                'Interval of x axis label (if nil, internally determined)'],
       ['ylabelint',  nil,
-               'Interval of y axis label (if nil, internally determined)']
+               'Interval of y axis label (if nil, internally determined)'],
+      ['xmaplabel',  false,
+               'If "lon"("lat"), use DCLExt::lon_ax(DCLExt::lat_ax) to draw xaxes; otherwise, DCL::usxaxs is used.'],
+      ['ymaplabel',  false,
+               'If "lon"("lat"), use DCLExt::lon_ax(DCLExt::lat_ax) to draw yaxes; otherwise, DCL::usyaxs is used.']
     )
     def set_axes(options)
       @@axes.set(options)
@@ -2460,26 +2748,50 @@
       opts = @@axes.interpret(options)
       if opts['xside'].length > 0
         xai = _get_axinfo(xax)
-        DCL.uscset('cxttl', (opts['xtitle'] || xai['title']) )
-        DCL.uscset('cxunit',(opts['xunits'] || xai['units']) )
-        DCL.uspset('dxt', opts['xtickint'])  if(opts['xtickint'])
-        DCL.uspset('dxl', opts['xlabelint']) if(opts['xlabelint'])
-        opts['xside'].split('').each{|s|     # scan('.') also works
-          DCL.usxaxs(s)
-        }
+        if opts['xmaplabel'] == "lon"
+          opts['xside'].split('').each{|s|     # scan('.') also works
+            DCLExt.lon_ax('cside'=>s, 'dtick1'=>opts['xtickint'], 'dtick2'=>opts['xlabelint'])
+          }
+          DCL.uxsttl('b', (opts['xtitle'] || xai['title']), 0.0)
+        elsif opts['xmaplabel'] == "lat"
+          opts['xside'].split('').each{|s|     # scan('.') also works
+            DCLExt.lat_ax('xax'=>true, 'cside'=>s, 'dtick1'=>opts['xtickint'], 'dtick2'=>opts['xlabelint'])
+          }
+          DCL.uxsttl('b', (opts['xtitle'] || xai['title']), 0.0)
+        else
+          DCL.uscset('cxttl', (opts['xtitle'] || xai['title']) )
+          DCL.uscset('cxunit',(opts['xunits'] || xai['units']) )
+          DCL.uspset('dxt', opts['xtickint'])  if(opts['xtickint'])
+          DCL.uspset('dxl', opts['xlabelint']) if(opts['xlabelint'])
+          opts['xside'].split('').each{|s|     # scan('.') also works
+            DCL.usxaxs(s)
+          }
+        end
       end
       if opts['yside'].length > 0
         yai = _get_axinfo(yax)
-        DCL.uscset('cyttl', (opts['ytitle'] || yai['title']) )
-        DCL.uscset('cyunit', (un=(opts['yunits'] || yai['units'])) )
-        DCL.uspset('dyt', opts['ytickint'])  if(opts['ytickint'])
-        DCL.uspset('dyl', opts['ylabelint']) if(opts['ylabelint'])
-        opts['yside'].split('').each{|s|   # scan('.') also works
-          DCL.usyaxs(s)
-          if s=='l' && un && un != ''
-            DCL.uzpset('roffxt', DCL.uzpget('rsizec1')*1.5 )
-          end
-        }
+        if opts['ymaplabel'] == "lon"
+          opts['yside'].split('').each{|s|   # scan('.') also works
+            DCLExt.lon_ax('yax'=>true, 'cside'=>s, 'dtick1'=>opts['ytickint'], 'dtick2'=>opts['ylabelint'])
+          }
+          DCL.uysttl('l', (opts['ytitle'] || yai['title']), 0.0)
+        elsif opts['ymaplabel'] == "lat"
+          opts['yside'].split('').each{|s|   # scan('.') also works
+            DCLExt.lat_ax('cside'=>s, 'dtick1'=>opts['ytickint'], 'dtick2'=>opts['ylabelint'])
+          }
+          DCL.uysttl('l', (opts['ytitle'] || yai['title']), 0.0)
+        else
+          DCL.uscset('cyttl', (opts['ytitle'] || yai['title']) )
+          DCL.uscset('cyunit', (un=(opts['yunits'] || yai['units'])) )
+          DCL.uspset('dyt', opts['ytickint'])  if(opts['ytickint'])
+          DCL.uspset('dyl', opts['ylabelint']) if(opts['ylabelint'])
+          opts['yside'].split('').each{|s|   # scan('.') also works
+            DCL.usyaxs(s)
+            if s=='l' && un && un != ''
+              DCL.uzpset('roffxt', DCL.uzpget('rsizec1')*1.5 )
+            end
+          }
+        end
       end
       nil
     end

require 'numru/ggraph'
include NumRu

wsn = ( ARGV[0] ? ARGV[0].to_i : 1 )

path = '../testdata/T.jan.nc'
var = 'T'
gp = GPhys::IO.open(path,var)

DCL.swpset('ldump',true) if wsn == 4
DCL.gropn(wsn)
DCL.sldiv('y',3,2)
#DCL.uzfact(0.8)
DCL.sgpset('lcntl',false)

GGraph.set_map('coast_world'=>true)

gpjpn = gp.cut(110..160,10..70,false)

itr = 10

# contour
GGraph.next_fig('itr'=>itr)
GGraph.contour(gp, true,'map_axes'=>true,'title'=>'default axes')

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat')
GGraph.contour(gp, true,'map_axes'=>true,'title'=>'lon/lat axes')

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat','xtickint'=>30, 'ytickint'=>10, 'xlabelint'=>90, 'ylabelint'=>30)
GGraph.contour(gp, true,'map_axes'=>true,'title'=>'lon/lat axes (set interval)')

# tone
GGraph.next_fig('itr'=>itr)
GGraph.tone(gp, true,'map_axes'=>true,'title'=>'default axes')

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat')
GGraph.tone(gp, true,'map_axes'=>true,'title'=>'lon/lat axes')

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat','xtickint'=>30, 'ytickint'=>10, 'xlabelint'=>90, 'ylabelint'=>30)
GGraph.tone(gp, true,'map_axes'=>true,'title'=>'lon/lat axes (set interval)')


# tone & contour
GGraph.next_fig('itr'=>itr)
GGraph.tone(gpjpn, true,'map_axes'=>true,'title'=>'default axes')
GGraph.contour( gpjpn, false )

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat')
GGraph.tone(gpjpn, true,'map_axes'=>true,'title'=>'lon/lat axes')
GGraph.contour( gpjpn, false )

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat','xtickint'=>10, 'ytickint'=>10, 'xlabelint'=>30, 'ylabelint'=>30)
GGraph.tone(gpjpn, true,'map_axes'=>true,'title'=>'lon/lat axes (set interval)')
GGraph.contour( gpjpn, false )


# vector ('flow_vect'=>false)
GGraph.next_fig('itr'=>itr)
GGraph.vector(gpjpn,gpjpn, true,'map_axes'=>true,'title'=>'default axes','flow_vect'=>false,'unit_vect'=>true)

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat')
GGraph.vector(gpjpn,gpjpn, true,'map_axes'=>true,'title'=>'lon/lat axes','flow_vect'=>false,'unit_vect'=>true)

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat','xtickint'=>10, 'ytickint'=>10, 'xlabelint'=>30, 'ylabelint'=>30)
GGraph.vector(gpjpn,gpjpn, true,'map_axes'=>true,'title'=>'lon/lat axes (set interval)','flow_vect'=>false,'unit_vect'=>true)

# vector ('flow_vect'=>true)
GGraph.next_fig('itr'=>itr)
GGraph.vector(gpjpn,gpjpn, true,'map_axes'=>true,'title'=>'default axes','unit_vect'=>true)

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat')
GGraph.vector(gpjpn,gpjpn, true,'map_axes'=>true,'title'=>'lon/lat axes','unit_vect'=>true)

GGraph.next_fig('itr'=>itr)
GGraph.next_axes('xmaplabel'=>'lon','ymaplabel'=>'lat','xtickint'=>10, 'ytickint'=>10, 'xlabelint'=>30, 'ylabelint'=>30)
GGraph.vector(gpjpn,gpjpn, true,'map_axes'=>true,'title'=>'lon/lat axes (set interval)','unit_vect'=>true)

DCL.grfrm
DCL.grfrm
DCL.grfrm

### DCLExt::lon_ax, DCLExt::lat_ax

DCL.grfrm
DCL.grswnd(0.0, 360.0, -90.0, 90.0)
DCL.grsvpt(0.15, 0.95, 0.3, 0.7)
DCL.grstrn(1)
DCL.grstrf
DCLExt.lon_ax
DCLExt.lat_ax
DCLExt.lon_ax('cside'=>'t')
DCLExt.lat_ax('cside'=>'r')

DCL.grfrm
DCL.grswnd(0.0, 360.0, -90.0, 90.0)
DCL.grsvpt(0.15, 0.95, 0.3, 0.7)
DCL.grstrn(1)
DCL.grstrf
DCLExt.lon_ax('dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('dtick1'=>10, 'dtick2'=>30)
DCLExt.lon_ax('cside'=>'t', 'dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('cside'=>'r', 'dtick1'=>10, 'dtick2'=>30)

DCL.grfrm
DCL.grswnd(-90.0, 90.0, 0.0, 360.0)
DCL.grsvpt(0.15, 0.95, 0.3, 0.7)
DCL.grstrn(1)
DCL.grstrf
DCLExt.lon_ax('yax'=>true,'dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('xax'=>true,'dtick1'=>10, 'dtick2'=>30)
DCLExt.lon_ax('yax'=>true,'cside'=>'r', 'dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('xax'=>true,'cside'=>'t', 'dtick1'=>10, 'dtick2'=>30)

DCL.grfrm
DCL.grswnd(90.0, -90.0, 360.0, 0.0)
DCL.grsvpt(0.15, 0.95, 0.3, 0.7)
DCL.grstrn(1)
DCL.grstrf
DCLExt.lon_ax('yax'=>true,'dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('xax'=>true,'dtick1'=>10, 'dtick2'=>30)
DCLExt.lon_ax('yax'=>true,'cside'=>'r', 'dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('xax'=>true,'cside'=>'t', 'dtick1'=>10, 'dtick2'=>30)

DCL.grfrm
DCL.grswnd(-90.0, 90.0, 1000.0, 1.0)
DCL.grsvpt(0.15, 0.95, 0.3, 0.7)
DCL.grstrn(2)
DCL.grstrf
DCL.ulpset('iytype',3)
DCL.ulylog('l', 3, 9)
DCL.ulylog('r', 3, 9)
DCLExt.lat_ax('xax'=>true,'dtick1'=>10, 'dtick2'=>30)
DCLExt.lat_ax('xax'=>true,'cside'=>'t', 'dtick1'=>10, 'dtick2'=>30)

DCL.grfrm
DCL.grswnd(-180.0, 180.0, -90.0, 90.0)
DCL.grsvpt(0.15, 0.95, 0.3, 0.7)
DCL.grstrn(1)
DCL.grstrf
DCLExt.lon_ax('dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('dtick1'=>10, 'dtick2'=>30)
DCLExt.lon_ax('cside'=>'t', 'dtick1'=>30, 'dtick2'=>90)
DCLExt.lat_ax('cside'=>'r', 'dtick1'=>10, 'dtick2'=>30)

DCL.grcls