Example #1
0
class Range(TimeDependentLayer):
    """
    An interval defined by lower and upper values as a function of time.
    """

    data = DataTrait(help='The time series object containing the data.')
    column_lower = ColumnTrait(None, help='The field in the time series containing the lower value of the data range.')
    column_upper = ColumnTrait(None, help='The field in the time series containing the upper value of the data range.')

    color = Color(None, help='The fill color of the range.')
    opacity = Opacity(0.2, help='The opacity of the fill color from 0 (transparent) to 1 (opaque).')

    edge_color = Color(None, help='The edge color of the range.')
    edge_opacity = Opacity(0.2, help='The opacity of the edge color from 0 (transparent) to 1 (opaque).')
    edge_width = PositiveCFloat(0, help='The thickness of the edge, in pixels.')

    # Potential properties that could be implemented: strokeCap, strokeDash

    def to_vega(self, yunit=None):
        vega = {'type': 'area',
                'name': self.uuids[0],
                'description': self.label,
                'clip': True,
                'from': {'data': self.data.uuid},
                'encode': {'enter': {'x': {'scale': 'xscale', 'field': self.time_column},
                                     'y': {'scale': 'yscale', 'field': self.column_lower},
                                     'y2': {'scale': 'yscale', 'field': self.column_upper},
                                     'fill': {'value': self.color or DEFAULT_COLOR},
                                     'fillOpacity': {'value': self.opacity},
                                     'stroke': {'value': self.edge_color or DEFAULT_COLOR},
                                     'strokeOpacity': {'value': self.edge_opacity},
                                     'strokeWidth': {'value': self.edge_width}}}}

        return [vega]

    def to_mpl(self, ax, yunit=None):

        x = self.data.time_series[self.time_column]
        y1 = self.data.column_to_values(self.column_lower, yunit)
        y2 = self.data.column_to_values(self.column_upper, yunit)

        ax.fill_between(x, y1, y2,
                        color=self.color or DEFAULT_COLOR,
                        alpha=self.opacity)

    @property
    def _required_xdata(self):
        return [(self.data, self.time_column)]

    @property
    def _required_ydata(self):
        return [(self.data, self.column_lower), (self.data, self.column_upper)]
Example #2
0
class HorizontalRange(BaseLayer):
    """
    A continuous range specified by a lower and upper value.
    """

    value_lower = AstropyQuantity(help='The value at which the range starts.')
    value_upper = AstropyQuantity(help='The value at which the range ends.')

    color = Color(None, help='The fill color of the range.')
    opacity = Opacity(0.2, help='The opacity of the fill color from 0 (transparent) to 1 (opaque).')

    edge_color = Color(None, help='The edge color of the range.')
    edge_opacity = Opacity(0.2, help='The opacity of the edge color from 0 (transparent) to 1 (opaque).')
    edge_width = PositiveCFloat(0, help='The thickness of the edge, in pixels.')

    # Potential properties that could be implemented: strokeCap, strokeDash

    def to_vega(self, yunit=None):

        if yunit is None:
            yunit = u.one

        value_lower = self.value_lower.to_value(yunit)
        value_upper = self.value_upper.to_value(yunit)

        vega = {'type': 'rect',
                'name': self.uuids[0],
                'description': self.label,
                'clip': True,
                'encode': {'enter': {'x': {'value': 0},
                                     'x2': {'field': {'group': 'width'}},
                                     'y': {'scale': 'yscale', 'value': float(value_lower)},
                                     'y2': {'scale': 'yscale', 'value': float(value_upper)},
                                     'fill': {'value': self.color or DEFAULT_COLOR},
                                     'fillOpacity': {'value': self.opacity},
                                     'stroke': {'value': self.edge_color or DEFAULT_COLOR},
                                     'strokeOpacity': {'value': self.edge_opacity},
                                     'strokeWidth': {'value': self.edge_width}}}}
        return [vega]

    def to_mpl(self, ax, yunit=None):

        value_lower = self.value_lower.to_value(yunit)
        value_upper = self.value_upper.to_value(yunit)

        ax.fill_between([-1e30, 1e30], value_lower, value_upper,
                        color=self.color or DEFAULT_COLOR,
                        alpha=self.opacity)
Example #3
0
class VerticalLine(BaseLayer):
    """
    A vertical line at a specific time.
    """

    time = AstropyTime(help='The date/time at which the vertical line is shown.')
    width = PositiveCFloat(1, help='The width of the line, in pixels.')

    color = Color(None, help='The color of the line.')
    opacity = Opacity(1, help='The opacity of the line from 0 (transparent) to 1 (opaque).')

    # Potential properties that could be implemented: strokeCap, strokeDash

    def to_vega(self, yunit=None):

        vega = {'type': 'rule',
                'name': self.uuids[0],
                'description': self.label,
                'clip': True,
                'encode': {'enter': {'x': {'scale': 'xscale', 'signal': time_to_vega(self.time)},
                                     'y': {'value': 0},
                                     'y2': {'field': {'group': 'height'}},
                                     'strokeWidth': {'value': self.width},
                                     'stroke': {'value': self.color or DEFAULT_COLOR},
                                     'strokeOpacity': {'value': self.opacity}}}}
        return [vega]

    def to_mpl(self, ax, yunit=None):
        ax.axvline(self.time,
                   linewidth=self.width,
                   color=self.color or DEFAULT_COLOR,
                   alpha=self.opacity)
