{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# VCS Templates \n", "\n", "This turorial describes how to use CDAT's VCS's templates.\n", "\n", "[Download the Jupyter Notebook](VCS_Templates.ipynb)\n", "\n", "\n", "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.\n", "\n", "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:\n", "\n", "* Data Ingestion: The data, which drives the visualization, is ingested into the system via cdms2 or other numeric modules such as numpy.\n", "* Graphics Method: The graphics method, which specifies the display technique.\n", "* 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.\n", "\n", "This tutorial explains how to control the template and its relation to VCS's other primary objects.\n", " " ] }, { "cell_type": "markdown", "metadata": { "toc": true }, "source": [ "

Table of Contents

\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Template elements\n", "\n", "### Generalities\n", "[Back to top](#top)\n", "\n", "\n", "The `template` object allows the user to control where various elements of the plots are being drawn.\n", "\n", "The following picture shows the various elements of a VCS image and the associated VCS template's atrribute:\n", "\n", "\n", "\n", "To create a text object simply use the `createtemplate` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "scrolled": true }, "outputs": [], "source": [ "from __future__ import print_function # For Python 2 compatibility\n", "import vcs\n", "x = vcs.init(bg=True)\n", "template = vcs.createtemplate()\n", "# the name is some bad random name:\n", "print(\"template name:\", template.name)\n", "# If you want you can name your template object for easier retrieval later\n", "# but keep in mind the name must be unique\n", "try:\n", " template = vcs.createtemplate(\"vcs_is_easy\")\n", "except Exception:\n", " print(\"Ooops already have a template named like this\")\n", " \n", "print(\"Nice named template:\", template.name)\n", "# fails on second try\n", "try:\n", " template = vcs.createtemplate(\"vcs_is_easy\")\n", " print(\"It worked\")\n", "except Exception:\n", " print(\"Second try: Ooops already have a template named like this\")\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also list all of your existing templates and use one of them as a starting point." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "mytemplates = vcs.listelements(\"template\")\n", "print(\"Existing templates:\", mytemplates) # notice the randomly named ones\n", "template = vcs.createtemplate(source=\"vcs_is_easy\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now in order to use this template either pass the template object to the vcs plot function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Get some data to plot\n", "vcs.download_sample_data_files()\n", "import cdms2\n", "import os\n", "with cdms2.open(os.path.join(vcs.sample_data,\"ta_ncep_87-6-88-4.nc\")) as f:\n", " data = f(\"ta\")\n", "# we need \n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's learn how to customize template objects.\n", "\n", "To see the list of available attributes on a template (and their own attributes/values) use the `list()` function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Data attribute\n", "[Back to top](#top)\n", "\n", "One of the most important attributes is the `data` attribute. It controls where the data will be drawn. \n", "\n", "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](#utilities) to help you manipulate everything at once.\n", "\n", "Let's try to move the data to the upper left part of the canvas.\n", "\n", "**All units are in percentage (%) of the canvas; the 0 representing the lower/left corner of the canvas and 1 the upper/right corner).**\n", "\n", "The `data` attribute has 5 sub-attributes:\n", "\n", "* `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.\n", "* `x1`: The lower left corner horizontal location (in %).\n", "* `x2`: The upper right corner horizontal location (in %).\n", "* `y1`: The lower left corner vertical location (in %).\n", "* `y2`: The upper right corner vertical location (in %)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.data.x1 = .1 # 10% from left\n", "template.data.x2 = .45 # 45% from left\n", "template.data.y1 = .45 # 45% from bottom\n", "template.data.y2 = .85 # 15% from top (or 85% from bottom)\n", "\n", "x.clear()\n", "x.plot(data,template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.box1.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The new attribute here is the `line` attribute. You can use any line object from vcs (or create one)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(vcs.listelements(\"line\"))\n", "template.box1.line = \"red\"\n", "# let's copy\n", "template.box1.x1 = template.data.x1\n", "template.box1.x2 = template.data.x2\n", "template.box1.y1 = template.data.y1\n", "template.box1.y2 = template.data.y2\n", "\n", "x.clear()\n", "x.plot(data,template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Tick Marks\n", "[Back to top](#top)\n", "\n", "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.\n", "\n", "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.\n", "\n", "With this in mind, the tickmark attributes are:\n", "\n", "`xtic1`, `xtic2`, `xmintic1`, `xmintic2`,\n", "`ytic1`, `ytic2`, `ymintic1`, `ymintic2`,\n", "\n", "\n", "#### Major Ticks\n", "[Back to top](#top)\n", "\n", "For example, for `xtic1` the attributes are:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.xtic1.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `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.\n", "* `y1`: start of tick line in the vertical direction (in % of canvas).\n", "* `y2`: end of tick line in the vertical direction (in % of canvas).\n", "* `line`: a vcs line object (or name) to use for the line.\n", "\n", "Similarly for the `y` ticks:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.ytic1.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `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.\n", "* `x1`: start of tick line in the horizontal direction (in % of canvas).\n", "* `x2`: end of tick line in the horizontal direction (in % of canvas).\n", "* `line`: a vcs line object (or name) to use for the line.\n", "\n", "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.\n", "\n", "Let's set the tick marks properly.\n", "\n", "##### First set of major ticks (x/y)\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# x major tick marks for first set of tick marks (1) drawn all the way across with grey lines\n", "template.xtic1.y1 = template.data.y1\n", "template.xtic1.y2 = template.data.y2\n", "grey = vcs.createline()\n", "grey.color = ['grey',]\n", "grey.width = [2]\n", "template.xtic1.line = grey # uses line object\n", "\n", "# y major for first set of tick marks (1) drawn all the way across with darker grey lines\n", "template.ytic1.x1 = template.data.x1\n", "template.ytic1.x2 = template.data.x2\n", "grey2 = vcs.createline()\n", "grey2.color = [(40, 40, 40),]\n", "grey2.width = [2,]\n", "template.ytic1.line = grey2.name # uses line name\n", "\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Second set of major ticks (x/y)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# x major tick marks for second set of tick marks (2) drawn outward in red\n", "template.xtic2.priority=1 # turn on\n", "template.xtic2.y1 = template.data.y2\n", "template.xtic2.y2 = template.data.y2 + .01 # extend a bit further\n", "template.xtic2.line=\"red\"\n", "\n", "# y major for second set of tick marks (2) drawn outward in red\n", "template.ytic2.priority=1 # turn on\n", "template.ytic2.x1 = template.data.x2\n", "template.ytic2.x2 = template.data.x2 + .01 # extends a bit past it\n", "template.ytic2.line = \"red\"\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Minor ticks (x/y)\n", "[Back to top](#top)\n", "\n", "Let's do the same for the minor tics or mintics, except using dotted lines and not extending them as far." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# x minor tick marks (set 1) drawn all the way across with grey lines\n", "template.xmintic1.priority = 1\n", "template.xmintic1.y1 = template.data.y1\n", "template.xmintic1.y2 = template.data.y2\n", "grey = vcs.createline(source=grey.name)\n", "grey.type= [\"dot\",]\n", "template.xmintic1.line = grey # re-uses line object\n", "\n", "# y minor (set 1) drawn all the way across using darker grey lines\n", "template.ymintic1.priority = 1\n", "template.ymintic1.x1 = template.data.x1\n", "template.ymintic1.x2 = template.data.x2\n", "grey2 = vcs.createline(source=grey2.name)\n", "grey2.type= [\"dot\",]\n", "template.ymintic1.line = grey2.name # uses line name\n", "\n", "# x minor tick marks (set 2) drawn outward in red (a bit less)\n", "template.xmintic2.priority=1 # turn on\n", "template.xmintic2.y1 = template.data.y2\n", "template.xmintic2.y2 = template.data.y2 + .005 # extend a bit further\n", "template.xmintic2.line=\"red\"\n", "\n", "# y minor (set 2) drawn outward in red\n", "template.ymintic2.priority=1 # turn on\n", "template.ymintic2.x1 = template.data.x2\n", "template.ymintic2.x2 = template.data.x2 + .005 # extends a bit past it\n", "template.ymintic2.line = \"red\"\n", "\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# too many tics; let's reduce their number\n", "box = vcs.createboxfill()\n", "box.xticlabels1 = {-180:\"180W\", -90:\"90W\", 0:\"0\", 90:\"90E\", 180:\"180E\", 270:\"270E\", 360:\"0\"}\n", "box.xticlabels2 = box.xticlabels1 # same on both ends\n", "box.yticlabels1 = {-90:\"90S\", -60:\"60S\", 0:\"Eq\", 60:\"60N\", 90:\"90N\"}\n", "box.yticlabels2 = box.yticlabels1\n", "\n", "# min ticks\n", "box.xmtics1 = {-135:\"135W\", -45:\"45W\", 45:\"45E\", 135:\"135E\", 315:\"315E\"}\n", "box.xmtics2 = box.xmtics1\n", "box.ymtics1 = {-45:\"45S\", 45:\"45N\"} # text does not matter as not drawn\n", "box.ymtics2 = box.ymtics1\n", "\n", "x.clear()\n", "x.plot(data, box, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Axes Labels\n", "[Back to top](#top)\n", "\n", "Now we also need to move the actual values on the major tick marks. These are controlled via \n", "`xlabel1`, `xlabel2`, `ylabel`, `ylabel2`.\n", "\n", "Attributes on these are:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.xlabel1.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `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.\n", "* `y`: location of the label in the vertical direction (in % of canvas).\n", "* `texttable`: vcs **texttable** object or name.\n", "* `textorientation`: vcs **textorientation** object or name.\n", "\n", " For more info on `texttable` and `textorientation` please see [the vcs text objects notebook](https://cdat.llnl.gov/Jupyter/VCS_Text_Objects/VCS_Text_Objects.html).\n", "\n", "##### First set of labels" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "text = vcs.createtext()\n", "text.font = \"Courier\"\n", "text.color = \"blue\"\n", "text.angle = -45\n", "\n", "template.xlabel1.priority=1\n", "template.xlabel1.texttable = text.Tt_name\n", "template.xlabel1.textorientation = text.To_name\n", "template.xlabel1.y = template.data.y1 - .03\n", "\n", "text = vcs.createtext()\n", "text.font = \"Times\"\n", "text.color = \"salmon\"\n", "text.angle = -90\n", "\n", "template.ylabel1.priority=1\n", "template.ylabel1.texttable = text.Tt_name\n", "template.ylabel1.textorientation = text.To_name\n", "template.ylabel1.x = template.data.x1 - .01\n", "\n", "x.clear()\n", "x.plot(data, template, box)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Second set of labels" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "text = vcs.createtext()\n", "text.font = \"Courier\"\n", "text.color = \"red\"\n", "text.angle = -45\n", "text.halign=\"right\"\n", "text.valign=\"top\"\n", "\n", "template.xlabel2.priority=1\n", "template.xlabel2.texttable = text.Tt_name\n", "template.xlabel2.textorientation = text.To_name\n", "template.xlabel2.y = template.data.y2 + .04\n", "\n", "text = vcs.createtext()\n", "text.font = \"Adelon\"\n", "text.color = \"pink\"\n", "text.angle = 90\n", "\n", "template.ylabel2.priority=1\n", "template.ylabel2.texttable = text.Tt_name\n", "template.ylabel2.textorientation = text.To_name\n", "template.ylabel2.x = template.data.x2 + .01\n", "\n", "x.clear()\n", "x.plot(data, template, box)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Axis names\n", "[Back to top](#top)\n", "\n", "The position of the axes is controlled via the `xname` and `yname` attributes.\n", "\n", "Their attributes are:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.xname.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `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.\n", "* `x`: location of the label in the horizontal direction (in % of canvas).\n", "* `y`: location of the label in the vertical direction (in % of canvas).\n", "* `texttable`: vcs **texttable** object or name.\n", "* `textorientation`: vcs **textorientation** object or name.\n", "\n", " For more info on `texttable` and `textorientation` please see [the vcs text objects notebook](https://cdat.llnl.gov/Jupyter/VCS_Text_Objects/VCS_Text_Objects.html).\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "text = vcs.createtext()\n", "text.color = \"blue\"\n", "text.height = 15\n", "text.halign = \"center\"\n", "text.font = \"Courier\"\n", "\n", "template.xname.x = (template.data.x1 + template.data.x2) / 2.\n", "template.xname.y = template.data.y1 -.05\n", "template.xname.texttable = text.Tt_name\n", "template.xname.textorientation = text.To_name\n", "template.xname.x = (template.data.x1 + template.data.x2) / 2.\n", "template.xname.y = template.data.y1 -.06\n", "\n", "text = vcs.createtext()\n", "text.color = \"salmon\"\n", "text.height = 25\n", "text.valign = \"half\"\n", "text.halign = \"center\"\n", "text.angle = -90\n", "text.font = \"Times\"\n", "template.yname.texttable = text.Tt_name\n", "template.yname.textorientation = text.To_name\n", "template.yname.x = template.data.x1 -.04\n", "template.yname.y = (template.data.y1 + template.data.y2) / 2. \n", "\n", "x.clear()\n", "x.plot(data, box, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Legend attribute\n", "[Back to top](#top)\n", "\n", "Now we need to move the legend bar. This is done via the `legend` attribute. Its attributes are:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.legend.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `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.\n", "* `x1`: start of the legend box in the horizontal direction (in % of canvas).\n", "* `x2`: end of the legend box in the horizontal direction (in % of canvas).\n", "* `y1`: start of the legend box in the vertical direction (in % of canvas).\n", "* `y2`: end of the legend box in the vertical direction (in % of canvas).\n", "* `texttable`: vcs **texttable** object or name.\n", "* `textorientation`: vcs **textorientation** object or name.\n", "* `offset`: how far from the bar the text should be (in % of canvas).\n", "\n", " For more info on `texttable` and `textorientation` please see [the vcs text objects notebook](https://cdat.llnl.gov/Jupyter/VCS_Text_Objects/VCS_Text_Objects.html).\n", "\n", "Depending on whether the legend is horizontal/vertical, the `x1`/`y1` attributes determine the side where the legend will be drawn.\n", "\n", "The legend labels themselves are controlled via the graphic method's `legend` attribute.\n", "\n", "Let's have a vertical legend with labels on the right side." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.legend.x1 = template.data.x2 + .08\n", "template.legend.x2 = template.data.x2 + .06\n", "template.legend.y1 = template.data.y1 + .02\n", "template.legend.y2 = template.data.y2 - .02\n", "text = vcs.createtext()\n", "text.color = \"cyan\"\n", "text.height=12\n", "text.angle=-45\n", "template.legend.texttable = text.Tt_name\n", "template.legend.textorientation = text.To_name\n", "template.legend.offset = .015\n", "\n", "box.legend = {220:\"Cold\", 320:\"HOT!\", 270:\"Mild\"}\n", "x.clear()\n", "x.plot(data, template, box)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Text controlling attributes\n", "[Back to top](#top)\n", "\n", "In addition, the template lets you display elements associated with the data itself.\n", "\n", "All the following attributes have the same set of their own attributes:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.dataname.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* `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.\n", "* `x`: text position in the horizontal direction (in % of canvas).\n", "* `y`: text position in the vertical direction (in % of canvas).\n", "* `texttable`: vcs **texttable** object or name.\n", "* `textorientation`: vcs **textorientation** object or name.\n", "\n", " For more info on `texttable` and `textorientation` please see [the vcs text objects notebook](https://cdat.llnl.gov/Jupyter/VCS_Text_Objects/VCS_Text_Objects.html)\n", "\n", "### Elements Controlled by Data Values\n", "[Back to top](#top)\n", "\n", "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.\n", "\n", "The `mean` value is plotted as follows:\n", "\n", "* Does the data have a `mean` attribute? If yes, use this.\n", "* Try to apply `cdutil.averager(data)`. If passes, use this.\n", "* Everything else failed: use `numpy.ma.average(data)`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.max.x = template.data.x2 + .2\n", "template.max.y = template.data.y2\n", "template.min.x = template.data.x2 + .2\n", "template.min.y = template.max.y - .03\n", "template.mean.x = template.data.x2 + .2\n", "template.mean.y = template.min.y - .03\n", "\n", "x.clear()\n", "x.plot(data, box, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Elements Controlled by Data Attributes\n", "[Back to top](#top)\n", "\n", "The main ones are:\n", "\n", "`source`, `dataname`, `title`, `units`.\n", "\n", "The following are legacy convenience attributes from the time when VCS was a GUI only. They are:\n", "\n", "`file`, `function`, `logicalmask`, `transformation`, `comment1`, `comment2`, `comment3`, `comment4`.\n", "\n", "\n", "Here is the mapping of these attributes to the attribute on the data:\n", "\n", "`dataname` $\\leftarrow$ $\\rightarrow$ `id`\n", "\n", "`title` $\\leftarrow$ $\\rightarrow$ `long_name`\n", "\n", "`source` $\\leftarrow$ $\\rightarrow$ `source`\n", "\n", "`units` $\\leftarrow$ $\\rightarrow$ `units`\n", "\n", "`file` $\\leftarrow$ $\\rightarrow$ `file`\n", "\n", "`function` $\\leftarrow$ $\\rightarrow$ `function`\n", "\n", "`logicalmask` $\\leftarrow$ $\\rightarrow$ `logicalmask`\n", "\n", "`transformation` $\\leftarrow$ $\\rightarrow$ `transformation`\n", "\n", "`comment1` $\\leftarrow$ $\\rightarrow$ `comment1`\n", "\n", "`comment2` $\\leftarrow$ $\\rightarrow$ `comment2`\n", "\n", "`comment3` $\\leftarrow$ $\\rightarrow$ `comment3`\n", "\n", "`comment4` $\\leftarrow$ $\\rightarrow$ `comment4`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data.id = \"DATANAME\"\n", "data.long_name = \"TITLE HERE\"\n", "template.dataname.x = template.data.x2 + .3\n", "template.dataname.y = template.data.y2\n", "\n", "for i, att in enumerate(\"source title units file function logicalmask transformation comment1 comment2 comment3 comment4\".split()):\n", " attr = getattr(template,att)\n", " attr.priority = 1\n", " attr.x = template.dataname.x\n", " attr.y = template.dataname.y - (i+1)*.025\n", " setattr(data,att, \"{} HERE\".format(att.upper()))\n", "\n", "x.clear()\n", "x.plot(data, box, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Elements Controlled by the Attributes of the Data's Axes\n", "[Back to top](#top)\n", "\n", "The following text values are determined based on the values of the input array axes.\n", "\n", "`xname`, `yname`, `ztname`, `tname`,\n", "`xunits`, `yunits`, `zunits`, `tunits`,\n", "`xvalue`, `yvalue`, `zvalue`, `tvalue`,\n", "`crdate`, `crtime`\n", "\n", "Where `x`, `y`, `z`, `t` represent the axes from the last index:\n", "\n", "`x` $\\leftarrow$ $\\rightarrow$ `data.getAxis(-1)`\n", "\n", "`y` $\\leftarrow$ $\\rightarrow$ `data.getAxis(-2)`\n", "\n", "`z` $\\leftarrow$ $\\rightarrow$ `data.getAxis(-3)`\n", "\n", "`t` $\\leftarrow$ $\\rightarrow$ `data.getAxis(-4)`\n", "\n", "\n", "`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}`) " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "for i, axis in enumerate([\"x\",\"y\",\"z\",\"t\"]):\n", " ax = data.getAxis(-i-1)\n", " print(\"Ax.id, units, val\", ax.id, ax.units, ax[0])\n", " for j, attribute in enumerate([\"name\",\"units\", \"value\"]):\n", " att = \"{}{}\".format(axis,attribute)\n", " if att in [\"xname\", \"yname\"]: # we already touched these\n", " continue\n", " obj = getattr(template,att)\n", " obj.priority = 1\n", " obj.x = template.data.x1 + (i+1)*.2\n", " obj.y = template.data.y1 - (j+2)*.05\n", " #obj.list()\n", "\n", "template.crdate.x = template.tunits.x\n", "template.crdate.y = template.tvalue.y - 0.05\n", "template.crtime.x = template.crdate.x\n", "template.crtime.y = template.crdate.y - 0.05\n", "\n", "\n", "x.clear()\n", "x.plot(data, template, box)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lines and Boxes\n", "\n", "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.\n", "\n", "Their attributes are:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.box1.list()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Template Utilities\n", "[Back to top](#top)\n", "\n", "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.\n", "\n", "\n", "### Scaling Functions\n", "\n", "The following functions allow you to scale all of a template's elements.\n", "\n", "#### scale\n", "\n", "Signature: template.scale(scale, axis='xy', font=-1)\n", "\n", "Scale a template along the axis 'x' or 'y' by scale defaults to 'xy' (both).\n", "Values of scale greater than 1 mean increase.\n", "The reference point is the template's x1 and y1 data. (i.e. this point will be unchanged).\n", "Fonts are scaled as well but can be left untouched." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template.scale(.5)\n", "x.clear()\n", "x.plot(data,template)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Now, not touching the fonts\n", "template = vcs.createtemplate()\n", "template.scale(.5,font=0)\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### scalefont\n", "\n", "We can scale the font at a later time." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template.scalefont(.7)\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### ratio\n", "\n", "Alternatively we can ask the template to get a specific ratio for the data area.\n", "\n", "The ratio means the y direction will be `ratio` times the x direction.\n", "\n", "The `box_and_ticks` option also scales box and ticks, or not (default on)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template.ratio(2)\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# we can also NOT scale ticks\n", "template = vcs.createtemplate()\n", "template.ratio(2, box_and_ticks=False)\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### moving functions\n", "[Back to top](#top)\n", "\n", "Once a template is scaled, we can then move it somewhere else.\n", "\n", "#### move\n", "\n", "Move a template by % along the axis 'x' or 'y'.\n", "Positive values of p mean movement toward right/top.\n", "Negative values of p mean movement toward left/bottom.\n", "The reference point is t.data.x1/y1" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template.scale(.5,font=False)\n", "template.scalefont(.8)\n", "template.move(.25,'x')\n", "template.move(.25,'y')\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### moveto\n", "\n", "Sometimes it is preferable to move to a destination point rather than a percent (%).\n", "\n", "Here the data x1/y1 will be moved to this location." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template.scale(.5,font=False)\n", "template.scalefont(.8)\n", "template.moveto(.5, .1)\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Plot Functions (Advanced Users)\n", "[Back to top](#top)\n", "\n", "#### drawColorBar\n", "\n", "This function draws the colorbar. It needs:\n", "\n", "* colors : The colors to be plotted.\n", "* levels : The levels that each color represents.\n", "* legend : Draw a box at certain values and display some specific text instead of the value. (This will overwrite the existing legend.)\n", "* ext_1 and ext_2: to draw the arrows.\n", "* x : the canvas, where to plot it." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "x.clear()\n", "template.drawColorBar([\"red\",\"white\", \"blue\",\"green\"],\n", " [0,50, 100, 1.e20],\n", " {0:\"EMPTY\", 50:\"HALF\", 100:\"FULL\"},\n", " ext_2=True, x=x)\n", "template2 = vcs.createtemplate()\n", "template2.legend.priority = 0\n", "x.plot(data,template2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### drawLinesAndMarkersLegend\n", "\n", "This function allows users to draw a legend box with lines and markers.\n", "\n", "Draws a legend with line/marker/text inside a template legend box.\n", "Auto adjusts text size to make it fit inside the box.\n", "Auto arranges the elements to fill the box nicely.\n", "\n", "\n", "template.drawLinesAndMarkersLegend(\n", " ['canvas', 'linecolors', 'linetypes', 'linewidths', 'markercolors', 'markertypes', 'markersizes', 'strings', 'scratched=None', 'stringscolors=None', \"stacking='horizontal'\", 'bg=False', 'render=True', 'smallestfontsize=None', 'backgroundcolor=None'],\n", ")\n", "\n", "\n", "* canvas: a VCS canvas object onto which to draw the legend\n", "* linecolors: A list containing the colors of each line to draw.\n", " Colors are represented as either an integer from 0-255, an RGBa tuple,\n", " or a string color name.\n", "* linetypes: A list containing the type of each line to draw.\n", " Line types are represented as either integers or strings.\n", " See :py:class:`vcs.line.Tl` for more information.\n", "* linewidths: A list containing numbers in float format representing the\n", " width of each line.\n", "* markercolors: A list of the marker colors to draw.\n", " Colors are represented as either an integer from 0-255, an RGBa tuple,\n", " or a string color name.\n", "* markertypes: A list of the marker types to draw.\n", " Marker types are represented as either integers or strings.\n", " See :py:class:`vcs.marker.Tm` for more information.\n", "* markersizes: A list of numbers in float format representing marker sizes.\n", "* strings: A list of strings to draw next to each line/marker.\n", "* scratched: A list indicating which strings should be \"scratched\"\n", " off in the template.\n", "\n", " To \"scratch\" a string, the corresponding location in the scratched\n", " list must contain either True or the line type to use for the\n", " scratch. A value of False at a given index will leave the\n", " corresponding index of strings untouched.\n", "\n", " Size of the scratched list must be equal to the size of the strings\n", " list.\n", "\n", " Scratch color will match that of text.\n", "\n", " If scratched is None, or is not provided, no strings will be\n", " scratched.\n", "* stringscolors: A list of the string colors to draw.\n", " Colors are represented as either an integer from 0-255, an RGBa tuple,\n", " or a string color name.\n", "* stacking: Prefered direction to stack element ('horizontal' or 'vertical')\n", "* bg: Boolean value indicating whether or not to draw in the\n", " background. Defaults to False.\n", "* render: Boolean value indicating whether or not to render.\n", " Defaults to True.\n", "* smallestfontsize: Integer value indicating the smallest font size we can use for rendering\n", " None means no limit, 0 means use original size. Downscaling will still be used by algorigthm\n", " to try to fit everything in the legend box.\n", "* backgroundcolor: A list indicating the background color of the legend box.\n", " Colors are represented as either an integer from 0-255, an RGBa tuple,\n", " or a string color name." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template2.scale(.5)\n", "x.clear()\n", "l_colors=[\"red\",\"blue\",\"green\"]\n", "l_types=[\"solid\",\"dash\",\"dot\"]\n", "l_widths=[1,4,2]\n", "m_colors=[\"blue\",\"green\",\"red\"]\n", "m_types=[\"cross\",\"square\",\"dot\"]\n", "m_sizes=[1,2,.5]\n", "strings=[\"sample A\",\"type B\",\"thing C\"]\n", "scratch=[True,False,True]\n", "background = 'grey'\n", "template.legend.x1 = .85\n", "template.legend.x2 = .99\n", "template.legend.y1 = .2\n", "template.legend.y2 = .8\n", "template.drawLinesAndMarkersLegend(x, l_colors, l_types, l_widths,\n", " m_colors, m_types, m_sizes, strings, scratch,\n", " backgroundcolor=background)\n", "x.plot(data,template2)\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Miscellaneous functions\n", "[Back to top](#top)\n", "\n", "#### blank\n", "\n", "The blank function allows users to set the priority of several template attributes at once. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template.blank([\"mean\", \"crdate\", \"crtime\", \"min\", \"dataname\"])\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If no attributes are passed, then everything is turned off except for `data`." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "template = vcs.createtemplate()\n", "template.blank()\n", "x.clear()\n", "x.plot(data, template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Special Case: Taylor Diagrams\n", "[Back to top](#top)\n", "\n", "Taylor Diagrams are controlled a bit differently. The default template used for Taylor Diagrams is: `deftaylor`.\n", "\n", "The image below describes how elements of a Taylor Diagram are controlled by the template:\n", "\n", "\n", "\n", "For more on Taylor Diagrams, please see the [Taylor Diagram Tutorial](https://cdat.llnl.gov/Jupyter/Taylor_Diagrams/Taylor_Diagrams.html).\n", "\n", "\n", "## VCS Addons\n", "[Back to top](#top)\n", "\n", "The VCS Addons provide a few utilities to help with templates.\n", "\n", "### Multiple Rows and Columns\n", "\n", "This package allows you to easily create templates for multiple rows/columns.\n", "\n", "Let's display the first 6 plots." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import vcsaddons\n", "x.clear()\n", "template = vcs.createtemplate()\n", "template.blank([\"transformation\", \"source\", \"dataname\", \"function\", \"logicalmask\",\n", " \"comment1\", \"comment2\", \"comment3\" ,\"comment4\", \"title\", \"file\"])\n", "Multi = vcsaddons.EzTemplate.Multi(rows=2, columns=3, template=template)\n", "Multi.spacing.horizontal = .08\n", "Multi.spacing.vertical = .1\n", "Multi.margins.bottom = .2 # lots of space at bottom\n", "local_legend = [\"global\", \"local\", None, \"local\", \"local\", None]\n", "for i in range(6):\n", " mytemplate = Multi.get(column=i%3, row=i//3, fontlimit=.8, legend=local_legend[i])\n", " d = x.plot(data[i], mytemplate)\n", "d" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Line (Spaghetti) Plots\n", "\n", "\n", "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.\n", "\n", "The EzPlot module helps with this.\n", "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import os\n", "import cdutil\n", "import math\n", "import random\n", "import vcsaddons.EzPlot\n", "\n", "x.clear()\n", "# Simple Plot with EzPlot\n", "\n", "\n", "variables = []\n", "line_type = []\n", "line_widths = []\n", "legend_texts = []\n", "legend_text_colors = []\n", "marker_type = []\n", "\n", "for v in range(0, 20):\n", " var = []\n", " for i in range(0, 100):\n", " if v%2 == 0:\n", " #var.append(random.random() * v * math.sin(2*math.pi*float(i-v)/100.0))\n", " var.append(v * math.sin(2*math.pi*float(i-v)/100.0))\n", " else:\n", " #var.append(random.random() * v * math.cos(2*math.pi*float(i-v)/100.0))\n", " var.append(v * math.cos(2*math.pi*float(i-v)/100.0))\n", " line_type += [\"solid\"]\n", " line_widths += [5]\n", " if i%2 == 0:\n", " legend_texts += [\"Sin\"]\n", " else: \n", " legend_texts += [\"Cos\"]\n", " legend_text_colors += ['black']\n", " marker_type += [None]\n", " variables.append(var)\n", "\n", "plotfunction = vcsaddons.EzPlot.EzLinePlot()\n", "\n", "d = plotfunction.lineplot(data=variables, canvas=x, title=\"Simple 2 EzLinePlot\", titlesize=30,\n", " #backgroundcolor=[0, 100, 0],\n", " linetypes=line_type, linewidths=line_widths,\n", " legendposition=[0.25, 0.35, 0.30, 0.40], legendtextcolors=legend_text_colors, \n", " legendtexts=legend_texts,\n", " legendbackgroundcolor=\"yellow\",\n", " enablegrid=True)\n", "\n", "d" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": false, "sideBar": false, "skip_h1_title": true, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": true, "toc_position": { "height": "520.8px", "left": "984px", "top": "143px", "width": "268.8px" }, "toc_section_display": false, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }