Interactive Plots Integration (Plotly, Bokeh, Highcharts)¶
PyBloqs also supports plotting with interactive plotting libraries such as Plotly(offline), Bokeh and Highcharts.
The plots will be rendered in HTML and will rely on your browser’s CSS and JS capabilities to provide interactivity.
Plotly Example¶
[1]:
import plotly.express as px
df = px.data.gapminder().query("country=='Canada'")
plotly_fig = px.line(df, x="year", y="lifeExp", title='Life expectancy in Canada')
plotly_fig
[2]:
import pybloqs as p
p.Block(plotly_fig)
Matplotlib is building the font cache; this may take a moment.
[2]:
Bokeh Example¶
[3]:
import numpy as np
from six.moves import zip
from bokeh.plotting import figure as b_fig
# The lines below are only needed for notebook output
from bokeh.io.output import output_notebook
from bokeh.resources import INLINE
output_notebook(resources=INLINE)
[4]:
N = 4000
x = np.random.random(size=N) * 100
y = np.random.random(size=N) * 100
radii = np.random.random(size=N) * 1.5
colors2 = ["#%02x%02x%02x" % (int(r), int(g), 150) for r, g in zip(50+2*x, 30+2*y)]
bokeh_fig = b_fig(width=300, height=300)
bokeh_fig.scatter(x,y, radius=radii, fill_color=colors2, fill_alpha=0.6, line_color=None)
[4]:
[5]:
p.Block(bokeh_fig)
[5]:
Combining Bokeh and Plotly plots with HStack¶
[6]:
p.HStack([p.Block(bokeh_fig), p.Block(plotly_fig)])
[6]:
Highcharts examples¶
Please note: Highcharts has a proprietary license
Simple line chart¶
When evaluated as the last expression in a Notebook Cell, the plot is automatically displayed inline. Note how the plot name (hover over the line to see the little popup) is taken from the input data (if available).
[7]:
import pandas as pd
import numpy as np
from datetime import datetime
df = pd.DataFrame((np.random.rand(200, 4)-0.5)/10,
columns=list("ABCD"),
index=pd.date_range(datetime(2000,1,1), periods=200))
df_cr = (df + 1).cumprod()
a = df_cr['A']
b = df_cr['B']
c = df_cr['C']
[8]:
import pybloqs.plot as pp
pp.interactive()
pp.Plot(a)
---------------------------------------------------------------------------
FileNotFoundError Traceback (most recent call last)
Input In [8], in <module>
----> 1 import pybloqs.plot as pp
2 pp.interactive()
3 pp.Plot(a)
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/plot/__init__.py:3, in <module>
1 from six import StringIO
----> 3 from pybloqs.plot.core import * # noqa F403
4 import pybloqs.static as static
7 def add_highcharts_shim_to_stream(stream, highcharts_all):
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/plot/core.py:80, in <module>
76 def _construct_arith(self, op, other):
77 return _PlotDim(self.fun_str + op + str(other))
---> 80 class Plot(BaseBlock):
81 """
82 A composable chart. When the input data is a list of plot objects, they will be merged into a single
83 figure.
84 """
86 resource_deps = [JScript(m) for m in HIGHCHARTS_ALL]
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/plot/core.py:86, in Plot()
80 class Plot(BaseBlock):
81 """
82 A composable chart. When the input data is a list of plot objects, they will be merged into a single
83 figure.
84 """
---> 86 resource_deps = [JScript(m) for m in HIGHCHARTS_ALL]
88 def __init__(self, data, *args, **kwargs):
89 """
90 Create a chart or composite chart from the supplied data.
91
(...)
106 block parameter.
107 """
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/plot/core.py:86, in <listcomp>(.0)
80 class Plot(BaseBlock):
81 """
82 A composable chart. When the input data is a list of plot objects, they will be merged into a single
83 figure.
84 """
---> 86 resource_deps = [JScript(m) for m in HIGHCHARTS_ALL]
88 def __init__(self, data, *args, **kwargs):
89 """
90 Create a chart or composite chart from the supplied data.
91
(...)
106 block parameter.
107 """
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/static/__init__.py:65, in JScript.__init__(self, file_name, script_string, name, encode)
56 def __init__(self, file_name=None, script_string=None, name=None, encode=True):
57 """
58 A JavaScript dependency definition. Ensures that multiple inclusions of the same function are handled safely.
59
(...)
63 :param encode: Whether to compress and base64 encode the script.
64 """
---> 65 super(JScript, self).__init__(file_name, 'js', script_string, name)
66 self.encode = encode
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/static/__init__.py:29, in Resource.__init__(self, file_name, extension, content_string, name)
27 else:
28 self.name = os.path.splitext(file_name)[0]
---> 29 with open(self._local_path(file_name, extension), encoding='utf-8') as f:
30 self.content_string = f.read()
FileNotFoundError: [Errno 2] No such file or directory: '/home/docs/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pybloqs/static/highstock.js'
Saving as interactive HTML¶
[9]:
pp.Plot(df).save("chart_sample.html")
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [9], in <module>
----> 1 pp.Plot(df).save("chart_sample.html")
NameError: name 'pp' is not defined
Scatter Plot¶
Regular scatter plot, with zooming on both the x and y axes.
[10]:
pp.Plot(df.values[:,:2], pp.Scatter(pp.Marker(enabled=True)), pp.Chart(zoom_type="xy"))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [10], in <module>
----> 1 pp.Plot(df.values[:,:2], pp.Scatter(pp.Marker(enabled=True)), pp.Chart(zoom_type="xy"))
NameError: name 'pp' is not defined
Bar Charts¶
Notice how when viewing all the data at once, the chart shows monthly data, yet zooming in reveals additional detail at up to daily resolution. This is accomplished by using a custom data grouping.
[11]:
bar_grouping = pp.DataGrouping(approximation="open", enabled=True, group_pixel_width=100)
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [11], in <module>
----> 1 bar_grouping = pp.DataGrouping(approximation="open", enabled=True, group_pixel_width=100)
NameError: name 'pp' is not defined
[12]:
# Bar chart from a dataframe
pp.Plot(df, pp.Column(bar_grouping))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [12], in <module>
1 # Bar chart from a dataframe
----> 2 pp.Plot(df, pp.Column(bar_grouping))
NameError: name 'pp' is not defined
[13]:
# Stacked bar chart
pp.Plot(df, pp.Column(bar_grouping, stacking="normal"))
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [13], in <module>
1 # Stacked bar chart
----> 2 pp.Plot(df, pp.Column(bar_grouping, stacking="normal"))
NameError: name 'pp' is not defined
[14]:
# Composite bar chart from two separate plots.
s2 = pp.Plot([pp.Plot(a, pp.Column(bar_grouping)),
pp.Plot(b, pp.Column(bar_grouping))])
s2
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [14], in <module>
1 # Composite bar chart from two separate plots.
----> 2 s2 = pp.Plot([pp.Plot(a, pp.Column(bar_grouping)),
3 pp.Plot(b, pp.Column(bar_grouping))])
4 s2
NameError: name 'pp' is not defined
Comparing series in a dataframe¶
Plot the cumulative percentage difference between input series (or columns of a dataframe). The cumulative difference is always calculated from the start of the observation window. This results in intuitively correct behavior when zooming in or sliding the window, as the chart will dynamically recalculate the values. Incredibly useful for comparing model performance over time for example as one doesn’t need to manually normalize money curves for different periods.
[15]:
s3 = pp.Plot(df_cr,
pp.PlotOptions(pp.Series(compare="percent")),
pp.TooltipPct(),
pp.YAxisPct())
s3
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [15], in <module>
----> 1 s3 = pp.Plot(df_cr,
2 pp.PlotOptions(pp.Series(compare="percent")),
3 pp.TooltipPct(),
4 pp.YAxisPct())
5 s3
NameError: name 'pp' is not defined
Three series on separate side-by-side Y axes¶
[16]:
s4 = pp.Plot([pp.Plot(a),
pp.Plot(b, pp.YAxis(pp.Title(text="B Axis"), opposite=True)),
pp.Plot(c, pp.YAxis(pp.Title(text="C Axis"), opposite=True, offset=40))])
s4
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [16], in <module>
----> 1 s4 = pp.Plot([pp.Plot(a),
2 pp.Plot(b, pp.YAxis(pp.Title(text="B Axis"), opposite=True)),
3 pp.Plot(c, pp.YAxis(pp.Title(text="C Axis"), opposite=True, offset=40))])
4 s4
NameError: name 'pp' is not defined
Two series on separate subplots¶
[17]:
s5 = pp.Plot([pp.Plot(a, pp.Line(), pp.YAxis(pp.Title(text="a only"), height=150)),
pp.Plot(b, pp.Column(), pp.YAxis(pp.Title(text="b only"),
top=200, height=100, offset=0))],
pp.Tooltip(value_decimals=2), height="400px")
s5
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [17], in <module>
----> 1 s5 = pp.Plot([pp.Plot(a, pp.Line(), pp.YAxis(pp.Title(text="a only"), height=150)),
2 pp.Plot(b, pp.Column(), pp.YAxis(pp.Title(text="b only"),
3 top=200, height=100, offset=0))],
4 pp.Tooltip(value_decimals=2), height="400px")
5 s5
NameError: name 'pp' is not defined
Creating a report from multiple charts and saving as HTML or PDF. Or sending it as email.¶
[18]:
import pandas.util.testing as pt
b = p.Block([p.Block(pt.makeTimeDataFrame().tail(10), title="A table", title_level=1),
p.Block([s2, s3], title="Side-by-side Plots", cols=2),
p.Block(title="Full Width Plots", styles={"page-break-before": "always"}),
p.Block(s4, title="Side by Side Axes"),
p.Block(s5, title="Composite Plots")], title="Dynamic Reports")
/tmp/ipykernel_1056/2729744213.py:1: FutureWarning:
pandas.util.testing is deprecated. Use the functions in the public API at pandas.testing instead.
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Input In [18], in <module>
1 import pandas.util.testing as pt
2 b = p.Block([p.Block(pt.makeTimeDataFrame().tail(10), title="A table", title_level=1),
----> 3 p.Block([s2, s3], title="Side-by-side Plots", cols=2),
4 p.Block(title="Full Width Plots", styles={"page-break-before": "always"}),
5 p.Block(s4, title="Side by Side Axes"),
6 p.Block(s5, title="Composite Plots")], title="Dynamic Reports")
NameError: name 's2' is not defined
[19]:
b.save("charts_test.pdf")
b.save("charts_test.html")
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Input In [19], in <module>
----> 1 b.save("charts_test.pdf")
2 b.save("charts_test.html")
File ~/checkouts/readthedocs.org/user_builds/pybloqs/envs/latest/lib/python3.8/site-packages/pandas/core/generic.py:5583, in NDFrame.__getattr__(self, name)
5576 if (
5577 name not in self._internal_names_set
5578 and name not in self._metadata
5579 and name not in self._accessors
5580 and self._info_axis._can_hold_identifiers_and_holds_name(name)
5581 ):
5582 return self[name]
-> 5583 return object.__getattribute__(self, name)
AttributeError: 'Series' object has no attribute 'save'