VCS Templates

This turorial describes how to use CDAT's VCS's templates.

Download the Jupyter Notebook

The CDAT software was developed by LLNL. This tutorial was written by Charles Doutriaux (18 Jan. 2017). This work was performed under the auspices of the U.S. Department of Energy by Lawrence Livermore National Laboratory under Contract DE-AC52-07NA27344.

In the VCS model, the data display is defined by a trio of named object sets, designated the “primary objects” (or “primary elements”). These include:

  • Data Ingestion: The data, which drives the visualization, is ingested into the system via cdms2 or other numeric modules such as numpy.
  • Graphics Method: The graphics method, which specifies the display technique.
  • Template: The picture template, which determines the appearance of each segment of the display. Tables for manipulating these primary objects are stored in VCS for later recall and possible use.

This tutorial explains how to control the template and its relation to VCS's other primary objects.

Template elements

Generalities

Back to top

The template object allows the user to control where various elements of the plots are being drawn.

The following picture shows the various elements of a VCS image and the associated VCS template's atrribute:

To create a text object simply use the createtemplate function.

In [1]:
from __future__ import print_function  # For Python 2 compatibility
import vcs
x = vcs.init(bg=True)
template = vcs.createtemplate()
# the name is some bad random name:
print("template name:", template.name)
# If you want you can name your template object for easier retrieval later
# but keep in mind the name must be unique
try:
    template = vcs.createtemplate("vcs_is_easy")
except Exception:
    print("Ooops already have a template named like this")
    
print("Nice named template:", template.name)
# fails on second try
try:
    template = vcs.createtemplate("vcs_is_easy")
    print("It worked")
except Exception:
    print("Second try: Ooops already have a template named like this")
    
template name: __template_341325303621890
Nice named template: vcs_is_easy
Second try: Ooops already have a template named like this

You can also list all of your existing templates and use one of them as a starting point.

In [2]:
mytemplates = vcs.listelements("template")
print("Existing templates:", mytemplates)  # notice the randomly named ones
template = vcs.createtemplate(source="vcs_is_easy")
Existing templates: ['ASD', 'ASD_dud', 'BL_of6_1legend', 'BLof6', 'BR_of6_1legend', 'BRof6', 'LLof4', 'LLof4_dud', 'LRof4', 'LRof4_dud', 'ML_of6', 'ML_of6_1legend', 'MR_of6', 'MR_of6_1legend', 'UL_of6_1legend', 'ULof4', 'ULof4_dud', 'ULof6', 'UR_of6', 'UR_of6_1legend', 'URof4', 'URof4_dud', '__template_341325303621890', 'bold_mid_of3', 'bold_top_of3', 'boldbot_of3_l', 'boldmid_of3_l', 'boldtop_of3_l', 'bot_of2', 'default', 'deftaylor', 'hovmuller', 'mollweide2', 'no_legend', 'polar', 'por_botof3', 'por_botof3_dud', 'por_midof3', 'por_midof3_dud', 'por_topof3', 'por_topof3_dud', 'quick', 'top_of2', 'vcs_is_easy']

Now in order to use this template either pass the template object to the vcs plot function.

In [3]:
# Get some data to plot
vcs.download_sample_data_files()
import cdms2
import os
with cdms2.open(os.path.join(vcs.sample_data,"ta_ncep_87-6-88-4.nc")) as f:
    data = f("ta")
# we need 
x.plot(data, template)
MD5: /home/nadeau1/.cache/Python-Eggs/vcs-v8.1_9_g266121be-py3.7.egg-tmp/share/vcs/sample_files.txt
Downloading: 'th_yr.nc' from 'https://cdat.llnl.gov/cdat/sample_data/' in: /software/anaconda53/envs/cdms2/share/cdat/sample_data/th_yr.nc
Downloading: 'th_yr.nc' from 'https://cdat.llnl.gov/cdat/sample_data/' in: /software/anaconda53/envs/cdms2/share/cdat/sample_data/th_yr.nc
Downloading: 'th_yr.nc' from 'https://cdat.llnl.gov/cdat/sample_data/' in: /software/anaconda53/envs/cdms2/share/cdat/sample_data/th_yr.nc
Out[3]:

Now let's learn how to customize template objects.

To see the list of available attributes on a template (and their own attributes/values) use the list() function.

In [4]:
template.list()
---------- Template (P) member (attribute) listings ----------
method = P
name = __template_77340719414112
orientation = 0
member =  file
     priority = 1
     x = 0.0500000007451
     y = 0.0130000002682
     texttable = default
     textorientation = default
member =  function
     priority = 1
     x = 0.0500000007451
     y = 0.0130000002682
     texttable = default
     textorientation = default
member =  logicalmask
     priority = 1
     x = 0.0500000007451
     y = 0.0329999998212
     texttable = default
     textorientation = default
