def broadcast_to_array_of(arg1, arg2): """Broadcast `arg1` to the shape `(1, *arg2.shape)`. `arg1` must be either a scalar, a 1-dim array, or have 1 dimension more than `arg2`. ## Example ```python-repl >>> import numpy as np >>> from vectorbt.base.reshape_fns import broadcast_to_array_of >>> broadcast_to_array_of([0.1, 0.2], np.empty((2, 2))) [[[0.1 0.1] [0.1 0.1]] [[0.2 0.2] [0.2 0.2]]] ``` """ arg1 = np.asarray(arg1) arg2 = np.asarray(arg2) if arg1.ndim == arg2.ndim + 1: if arg1.shape[1:] == arg2.shape: return arg1 # From here on arg1 can be only a 1-dim array if arg1.ndim == 0: arg1 = to_1d(arg1) checks.assert_ndim(arg1, 1) if arg2.ndim == 0: return arg1 for i in range(arg2.ndim): arg1 = np.expand_dims(arg1, axis=-1) return np.tile(arg1, (1, *arg2.shape))
def test_assert_ndim(self): checks.assert_ndim(0, 0) checks.assert_ndim(np.zeros(1), 1) checks.assert_ndim(pd.Series([1, 2, 3]), (1, 2)) checks.assert_ndim(pd.DataFrame([1, 2, 3]), (1, 2)) with pytest.raises(Exception) as e_info: checks.assert_ndim(np.zeros((3, 3, 3)), (1, 2))
def wrap(self, a, index=None, columns=None, dtype=None, group_by=None): """Wrap a NumPy array using the stored metadata.""" checks.assert_ndim(a, (1, 2)) _self = self.resolve(group_by=group_by) a = np.asarray(a) a = reshape_fns.soft_to_ndim(a, self.ndim) if index is None: index = _self.index if columns is None: columns = _self.columns if columns is not None and len(columns) == 1: name = columns[0] if name == 0: # was a Series before name = None else: name = None if index is not None: checks.assert_shape_equal(a, index, axis=(0, 0)) if a.ndim == 2 and columns is not None: checks.assert_shape_equal(a, columns, axis=(1, 0)) if a.ndim == 1: return pd.Series(a, index=index, name=name, dtype=dtype) if a.ndim == 2: if a.shape[1] == 1 and _self.ndim == 1: return pd.Series(a[:, 0], index=index, name=name, dtype=dtype) return pd.DataFrame(a, index=index, columns=columns, dtype=dtype) raise ValueError(f"{a.ndim}-d input is not supported")
def wrap(self, a, index=None, columns=None, ndim=None, dtype=None): """Wrap a NumPy array using the stored metadata.""" checks.assert_ndim(a, (1, 2)) a = np.asarray(a) if ndim is None: ndim = self.ndim if ndim is not None: a = reshape_fns.soft_to_ndim(a, self.ndim) if index is None: index = self.index if columns is None: columns = self.columns if columns is not None and len(columns) == 1: name = columns[0] if name == 0: # was a Series before name = None else: name = None # Perform checks if index is not None: checks.assert_same_shape(a, index, axis=(0, 0)) if a.ndim == 2 and columns is not None: checks.assert_same_shape(a, columns, axis=(1, 0)) if a.ndim == 1: return pd.Series(a, index=index, name=name, dtype=dtype) return pd.DataFrame(a, index=index, columns=columns, dtype=dtype)
def __init__(self, main_price, init_capital, orders, cash, shares, freq=None, year_freq=None, levy_alpha=None, risk_free=None, required_return=None, cutoff=None, factor_returns=None, incl_unrealized_stats=False): # Perform checks checks.assert_type(main_price, (pd.Series, pd.DataFrame)) if checks.is_frame(main_price): checks.assert_type(init_capital, pd.Series) checks.assert_same(main_price.columns, init_capital.index) else: checks.assert_ndim(init_capital, 0) checks.assert_same_meta(main_price, cash) checks.assert_same_meta(main_price, shares) # Store passed arguments self._main_price = main_price self._init_capital = init_capital self._orders = orders self._cash = cash self._shares = shares self._incl_unrealized_stats = incl_unrealized_stats freq = main_price.vbt(freq=freq).freq if freq is None: raise ValueError( "Couldn't parse the frequency of index. You must set `freq`.") self._freq = freq year_freq = main_price.vbt.returns(year_freq=year_freq).year_freq if freq is None: raise ValueError("You must set `year_freq`.") self._year_freq = year_freq # Parameters self._levy_alpha = defaults.portfolio[ 'levy_alpha'] if levy_alpha is None else levy_alpha self._risk_free = defaults.portfolio[ 'risk_free'] if risk_free is None else risk_free self._required_return = defaults.portfolio[ 'required_return'] if required_return is None else required_return self._cutoff = defaults.portfolio[ 'cutoff'] if cutoff is None else cutoff self._factor_returns = defaults.portfolio[ 'factor_returns'] if factor_returns is None else factor_returns # Supercharge PandasIndexer.__init__(self, _indexing_func) self.wrapper = ArrayWrapper.from_obj(main_price, freq=freq)
def test_assert_ndim(self): checks.assert_ndim(0, 0) checks.assert_ndim(np.zeros(1), 1) checks.assert_ndim(pd.Series([1, 2, 3]), (1, 2)) checks.assert_ndim(pd.DataFrame([1, 2, 3]), (1, 2)) try: checks.assert_ndim(np.zeros((3, 3, 3)), (1, 2)) raise Exception except: pass
def broadcast_to_array_of(arg1, arg2): """Bring first argument to the shape of an array of second argument.""" arg1 = np.asarray(arg1) arg2 = np.asarray(arg2) if arg1.ndim == arg2.ndim + 1: if arg1.shape[1:] == arg2.shape: return arg1 # From here on arg1 can be only a 1-dim array if arg1.ndim == 0: arg1 = to_1d(arg1) checks.assert_ndim(arg1, 1) if arg2.ndim == 0: return arg1 for i in range(arg2.ndim): arg1 = np.expand_dims(arg1, axis=-1) return np.tile(arg1, (1, *arg2.shape))
def wrap(self, a: tp.ArrayLike, index: tp.Optional[tp.IndexLike] = None, columns: tp.Optional[tp.IndexLike] = None, dtype: tp.Optional[tp.PandasDTypeLike] = None, group_by: tp.GroupByLike = None) -> tp.SeriesFrame: """Wrap a NumPy array using the stored metadata.""" checks.assert_ndim(a, (1, 2)) _self = self.resolve(group_by=group_by) if index is None: index = _self.index if not isinstance(index, pd.Index): index = pd.Index(index) if columns is None: columns = _self.columns if not isinstance(columns, pd.Index): columns = pd.Index(columns) if len(columns) == 1: name = columns[0] if name == 0: # was a Series before name = None else: name = None arr = np.asarray(a) arr = reshape_fns.soft_to_ndim(arr, self.ndim) checks.assert_shape_equal(arr, index, axis=(0, 0)) if arr.ndim == 2: checks.assert_shape_equal(arr, columns, axis=(1, 0)) if arr.ndim == 1: return pd.Series(arr, index=index, name=name, dtype=dtype) if arr.ndim == 2: if arr.shape[1] == 1 and _self.ndim == 1: return pd.Series(arr[:, 0], index=index, name=name, dtype=dtype) return pd.DataFrame(arr, index=index, columns=columns, dtype=dtype) raise ValueError(f"{arr.ndim}-d input is not supported")
def _wrap(arr): arr = np.asarray(arr) checks.assert_ndim(arr, (1, 2)) if fillna is not None: arr[pd.isnull(arr)] = fillna arr = reshape_fns.soft_to_ndim(arr, self.ndim) checks.assert_shape_equal(arr, index, axis=(0, 0)) if arr.ndim == 2: checks.assert_shape_equal(arr, columns, axis=(1, 0)) if arr.ndim == 1: return pd.Series(arr, index=index, name=name, dtype=dtype) if arr.ndim == 2: if arr.shape[1] == 1 and _self.ndim == 1: return pd.Series(arr[:, 0], index=index, name=name, dtype=dtype) return pd.DataFrame(arr, index=index, columns=columns, dtype=dtype) raise ValueError(f"{arr.ndim}-d input is not supported")
def wrap(self, a, index=None, columns=None, dtype=None, collapse=None, **kwargs): """Wrap a NumPy array using the stored metadata.""" checks.assert_ndim(a, (1, 2)) group_by = self.grouper.resolve_group_by(**kwargs) a = np.asarray(a) a = reshape_fns.soft_to_ndim(a, self.ndim) if index is None: index = self.index if columns is None: columns = self.grouper.get_columns(**kwargs) if collapse is None: collapse = group_by is not None and group_by is not False and self.grouped_ndim == 1 if columns is not None and len(columns) == 1: name = columns[0] if name == 0: # was a Series before name = None else: name = None # Perform checks if index is not None: checks.assert_shape_equal(a, index, axis=(0, 0)) if a.ndim == 2 and columns is not None: checks.assert_shape_equal(a, columns, axis=(1, 0)) if a.ndim == 1: return pd.Series(a, index=index, name=name, dtype=dtype) if a.ndim == 2 and a.shape[1] == 1 and collapse: return pd.Series(a[:, 0], index=index, name=name, dtype=dtype) return pd.DataFrame(a, index=index, columns=columns, dtype=dtype)
def __init__(self, data=None, x_labels=None, y_labels=None, z_labels=False, trace_kwargs=None, add_trace_kwargs=None, scene_name='scene', fig=None, **layout_kwargs): """Create a volume plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be a 3-dim array. x_labels (array_like): X-axis labels. y_labels (array_like): Y-axis labels. z_labels (array_like): Z-axis labels. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. scene_name (str): Reference to the 3D scene. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. !!! note Figure widgets have currently problems displaying NaNs. Use `.show()` method for rendering. ## Example ```python-repl >>> import vectorbt as vbt >>> import numpy as np >>> volume = vbt.plotting.Volume( ... data=np.random.randint(1, 10, size=(3, 3, 3)), ... x_labels=['a', 'b', 'c'], ... y_labels=['d', 'e', 'f'], ... z_labels=['g', 'h', 'i'] ... ) >>> volume.fig ``` ![](/vectorbt/docs/img/Volume.png) """ Configured.__init__(self, data=data, x_labels=x_labels, y_labels=y_labels, z_labels=z_labels, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, scene_name=scene_name, fig=fig, **layout_kwargs) from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_trace_kwargs = {} if data is None: if x_labels is None or y_labels is None or z_labels is None: raise ValueError( "At least x_labels, y_labels and z_labels must be passed") x_len = len(x_labels) y_len = len(y_labels) z_len = len(z_labels) else: checks.assert_ndim(data, 3) data = np.asarray(data) x_len, y_len, z_len = data.shape if x_labels is None: x_labels = np.arange(x_len) else: x_labels = clean_labels(x_labels) if y_labels is None: y_labels = np.arange(y_len) else: y_labels = clean_labels(y_labels) if z_labels is None: z_labels = np.arange(z_len) else: z_labels = clean_labels(z_labels) x_labels = np.asarray(x_labels) y_labels = np.asarray(y_labels) z_labels = np.asarray(z_labels) if fig is None: fig = FigureWidget() if 'width' in layout: # Calculate nice width and height fig.update_layout(width=layout['width'], height=0.7 * layout['width']) # Non-numeric data types are not supported by go.Volume, so use ticktext # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible more_layout = dict() if not np.issubdtype(x_labels.dtype, np.number): x_ticktext = x_labels x_labels = np.arange(x_len) more_layout[scene_name] = dict(xaxis=dict( ticktext=x_ticktext, tickvals=x_labels, tickmode='array')) if not np.issubdtype(y_labels.dtype, np.number): y_ticktext = y_labels y_labels = np.arange(y_len) more_layout[scene_name] = dict(yaxis=dict( ticktext=y_ticktext, tickvals=y_labels, tickmode='array')) if not np.issubdtype(z_labels.dtype, np.number): z_ticktext = z_labels z_labels = np.arange(z_len) more_layout[scene_name] = dict(zaxis=dict( ticktext=z_ticktext, tickvals=z_labels, tickmode='array')) fig.update_layout(**more_layout) fig.update_layout(**layout_kwargs) # Arrays must have the same length as the flattened data array x = np.repeat(x_labels, len(y_labels) * len(z_labels)) y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels)) z = np.tile(z_labels, len(x_labels) * len(y_labels)) volume = go.Volume( x=x, y=y, z=z, opacity=0.2, surface_count=15, # keep low for big data colorscale='Plasma') volume.update(**trace_kwargs) fig.add_trace(volume, **add_trace_kwargs) TraceUpdater.__init__(self, fig, [fig.data[-1]]) if data is not None: self.update(data)
def create_volume(data=None, x_labels=None, y_labels=None, z_labels=False, trace_kwargs={}, fig=None, **layout_kwargs): """Create a volume plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be a 3-dim array. x_labels (array_like): X-axis labels. y_labels (array_like): Y-axis labels. z_labels (array_like): Z-axis labels. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. !!! note Figure widgets have currently problems displaying NaNs. Use `.show()` method for rendering. Example: ```py import vectorbt as vbt import numpy as np vbt.plotting.create_volume( data=np.random.randint(1, 10, size=(3, 3, 3)), x_labels=['a', 'b', 'c'], y_labels=['d', 'e', 'f'], z_labels=['g', 'h', 'i'] ) ``` ![](/vectorbt/docs/img/create_volume.png) """ if data is None: raise ValueError("Data must be passed") data = np.asarray(data) checks.assert_ndim(data, 3) if x_labels is None: x_labels = np.arange(data.shape[0]) if y_labels is None: y_labels = np.arange(data.shape[1]) if z_labels is None: z_labels = np.arange(data.shape[2]) x_labels = np.asarray(x_labels) y_labels = np.asarray(y_labels) z_labels = np.asarray(z_labels) if fig is None: fig = CustomFigureWidget() fig.update_layout( width=700, height=450 ) # Non-numeric data types are not supported by go.Volume, so use ticktext # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible if not np.issubdtype(x_labels.dtype, np.number): x_ticktext = x_labels x_labels = np.arange(data.shape[0]) fig.update_layout(scene=dict(xaxis=dict(ticktext=x_ticktext, tickvals=x_labels, tickmode='array'))) if not np.issubdtype(y_labels.dtype, np.number): y_ticktext = y_labels y_labels = np.arange(data.shape[1]) fig.update_layout(scene=dict(yaxis=dict(ticktext=y_ticktext, tickvals=y_labels, tickmode='array'))) if not np.issubdtype(z_labels.dtype, np.number): z_ticktext = z_labels z_labels = np.arange(data.shape[2]) fig.update_layout(scene=dict(zaxis=dict(ticktext=z_ticktext, tickvals=z_labels, tickmode='array'))) # Arrays must have the same length as the flattened data array x = np.repeat(x_labels, len(y_labels) * len(z_labels)) y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels)) z = np.tile(z_labels, len(x_labels) * len(y_labels)) fig.update_layout(**layout_kwargs) volume = go.Volume( x=x, y=y, z=z, value=data.flatten(), opacity=0.15, surface_count=15, # keep low for big data colorscale='Plasma' ) volume.update(**trace_kwargs) fig.add_trace(volume) return fig
def create_volume(data=None, x_labels=None, y_labels=None, z_labels=False, trace_kwargs=None, return_trace_idx=False, row=None, col=None, scene_name='scene', fig=None, **layout_kwargs): """Create a volume plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be a 3-dim array. x_labels (array_like): X-axis labels. y_labels (array_like): Y-axis labels. z_labels (array_like): Z-axis labels. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`. return_trace_idx (bool): Whether to return trace index for `update_volume_data`. row (int): Row position. col (int): Column position. scene_name (str): Reference to the 3D scene. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. !!! note Figure widgets have currently problems displaying NaNs. Use `.show()` method for rendering. ## Example ```python-repl >>> import vectorbt as vbt >>> import numpy as np >>> vbt.plotting.create_volume( ... data=np.random.randint(1, 10, size=(3, 3, 3)), ... x_labels=['a', 'b', 'c'], ... y_labels=['d', 'e', 'f'], ... z_labels=['g', 'h', 'i'] ... ) ``` ![](/vectorbt/docs/img/create_volume.png) """ from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if data is None: raise ValueError("Data must be passed") data = np.asarray(data) checks.assert_ndim(data, 3) if x_labels is None: x_labels = np.arange(data.shape[0]) if y_labels is None: y_labels = np.arange(data.shape[1]) if z_labels is None: z_labels = np.arange(data.shape[2]) x_labels = np.asarray(x_labels) y_labels = np.asarray(y_labels) z_labels = np.asarray(z_labels) if fig is None: fig = CustomFigureWidget() if 'width' in layout: # Calculate nice width and height fig.update_layout(width=layout['width'], height=0.7 * layout['width']) # Non-numeric data types are not supported by go.Volume, so use ticktext # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible more_layout = dict() if not np.issubdtype(x_labels.dtype, np.number): x_ticktext = x_labels x_labels = np.arange(data.shape[0]) more_layout[scene_name] = dict(xaxis=dict( ticktext=x_ticktext, tickvals=x_labels, tickmode='array')) if not np.issubdtype(y_labels.dtype, np.number): y_ticktext = y_labels y_labels = np.arange(data.shape[1]) more_layout[scene_name] = dict(yaxis=dict( ticktext=y_ticktext, tickvals=y_labels, tickmode='array')) if not np.issubdtype(z_labels.dtype, np.number): z_ticktext = z_labels z_labels = np.arange(data.shape[2]) more_layout[scene_name] = dict(zaxis=dict( ticktext=z_ticktext, tickvals=z_labels, tickmode='array')) fig.update_layout(**more_layout) fig.update_layout(**layout_kwargs) # Arrays must have the same length as the flattened data array x = np.repeat(x_labels, len(y_labels) * len(z_labels)) y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels)) z = np.tile(z_labels, len(x_labels) * len(y_labels)) volume = go.Volume( x=x, y=y, z=z, value=data.flatten(), opacity=0.2, surface_count=15, # keep low for big data colorscale='Plasma') volume.update(**trace_kwargs) fig.add_trace(volume, row=row, col=col) trace_idx = len(fig.data) - 1 if return_trace_idx: return fig, trace_idx return fig