def test_hash_omit_style(self): class N(Node): my_attr = tl.Int().tag(attr=True) n1 = N(my_attr=1, style=Style(name="a")) n2 = N(my_attr=1, style=Style(name="b")) # json has style in it assert n1.json != n2.json # but hash does not assert n1.hash == n2.hash
def test_eq_ignore_style(self): class N(Node): my_attr = tl.Int().tag(attr=True) n1 = N(my_attr=1, style=Style(name="a")) n2 = N(my_attr=1, style=Style(name="b")) # json has style in it assert n1.json != n2.json # but == and != don't care assert n1 == n2 assert not n1 != n2
def test_enumeration(self): # matplotlib enumeration tuples style = Style( enumeration_colors={ 1: "r", 3: "o" }, enumeration_legend={ 1: "apples", 3: "oranges" }, default_enumeration_color="k", ) assert style.full_enumeration_colors == ("r", "k", "o") assert style.full_enumeration_legend == ("apples", "unknown", "oranges") # negative key style = Style( enumeration_colors={ -1: "r", 1: "o" }, enumeration_legend={ -1: "apples", 1: "oranges" }, default_enumeration_color="k", ) assert style.full_enumeration_colors == ("r", "k", "o") assert style.full_enumeration_legend == ("apples", "unknown", "oranges") # invalid with pytest.raises( ValueError, match= "Style enumeration_legend keys must match enumeration_colors keys" ): style = Style(enumeration_colors={ 1: "r", 3: "o" }, enumeration_legend={1: "apples"}) with pytest.raises( TypeError, match="Style enumeration_legend requires enumeration_colors"): style = Style(enumeration_legend={-1: "apples", 3: "oranges"})
def test_eq(self): style1 = Style(name="test") style2 = Style(name="test") style3 = Style(name="other") assert style1 is not style2 assert style1 is not style3 assert style2 is not style3 assert style1 == style1 assert style2 == style2 assert style3 == style3 assert style1 == style2 assert style1 != style3
def test_cmap(self): style = Style() assert style.cmap.name == "viridis" style = Style(colormap="cividis") assert style.cmap.name == "cividis" style = Style(enumeration_colors=("c", "k")) assert style.cmap.name == "from_list" assert style.cmap.colors == ("c", "k") with pytest.raises( TypeError, match="Style can have a colormap or enumeration_colors"): style = Style(colormap="cividis", enumeration_colors=("c", "k"))
def test_serialization_deserialization(self): n_lats = 3 n_lons = 4 n_alts = 2 a = UnitsDataArray( np.arange(n_lats * n_lons * n_alts).reshape( (n_lats, n_lons, n_alts)), dims=["lat", "lon", "alt"], attrs={ "units": ureg.meter, "layer_style": Style() }, ) f = a.to_netcdf() b = UnitsDataArray(xr.open_dataarray(f)) assert a.attrs["units"] == b.attrs["units"] assert a.attrs["layer_style"].json == b.attrs["layer_style"].json
def test_serialization(self): # default style = Style() d = style.definition assert isinstance(d, OrderedDict) assert len(d.keys()) == 0 s = Style.from_json(style.json) assert isinstance(s, Style) # with traits style = Style(name="test", units="meters", colormap="cividis", clim=(-1, 1)) d = style.definition assert isinstance(d, OrderedDict) assert set(d.keys()) == {"name", "units", "colormap", "clim"} assert d["name"] == "test" assert d["units"] == "meters" assert d["colormap"] == "cividis" assert d["clim"] == [-1, 1] s = Style.from_json(style.json) assert s.name == style.name assert s.units == style.units assert s.colormap == style.colormap assert s.clim == style.clim # enumeration traits style = Style(enumeration_legend=({ 0: "apples", 1: "oranges" }), enumeration_colors=({ 0: "r", 1: "o" })) d = style.definition assert isinstance(d, OrderedDict) assert set(d.keys()) == {"enumeration_legend", "enumeration_colors"} assert d["enumeration_legend"] == {0: "apples", 1: "oranges"} assert d["enumeration_colors"] == {0: "r", 1: "o"} s = Style.from_json(style.json) assert s.enumeration_legend == style.enumeration_legend assert s.enumeration_colors == style.enumeration_colors assert s.cmap.colors == style.cmap.colors
def test_style(self): node = podpac.data.Array( source=[10, 20, 30], coordinates=podpac.Coordinates([[0, 1, 2]], dims=["lat"]), style=Style(name="test", units="m"), ) d = node.definition assert "style" in d[node.base_ref] node2 = Node.from_definition(d) assert node2 is not node assert isinstance(node2, podpac.data.Array) assert node2.style is not node.style assert node2.style == node.style assert node2.style.name == "test" assert node2.style.units == "m" # default style node = podpac.data.Array(source=[10, 20, 30], coordinates=podpac.Coordinates([[0, 1, 2]], dims=["lat"])) d = node.definition assert "style" not in d[node.base_ref]
def _default_style(self): return Style(clim=[-1.0, 1.0], colormap="jet")
def test_init(self): s = Style()
def from_definition(cls, definition): """ Create podpac Node from a dictionary definition. Arguments --------- d : dict node definition Returns ------- :class:`Node` podpac Node See Also -------- definition : node definition as a dictionary from_json : create podpac node from a JSON definition load : create a node from file """ if "podpac_version" in definition and definition[ "podpac_version"] != podpac.__version__: warnings.warn("node definition version mismatch " "(this node was created with podpac version '%s', " "but your current podpac version is '%s')" % (definition["podpac_version"], podpac.__version__)) if len(definition) == 0: raise ValueError("Invalid definition: definition cannot be empty.") # parse node definitions in order nodes = OrderedDict() for name, d in definition.items(): if name == "podpac_version": continue if "node" not in d: raise ValueError( "Invalid definition for node '%s': 'node' property required" % name) # get node class module_root = d.get("plugin", "podpac") node_string = "%s.%s" % (module_root, d["node"]) module_name, node_name = node_string.rsplit(".", 1) try: module = importlib.import_module(module_name) except ImportError: raise ValueError( "Invalid definition for node '%s': no module found '%s'" % (name, module_name)) try: node_class = getattr(module, node_name) except AttributeError: raise ValueError( "Invalid definition for node '%s': class '%s' not found in module '%s'" % (name, node_name, module_name)) # parse and configure kwargs kwargs = {} for k, v in d.get("attrs", {}).items(): kwargs[k] = v for k, v in d.get("inputs", {}).items(): kwargs[k] = _lookup_input(nodes, name, v) for k, v in d.get("lookup_attrs", {}).items(): kwargs[k] = _lookup_attr(nodes, name, v) if "style" in d: kwargs["style"] = Style.from_definition(d["style"]) for k in d: if k not in [ "node", "inputs", "attrs", "lookup_attrs", "plugin", "style" ]: raise ValueError( "Invalid definition for node '%s': unexpected property '%s'" % (name, k)) nodes[name] = node_class(**kwargs) return list(nodes.values())[-1]
def test_init_from_node(self): from podpac.core.node import Node node = Node() s = Style(node)
def test_base_definition_style(self): node = Node(style=Style(name="test")) d = node._base_definition assert "style" in node._base_definition
def test_basic_creation(self): s = Style()
def to_image(data, format="png", vmin=None, vmax=None, return_base64=False): """Return a base64-encoded image of data Parameters ---------- data : array-like data to output, usually a UnitsDataArray format : str, optional Default is 'png'. Type of image. vmin : number, optional Minimum value of colormap vmax : vmax, optional Maximum value of colormap return_base64: bool, optional Default is False. Normally this returns an io.BytesIO, but if True, will return a base64 encoded string. Returns ------- BytesIO/str Binary or Base64 encoded image. """ import matplotlib import matplotlib.cm from matplotlib.image import imsave with warnings.catch_warnings(): warnings.simplefilter("ignore") matplotlib.use("agg") if format != "png": raise ValueError("Invalid image format '%s', must be 'png'" % format) style = None if isinstance(data, xr.DataArray): style = data.attrs.get("layer_style", None) if isinstance(style, string_types): style = Style.from_json(style) dims = data.squeeze().dims y = data.coords[dims[0]] x = data.coords[dims[1]] data = data.data if y[1] > y[0]: data = data[::-1, :] if x[1] < x[0]: data = data[:, ::1] data = data.squeeze() if not np.any(np.isfinite(data)): vmin = 0 vmax = 1 else: if vmin is None or np.isnan(vmin): if style is not None and style.clim[0] != None: vmin = style.clim[0] else: vmin = np.nanmin(data) if vmax is None or np.isnan(vmax): if style is not None and style.clim[1] != None: vmax = style.clim[1] else: vmax = np.nanmax(data) if vmax == vmin: vmax += 1e-15 # get the colormap if style is None: cmap = matplotlib.cm.viridis else: cmap = style.cmap c = (data - vmin) / (vmax - vmin) i = cmap(c, bytes=True) i[np.isnan(c), 3] = 0 im_data = BytesIO() imsave(im_data, i, format=format) im_data.seek(0) if return_base64: return base64.b64encode(im_data.getvalue()) else: return im_data
def test_get_default_cmap(self): style = Style() style.cmap
def test_create_with_node(self): node = Node() s = Style(node)
def _style_default(self): return Style()
def from_definition(cls, definition): """ Create podpac Node from a dictionary definition. Arguments --------- d : dict node definition Returns ------- :class:`Node` podpac Node See Also -------- definition : node definition as a dictionary from_json : create podpac node from a JSON definition load : create a node from file """ if "podpac_version" in definition and definition["podpac_version"] != podpac.__version__: warnings.warn( "node definition version mismatch " "(this node was created with podpac version '%s', " "but your current podpac version is '%s')" % (definition["podpac_version"], podpac.__version__) ) if len(definition) == 0: raise ValueError("Invalid definition: definition cannot be empty.") # parse node definitions in order nodes = OrderedDict() for name, d in definition.items(): if name == "podpac_version": continue if "node" not in d: raise ValueError("Invalid definition for node '%s': 'node' property required" % name) # get node class module_root = d.get("plugin", "podpac") node_string = "%s.%s" % (module_root, d["node"]) module_name, node_name = node_string.rsplit(".", 1) try: module = importlib.import_module(module_name) except ImportError: raise ValueError("Invalid definition for node '%s': no module found '%s'" % (name, module_name)) try: node_class = getattr(module, node_name) except AttributeError: raise ValueError( "Invalid definition for node '%s': class '%s' not found in module '%s'" % (name, node_name, module_name) ) # parse and configure kwargs kwargs = {} for k, v in d.get("attrs", {}).items(): kwargs[k] = v for k, v in d.get("inputs", {}).items(): kwargs[k] = _lookup_input(nodes, name, v) for k, v in d.get("lookup_attrs", {}).items(): kwargs[k] = _lookup_attr(nodes, name, v) if "style" in d: style_class = getattr(node_class, 'style', Style) if isinstance(style_class, tl.TraitType): # Now we actually have to look through the class to see # if there is a custom initializer for style for attr in dir(node_class): atr = getattr(node_class, attr) if not isinstance(atr, tl.traitlets.DefaultHandler) or atr.trait_name != 'style': continue try: style_class = atr(node_class) except Exception as e: # print ("couldn't make style from class", e) try: style_class = atr(node_class()) except: # print ("couldn't make style from class instance", e) style_class = style_class.klass try: kwargs["style"] = style_class.from_definition(d["style"]) except Exception as e: kwargs["style"] = Style.from_definition(d["style"]) # print ("couldn't make style from inferred style class", e) for k in d: if k not in ["node", "inputs", "attrs", "lookup_attrs", "plugin", "style"]: raise ValueError("Invalid definition for node '%s': unexpected property '%s'" % (name, k)) nodes[name] = node_class(**kwargs) return list(nodes.values())[-1]
def _default_style(self): return Style()