member =  transformation
     priority = 1
     x = 0.0500000007451
     y = 0.0529999993742
     texttable = default
     textorientation = default
member =  source
     priority = 1
     x = 0.0500000007451
     y = 0.941999971867
     texttable = default
     textorientation = default
member =  dataname
     priority = 1
     x = 0.0500000007451
     y = 0.922999978065
     texttable = default
     textorientation = default
member =  title
     priority = 1
     x = 0.15000000596
     y = 0.922999978065
     texttable = default
     textorientation = default
member =  units
     priority = 1
     x = 0.670000016689
     y = 0.922999978065
     texttable = default
     textorientation = default
member =  crdate
     priority = 1
     x = 0.75
     y = 0.922999978065
     texttable = default
     textorientation = default
member =  crtime
     priority = 1
     x = 0.850000023842
     y = 0.922999978065
     texttable = default
     textorientation = default
member =  comment1
     priority = 1
     x = 0.10000000149
     y = 0.954999983311
     texttable = default
     textorientation = default
member =  comment2
     priority = 1
     x = 0.10000000149
     y = 0.975000023842
     texttable = default
     textorientation = default
member =  comment3
     priority = 1
     x = 0.10000000149
     y = 0.995000004768
     texttable = default
     textorientation = default
member =  comment4
     priority = 1
     x = 0.10000000149
     y = 0.999000012875
     texttable = default
     textorientation = default
member =  xname
     priority = 1
     x = 0.5
     y = 0.21
     texttable = default
     textorientation = defcenter
member =  yname
     priority = 1
     x = 0.006
     y = 0.56
     texttable = default
     textorientation = defup
member =  zname
     priority = 0
     x = 0.0
     y = 0.995000004768
     texttable = default
     textorientation = default
member =  tname
     priority = 0
     x = 0.0
     y = 0.995000004768
     texttable = default
     textorientation = default
member =  xunits
     priority = 0
     x = 0.600000023842
     y = 0.21
     texttable = default
     textorientation = default
member =  yunits
     priority = 0
     x = 0.006
     y = 0.658999979496
     texttable = default
     textorientation = defup
member =  zunits
     priority = 0
     x = 0.0
     y = 0.995000004768
     texttable = default
     textorientation = default
member =  tunits
     priority = 0
     x = 0.0
     y = 0.995000004768
     texttable = default
     textorientation = default
member =  xvalue
     priority = 0
     x = 0.800000011921
     y = 0.941999971867
     format = default
     texttable = default
     textorientation = default
member =  yvalue
     priority = 0
     x = 0.800000011921
     y = 0.922999978065
     format = default
     texttable = default
     textorientation = default
member =  zvalue
     priority = 1
     x = 0.800000011921
     y = 0.902999997139
     format = default
     texttable = default
     textorientation = default
member =  tvalue
     priority = 0
     x = 0.800000011921
     y = 0.883000016212
     format = default
     texttable = default
     textorientation = default
member =  mean
     priority = 1
     x = 0.0500000007451
     y = 0.899999976158
     format = default
     texttable = default
     textorientation = default
member =  min
     priority = 1
     x = 0.449999988079
     y = 0.899999976158
     format = default
     texttable = default
     textorientation = default
member =  max
     priority = 1
     x = 0.25
     y = 0.899999976158
     format = default
     texttable = default
     textorientation = default
member =  xtic1
     priority = 1
     y1 = 0.259999990463
     y2 = 0.24699999392
     line = default
member =  xtic2
     priority = 1
     y1 = 0.860000014305
     y2 = 0.871999979019
     line = default
member =  xmintic1
     priority = 0
     y1 = 0.259999990463
     y2 = 0.248999999285
     line = default
member =  xmintic2
     priority = 0
     y1 = 0.860000014305
     y2 = 0.868000014305
     line = default
member =  ytic1
     priority = 1
     x1 = 0.0500000007451
     x2 = 0.0399999991059
     line = default
member =  ytic2
     priority = 1
     x1 = 0.949999988079
     x2 = 0.959999978542
     line = default
member =  ymintic1
     priority = 0
     x1 = 0.0500000007451
     x2 = 0.0450000017881
     line = default
member =  ymintic2
     priority = 0
     x1 = 0.949999988079
     x2 = 0.954999983311
     line = default
member =  xlabel1
     priority = 1
     y = 0.234999999404
     texttable = default
     textorientation = defcenter
member =  xlabel2
     priority = 0
     y = 0.880000004768
     texttable = default
     textorientation = defcenter
member =  ylabel1
     priority = 1
     x = 0.0399999991059
     texttable = default
     textorientation = defright
member =  ylabel2
     priority = 0
     x = 0.959999978542
     texttable = default
     textorientation = default
