Exemple #1
0
    def from_ts(cls: tp.Type[RangesT],
                ts: tp.ArrayLike,
                gap_value: tp.Optional[tp.Scalar] = None,
                attach_ts: bool = True,
                wrapper_kwargs: tp.KwargsLike = None,
                **kwargs) -> RangesT:
        """Build `Ranges` from time series `ts`.

        Searches for sequences of

        * True values in boolean data (False acts as a gap),
        * positive values in integer data (-1 acts as a gap), and
        * non-NaN values in any other data (NaN acts as a gap).

        `**kwargs` will be passed to `Ranges.__init__`."""
        if wrapper_kwargs is None:
            wrapper_kwargs = {}

        ts_pd = to_pd_array(ts)
        ts_arr = to_2d_array(ts_pd)
        if gap_value is None:
            if np.issubdtype(ts_arr.dtype, np.bool_):
                gap_value = False
            elif np.issubdtype(ts_arr.dtype, np.integer):
                gap_value = -1
            else:
                gap_value = np.nan
        records_arr = nb.find_ranges_nb(ts_arr, gap_value)
        wrapper = ArrayWrapper.from_obj(ts_pd, **wrapper_kwargs)
        return cls(wrapper,
                   records_arr,
                   ts=ts_pd if attach_ts else None,
                   **kwargs)
Exemple #2
0
    def update(self, data: tp.ArrayLike) -> None:
        """Update the trace data."""
        data = reshape_fns.to_2d_array(data)

        with self.fig.batch_update():
            for i, trace in enumerate(self.traces):
                trace.y = data[:, i]
Exemple #3
0
 def indexing_func(self: OrdersT, pd_indexing_func: tp.PandasIndexingFunc, **kwargs) -> OrdersT:
     """Perform indexing on `Orders`."""
     new_wrapper, new_records_arr, group_idxs, col_idxs = \
         Records.indexing_func_meta(self, pd_indexing_func, **kwargs)
     if self.close is not None:
         new_close = new_wrapper.wrap(to_2d_array(self.close)[:, col_idxs], group_by=False)
     else:
         new_close = None
     return self.replace(
         wrapper=new_wrapper,
         records_arr=new_records_arr,
         close=new_close
     )
Exemple #4
0
    def from_ts(cls: tp.Type[DrawdownsT],
                ts: tp.ArrayLike,
                attach_ts: bool = True,
                wrapper_kwargs: tp.KwargsLike = None,
                **kwargs) -> DrawdownsT:
        """Build `Drawdowns` from time series `ts`.

        `**kwargs` will be passed to `Drawdowns.__init__`."""
        ts_pd = to_pd_array(ts)
        records_arr = nb.get_drawdowns_nb(to_2d_array(ts_pd))
        wrapper = ArrayWrapper.from_obj(ts_pd, **merge_dicts({},
                                                             wrapper_kwargs))
        return cls(wrapper,
                   records_arr,
                   ts=ts_pd if attach_ts else None,
                   **kwargs)
Exemple #5
0
    def update(self, data: tp.ArrayLike) -> None:
        """Update the trace data.

        ## Example

        ```python-repl
        >>> bar.update([[2, 1], [4, 3]])
        >>> bar.fig
        ```
        ![](/docs/img/Bar_updated.svg)
        """
        data = reshape_fns.to_2d_array(data)
        with self.fig.batch_update():
            for i, bar in enumerate(self.traces):
                bar.y = data[:, i]
                if bar.marker.colorscale is not None:
                    bar.marker.color = data[:, i]
Exemple #6
0
    def update(self, data: tp.ArrayLike) -> None:
        """Update the trace data.

        Usage:
            ```pycon
            >>> bar.update([[2, 1], [4, 3]])
            >>> bar.fig
            ```

            ![](/assets/images/Bar_updated.svg)
        """
        data = reshape_fns.to_2d_array(data)
        with self.fig.batch_update():
            for i, bar in enumerate(self.traces):
                bar.y = data[:, i]
                if bar.marker.colorscale is not None:
                    bar.marker.color = data[:, i]
Exemple #7
0
    def update(self, data: tp.ArrayLike) -> None:
        """Update the trace data."""
        data = reshape_fns.to_2d_array(data)

        with self.fig.batch_update():
            for i, trace in enumerate(self.traces):
                d = data[:, i]
                if self.remove_nan:
                    d = d[~np.isnan(d)]
                mask = np.full(d.shape, True)
                if self.from_quantile is not None:
                    mask &= d >= np.quantile(d, self.from_quantile)
                if self.to_quantile is not None:
                    mask &= d <= np.quantile(d, self.to_quantile)
                d = d[mask]
                if self.horizontal:
                    trace.x = d
                    trace.y = None
                else:
                    trace.x = None
                    trace.y = d
Exemple #8
0
            def plot_func(self,
                          *args,
                          _px_func_name: str = px_func_name,
                          _px_func: tp.Callable = px_func,
                          **kwargs) -> tp.BaseFigure:
                from vectorbt._settings import settings
                layout_cfg = settings['plotting']['layout']

                layout_kwargs = dict(
                    template=kwargs.pop('template', layout_cfg['template']),
                    width=kwargs.pop('width', layout_cfg['width']),
                    height=kwargs.pop('height', layout_cfg['height']))
                # Fix category_orders
                if 'color' in kwargs:
                    if isinstance(kwargs['color'], str):
                        if isinstance(self.obj, pd.DataFrame):
                            if kwargs['color'] in self.obj.columns:
                                category_orders = dict()
                                category_orders[kwargs['color']] = sorted(
                                    self.obj[kwargs['color']].unique())
                                kwargs = merge_dicts(
                                    dict(category_orders=category_orders),
                                    kwargs)

                # Fix Series name
                obj = self.obj.copy(deep=False)
                if isinstance(obj, pd.Series):
                    if obj.name is not None:
                        obj = obj.rename(str(obj.name))
                else:
                    obj.columns = clean_labels(obj.columns)
                obj.index = clean_labels(obj.index)

                if _px_func_name == 'imshow':
                    return make_figure(_px_func(to_2d_array(obj), *args,
                                                **layout_kwargs, **kwargs),
                                       layout=layout_kwargs)
                return make_figure(_px_func(obj, *args, **layout_kwargs,
                                            **kwargs),
                                   layout=layout_kwargs)
Exemple #9
0
    def to_2d_array(self) -> tp.Array2d:
        """Convert to 2-dim NumPy array.

        See `vectorbt.base.reshape_fns.to_2d`."""
        return reshape_fns.to_2d_array(self.obj)
Exemple #10
0
    def update(self, data: tp.ArrayLike) -> None:
        """Update the trace data."""
        data = reshape_fns.to_2d_array(data)

        with self.fig.batch_update():
            self.traces[0].z = data
Exemple #11
0
    def __init__(self,
                 data: tp.Optional[tp.ArrayLike] = None,
                 x_labels: tp.Optional[tp.Labels] = None,
                 y_labels: tp.Optional[tp.Labels] = None,
                 is_x_category: bool = False,
                 is_y_category: bool = False,
                 trace_kwargs: tp.KwargsLike = None,
                 add_trace_kwargs: tp.KwargsLike = None,
                 fig: tp.Optional[tp.BaseFigure] = None,
                 **layout_kwargs) -> None:
        """Create a heatmap plot.

        Args:
            data (array_like): Data in any format that can be converted to NumPy.

                Must be of shape (`y_labels`, `x_labels`).
            x_labels (array_like): X-axis labels, corresponding to columns in pandas.
            y_labels (array_like): Y-axis labels, corresponding to index in pandas.
            is_x_category (bool): Whether X-axis is a categorical axis.
            is_y_category (bool): Whether Y-axis is a categorical axis.
            trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`.
            add_trace_kwargs (dict): Keyword arguments passed to `add_trace`.
            fig (Figure or FigureWidget): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> import vectorbt as vbt

        >>> heatmap = vbt.plotting.Heatmap(
        ...     data=[[1, 2], [3, 4]],
        ...     x_labels=['a', 'b'],
        ...     y_labels=['x', 'y']
        ... )
        >>> heatmap.fig
        ```
        ![](/docs/img/Heatmap.svg)
        """
        Configured.__init__(
            self,
            data=data,
            x_labels=x_labels,
            y_labels=y_labels,
            trace_kwargs=trace_kwargs,
            add_trace_kwargs=add_trace_kwargs,
            fig=fig,
            **layout_kwargs
        )

        from vectorbt._settings import settings
        layout_cfg = settings['plotting']['layout']

        if trace_kwargs is None:
            trace_kwargs = {}
        if add_trace_kwargs is None:
            add_trace_kwargs = {}
        if data is not None:
            data = reshape_fns.to_2d_array(data)
            if x_labels is not None:
                checks.assert_shape_equal(data, x_labels, (1, 0))
            if y_labels is not None:
                checks.assert_shape_equal(data, y_labels, (0, 0))
        else:
            if x_labels is None or y_labels is None:
                raise ValueError("At least data, or x_labels and y_labels must be passed")
        if x_labels is not None:
            x_labels = clean_labels(x_labels)
        if y_labels is not None:
            y_labels = clean_labels(y_labels)

        if fig is None:
            fig = make_figure()
            if 'width' in layout_cfg:
                # Calculate nice width and height
                max_width = layout_cfg['width']
                if data is not None:
                    x_len = data.shape[1]
                    y_len = data.shape[0]
                else:
                    x_len = len(x_labels)
                    y_len = len(y_labels)
                width = math.ceil(renormalize(
                    x_len / (x_len + y_len),
                    (0, 1),
                    (0.3 * max_width, max_width)
                ))
                width = min(width + 150, max_width)  # account for colorbar
                height = math.ceil(renormalize(
                    y_len / (x_len + y_len),
                    (0, 1),
                    (0.3 * max_width, max_width)
                ))
                height = min(height, max_width * 0.7)  # limit height
                fig.update_layout(
                    width=width,
                    height=height
                )

        heatmap = go.Heatmap(
            hoverongaps=False,
            colorscale='Plasma',
            x=x_labels,
            y=y_labels
        )
        heatmap.update(**trace_kwargs)
        fig.add_trace(heatmap, **add_trace_kwargs)

        axis_kwargs = dict()
        if is_x_category:
            if fig.data[-1]['xaxis'] is not None:
                axis_kwargs['xaxis' + fig.data[-1]['xaxis'][1:]] = dict(type='category')
            else:
                axis_kwargs['xaxis'] = dict(type='category')
        if is_y_category:
            if fig.data[-1]['yaxis'] is not None:
                axis_kwargs['yaxis' + fig.data[-1]['yaxis'][1:]] = dict(type='category')
            else:
                axis_kwargs['yaxis'] = dict(type='category')
        fig.update_layout(**axis_kwargs)
        fig.update_layout(**layout_kwargs)

        TraceUpdater.__init__(self, fig, (fig.data[-1],))

        if data is not None:
            self.update(data)
Exemple #12
0
    def __init__(self,
                 data: tp.Optional[tp.ArrayLike] = None,
                 trace_names: tp.TraceNames = None,
                 horizontal: bool = False,
                 remove_nan: bool = True,
                 from_quantile: tp.Optional[float] = None,
                 to_quantile: tp.Optional[float] = None,
                 trace_kwargs: tp.KwargsLikeSequence = None,
                 add_trace_kwargs: tp.KwargsLike = None,
                 fig: tp.Optional[tp.BaseFigure] = None,
                 **layout_kwargs) -> None:
        """Create a box plot.

        For keyword arguments, see `Histogram`.

        ## Example

        ```python-repl
        >>> import vectorbt as vbt

        >>> box = vbt.plotting.Box(
        ...     data=[[1, 2], [3, 4], [2, 1]],
        ...     trace_names=['a', 'b']
        ... )
        >>> box.fig
        ```
        ![](/docs/img/Box.svg)
        """
        Configured.__init__(
            self,
            data=data,
            trace_names=trace_names,
            horizontal=horizontal,
            remove_nan=remove_nan,
            from_quantile=from_quantile,
            to_quantile=to_quantile,
            trace_kwargs=trace_kwargs,
            add_trace_kwargs=add_trace_kwargs,
            fig=fig,
            **layout_kwargs
        )

        if trace_kwargs is None:
            trace_kwargs = {}
        if add_trace_kwargs is None:
            add_trace_kwargs = {}
        if data is not None:
            data = reshape_fns.to_2d_array(data)
            if trace_names is not None:
                checks.assert_shape_equal(data, trace_names, (1, 0))
        else:
            if trace_names is None:
                raise ValueError("At least data or trace_names must be passed")
        if trace_names is None:
            trace_names = [None] * data.shape[1]
        if isinstance(trace_names, str):
            trace_names = [trace_names]

        if fig is None:
            fig = make_figure()
        fig.update_layout(**layout_kwargs)

        for i, trace_name in enumerate(trace_names):
            _trace_kwargs = resolve_dict(trace_kwargs, i=i)
            trace_name = _trace_kwargs.pop('name', trace_name)
            if trace_name is not None:
                trace_name = str(trace_name)
            box = go.Box(
                name=trace_name,
                showlegend=trace_name is not None
            )
            box.update(**_trace_kwargs)
            fig.add_trace(box, **add_trace_kwargs)

        TraceUpdater.__init__(self, fig, fig.data[-len(trace_names):])
        self._horizontal = horizontal
        self._remove_nan = remove_nan
        self._from_quantile = from_quantile
        self._to_quantile = to_quantile

        if data is not None:
            self.update(data)
Exemple #13
0
    def __init__(self,
                 data: tp.Optional[tp.ArrayLike] = None,
                 trace_names: tp.TraceNames = None,
                 horizontal: bool = False,
                 remove_nan: bool = True,
                 from_quantile: tp.Optional[float] = None,
                 to_quantile: tp.Optional[float] = None,
                 trace_kwargs: tp.KwargsLikeSequence = None,
                 add_trace_kwargs: tp.KwargsLike = None,
                 fig: tp.Optional[tp.BaseFigure] = None,
                 **layout_kwargs) -> None:
        """Create a histogram plot.

        Args:
            data (array_like): Data in any format that can be converted to NumPy.

                Must be of shape (any, `trace_names`).
            trace_names (str or list of str): Trace names, corresponding to columns in pandas.
            horizontal (bool): Whether to plot horizontally.
            remove_nan (bool): Whether to remove NaN values.
            from_quantile (float): Filter out data points before this quantile.

                Should be in range `[0, 1]`.
            to_quantile (float): Filter out data points after this quantile.

                Should be in range `[0, 1]`.
            trace_kwargs (dict or list of dict): Keyword arguments passed to `plotly.graph_objects.Histogram`.

                Can be specified per trace as a sequence of dicts.
            add_trace_kwargs (dict): Keyword arguments passed to `add_trace`.
            fig (Figure or FigureWidget): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> import vectorbt as vbt

        >>> hist = vbt.plotting.Histogram(
        ...     data=[[1, 2], [3, 4], [2, 1]],
        ...     trace_names=['a', 'b']
        ... )
        >>> hist.fig
        ```
        ![](/docs/img/Histogram.svg)
        """
        Configured.__init__(
            self,
            data=data,
            trace_names=trace_names,
            horizontal=horizontal,
            remove_nan=remove_nan,
            from_quantile=from_quantile,
            to_quantile=to_quantile,
            trace_kwargs=trace_kwargs,
            add_trace_kwargs=add_trace_kwargs,
            fig=fig,
            **layout_kwargs
        )

        if trace_kwargs is None:
            trace_kwargs = {}
        if add_trace_kwargs is None:
            add_trace_kwargs = {}
        if data is not None:
            data = reshape_fns.to_2d_array(data)
            if trace_names is not None:
                checks.assert_shape_equal(data, trace_names, (1, 0))
        else:
            if trace_names is None:
                raise ValueError("At least data or trace_names must be passed")
        if trace_names is None:
            trace_names = [None] * data.shape[1]
        if isinstance(trace_names, str):
            trace_names = [trace_names]

        if fig is None:
            fig = make_figure()
            fig.update_layout(barmode='overlay')
        fig.update_layout(**layout_kwargs)

        for i, trace_name in enumerate(trace_names):
            _trace_kwargs = resolve_dict(trace_kwargs, i=i)
            trace_name = _trace_kwargs.pop('name', trace_name)
            if trace_name is not None:
                trace_name = str(trace_name)
            hist = go.Histogram(
                opacity=0.75 if len(trace_names) > 1 else 1,
                name=trace_name,
                showlegend=trace_name is not None
            )
            hist.update(**_trace_kwargs)
            fig.add_trace(hist, **add_trace_kwargs)

        TraceUpdater.__init__(self, fig, fig.data[-len(trace_names):])
        self._horizontal = horizontal
        self._remove_nan = remove_nan
        self._from_quantile = from_quantile
        self._to_quantile = to_quantile

        if data is not None:
            self.update(data)
