"""
=====================================
VCS: Visualization and Control System
=====================================
-------
Authors
-------
Creator: `Dean Williams`_ (LLNL, AIMS Team)
Lead Developer: `Charles Doutriaux`_ (LLNL, AIMS Team)
Contributors: https://github.com/CDAT/cdat/graphs/contributors
Support Email: cdat-support@llnl.gov
Project Site: http://cdat.llnl.gov/
Project Repo: https://github.com/CDAT/cdat/graphs/contributors
.. _Dean Williams: http://computation.llnl.gov/about/our-people/highlights/dean-williams
.. _Charles Doutriaux: https://github.com/doutriaux1
-----------
Description
-----------
VCS is a visualization library for scientific data. It has a simple
model for defining a plot, that is decomposed into three parts:
1. **Data**: If it's iterable, we'll plot it... or at least try!
Currently we support numpy arrays, lists (nested and not),
and CDMS2 variables (there's some special support for metadata
from CDMS2 that gives some niceties in your plot, but it's not
mandatory).
2. **Graphics Method**: We have a variety of plot types that we
support out-of-the box; you can easily customize every aspect
of them to create the effect that you're looking for. If you can't,
we also support defining your own graphics methods, which you can
share with other users using standard python infrastructure (conda, pip).
3. **Template**: Templates control the appearance of everything that
*isn't* your data. They position labels, control fonts, adjust borders,
place legends, and more. They're very flexible, and give the fine-grained
control of your plot that is needed for the truly perfect plot. Once you've
customized them, you can also save them out for later use, and distribute
them to other users.
"""
import warnings
import difflib
import pkg_resources
vcs_egg_path = pkg_resources.resource_filename(pkg_resources.Requirement.parse("vcs"), "share/vcs")
class bestMatch(object):
def __setattr__(self, a, v):
try:
prop = getattr(self.__class__, a)
isprop = isinstance(prop, property)
except Exception:
isprop = False
if isprop or not hasattr(self, "__slots__") or a in self.__slots__:
super(bestMatch, self).__setattr__(a, v)
else:
props = []
for attr in dir(self.__class__):
if isinstance(getattr(self.__class__, attr), property):
props.append(attr)
possible = self.__slots__ + props
matches = difflib.get_close_matches(a, possible)
real_matches = []
for m in matches:
if m[0] != "_":
real_matches.append(m)
if len(real_matches) == 1:
raise AttributeError(
"'%s' object has no attribute '%s' did you mean %s ?" %
(self.__class__.__name__, a, repr(real_matches[0])))
elif len(real_matches) > 1:
raise AttributeError(
"'%s' object has no attribute '%s' did you mean one of %s ?" %
(self.__class__.__name__, a, repr(real_matches)))
else:
raise AttributeError(
"'%s' object has no attribute '%s' valid attributes are: %s" %
(self.__class__.__name__, a, repr(
self.__slots__)))
[docs]class VCSDeprecationWarning(DeprecationWarning):
pass
# Python < 3 DeprecationWarning ignored by default
# warnings.simplefilter('default')
warnings.simplefilter("default", VCSDeprecationWarning)
warnings.filterwarnings('ignore', message="Conversion of the second argument of issubdtype from `complex")
warnings.filterwarnings('ignore', message="Using a non-tuple sequence for multidimensional indexing")
_doValidation = True
next_canvas_id = 1
import cdat_info # noqa
prefix = cdat_info.get_prefix()
sample_data = cdat_info.get_sampledata_path()
from .utils import * # noqa
from . import colors # noqa
from . import Canvas # noqa
from .vcshelp import * # noqa
from .queries import * # noqa
from . import install_vcs # noqa
import os # noqa
from .manageElements import * # noqa
import collections # noqa
_colorMap = "viridis"
_default_time_units = 'days since 2000'
#
#
# Set up the User's directory if necessary. Copy files from #
# $PYTHONHOME/bin to the newly created $HOME/.uvcdat directory. #
#
#
install_vcs._files()
#
#
# Set the user's XGKSFontDir environment variable. #
#
#
elements = collections.OrderedDict()
elements["list"] = {}
elements["projection"] = {}
elements["texttable"] = {}
elements["textorientation"] = {}
elements["textcombined"] = {}
elements["line"] = {}
elements["marker"] = {}
elements["fillarea"] = {}
elements["font"] = {}
elements["fontNumber"] = {}
elements["boxfill"] = {}
elements["isofill"] = {}
elements["isoline"] = {}
elements["meshfill"] = {}
elements["3d_scalar"] = {}
elements["3d_dual_scalar"] = {}
elements["3d_vector"] = {}
elements["template"] = {}
elements["taylordiagram"] = {}
elements["1d"] = {}
elements["vector"] = {}
elements["streamline"] = {}
elements["yxvsx"] = {}
elements["xyvsy"] = {}
elements["xvsy"] = {}
elements["scatter"] = {}
elements["colormap"] = {}
elements["display"] = {}
elements["format"] = {}
_protected_elements = {}
for k in list(elements.keys()):
_protected_elements[k] = set()
dic = {}
for i in range(-5, 5):
for j in range(-180, 181, 30):
if j < 0:
dic[i * 360 + j] = "%iW" % (-j)
elif j > 0:
dic[i * 360 + j] = "%iE" % j
else:
dic[i * 360] = "0"
elements["list"]["Lon30"] = dic
dic = {}
for j in range(-80, 81, 20):
if j < 0:
dic[j] = "%iS" % (-j)
elif j > 0:
dic[j] = "%iN" % j
else:
dic[0] = "Eq"
dic[-90] = "90S"
dic[90] = "90N"
elements["list"]["Lat20"] = dic
elements["list"]["Lat_wt"] = {-90.: "90S", -60: "60S", -45: "45S", -30: "30S", -15: "15S",
0: "Eq",
15: "15N", 30: "30S", 45: "45N", 60: "60N", 90: "90N"}
i = 1
for nm, fnt in [
("default", "AvantGarde-Book_Bold.ttf"),
("Clarendon", "Clarendon.ttf"),
("Courier", "Courier.ttf"),
("Helvetica", "HelvMono.ttf"),
("Adelon", "Adelon_Regular.ttf"),
("Times", "Times_CG_ATT.ttf"),
("Arabic", "Arabic.ttf"),
("Chinese", "Chinese_Generic1.ttf"),
("Greek", "Athens_Greek.ttf"),
("Hebrew", "hebrew.ttf"),
("Russian", "Russian.ttf"),
("Maths1", "jsMath-msam10.ttf"),
("Maths2", "blex.ttf"),
("Maths3", "jsMath-wasy10.ttf"),
("Maths4", "blsy.ttf"),
("AvantGarde", "AvantGarde-Book_Bold.ttf"),
("DejaVuSans-Bold", "DejaVuSans-Bold.ttf"),
("DejaVuSans-BoldOblique", "DejaVuSans-BoldOblique.ttf"),
("DejaVuSans-ExtraLight", "DejaVuSans-ExtraLight.ttf"),
("DejaVuSans-Oblique", "DejaVuSans-Oblique.ttf"),
("DejaVuSans", "DejaVuSans.ttf"),
("DejaVuSansCondensed-Bold", "DejaVuSansCondensed-Bold.ttf"),
("DejaVuSansCondensed-BoldOblique", "DejaVuSansCondensed-BoldOblique.ttf"),
("DejaVuSansCondensed-Oblique", "DejaVuSansCondensed-Oblique.ttf"),
("DejaVuSansCondensed", "DejaVuSansCondensed.ttf"),
]:
pth = os.path.join(
vcs_egg_path,
"fonts",
fnt)
if os.path.exists(pth):
vcs.elements["font"][nm] = pth
vcs.elements["fontNumber"][i] = nm
i += 1
p = projection.Proj("default")
p = projection.Proj("linear")
line.Tl("default")
line.Tl("solid")
line.Tl("deftaylordot")
line.type = ["dot"]
texttable.Tt("default")
textorientation.To("default")
to = textorientation.To("defcenter")
to.halign = "center"
to = textorientation.To("defup")
to.angle = -90
to.valign = "half"
to.halign = "center"
to = textorientation.To("defcentup")
to.angle = -90
to.valign = "half"
to.halign = "center"
to = textorientation.To("defright")
to.halign = "right"
boxfill.Gfb("default")
isofill.Gfi("default")
isoline.Gi("default")
unified1D.G1d("default")
yx = unified1D.G1d("default_yxvsx_")
vcs.elements["yxvsx"]["default"] = yx
xy = unified1D.G1d("default_xyvsy_")
xy.flip = True
vcs.elements["xyvsy"]["default"] = xy
sc = unified1D.G1d("default_scatter_")
sc._linewidth = 0
vcs.elements["scatter"]["default"] = sc
xvy = unified1D.G1d("default_xvsy_")
vcs.elements["xvsy"]["default"] = xvy
vector.Gv("default")
streamline.Gs("default")
marker.Tm("default")
meshfill.Gfm("default")
colormap.Cp("default")
displayplot.Dp("default")
dv3d.Gf3Dvector("default")
dv3d.Gf3Dscalar("default")
dv3d.Gf3Dscalar("Hovmoller3D")
dv3d.Gf3DDualScalar("default")
# formats
# see: https://pyformat.info/
elements["format"]["default"] = ""
# old % style equivalents
elements["format"]["d"] = ""
elements["format"]["s"] = "0!s"
elements["format"]["r"] = "0!r"
elements["format"]["a"] = "0!a"
elements["format"]["g"] = ":g"
elements["format"]["G"] = ":G"
# convenience and thier old style?
elements["format"]["0padded2digint"] = ":02d"
elements["format"]["02d"] = ":02d"
elements["format"]["0padded3digint"] = ":03d"
elements["format"]["03d"] = ":03d"
elements["format"]["0padded4digint"] = ":04d"
elements["format"]["04d"] = ":04d"
elements["format"]["spacepadded2digint"] = ":2d"
elements["format"]["2d"] = ":2d"
elements["format"]["spacepadded3digint"] = ":3d"
elements["format"]["3d"] = ":3d"
elements["format"]["spacepadded4digint"] = ":4d"
elements["format"]["4d"] = ":4d"
elements["format"]["float2dig"] = ":.2f"
elements["format"]["2f"] = ":.2f"
elements["format"]["float3dig"] = ":.3f"
elements["format"]["3f"] = ":.3f"
on = {'state': 1}
off = {'state': 0}
for nm in ["mercator", "orthographic", "lambert", "polar", "polyconic", "robinson",
"mollweide", ]:
p = projection.Proj(nm)
if nm == "polar":
p.type = -3
else:
p.type = nm
fillarea.Tf("default")
template.P("default")
t = taylor.Gtd("default")
pth = [vcs_egg_path, 'initial.attributes']
try:
vcs.scriptrun(os.path.join(*pth))
except BaseException:
pass
for typ in list(elements.keys()):
elts = elements[typ]
for k in vcs.listelements(typ): # let's save which elements should be saved and untouched
_protected_elements[typ].add(k)
_dotdir, _dotdirenv = vcs.getdotdirectory()
user_init = os.path.join(
os.path.expanduser("~"),
_dotdir,
'initial.attributes')
if os.path.exists(user_init):
vcs.scriptrun(user_init)
canvaslist = []
[docs]def init(mode=1, pause_time=0, call_from_gui=0, size=None, backend="vtk",
geometry=None, bg=None, display_target=None):
"""Initialize and construct a VCS Canvas object.
:Example:
.. doctest:: vcs_init
>>> import vcs
>>> portrait = vcs.init(size=.5) # Portrait of 1 width per 2 height
>>> letter = vcs.init(size="letter") # also accepts "usletter"
>>> a4 = vcs.init(size="a4")
>>> import vtk
>>> my_win = vtk.vtkRenderWindow() # To embed VCS in other applications
>>> embedded = vcs.init(backend=my_win)
>>> dict_init = vcs.init(geometry={"width": 1200, "height": 600})
>>> tuple_init = vcs.init(geometry=(1200, 600))
>>> bg_canvas = vcs.init(bg=True)
:param size: Aspect ratio for canvas (width / height)
:param backend: Which VCS backend to use
:param geometry: Size (in pixels) you want the canvas to be.
:param bg: Initialize a canvas to render in "background" mode (without
displaying a window
:param: display_target: A jupyterlab notebook target object in which to render vcs pictures
(only works in jupyterlab), if you pass True will create a new one for you
sidecar gets attached to Canvas and can be reused for other Canvases to share it.
Pass "inline", "off", or "no" to disable the target feature
:type size: float or case-insensitive str
:type backend: str, :py:class:`vtk.vtkRenderWindow`
:type geometry: dict or tuple
:type bg: bool
:type display_target: None, str, :py:class:sidecar.sidecar.Sidecar
:return: An initialized canvas
:rtype: vcs.Canvas.Canvas
"""
canvas = Canvas.Canvas(
mode=mode,
pause_time=pause_time,
call_from_gui=call_from_gui,
size=size,
backend=backend,
geometry=geometry,
bg=bg,
display_target=display_target)
global canvaslist
canvaslist.append(canvas)
return canvas