member =  box1
     priority = 1
     x1 = 0.0500000007451
     y1 = 0.259999990463
     x2 = 0.949999988079
     y2 = 0.860000014305
     line = default
member =  box2
     priority = 0
     x1 = 0.0
     y1 = 0.300000011921
     x2 = 0.920000016689
     y2 = 0.879999995232
     line = default
member =  box3
     priority = 0
     x1 = 0.0
     y1 = 0.319999992847
     x2 = 0.910000026226
     y2 = 0.860000014305
     line = default
member =  box4
     priority = 0
     x1 = 0.0
     y1 = 0.0
     x2 = 0.0
     y2 = 0.0
     line = default
member =  line1
     priority = 0
     x1 = 0.0500000007451
     y1 = 0.560000002384
     x2 = 0.949999988079
     y2 = 0.560000002384
     line = default
member =  line2
     priority = 0
     x1 = 0.5
     y1 = 0.259999990463
     x2 = 0.5
     y2 = 0.860000014305
     line = default
member =  line3
     priority = 0
     x1 = 0.0
     y1 = 0.52999997139
     x2 = 0.899999976158
     y2 = 0.52999997139
     line = default
member =  line4
     priority = 0
     x1 = 0.0
     y1 = 0.990000009537
     x2 = 0.899999976158
     y2 = 0.990000009537
     line = default
member =  legend
     priority = 1
     x1 = 0.0500000007451
     y1 = 0.129999995232
     x2 = 0.949999988079
     y2 = 0.159999996424
     line = default
     texttable = default
     textorientation = defcenter
     offset = 0.01
member =  data
     priority = 1
     x1 = 0.0500000007451
     y1 = 0.259999990463
     x2 = 0.949999988079
     y2 = 0.860000014305

Data attribute

Back to top

One of the most important attributes is the data attribute. It controls where the data will be drawn.

Note that changing the data attribute alone is not sufficient; other attributes will need to be moved as well. See the latter part of this tutorial for utility functions to help you manipulate everything at once.

Let's try to move the data to the upper left part of the canvas.

All units are in percentage (%) of the canvas; the 0 representing the lower/left corner of the canvas and 1 the upper/right corner).

The data attribute has 5 sub-attributes:

  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • x1: The lower left corner horizontal location (in %).
  • x2: The upper right corner horizontal location (in %).
  • y1: The lower left corner vertical location (in %).
  • y2: The upper right corner vertical location (in %).
In [5]:
template.data.x1 = .1 # 10% from left
template.data.x2 = .45  # 45% from left
template.data.y1 = .45  # 45% from bottom
template.data.y2 = .85  # 15% from top (or 85% from bottom)

x.clear()
x.plot(data,template)
Out[5]:

As mentioned, other attributes need to be moved as well. First let's move the box around the data area. It is controlled via box1 which has the following attributes:

In [6]:
template.box1.list()
member =  box1
     priority = 1
     x1 = 0.0500000007451
     y1 = 0.259999990463
     x2 = 0.949999988079
     y2 = 0.860000014305
     line = default

The new attribute here is the line attribute. You can use any line object from vcs (or create one).

In [7]:
print(vcs.listelements("line"))
template.box1.line = "red"
# let's copy
template.box1.x1 = template.data.x1
template.box1.x2 = template.data.x2
template.box1.y1 = template.data.y1
template.box1.y2 = template.data.y2

x.clear()
x.plot(data,template)
['black', 'blue', 'brown', 'continents', 'cyan', 'default', 'deftaylordot', 'green', 'ltblue', 'navy', 'pink', 'purple', 'red', 'solid', 'std', 'thick', 'white']
Out[7]:

Tick Marks

Back to top

Now let's move the tick marks. There are two types of tick marks: "major" and "min". The main difference is that "major" tick marks have text associated with them.

There are tick marks for the x axis and for the y axis. Each axis has two sets of tick marks. By default 1 is for the left/bottom tick marks while 2 is for the right/top ones.

With this in mind, the tickmark attributes are:

xtic1, xtic2, xmintic1, xmintic2, ytic1, ytic2, ymintic1, ymintic2,

Major Ticks

Back to top

For example, for xtic1 the attributes are:

In [8]:
template.xtic1.list()
member =  xtic1
     priority = 1
     y1 = 0.259999990463
     y2 = 0.24699999392
     line = default
  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • y1: start of tick line in the vertical direction (in % of canvas).
  • y2: end of tick line in the vertical direction (in % of canvas).
  • line: a vcs line object (or name) to use for the line.

Similarly for the y ticks:

In [9]:
template.ytic1.list()
member =  ytic1
     priority = 1
     x1 = 0.0500000007451
     x2 = 0.0399999991059
     line = default
  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • x1: start of tick line in the horizontal direction (in % of canvas).
  • x2: end of tick line in the horizontal direction (in % of canvas).
  • line: a vcs line object (or name) to use for the line.