Exemple #14
0
    def __init__(self,
                 data: tp.Optional[tp.ArrayLike] = None,
                 trace_names: tp.TraceNames = None,
                 x_labels: tp.Optional[tp.Labels] = None,
                 trace_kwargs: tp.KwargsLikeSequence = None,
                 add_trace_kwargs: tp.KwargsLike = None,
                 fig: tp.Optional[tp.BaseFigure] = None,
                 **layout_kwargs) -> None:
        """Create a scatter plot.

        Args:
            data (array_like): Data in any format that can be converted to NumPy.

                Must be of shape (`x_labels`, `trace_names`).
            trace_names (str or list of str): Trace names, corresponding to columns in pandas.
            x_labels (array_like): X-axis labels, corresponding to index in pandas.
            trace_kwargs (dict or list of dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.

                Can be specified per trace as a sequence of dicts.
            add_trace_kwargs (dict): Keyword arguments passed to `add_trace`.
            fig (Figure or FigureWidget): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> import vectorbt as vbt

        >>> scatter = vbt.plotting.Scatter(
        ...     data=[[1, 2], [3, 4]],
        ...     trace_names=['a', 'b'],
        ...     x_labels=['x', 'y']
        ... )
        >>> scatter.fig
        ```
        ![](/docs/img/Scatter.svg)
        """
        Configured.__init__(
            self,
            data=data,
            trace_names=trace_names,
            x_labels=x_labels,
            trace_kwargs=trace_kwargs,
            add_trace_kwargs=add_trace_kwargs,
            fig=fig,
            **layout_kwargs
        )

        if trace_kwargs is None:
            trace_kwargs = {}
        if add_trace_kwargs is None:
            add_trace_kwargs = {}
        if data is not None:
            data = reshape_fns.to_2d_array(data)
            if trace_names is not None:
                checks.assert_shape_equal(data, trace_names, (1, 0))
        else:
            if trace_names is None:
                raise ValueError("At least data or trace_names must be passed")
        if trace_names is None:
            trace_names = [None] * data.shape[1]
        if isinstance(trace_names, str):
            trace_names = [trace_names]
        if x_labels is not None:
            x_labels = clean_labels(x_labels)

        if fig is None:
            fig = make_figure()
        fig.update_layout(**layout_kwargs)

        for i, trace_name in enumerate(trace_names):
            _trace_kwargs = resolve_dict(trace_kwargs, i=i)
            trace_name = _trace_kwargs.pop('name', trace_name)
            if trace_name is not None:
                trace_name = str(trace_name)
            scatter = go.Scatter(
                x=x_labels,
                name=trace_name,
                showlegend=trace_name is not None
            )
            scatter.update(**_trace_kwargs)
            fig.add_trace(scatter, **add_trace_kwargs)

        TraceUpdater.__init__(self, fig, fig.data[-len(trace_names):])

        if data is not None:
            self.update(data)