Example #4
0
class Text(BaseLayer):
    """
    A text label.
    """

    text = Unicode(help='The text label to show.')
    time = AstropyTime(help='The date/time at which the text is shown.')
    value = AstropyQuantity(help='The y value at which the text is shown.')
    weight = UnicodeChoice('normal', help='The weight of the text.',
                           choices=['normal', 'bold'])
    baseline = UnicodeChoice('alphabetic', help='The vertical text baseline.',
                             choices=['alphabetic', 'top', 'middle', 'bottom'])
    align = UnicodeChoice('left', help='The horizontal text alignment.',
                          choices=['left', 'center', 'right'])
    angle = CFloat(0, help='The rotation angle of the text in degrees (default 0).')

    color = Color(None, help='The color of the text.')
    opacity = Opacity(1, help='The opacity of the text from 0 (transparent) to 1 (opaque).')

    def to_vega(self, yunit=None):

        if yunit is None:
            yunit = u.one

        value = self.value.to_value(yunit)

        vega = {'type': 'text',
                'name': self.uuids[0],
                'description': self.label,
                'clip': True,
                'encode': {'enter': {'x': {'scale': 'xscale', 'signal': time_to_vega(self.time)},
                                     'y': {'scale': 'yscale', 'value': float(value)},
                                     'text': {'value': self.text},
                                     'fill': {'value': self.color or DEFAULT_COLOR},
                                     'fillOpacity': {'value': self.opacity},
                                     'fontWeigth': {'value': self.weight},
                                     'baseline': {'value': self.baseline},
                                     'align': {'value': self.align},
                                     'angle': {'value': self.angle}}}}
        return [vega]

    def to_mpl(self, ax, yunit=None):

        if yunit is None:
            yunit = u.one

        x = self.time
        value = self.value.to_value(yunit)

        ax.text(x, value, self.text,
                color=self.color or DEFAULT_COLOR,
                alpha=self.opacity)
Example #5
0
class Line(TimeDependentLayer):
    """
    A set of time series data points connected by a line.
    """

    data = DataTrait(help='The time series object containing the data.')
    column = ColumnTrait(None, help='The field in the time series containing the data.')
    width = PositiveCFloat(1, help='The width of the line, in pixels.')

    color = Color(None, help='The color of the line.')
    opacity = Opacity(1, help='The opacity of the line from 0 (transparent) to 1 (opaque).')

    def to_vega(self, yunit=None):
        vega = {'type': 'line',
                'name': self.uuids[0],
                'description': self.label,
                'clip': True,
                'from': {'data': self.data.uuid},
                'encode': {'enter': {'x': {'scale': 'xscale', 'field': self.time_column},
                                     'y': {'scale': 'yscale', 'field': self.column},
                                     'stroke': {'value': self.color or DEFAULT_COLOR},
                                     'strokeOpacity': {'value': self.opacity},
                                     'strokeWidth': {'value': self.width}}}}
        return [vega]

    def to_mpl(self, ax, yunit=None):

        x = self.data.time_series[self.time_column]
        y = self.data.column_to_values(self.column, yunit)

        ax.plot(x, y, '-',
                linewidth=self.width,
                color=self.color or DEFAULT_COLOR,
                alpha=self.opacity)

    @property
    def _required_xdata(self):
        return [(self.data, self.time_column)]

    @property
    def _required_ydata(self):
        return [(self.data, self.column)]
Example #6
0
class HorizontalLine(BaseLayer):
    """
    A horizontal line at a specific y value.
    """

    # TODO: validate value and allow it to be a quantity
    value = AstropyQuantity(help='The y value at which the horizontal line is shown.')
    width = PositiveCFloat(1, help='The width of the line, in pixels.')

    color = Color(None, help='The color of the line.')
    opacity = Opacity(1, help='The opacity of the line from 0 (transparent) to 1 (opaque).')

    # Potential properties that could be implemented: strokeCap, strokeDash

    def to_vega(self, yunit=None):

        if yunit is None:
            yunit = u.one

        value = self.value.to_value(yunit)

        vega = {'type': 'rule',
                'name': self.uuids[0],
                'description': self.label,
                'clip': True,
                'encode': {'enter': {'x': {'value': 0},
                                     'x2': {'field': {'group': 'width'}},
                                     'y': {'scale': 'yscale', 'value': float(value)},
                                     'strokeWidth': {'value': self.width},
                                     'stroke': {'value': self.color or DEFAULT_COLOR},
                                     'strokeOpacity': {'value': self.opacity}}}}
        return [vega]

    def to_mpl(self, ax, yunit=None):
        if yunit is None:
            yunit = u.one
        ax.axhline(self.value.to_value(yunit),
                   linewidth=self.width,
                   color=self.color or DEFAULT_COLOR,
                   alpha=self.opacity)