Note that a template only controls the extent of the tick marks, not their location/values. This is controlled via the graphic method's [x/y]ticlabels[1/2] and [x/y]mtics[1/2] attributes.

Let's set the tick marks properly.

First set of major ticks (x/y)
In [10]:
# x major tick marks for first set of tick marks (1) drawn all the way across with grey lines
template.xtic1.y1 = template.data.y1
template.xtic1.y2 = template.data.y2
grey = vcs.createline()
grey.color = ['grey',]
grey.width = [2]
template.xtic1.line = grey  # uses line object

# y major for first set of tick marks (1) drawn all the way across with darker grey lines
template.ytic1.x1 = template.data.x1
template.ytic1.x2 = template.data.x2
grey2 = vcs.createline()
grey2.color = [(40, 40, 40),]
grey2.width = [2,]
template.ytic1.line = grey2.name  # uses line name

x.clear()
x.plot(data, template)
Out[10]:
Second set of major ticks (x/y)
In [11]:
# x major tick marks for second set of tick marks (2) drawn outward in red
template.xtic2.priority=1  # turn on
template.xtic2.y1 = template.data.y2
template.xtic2.y2 = template.data.y2 + .01 # extend a bit further
template.xtic2.line="red"

# y major for second set of tick marks (2) drawn outward in red
template.ytic2.priority=1  # turn on
template.ytic2.x1 = template.data.x2
template.ytic2.x2 = template.data.x2 + .01 # extends a bit past it
template.ytic2.line = "red"
x.clear()
x.plot(data, template)
Out[11]:

Minor ticks (x/y)

Back to top

Let's do the same for the minor tics or mintics, except using dotted lines and not extending them as far.

In [12]:
# x minor tick marks (set 1) drawn all the way across with grey lines
template.xmintic1.priority = 1
template.xmintic1.y1 = template.data.y1
template.xmintic1.y2 = template.data.y2
grey = vcs.createline(source=grey.name)
grey.type= ["dot",]
template.xmintic1.line = grey  # re-uses line object

# y minor (set 1) drawn all the way across using darker grey lines
template.ymintic1.priority = 1
template.ymintic1.x1 = template.data.x1
template.ymintic1.x2 = template.data.x2
grey2 = vcs.createline(source=grey2.name)
grey2.type= ["dot",]
template.ymintic1.line = grey2.name  # uses line name

# x minor tick marks (set 2) drawn outward in red (a bit less)
template.xmintic2.priority=1  # turn on
template.xmintic2.y1 = template.data.y2
template.xmintic2.y2 = template.data.y2 + .005 # extend a bit further
template.xmintic2.line="red"

# y minor (set 2) drawn outward in red
template.ymintic2.priority=1  # turn on
template.ymintic2.x1 = template.data.x2
template.ymintic2.x2 = template.data.x2 + .005 # extends a bit past it
template.ymintic2.line = "red"

x.clear()
x.plot(data, template)
Out[12]:
In [13]:
# too many tics; let's reduce their number
box = vcs.createboxfill()
box.xticlabels1 = {-180:"180W", -90:"90W", 0:"0", 90:"90E", 180:"180E", 270:"270E", 360:"0"}
box.xticlabels2 = box.xticlabels1 # same on both ends
box.yticlabels1 = {-90:"90S", -60:"60S", 0:"Eq", 60:"60N", 90:"90N"}
box.yticlabels2 = box.yticlabels1

# min ticks
box.xmtics1 = {-135:"135W", -45:"45W", 45:"45E", 135:"135E", 315:"315E"}
box.xmtics2 = box.xmtics1
box.ymtics1 = {-45:"45S", 45:"45N"}  # text does not matter as not drawn
box.ymtics2 = box.ymtics1

x.clear()
x.plot(data, box, template)
Out[13]:

Axes Labels

Back to top

Now we also need to move the actual values on the major tick marks. These are controlled via xlabel1, xlabel2, ylabel, ylabel2.

Attributes on these are:

In [14]:
template.xlabel1.list()
member =  xlabel1
     priority = 1
     y = 0.234999999404
     texttable = default
     textorientation = defcenter
  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • y: location of the label in the vertical direction (in % of canvas).
  • texttable: vcs texttable object or name.
  • textorientation: vcs textorientation object or name.

    For more info on texttable and textorientation please see the vcs text objects notebook.

First set of labels
In [15]:
text = vcs.createtext()
text.font = "Courier"
text.color = "blue"
text.angle = -45

template.xlabel1.priority=1
template.xlabel1.texttable = text.Tt_name
template.xlabel1.textorientation = text.To_name
template.xlabel1.y = template.data.y1 - .03

