How to specify a rectangle on a datetimeaxis plot? - python

I want to draw a Rectangle (hv.Bounds) on a plot that has a datetime axis. However it's not clear from the documentation how one would specify the corner points.
Naturally I tried to specify a datetime object, however this results in the following error message:
ValueError: lbrt: tuple element is not numeric
import holoviews as hv
import pandas as pd
hv.extension('bokeh')
%%opts Curve [width=500]
xs = pd.date_range('1.1.2019', '31.1.2019')
ys = np.sin(range(len(xs)))
box=hv.Bounds((pd.to_datetime('5.1.2019'), 0.1, pd.to_datetime('7.1.2019'), .8))
hv.Curve((xs,ys))

As of version 1.12.3 it's possible to do this:
import holoviews as hv
import pandas as pd
import numpy as np
import hvplot.pandas
hv.extension('bokeh')
index = pd.date_range('1.1.2019', '2.28.2019')
df = pd.DataFrame(np.random.rand(len(index)), index)
pts = pd.to_datetime(['1.15.2019', '2.15.2019'])
box = hv.Bounds((pts[0], 0.1, pts[1], .9)).opts(color='red')
df.hvplot.scatter() * box

As of now, Bounds only accepts numeric bounds, but see this PR if you feel like testing it: https://github.com/pyviz/holoviews/pull/3640

Related

How can you decimate data depending on zoom level of plot?

The documentation for holoviews' decimate operation seems to imply that if max_samples=100, say, you get a plot with 100 points at most no matter the zoom level.
With the following example, I see no new dots appear as I zoom in... can holoviews achieve this? can some other package?
import numpy as np
import holoviews as hv
import pandas as pd
import numpy as np
# from holoviews import opts
# from holoviews.operation.datashader import datashade, shade, dynspread, spread
# from holoviews.operation.datashader import rasterize, ResamplingOperation
from holoviews.operation import decimate
hv.extension('bokeh', width=200)
# Default values suitable for this notebook
decimate.max_samples=100
np.random.seed(1)
points = hv.Points(np.random.multivariate_normal((0,0), [[0.1, 0.1], [0.1, 1.0]], (1_000_000,)))
decimate(points)
The above code seems to decimate data once, and then show the same dots regardless of x_range and y_range...
Any ideas?
Thanks!

Adding arrows to mpf finance plots

I am trying to add an arrow on a given date and price to mpf plot. To do this i have the following code:
import pandas as pd
import yfinance as yf
import datetime
from dateutil.relativedelta import relativedelta
import pandas as pd, mplfinance as mpf, matplotlib.pyplot as plt
db = yf.download(tickers='goog', start=datetime.datetime.now()-relativedelta(days=7), end= datetime.datetime.now(), interval="5m")
db = db.dropna()
a = db['Close'][31:32]
test = mpf.make_addplot(a, type='scatter', markersize=200, marker='^')
mpf.plot(db, type='candle', style= 'charles', addplot=test)
But it is producing the following error:
ValueError: x and y must be the same size
Could you please advise how can i resolve this.
The data passed into mpf.make_addplot() must be the same length as the dataframe passed into mpf.plot(). To plot only some points, the remaining points must be filled with nan values (float('nan'), or np.nan).
You can see this clearly in the documentation at cell **In [7]** (and used in the following cells). See there where the signal data is generated as follows:
def percentB_belowzero(percentB,price):
import numpy as np
signal = []
previous = -1.0
for date,value in percentB.iteritems():
if value < 0 and previous >= 0:
signal.append(price[date]*0.99)
else:
signal.append(np.nan) # <- Make `nan` where no marker needed.
previous = value
return signal
Note: alternatively the signal data can be generated by first initializing to all nan values, and then replacing those nans where you want your arrows:
signal = [float('nan')]*len(db)
signal[31] = db['Close'][31:32]
test = mpf.make_addplot(signal, type='scatter', markersize=200, marker='^')
...
If your ultimate goal is to add an arrow to the title of the question, you can add it in the way shown in #Daniel Goldfarb's How to add value of hlines in y axis using mplfinance python. I used this answer to create a code that meets the end goal. As you can see in the answer, the way to do this is to get the axis and then add an annotation for that axis, where 31 is the date/time index and a[0] is the closing price.
import pandas as pd
import yfinance as yf
import datetime
from dateutil.relativedelta import relativedelta
import pandas as pd
import mplfinance as mpf
import matplotlib.pyplot as plt
db = yf.download(tickers='goog', start=datetime.datetime.now()-relativedelta(days=7), end= datetime.datetime.now(), interval="5m")
db = db.dropna()
a = db['Close'][31:32]
#test = mpf.make_addplot(a, type='scatter', markersize=200, marker='^')
fig, axlist = mpf.plot(db, type='candle', style= 'charles', returnfig=True)#addplot=test
axlist[0].annotate('X', (31, a[0]), fontsize=20, xytext=(34, a[0]+20),
color='r',
arrowprops=dict(
arrowstyle='->',
facecolor='r',
edgecolor='r'))
mpf.show()

