;================================================; ; mptick_9.ncl ;================================================; ; ; Concepts illustrated: ; - Explicitly setting map tickmarks and labels ; - Attaching a plot as an annotation of another plot ; - Drawing a lambert conformal map ; - Drawing a mercator map ; - Maximizing plots after they've been created ; - Converting NDC values to lat/lon values ; - Using "getvalues" to retrieve the size of a plot ; - Creating a blank plot ; - Drawing a map using the medium resolution map outlines ; - Moving the main title up ;================================================; ; ; These files are loaded by default in NCL V6.2.0 and newer ; load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_code.ncl" ; load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/gsn_csm.ncl" ;------------------------------------------------------------------------------ ; This is a generic function that attaches tickmarks to a rectangular map. ; ; It allows you to explicitly indicate where you want tickmarks for any ; of the four axes. ; ; Use a separate resource list for this function. Depending on ; whether you want to set the bottom, top, left, right tickmarks, ; set the corresponding tmXBValues, tmXTValues, tmYLValues, and/or ; tmYRValues resources to indicate where you want map tickmarks ; and labels. ; ; You can also set other tm resources, like tmXBLabelFontHeightF, ; to control the size of the font. ; ; Note: we called it "add_map_tickmarks2" because there's already an ; internal function called "add_map_tickmarks". ;------------------------------------------------------------------------------ undef("add_map_tickmarks2") function add_map_tickmarks2(wks,plot,res) local res2, bres, vpx, vpy, vpw, vph, xndc, yndc, npts, n, j, nlat, \ nlon, delta, bot_lon, top_lon, lft_lat, rgt_lat, xblabels, xbvalues, \ xtlabels, xtvalues, yllabels, ylvalues, yrlabels, yrvalues, xfix, \ xlat, xlon, yfix, annoid, anno_str begin ;---Make a copy of the original resource list. res2 = res ;---Retrieve edges of plot in NDC space. getvalues plot "vpXF" : vpx "vpYF" : vpy "vpWidthF" : vpw "vpHeightF" : vph end getvalues ;---Turn off tickmarks associated with map. We want to add our own. setvalues plot "pmTickMarkDisplayMode" : "Never" end setvalues ;---Initialize resources for tickmark plot. User shouldn't change these. bres = True bres@vpXF = vpx bres@vpYF = vpy bres@vpWidthF = vpw bres@vpHeightF = vph bres@trXMinF = vpx bres@trXMaxF = vpx + vpw bres@trYMinF = vpy - vph bres@trYMaxF = vpy bres@tmEqualizeXYSizes = True ;---This resource the user can change in main code if desired. bres@gsnTickMarksPointOutward = get_res_value(res2,"gsnTickMarksPointOutward",True) ; ; NDC Points to scan on X and Y axes. These arrays will be used to ; find the closest NDC pair that gets us close to the location where ; we want a tickmark. ; npts = 100000 ; Increase to get closer match for tickmarks xndc = fspan(vpx,vpx+vpw,npts) yndc = fspan(vpy-vph,vpy,npts) n = dimsizes(yndc) xfix = new(n,float) yfix = new(n,float) xlon = new(n,float) xlat = new(n,float) delta = 0.001 ;---Left axis tickmarks if(isatt(res2,"tmYLValues")) then lft_lat = get_res_value(res2,"tmYLValues",-1) nlat = dimsizes(lft_lat) ylvalues = new(nlat,float) yllabels = new(nlat,string) xfix = vpx + 0.0001 ; Just a smidge into the plot to make sure we don't ; get missing values returned. ; ; Loop across each left latitude value that we want a tickmark for, ; and try to find the closest X,Y NDC coordinate pair along this axis. ; NhlNDCToData(plot,xfix,yndc,xlon,xlat) do j=0,dimsizes(lft_lat)-1 NhlNDCToData(plot,xfix,yndc,xlon,xlat) ii = minind(fabs(xlat-lft_lat(j))) if(.not.any(ismissing(ii)).and.fabs(xlat(ii)-lft_lat(j)).le.delta) yllabels(j) = fabs(lft_lat(j)) + "" ylvalues(j) = yndc(ii(0)) if(lft_lat(j).lt.0) then yllabels(j) = yllabels(j) + "~S~o~N~S" end if if(lft_lat(j).gt.0) then yllabels(j) = yllabels(j) + "~S~o~N~N" end if end if delete(ii) end do bres@tmYLMode = "Explicit" bres@tmYLValues = ylvalues bres@tmYLLabels = get_res_value(res2,"tmYLLabels",yllabels) else bres@tmYLOn = False bres@tmYLLabelsOn = False end if ;---Right axis tickmarks if(isatt(res2,"tmYRValues")) then rgt_lat = get_res_value(res2,"tmYRValues",-1) nlat = dimsizes(rgt_lat) yrvalues = new(nlat,float) yrlabels = new(nlat,string) xfix = vpx + vpw - 0.0001 ; Just a smidge into the plot to make sure we don't ; get missing values returned. ; ; Loop across each right latitude value that we want a tickmark for, ; and try to find the closest X,Y NDC coordinate pair along this axis. ; do j=0,dimsizes(rgt_lat)-1 NhlNDCToData(plot,xfix,yndc,xlon,xlat) ii = minind(fabs(xlat-rgt_lat(j))) if(.not.any(ismissing(ii)).and.fabs(xlat(ii)-rgt_lat(j)).le.delta) yrlabels(j) = fabs(rgt_lat(j)) + "" yrvalues(j) = yndc(ii(0)) if(rgt_lat(j).lt.0) then yrlabels(j) = yrlabels(j) + "~S~o~N~S" end if if(rgt_lat(j).gt.0) then yrlabels(j) = yrlabels(j) + "~S~o~N~N" end if end if delete(ii) end do bres@tmYROn = True bres@tmYRLabelsOn = True bres@tmYUseLeft = False bres@tmYRMode = "Explicit" bres@tmYRValues = yrvalues bres@tmYRLabels = get_res_value(res2,"tmYRLabels",yrlabels) else bres@tmYUseLeft = False bres@tmYROn = False bres@tmYRLabelsOn = False end if ;---Top axis tickmarks if(isatt(res2,"tmXTValues")) then top_lon = get_res_value(res2,"tmXTValues",-1) nlon = dimsizes(top_lon) xtvalues = new(nlon,float) xtlabels = new(nlon,string) yfix = vpy - 0.0001 ; Just a smidge into the plot to make sure we don't ; get missing values returned. ; ; Loop across each top longitude value that we want a tickmark for, ; and try to find the closest X,Y NDC coordinate pair along this axis. ; do j=0,dimsizes(top_lon)-1 NhlNDCToData(plot,xndc,yfix,xlon,xlat) ii = minind(fabs(xlon-top_lon(j))) if(.not.any(ismissing(ii)).and.fabs(xlon(ii)-top_lon(j)).le.delta) xtlabels(j) = fabs(top_lon(j)) + "" xtvalues(j) = xndc(ii(0)) if(top_lon(j).lt.0) then xtlabels(j) = xtlabels(j) + "~S~o~N~W" end if if(top_lon(j).gt.0) then xtlabels(j) = xtlabels(j) + "~S~o~N~E" end if end if delete(ii) end do bres@tmXTOn = True bres@tmXTLabelsOn = True bres@tmXUseBottom = False bres@tmXTMode = "Explicit" bres@tmXTValues = xtvalues bres@tmXTLabels = get_res_value(res2,"tmXTLabels",xtlabels) else bres@tmXUseBottom = False bres@tmXTOn = False bres@tmXTLabelsOn = False end if ;---Bottom axis tickmarks if(isatt(res2,"tmXBValues")) then bot_lon = get_res_value(res2,"tmXBValues",-1) nlon = dimsizes(bot_lon) xbvalues = new(nlon,float) xblabels = new(nlon,string) yfix = vpy-vph + 0.0001 ; Just a smidge into the plot to make sure ; we don't get missing values returned. ; ; Loop across each bottom longitude value that we want a tickmark for, ; and try to find the closest X,Y NDC coordinate pair along this axis. ; do j=0,dimsizes(bot_lon)-1 NhlNDCToData(plot,xndc,yfix,xlon,xlat) ii = minind(fabs(xlon-bot_lon(j))) if(.not.any(ismissing(ii)).and.fabs(xlon(ii)-bot_lon(j)).le.delta) xblabels(j) = fabs(bot_lon(j)) + "" xbvalues(j) = xndc(ii(0)) if(bot_lon(j).lt.0) then xblabels(j) = xblabels(j) + "~S~o~N~W" end if if(bot_lon(j).gt.0) then xblabels(j) = xblabels(j) + "~S~o~N~E" end if end if delete(ii) end do bres@tmXBMode = "Explicit" bres@tmXBValues = xbvalues bres@tmXBLabels = get_res_value(res2,"tmXBLabels",xblabels) else bres@tmXBOn = False bres@tmXBLabelsOn = False end if ; ; Now that we are done figuring out where to put tickmarks, and ; what labels to use, get any "tm" resources that might have been ; set by the user, and create a blank plot with thes new tickmarks. ; ;---Get rest of user resources that were set with "tm". bres = get_res_eq(res2,"tm") bres = True ; Above call will set bres to True if no "tm" resources, so ; make sure it is True still. bres@gsnDraw = False bres@gsnFrame = False ; ; Create blank plot with new tickmarks (don't use gsn_csm_blank_plot, ; because it wants to scale the size of your X and Y axes.) ; blank = gsn_blank_plot(wks,bres) ; ; Attach new tickmarks to original plot. This will allow resizing ; if desired. The default is to attach one plot to the center of ; the other one. These two plots are already the same size. ; annoid = gsn_add_annotation(plot,blank,False) ; ; Be sure to return the annotation id, otherwise the ; tickmarks will disappear. ; anno_str = unique_string("annoid") plot@$anno_str$ = annoid return(plot) end ;---------------------------------------------------------------------- ; MAIN CODE ;---------------------------------------------------------------------- begin wks = gsn_open_wks("png","mptick") ; send graphics to PNG file res = True res@gsnDraw = False res@gsnFrame = False res@tiMainString = "Lambert Conformal Map" res@tiMainOffsetYF = 0.05 res@mpProjection = "LambertConformal" res@mpLambertParallel1F = 10 res@mpLambertParallel2F = 70 res@mpLambertMeridianF = -100 res@mpLimitMode = "LatLon" res@mpMinLatF = 20 res@mpMaxLatF = 55 res@mpMinLonF = -140 res@mpMaxLonF = -60 res@mpGridAndLimbOn = True res@mpGridSpacingF = 10. res@pmTickMarkDisplayMode = "Always" ;---Create the map, but don't draw it yet. map = gsn_csm_map(wks,res) tmres = True ;---Set the values you want for the map tickmarks. tmres@tmXBLabelFontHeightF = 0.008 ; Default is a bit large ;---We're putting tickmarks on all four axes. tmres@tmYLValues = ispan(20,50,10) tmres@tmYRValues = ispan(20,50,10) tmres@tmXBValues = ispan(-130,-70,10) tmres@tmXTValues = ispan(-160,-40,10) ;---Attach the new map tickmarks. map = add_map_tickmarks2(wks,map,tmres) ;---Re-maxmize plot just in case. This will draw and advance frame too. maximize_output(wks,True) ;---Start over with a new resource list. This time create a Mercator map. delete(res) res = True res@gsnMaximize = True res@gsnDraw = False res@gsnFrame = False res@tiMainString = "Mercator Map" res@mpDataBaseVersion = "MediumRes" ; use finer database res@pmTickMarkDisplayMode = "Always" ; turn on tickmarks res@mpProjection = "mercator" ; projection res@mpLimitMode = "Corners" ; method to zoom res@mpLeftCornerLatF = 32 res@mpLeftCornerLonF = 128 res@mpRightCornerLatF = 55 res@mpRightCornerLonF = 144 res@mpFillOn = False map = gsn_csm_map (wks,res) ;---We're putting tickmarks on all four axes. res@tmYLValues = ispan(32,55,3) res@tmXBValues = ispan(128,144,4) ;---Attach the new map tickmarks. map = add_map_tickmarks2(wks,map,res) ;---Re-maxmize plot just in case. This will draw and advance frame too. maximize_output(wks,True) end