text = vcs.createtext()
text.font = "Times"
text.color = "salmon"
text.angle = -90

template.ylabel1.priority=1
template.ylabel1.texttable = text.Tt_name
template.ylabel1.textorientation = text.To_name
template.ylabel1.x = template.data.x1 - .01

x.clear()
x.plot(data, template, box)
Out[15]:
Second set of labels
In [16]:
text = vcs.createtext()
text.font = "Courier"
text.color = "red"
text.angle = -45
text.halign="right"
text.valign="top"

template.xlabel2.priority=1
template.xlabel2.texttable = text.Tt_name
template.xlabel2.textorientation = text.To_name
template.xlabel2.y = template.data.y2 + .04

text = vcs.createtext()
text.font = "Adelon"
text.color = "pink"
text.angle = 90

template.ylabel2.priority=1
template.ylabel2.texttable = text.Tt_name
template.ylabel2.textorientation = text.To_name
template.ylabel2.x = template.data.x2 + .01

x.clear()
x.plot(data, template, box)
Out[16]:

Axis names

Back to top

The position of the axes is controlled via the xname and yname attributes.

Their attributes are:

In [17]:
template.xname.list()
member =  xname
     priority = 1
     x = 0.5
     y = 0.21
     texttable = default
     textorientation = defcenter
  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • x: location of the label in the horizontal direction (in % of canvas).
  • y: location of the label in the vertical direction (in % of canvas).
  • texttable: vcs texttable object or name.
  • textorientation: vcs textorientation object or name.

    For more info on texttable and textorientation please see the vcs text objects notebook.

In [18]:
text = vcs.createtext()
text.color = "blue"
text.height = 15
text.halign = "center"
text.font = "Courier"

template.xname.x = (template.data.x1 + template.data.x2) / 2.
template.xname.y = template.data.y1 -.05
template.xname.texttable = text.Tt_name
template.xname.textorientation = text.To_name
template.xname.x = (template.data.x1 + template.data.x2) / 2.
template.xname.y = template.data.y1 -.06

text = vcs.createtext()
text.color = "salmon"
text.height = 25
text.valign = "half"
text.halign = "center"
text.angle = -90
text.font = "Times"
template.yname.texttable = text.Tt_name
template.yname.textorientation = text.To_name
template.yname.x = template.data.x1 -.04
template.yname.y = (template.data.y1 + template.data.y2) / 2. 

x.clear()
x.plot(data, box, template)
Out[18]:

Legend attribute

Back to top

Now we need to move the legend bar. This is done via the legend attribute. Its attributes are:

In [19]:
template.legend.list()
member =  legend
     priority = 1
     x1 = 0.0500000007451
     y1 = 0.129999995232
     x2 = 0.949999988079
     y2 = 0.159999996424
     line = default
     texttable = default
     textorientation = defcenter
     offset = 0.01
  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • x1: start of the legend box in the horizontal direction (in % of canvas).
  • x2: end of the legend box in the horizontal direction (in % of canvas).
  • y1: start of the legend box in the vertical direction (in % of canvas).
  • y2: end of the legend box in the vertical direction (in % of canvas).
  • texttable: vcs texttable object or name.
  • textorientation: vcs textorientation object or name.
  • offset: how far from the bar the text should be (in % of canvas).

    For more info on texttable and textorientation please see the vcs text objects notebook.

Depending on whether the legend is horizontal/vertical, the x1/y1 attributes determine the side where the legend will be drawn.

The legend labels themselves are controlled via the graphic method's legend attribute.

Let's have a vertical legend with labels on the right side.

In [20]:
template.legend.x1 = template.data.x2 + .08
template.legend.x2 = template.data.x2 + .06
template.legend.y1 = template.data.y1 + .02
template.legend.y2 = template.data.y2 - .02
text = vcs.createtext()
text.color = "cyan"
text.height=12
text.angle=-45
template.legend.texttable = text.Tt_name
template.legend.textorientation = text.To_name
template.legend.offset = .015

box.legend = {220:"Cold", 320:"HOT!", 270:"Mild"}
x.clear()
x.plot(data, template, box)
Out[20]:

Text controlling attributes

Back to top

In addition, the template lets you display elements associated with the data itself.

All the following attributes have the same set of their own attributes:

In [21]:
template.dataname.list()
member =  dataname
     priority = 1
     x = 0.0500000007451
     y = 0.922999978065
     texttable = default
     textorientation = default
  • priority: the priority represents the layer on which the attribute will be drawn. A higher number means the attribute will be drawn on top of attributes with lower numbers.
  • x: text position in the horizontal direction (in % of canvas).
  • y: text position in the vertical direction (in % of canvas).
  • texttable: vcs texttable object or name.
  • textorientation: vcs textorientation object or name.

    For more info on texttable and textorientation please see the vcs text objects notebook

