Source code for ladybug.graphic

# coding=utf-8
from __future__ import division

from .legend import Legend, LegendParameters, LegendParametersCategorized

from .datatype.base import DataTypeBase

from ladybug_geometry.geometry2d.pointvector import Point2D
from ladybug_geometry.geometry3d.pointvector import Point3D
from ladybug_geometry.geometry3d.plane import Plane


[docs]class GraphicContainer(object): """Graphic container used to get legends, title locations, and colors for a graphic. Args: values: A List or Tuple of numerical values that will be used to generate the legend and colors. min_point: A Point3D object for the minimum of the bounding box around the graphic geometry. max_point: A Point3D object for the maximum of the bounding box around the graphic geometry. legend_parameters: An Optional LegendParameter object to override default parameters of the legend. None indicates that default legend parameters will be used. (Default: None). data_type: Optional DataType from the ladybug datatype subpackage (ie. Temperature()) , which will be used to assign default legend properties. If None, the legend associated with this object will contain no units unless a unit below is specified. (Default: None). unit: Optional text string for the units of the values. (ie. 'C'). If None, the default units of the data_type will be used. (Default: None). Properties: * values * min_point * max_point * legend_parameters * data_type * unit * legend * value_colors * lower_title_location * upper_title_location """ __slots__ = ('_legend', '_min_point', '_max_point', '_data_type', '_unit') def __init__(self, values, min_point, max_point, legend_parameters=None, data_type=None, unit=None): """Initialize graphic container.""" # check the input points and legend information if isinstance(min_point, Point2D): min_point = Point3D(min_point.x, min_point.y) if isinstance(max_point, Point2D): max_point = Point3D(max_point.x, max_point.y) assert isinstance(min_point, Point3D), \ 'min_point should be a ladybug Point3D. Got {}'.format(type(min_point)) assert isinstance(max_point, Point3D), \ 'max_point should be a ladybug Point3D. Got {}'.format(type(max_point)) self._legend = Legend(values, legend_parameters) self._min_point = min_point self._max_point = max_point # set default legend parameters based on input data_type and unit self._data_type = data_type self._unit = unit if data_type is not None: assert isinstance(data_type, DataTypeBase), \ 'data_type should be a ladybug DataType. Got {}'.format(type(data_type)) if self.legend_parameters.is_title_default: unit = unit if unit else data_type.units[0] data_type.is_unit_acceptable(unit) self.legend_parameters.title = unit if \ self.legend_parameters.vertical \ else '{} ({})'.format(data_type.name, unit) if data_type.unit_descr is not None and \ self.legend_parameters.ordinal_dictionary is None and not \ isinstance(self.legend_parameters, LegendParametersCategorized): self.legend_parameters.ordinal_dictionary = data_type.unit_descr sorted_keys = sorted(data_type.unit_descr.keys()) if self.legend.is_min_default: self.legend_parameters._min = sorted_keys[0] if self.legend.is_max_default: self.legend_parameters._max = sorted_keys[-1] assert self.legend_parameters._min <= self.legend_parameters._max, \ 'Legend min is greater than legend max. {} > {}.'.format( self.legend_parameters._min, self.legend_parameters._max) if self.legend_parameters.is_segment_count_default: try: # try to set the number of segments to align with ordinal text min_i = sorted_keys.index(self.legend_parameters.min) max_i = sorted_keys.index(self.legend_parameters.max) self.legend_parameters.segment_count = \ len(sorted_keys[min_i:max_i + 1]) except IndexError: pass elif unit and self.legend_parameters.is_title_default: assert isinstance(unit, str), \ 'Expected string for unit. Got {}.'.format(type(unit)) self.legend_parameters.title = unit # set the default segment_height if self.legend_parameters.is_segment_height_default: s_count = self.legend_parameters.segment_count denom = s_count if s_count >= 8 else 8 if self.legend_parameters.vertical: seg_height = float((self._max_point.y - self._min_point.y) / denom) if seg_height == 0: seg_height = float((self._max_point.x - self._min_point.x) / denom) else: seg_height = float((self._max_point.x - self._min_point.x) / (denom * 2)) if seg_height == 0: seg_height = float((self._max_point.y - self._min_point.y) / denom) self.legend_parameters.properties_3d.segment_height = seg_height self.legend_parameters.properties_3d._is_segment_height_default = True # set the default segment_width if self.legend_parameters.is_segment_width_default: if self.legend_parameters.vertical: seg_width = self.legend_parameters.segment_height / 2 else: seg_width = self.legend_parameters.text_height * \ (len(str(int(self.legend_parameters.max))) + self.legend_parameters.decimal_count + 2) self.legend_parameters.properties_3d.segment_width = seg_width self.legend_parameters.properties_3d._is_segment_width_default = True # set the default base point if self.legend_parameters.is_base_plane_default: if self.legend_parameters.vertical: base_pt = Point3D( self._max_point.x + self.legend_parameters.segment_width, self._min_point.y, self._min_point.z) else: base_pt = Point3D( self._max_point.x, self._max_point.y + 3 * self.legend_parameters.text_height, self._min_point.z) self.legend_parameters.properties_3d.base_plane = Plane(o=base_pt) self.legend_parameters.properties_3d._is_base_plane_default = True
[docs] @classmethod def from_dict(cls, data): """Create a graphic container from a dictionary. Args: data: A python dictionary in the following format .. code-block:: python { "values": [0, 10], "min_point": {"x": 0, "y": 0, "z": 0}, "max_point": {"x": 10, "y": 10, "z": 0}, "legend_parameters": {}, # optional LegendParameter specification "data_type": {}, # optional DataType object "unit": "C" # optional text for the units } """ legend_parameters = None if 'legend_parameters' in data and data['legend_parameters'] is not None: if data['legend_parameters']['type'] == 'LegendParametersCategorized': legend_parameters = LegendParametersCategorized.from_dict( data['legend_parameters']) else: legend_parameters = LegendParameters.from_dict(data['legend_parameters']) data_type = None if 'data_type' in data and data['data_type'] is not None: data_type = DataTypeBase.from_dict(data['data_type']) unit = data['unit'] if 'unit' in data else None return cls(data['values'], Point3D.from_dict(data['min_point']), Point3D.from_dict(data['max_point']), legend_parameters, data_type, unit)
@property def values(self): """The assigned data set of values.""" return self._legend.values @property def min_point(self): """Point3D for the minimum of the bounding box around referenced geometry.""" return self._min_point @property def max_point(self): """Point3D for the maximum of the bounding box around referenced geometry.""" return self._max_point @property def legend_parameters(self): """The legend parameters assigned to this graphic.""" return self._legend._legend_par @property def data_type(self): """The data_type input to this object (if it exists).""" return self._data_type @property def unit(self): """The unit input to this object (if it exists).""" return self._unit @property def legend(self): """The legend assigned to this graphic.""" return self._legend @property def value_colors(self): """A List of colors associated with the assigned values.""" return self._legend.value_colors @property def lower_title_location(self): """A Plane for the lower location of title text.""" return Plane(o=Point3D( self._min_point.x, self._min_point.y - 2.5 * self._legend.legend_parameters.text_height, self._min_point.z)) @property def upper_title_location(self): """A Plane for the upper location of title text.""" return Plane(o=Point3D( self._min_point.x, self._max_point.y + self._legend.legend_parameters.text_height, self._min_point.z))
[docs] def to_dict(self): """Get graphic container as a dictionary.""" base = { 'type': 'GraphicContainer', 'values': self.values, 'min_point': self.min_point.to_dict(), 'max_point': self.max_point.to_dict(), 'legend_parameters': self.legend_parameters.to_dict() } if self.data_type is not None: base['data_type'] = self.data_type.to_dict() if self.unit is not None: base['unit'] = self.unit return base
def __len__(self): """Return length of values on the object.""" return len(self._legend._values) def __getitem__(self, key): """Return one of the values.""" return self._legend._values[key] def __iter__(self): """Iterate through the values.""" return iter(self._legend._values)
[docs] def ToString(self): """Overwrite .NET ToString.""" return self.__repr__()
def __repr__(self): """GraphicContainer representation.""" return 'Graphic Container ({} values)'.format(len(self))