Example #7
0
class Markers(TimeDependentLayer):
    """
    A set of time series data points represented by markers.
    """

    n_uuids = 2

    data = DataTrait(help='The time series object containing the data.')
    column = ColumnTrait(None, help='The field in the time series containing the data.')
    error = ColumnTrait(None, help='The field in the time series '
                                   'containing the data uncertainties.')

    shape = UnicodeChoice('circle', help='The symbol shape.', choices=MARKER_SHAPES)

    size = PositiveCFloat(20, help='The area in pixels of the bounding box of the symbols.\n\n'
                                   'Note that this value sets the area of the symbol; the '
                                   'side lengths will increase with the square root of this '
                                   'value.')

    color = Color(None, help='The fill color of the symbols.')
    opacity = Opacity(1, help='The opacity of the fill color from 0 (transparent) to 1 (opaque).')

    edge_color = Color(None, help='The edge color of the symbol.')
    edge_opacity = Opacity(0.2, help='The opacity of the edge color from 0 (transparent) to 1 (opaque).')
    edge_width = PositiveCFloat(0, help='The thickness of the edge, in pixels.')

    error_width = PositiveCFloat(1, help='The width of the error bar, in pixels.')

    tooltip = Tooltip(True, help='Whether to show a tooltip (`False` or '
                                 '`True`). Can also be set to a list of data '
                                 'columns to show, or a dictionary mapping the '
                                 'display name to the column name.')

    def to_vega(self, yunit=None):

        default_tooltip = {'signal': "{{'{0}': datum.{0}, '{1}': datum.{1}}}".format(self.time_column, self.column)}

        # The main markers
        vega = [{'type': 'symbol',
                 'name': self.uuids[0],
                 'description': self.label,
                 'clip': True,
                 'from': {'data': self.data.uuid},
                 'encode': {'enter': {'x': {'scale': 'xscale', 'field': self.time_column},
                                      'y': {'scale': 'yscale', 'field': self.column},
                                      'shape': {'value': self.shape}},
                            'update': {'shape': {'value': self.shape},
                                       'size': {'value': self.size},
                                       'fill': {'value': self.color or DEFAULT_COLOR},
                                       'fillOpacity': {'value': self.opacity},
                                       'stroke': {'value': self.edge_color or DEFAULT_COLOR},
                                       'strokeOpacity': {'value': self.edge_opacity},
                                       'strokeWidth': {'value': self.edge_width}}}}]

        if self.tooltip:
            vega[0]['encode']['hover'] = {'size': {'value': self.size * 4},
                                          'tooltip': generate_tooltip(self.tooltip, default_tooltip)}

        # The error bars (if requested)
        if self.error:
            vega.append({'type': 'rect',
                         'name': self.uuids[1],
                         'description': self.label,
                         'clip': True,
                         'from': {'data': self.data.uuid},
                         'encode': {'enter': {'x': {'scale': 'xscale', 'field': self.time_column},
                                              'y': {'scale': 'yscale', 'signal': f"datum['{self.column}'] - datum['{self.error}']"},
                                              'y2': {'scale': 'yscale', 'signal': f"datum['{self.column}'] + datum['{self.error}']"}},
                                    'update': {'shape': {'value': self.shape},
                                               'width': {'value': self.error_width},
                                               'fill': {'value': self.color or DEFAULT_COLOR},
                                               'fillOpacity': {'value': self.opacity},
                                               'stroke': {'value': self.edge_color or DEFAULT_COLOR},
                                               'strokeOpacity': {'value': self.edge_opacity},
                                               'strokeWidth': {'value': self.edge_width}}}})

        return vega

    def to_mpl(self, ax, yunit=None):

        x = self.data.time_series[self.time_column]
        y = self.data.column_to_values(self.column, yunit)

        ax.scatter(x, y, s=self.size / 2,
                   color=self.color or DEFAULT_COLOR,
                   alpha=self.opacity)

        if self.error:
            yerr = self.data.column_to_values(self.error, yunit)
            ax.errorbar(x, y, yerr=yerr, fmt='none',
                        color=self.color or DEFAULT_COLOR,
                        alpha=self.opacity, linewidth=self.error_width)

    @property
    def _required_xdata(self):
        return [(self.data, self.time_column)]

    @property
    def _required_ydata(self):
        return [(self.data, self.column), (self.data, self.error)]

    @property
    def _required_tooltipdata(self):
        if isinstance(self.tooltip, bool):
            if self.tooltip:
                return self._required_xdata + self._required_ydata
            else:
                return []
        elif isinstance(self.tooltip, (tuple, list, dict)):
            return [(self.data, col) for col in self.tooltip]