Elements Controlled by Data Values

Back to top

The mean, min, and max attributes' values are controlled by the input plotted, not the full array. For example, if you plot a 3D array with a boxfill, the values will be determined by the 2D data plotted, not by the full 3D array.

The mean value is plotted as follows:

  • Does the data have a mean attribute? If yes, use this.
  • Try to apply cdutil.averager(data). If passes, use this.
  • Everything else failed: use numpy.ma.average(data).
In [22]:
template.max.x = template.data.x2 + .2
template.max.y = template.data.y2
template.min.x = template.data.x2 + .2
template.min.y = template.max.y - .03
template.mean.x = template.data.x2 + .2
template.mean.y = template.min.y - .03

x.clear()
x.plot(data, box, template)
Out[22]:

Elements Controlled by Data Attributes

Back to top

The main ones are:

source, dataname, title, units.

The following are legacy convenience attributes from the time when VCS was a GUI only. They are:

file, function, logicalmask, transformation, comment1, comment2, comment3, comment4.

Here is the mapping of these attributes to the attribute on the data:

dataname $\leftarrow$ $\rightarrow$ id

title $\leftarrow$ $\rightarrow$ long_name

source $\leftarrow$ $\rightarrow$ source

units $\leftarrow$ $\rightarrow$ units

file $\leftarrow$ $\rightarrow$ file

function $\leftarrow$ $\rightarrow$ function

logicalmask $\leftarrow$ $\rightarrow$ logicalmask

transformation $\leftarrow$ $\rightarrow$ transformation

comment1 $\leftarrow$ $\rightarrow$ comment1

comment2 $\leftarrow$ $\rightarrow$ comment2

comment3 $\leftarrow$ $\rightarrow$ comment3

comment4 $\leftarrow$ $\rightarrow$ comment4

In [23]:
data.id = "DATANAME"
data.long_name = "TITLE HERE"
template.dataname.x = template.data.x2 + .3
template.dataname.y = template.data.y2

for i, att in enumerate("source title units file function logicalmask transformation comment1 comment2 comment3 comment4".split()):
    attr = getattr(template,att)
    attr.priority = 1
    attr.x = template.dataname.x
    attr.y = template.dataname.y - (i+1)*.025
    setattr(data,att, "{} HERE".format(att.upper()))

x.clear()
x.plot(data, box, template)
Out[23]:

Elements Controlled by the Attributes of the Data's Axes

Back to top

The following text values are determined based on the values of the input array axes.

xname, yname, ztname, tname, xunits, yunits, zunits, tunits, xvalue, yvalue, zvalue, tvalue, crdate, crtime

Where x, y, z, t represent the axes from the last index:

x $\leftarrow$ $\rightarrow$ data.getAxis(-1)

y $\leftarrow$ $\rightarrow$ data.getAxis(-2)

z $\leftarrow$ $\rightarrow$ data.getAxis(-3)

t $\leftarrow$ $\rightarrow$ data.getAxis(-4)

crdate and crtime will try to obtain the time axis (data.getTime()) and use the current time point to determine the date (format: {:%Y/%m}) and time I(format: {:%H-%M-%S})

In [24]:
for i, axis in enumerate(["x","y","z","t"]):
    ax = data.getAxis(-i-1)
    print("Ax.id, units, val", ax.id, ax.units, ax[0])
    for j, attribute in enumerate(["name","units", "value"]):
        att = "{}{}".format(axis,attribute)
        if att in ["xname", "yname"]:  # we already touched these
            continue
        obj = getattr(template,att)
        obj.priority = 1
        obj.x = template.data.x1 + (i+1)*.2
        obj.y = template.data.y1 - (j+2)*.05
        #obj.list()

template.crdate.x = template.tunits.x
template.crdate.y = template.tvalue.y - 0.05
template.crtime.x = template.crdate.x
template.crtime.y = template.crdate.y - 0.05


x.clear()
x.plot(data, template, box)
Ax.id, units, val longitude degrees_east 0.0
Ax.id, units, val latitude degrees_north -90.0
Ax.id, units, val level lev 1000.0
Ax.id, units, val time months since 1949-1-1 0:0 461.0
Out[24]:

Lines and Boxes

Again as legacy features from when VCS was purely GUI-based, the template lets you draw 4 boxes and 4 lines. The box1 usually is reserved for the box around the data area.

Their attributes are:

In [25]:
template.box1.list()
member =  box1
     priority = 1
     x1 = 0.1
     y1 = 0.45
     x2 = 0.45
     y2 = 0.85
     line = red

Template Utilities

Back to top

Now that we understand how each attribute works, let's take a look at some of the built-in utility functions for VCS objects to help us manipulate all this a bit faster.

Scaling Functions

The following functions allow you to scale all of a template's elements.

