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)
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]
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 )
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)
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]
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]
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
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)
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)
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
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)
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)
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)
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)