How do i get a horizontal violin plot or boxplot? (default is vertical in hvplot holoviews)

Hvplot plots default a vertical violinplot or boxplot. See example below.
How do I get this to be a horizontal plot? So basically I would like to rotate this plot.
import numpy as np
import pandas as pd
import hvplot
import hvplot.pandas
df = pd.DataFrame(np.random.normal(size=[100, 2]), columns=['col1', 'col2'])
plot_hvplot = df.hvplot(kind='box')
You can do this by adding argument invert=True, like this:
plot_hvplot = df.hvplot(kind='box', invert=True)
or by using method .opts(invert_axes=True):
plot_hvplot = df.hvplot(kind='box').opts(invert_axes=True)

How to acess/export holoviews (HexTiles) rendered data

Is there a way to access the aggregated data contained in, e.g.,
import holoviews as hv
import numpy as np
hv.HexTiles(np.random.rand(100,2)).options(gridsize=4)
that is the locations and values (here: counts) of all hexagons?
There is, matplotlib performs the aggregation internally but the bokeh backend uses an operation that returns the aggregated data, and q and r coordinates, which define the hex grid. You can import and use the operation like this:
import holoviews as hv
import numpy as np
from holoviews.plotting.bokeh.hex_tiles import hex_binning
hextiles = hv.HexTiles(np.random.rand(100,2))
df = hex_binning(hextiles, gridsize=4).dframe()
df.head()
If you need to compute the hexagon's x/y-locations you'll have to read up on hexagon offset coordinates.

Changing colormap for categorical data in Holoviews/Datashader

I'm trying to visualize categorical spatial data using Datashader and Holoviews, similarly to https://anaconda.org/jbednar/census-hv-dask/notebook. However, when I try to assign different colors to categories, I always end up with same (presumably default) colors (An example of the output image.)
Here is the code I'm running in Jupyter notebook. Could anyone advise me on how to make the custom color map work? Or at least run the code to see if you end up with colors matching the legend or not. Thank you!
from sklearn.datasets.samples_generator import make_blobs
from matplotlib import pyplot
import pandas as pd
import holoviews as hv
import geoviews as gv
import datashader as ds
from cartopy import crs
from matplotlib.cm import get_cmap
from holoviews.operation.datashader import datashade, aggregate
hv.notebook_extension('bokeh', width=95)
# Generating blob data:
X, y = make_blobs(n_samples=5000000, centers=5, n_features=2)
df = pd.DataFrame(dict(x=X[:,0], y=X[:,1], label=y))
# Plotting the blobs using datashader and holoviews:
%opts Overlay [width=800 height=455 xaxis=None yaxis=None show_grid=False]
%opts Shape (fill_color=None line_width=1.5) [apply_ranges=False]
%opts Points [apply_ranges=False] WMTS (alpha=0.5) NdOverlay [tools=['tap']]
color_key = {0:'red', 1:'blue', 2:'green', 3:'yellow', 4:'black'}
labels = {0:'red', 1:'blue', 2:'green', 3:'yellow', 4:'black'}
color_points = hv.NdOverlay({labels[k]: gv.Points([0,0], crs=crs.PlateCarree(),
label=labels[k])(style=dict(color=v))
for k, v in color_key.items()})
dataset = gv.Dataset(df, kdims=['x', 'y'], vdims=['label'])
shaded = datashade(hv.Points(dataset), cmap=color_key, aggregator=ds.count_cat('label'))
shaded * color_points
That code doesn't seem to be runnable (races is not defined, and gv is not imported), but in any case, categorical colors are determined by the color_key argument, not cmap, so you'd need to change cmap=color_key to color_key=color_key.

Categories

Resources