scale

Signature: template.scale(scale, axis='xy', font=-1)

Scale a template along the axis 'x' or 'y' by scale defaults to 'xy' (both). Values of scale greater than 1 mean increase. The reference point is the template's x1 and y1 data. (i.e. this point will be unchanged). Fonts are scaled as well but can be left untouched.

In [26]:
template = vcs.createtemplate()
template.scale(.5)
x.clear()
x.plot(data,template)
Out[26]:
In [27]:
# Now, not touching the fonts
template = vcs.createtemplate()
template.scale(.5,font=0)
x.clear()
x.plot(data, template)
Out[27]:

scalefont

We can scale the font at a later time.

In [28]:
template.scalefont(.7)
x.clear()
x.plot(data, template)
Out[28]:

ratio

Alternatively we can ask the template to get a specific ratio for the data area.

The ratio means the y direction will be ratio times the x direction.

The box_and_ticks option also scales box and ticks, or not (default on).

In [29]:
template = vcs.createtemplate()
template.ratio(2)
x.clear()
x.plot(data, template)
Out[29]:
In [30]:
# we can also NOT scale ticks
template = vcs.createtemplate()
template.ratio(2, box_and_ticks=False)
x.clear()
x.plot(data, template)
Out[30]:

moving functions

Back to top

Once a template is scaled, we can then move it somewhere else.

move

Move a template by % along the axis 'x' or 'y'. Positive values of p mean movement toward right/top. Negative values of p mean movement toward left/bottom. The reference point is t.data.x1/y1

In [31]:
template = vcs.createtemplate()
template.scale(.5,font=False)
template.scalefont(.8)
template.move(.25,'x')
template.move(.25,'y')
x.clear()
x.plot(data, template)
Out[31]:

moveto

Sometimes it is preferable to move to a destination point rather than a percent (%).

Here the data x1/y1 will be moved to this location.

In [32]:
template = vcs.createtemplate()
template.scale(.5,font=False)
template.scalefont(.8)
template.moveto(.5, .1)
x.clear()
x.plot(data, template)
Out[32]:

Plot Functions (Advanced Users)

Back to top

drawColorBar

This function draws the colorbar. It needs:

  • colors : The colors to be plotted.
  • levels : The levels that each color represents.
  • legend : Draw a box at certain values and display some specific text instead of the value. (This will overwrite the existing legend.)
  • ext_1 and ext_2: to draw the arrows.
  • x : the canvas, where to plot it.
In [33]:
template = vcs.createtemplate()
x.clear()
template.drawColorBar(["red","white", "blue","green"],
                      [0,50, 100, 1.e20],
                      {0:"EMPTY", 50:"HALF", 100:"FULL"},
                      ext_2=True, x=x)
template2 = vcs.createtemplate()
template2.legend.priority = 0
x.plot(data,template2)
Out[33]:

drawLinesAndMarkersLegend

This function allows users to draw a legend box with lines and markers.

Draws a legend with line/marker/text inside a template legend box. Auto adjusts text size to make it fit inside the box. Auto arranges the elements to fill the box nicely.

template.drawLinesAndMarkersLegend( ['canvas', 'linecolors', 'linetypes', 'linewidths', 'markercolors', 'markertypes', 'markersizes', 'strings', 'scratched=None', 'stringscolors=None', "stacking='horizontal'", 'bg=False', 'render=True', 'smallestfontsize=None', 'backgroundcolor=None'], )

  • canvas: a VCS canvas object onto which to draw the legend
  • linecolors: A list containing the colors of each line to draw. Colors are represented as either an integer from 0-255, an RGBa tuple, or a string color name.
  • linetypes: A list containing the type of each line to draw. Line types are represented as either integers or strings. See :py:class:vcs.line.Tl for more information.
  • linewidths: A list containing numbers in float format representing the width of each line.
  • markercolors: A list of the marker colors to draw. Colors are represented as either an integer from 0-255, an RGBa tuple, or a string color name.
  • markertypes: A list of the marker types to draw. Marker types are represented as either integers or strings. See :py:class:vcs.marker.Tm for more information.
  • markersizes: A list of numbers in float format representing marker sizes.
  • strings: A list of strings to draw next to each line/marker.
  • scratched: A list indicating which strings should be "scratched" off in the template.

    To "scratch" a string, the corresponding location in the scratched list must contain either True or the line type to use for the scratch. A value of False at a given index will leave the corresponding index of strings untouched.

    Size of the scratched list must be equal to the size of the strings list.

    Scratch color will match that of text.

    If scratched is None, or is not provided, no strings will be scratched.

  • stringscolors: A list of the string colors to draw. Colors are represented as either an integer from 0-255, an RGBa tuple, or a string color name.
  • stacking: Prefered direction to stack element ('horizontal' or 'vertical')
  • bg: Boolean value indicating whether or not to draw in the background. Defaults to False.
  • render: Boolean value indicating whether or not to render. Defaults to True.
  • smallestfontsize: Integer value indicating the smallest font size we can use for rendering None means no limit, 0 means use original size. Downscaling will still be used by algorigthm to try to fit everything in the legend box.
  • backgroundcolor: A list indicating the background color of the legend box. Colors are represented as either an integer from 0-255, an RGBa tuple, or a string color name.
