Source code for figures
"""
A single function for plotting maps the AR6 way, possibly with hatching
"""
from __future__ import division, print_function , unicode_literals, absolute_import
from climaf.api import *
import os
[docs]def change_figure(variable, derivation_label, field,
shade=True, mask1="", mask2="",pattern1="hatching",
pattern2="stippling",
relative=True, labelbar="True",
title=None, custom_plot={}, number=None, mask=None) :
"""
Returns a CliMAF plot object showing a 2d FIELD, with
superimposition of PATTERN1 (resp. PATTERN2) where field
MASK1 (resp. MASK2) is 'set' (actually where it exceeds value 0.9)
PATTERN1 and 2 are either :
- Ncl settings for patterns, such as 'gsnShadeHigh=3', or
- keywords : 'hatching', 'stippling', 'crosses'
PATTERN1 default to hatching, PATTERN2 to stippling
Plot characteristics comply with AR6/WGI TSU guidelines
re. colormaps, projection, ... (except if changed through arg
CUSTOM_PLOT, see below)
Toggle LABELBAR drives the presence of a labelbar in the plot. Its type is
string => value must be "True" or "False"
The provided TITLE is plotted too. If a NUMBER is provided, it will
be plotted in upper righ corner
VARIABLE, DERIVATION_LABEL, and logical toggle RELATIVE are used in order
to choose a colormap and sensible data intervals for a change of the variable
(arg RELATIVE indicating if FIELD is for a relative change)
However, this can be superseded by providing through CUSTOM_PLOT
argument a dict of arguments for CliMAF function plot(), as e.g.
>>> custom_plot={"color":"AR6_Precip_12","min":-2, "max":2,"delta":0.4 ,focus:"land"}
For the time being, the most used value for DERIVATION_LABEL is 'plain',
and the only other known cases are 'dry' (which stands for: the number of dry
days per year) and 'drain' (daily rain depth for rainy days)
"""
plot_args=dict( proj="Robinson", mpCenterLonF=2.0, gsnLeftString="", vcb=False)
patterns={
"hlines" : "gsnShadeHigh=1|gsnShadeFillScaleF=0.4.",
"slashes" : "gsnShadeHigh=3|gsnShadeFillScaleF=0.8",
"backslashes" : "gsnShadeHigh=4|gsnShadeFillScaleF=0.8",
"crosses" : "gsnShadeHigh=6|gsnShadeFillScaleF=0.8",
"hatching" : "gsnShadeHigh=3",
"stippling" : "gsnShadeHigh=17|gsnShadeFillScaleF=1|gsnShadeFillDotSizeF=0.004",
}
if mask1 != "" and shade :
pattern1 = patterns.get(pattern1,pattern1)
plot_args.update(shading_options="%s|gsnAddCyclic=True"%pattern1, shade_above=0.9)
if mask2 != "" and shade :
pattern2 = patterns.get(pattern2,pattern2)
plot_args.update( shade2_options="%s|gsnAddCyclic=True"%pattern2, shade2_below=-0.1, shade2_above=0.9)
options_format="lbLabelBarOn=%s|lbBoxEndCapStyle=TriangleBothEnds|lbLabelFont=helvetica|" +\
"lbTitleOn=True|lbTitleString='%s'|lbTitleFont=helvetica|lbTitlePosition=Bottom|"+\
"lbLabelFontHeightF=0.015|cnMissingValFillColor=grey|cnInfoLabelOn=False|"+\
"gsnRightStringFontHeightF=0.018|cnFillMode=CellFill|"
#
def colormap(variable) :
if variable in ["pr","pr_drain","pr_iav","P-E","mrro"] : return {"color":"AR6_Precip_12" }
elif variable in ["pr_dry"] : return {"color":"AR6_Evap_12" }
elif variable in ["pr_seasonality"] : return {}
elif variable in ["evspsbl"] : return {"color":"AR6_Temp_12" }
elif variable in ["mrsos","mrso"] : return {"color":"AR6_Precip_12" }
elif variable in ["sos"] : return {"color":"AR6_Salinity_12" }
else : return {}
#
def unit_string(variable) :
if variable in ["pr","P-E", "evspsbl"] : return "mm/d"
elif variable == "pr_drain" : return "mm"
elif variable == "pr_seasonality" : return "-"
elif variable == "pr_dry" : return "day"
elif variable in ["mrso","mrsos"] : return "kg/m**2"
elif variable in ["mrro"] : return "kg/m**2/d"
elif variable == "sos" : return "psu"
else : return "?"
#
def scale(variable) :
if variable in ["pr","P-E","mrro","evspsbl"] : return {"scale":24.*3600 }
else : return {}
def minmax(variable) :
if variable == "pr" : return { "min":-2, "max":2,"delta":0.4}
elif variable == "pr_dry" : return { "colors":"-32 -16 -8 -4 -2 0 2 4 8 16 32"}
elif variable == "pr_drain":return { "colors":"-2 -1 -0.5 -0.2 -0.1 0 0.1 0.2 0.5 1 2"}
elif variable == "pr_seasonality": return { "min":0.2, "max":1.5, "delta":0.1 }
elif variable == "P-E" : return { "min":-2, "max":2,"delta":0.4}
elif variable == "evspsbl": return { "min":-1, "max":1,"delta":0.2},
elif variable == "mrsos" : return { "colors":"-5 -2 -1 -0.5 -0.25 0.25 0.5 1 2 5"}
elif variable == "mrro" : return { "min":-0.5, "max":0.5,"delta":0.1}
else : return {}
def relative_minmax(variable) :
if variable == "mrso" : return dict(colors="-5 -2 -1 -0.5 -0.25 0 0.25 0.5 1 2 5")
elif variable == "sos" : return dict(colors=" -4. -3. -2. -1. -0.5 0. 0.5 1. 2. 3. 4. ")
elif variable == "evspsbl" : return dict(colors=" -100. -50. -25. -10. -5 0. 5 10. 25. 50. 100. ")
else : return dict(colors=" -50. -40. -30. -20. -10. 0. 10. 20. 30. 40. 50.")
#
def apply_mask(field,mask_field):
"""
Assumes that mask field has non-zero non-missing values on interesting places (to keep),
and zero or missing on places to mask
Result has input field value on interesting places, and missing value elsewhere
Assumes that grids for both fields are consistent
"""
if type(mask_field) is str :
mask_field=fds(mask_field)
return ccdo2_flip(field,mask_field,operator="ifthen")
var2=variable
if derivation_label != 'plain' :
var2=variable+"_"+derivation_label
if relative :
plot_args.update(**relative_minmax(var2))
plot_args.update(options=options_format%(labelbar,"%"))
else:
plot_args.update(**minmax(var2))
plot_args.update(**scale(var2))
ustring=custom_plot.get("units",unit_string(var2))
plot_args.update(options=options_format%(labelbar,ustring))
plot_args.update(**colormap(var2))
#
# Must combine 'options' defined above and those in custom_plot
custom_options=custom_plot.pop("options","")
plot_args["options"]=plot_args["options"]+custom_options
#
# Apply caller's custom options
plot_args.update(custom_plot)
#
if number is not None :
if type(number) is int : number_string="%d "%number
else : number_string="%s "%number
plot_args.update(gsnRightString=number_string)
#
if mask is not None :
field = apply_mask(field,mask)
if mask1 != "" :
mask1 = apply_mask(mask1,mask)
if mask2 != "" :
mask2 = apply_mask(mask2 ,mask)
#
# write plot arguments in subdir .figures, in a file named after title
outdir="./figures"
if not os.path.exists(outdir) : os.makedirs(outdir)
fn=outdir+"/plotargs_"+title.replace(" ","_").replace(",","_").replace("(","").replace(")","")
with open(fn,"w") as f :
f.write(repr(plot_args))
#
return plot(field,mask1,"","",mask2,title=title, **plot_args)