In [34]:
template = vcs.createtemplate()
template2.scale(.5)
x.clear()
l_colors=["red","blue","green"]
l_types=["solid","dash","dot"]
l_widths=[1,4,2]
m_colors=["blue","green","red"]
m_types=["cross","square","dot"]
m_sizes=[1,2,.5]
strings=["sample A","type B","thing C"]
scratch=[True,False,True]
background = 'grey'
template.legend.x1 = .85
template.legend.x2 = .99
template.legend.y1 = .2
template.legend.y2 = .8
template.drawLinesAndMarkersLegend(x, l_colors, l_types, l_widths,
                                   m_colors, m_types, m_sizes, strings, scratch,
                                   backgroundcolor=background)
x.plot(data,template2)
Out[34]:

Miscellaneous functions

Back to top

blank

The blank function allows users to set the priority of several template attributes at once.

The attributes you pass to the blank function will not be shown on the plot. In the next example, "mean", "crdate", "crtime", "min", and "dataname" have been removed from the standard plot which normally shows these attributes.

In [35]:
template = vcs.createtemplate()
template.blank(["mean", "crdate", "crtime", "min", "dataname"])
x.clear()
x.plot(data, template)
Out[35]:

If no attributes are passed, then everything is turned off except for data.

In [36]:
template = vcs.createtemplate()
template.blank()
x.clear()
x.plot(data, template)
Out[36]:

Special Case: Taylor Diagrams

Back to top

Taylor Diagrams are controlled a bit differently. The default template used for Taylor Diagrams is: deftaylor.

The image below describes how elements of a Taylor Diagram are controlled by the template:

For more on Taylor Diagrams, please see the Taylor Diagram Tutorial.

VCS Addons

Back to top

The VCS Addons provide a few utilities to help with templates.

Multiple Rows and Columns

This package allows you to easily create templates for multiple rows/columns.

Let's display the first 6 plots.

In [37]:
import vcsaddons
x.clear()
template = vcs.createtemplate()
template.blank(["transformation", "source", "dataname", "function", "logicalmask",
                "comment1", "comment2", "comment3" ,"comment4", "title", "file"])
Multi = vcsaddons.EzTemplate.Multi(rows=2, columns=3, template=template)
Multi.spacing.horizontal = .08
Multi.spacing.vertical = .1
Multi.margins.bottom = .2 # lots of space at bottom
local_legend = ["global", "local", None, "local", "local", None]
for i in range(6):
    mytemplate = Multi.get(column=i%3, row=i//3, fontlimit=.8, legend=local_legend[i])
    d = x.plot(data[i], mytemplate)
d
Out[37]:

Line (Spaghetti) Plots

Because the legend's position comes from the template, plotting multiple line plots together can be a problem as one template needs to be created for each line plot.

The EzPlot module helps with this.

In [38]:
import os
import cdutil
import math
import random
import vcsaddons.EzPlot

x.clear()
# Simple Plot with EzPlot


variables  = []
line_type  = []
line_widths = []
legend_texts = []
legend_text_colors = []
marker_type = []

for v in range(0, 20):
    var = []
    for i in range(0, 100):
        if v%2 == 0:
            #var.append(random.random() * v * math.sin(2*math.pi*float(i-v)/100.0))
            var.append(v * math.sin(2*math.pi*float(i-v)/100.0))
        else:
            #var.append(random.random() * v * math.cos(2*math.pi*float(i-v)/100.0))
            var.append(v * math.cos(2*math.pi*float(i-v)/100.0))
    line_type += ["solid"]
    line_widths += [5]
    if i%2 == 0:
        legend_texts += ["Sin"]
    else:    
        legend_texts += ["Cos"]
    legend_text_colors += ['black']
    marker_type += [None]
    variables.append(var)

plotfunction = vcsaddons.EzPlot.EzLinePlot()

d = plotfunction.lineplot(data=variables, canvas=x, title="Simple 2 EzLinePlot", titlesize=30,
                          #backgroundcolor=[0, 100, 0],
                          linetypes=line_type, linewidths=line_widths,
                          legendposition=[0.25, 0.35, 0.30, 0.40], legendtextcolors=legend_text_colors, 
                          legendtexts=legend_texts,
                          legendbackgroundcolor="yellow",
                          enablegrid=True)

d
Out[38]: