A picture is not worth a thousand words [reference]. Likewise, a data visualization is not worth a thousand words. A data visualization is worth only the words that are supported by information contained in the visualization. In this blog post, interactive data visualization is used to deliver information about tech stock prices in 2018 (but only a limited amount).
Complete price information for 19 tech stocks for each day of 2018 is contained in the data visualization below—interact and find it.
Stocks are down after a volatile year, but that’s not the whole picture https://t.co/BJXs4SEElG
— The Washington Post (@washingtonpost) January 1, 2019
tiingo
librarytiingo
library provides access to the Tiingo API, which is a commercial product providing a Starter (free) access level for users with an API key. Complete Python code (except for the API key you can get for free) to download historical AAPL stock price data into a pandas
DataFrame object is below. All data in the interactive visualization above was downloaded with the Python tiingo
library at a rate well below the limits of the Starter plan.
import pandas as pd
from io import StringIO
from tiingo import TiingoClient
API_KEY = '' # your API KEY here
client = TiingoClient({'api_key': API_KEY})
df = pd.read_csv(StringIO(client.get_ticker_price('AAPL',
fmt='csv',
startDate='01-01-2019',
endDate='01-15-2019')))
bokeh
bokeh
data visualization above is the diverging and asymmetric colorbar. The matplotlib colormap reference and bokeh colormap reference both document diverging colormaps that alway diverge at exactly the midpoint (symmetrically). For example, the matplotlib
RdGy colormap (diverging and symmetric) is below.
matplotlib
that diverges somewhere other than the midpoint (asymmetrically). This blog post describes then how to create and use a diverging asymmetric colorbar in bokeh
, two examples of which are below. In both cases they reproduce the RdGy colormap above but diverge away from the midpoint.
bokeh
is below. The colormap is built from two sequential matplotlib
colormaps — these appear as cm.Reds
and cm.Greys
in the function. The idea is to line up the two independent colormaps, aligning the ends and scaling everything correctly, and then use the matplotlib
colormap implementation to create an object that bokeh
understands and can use with a 3D visualization. Note that the function with all default inputs recreates the matplotlib
RdGy colormap.
import numpy as np
from matplotlib import cm
from bokeh.models import LinearColorMapper
def bokeh_diverging_asymmetric_color_mapper(low=0, high=1, center=0.5,
ncolors=256, cmaps=[cm.Reds, cm.Greys]):
"""
create and return a bokeh LinearColorMapper object representing a
diverging and asymmetric colormap
* inputs 'low' and 'high' represent same as in LinearColorMapper
* 'center' is the midpoint of the colormap (low < center < high)
* 'ncolors' defines the resolution of the colormap
* the colormap is built from the 2 matplotlib colormaps in 'cmaps'
"""
assert low < center < high
assert len(cmaps) == 2
nmaps = [(center - low) / (high - low), (high - center) / (high - low)]
nmaps = np.round(ncolors * np.array(nmaps)).astype(np.int)
fracs = [[1 * x / nmap for x in range(nmap)] for nmap in nmaps]
palette = [cm.colors.rgb2hex(cmaps[0](x)) for x in fracs[0]][::-1] + \
[cm.colors.rgb2hex(cmaps[1](x)) for x in fracs[1]]
return LinearColorMapper(palette=palette, low=low, high=high)
bokeh
3D data visualization — Python code for all of that is below. The 3D data is created in numpy
and represents a rectagular grid of random numbers in the default range of the random function (0 to 1). These data are then represented in a bokeh
figure as rectangle objects. In order to apply the colormap, the fill_color
of the rectange objects and the bokeh.models.Colorbar
object both need to both be mapped to the output of the bokeh_diverging_asymmetric_color_mapper
function (in this case configured to create a red-grey colormap with midpoint at 0.6).
import pandas as pd
from bokeh.plotting import figure, output_file, show
from bokeh.models import ColorBar
# create 3D data in a DataFrame
x, y = np.arange(60), np.arange(30)
xx, yy = np.meshgrid(x, y)
zz = np.random.random(xx.shape)
df = pd.DataFrame(
{'x': np.ravel(xx), 'y': np.ravel(yy), 'z': np.ravel(zz)})
# create a bokeh diverging asymmetric color mapper object
mapper = bokeh_diverging_asymmetric_color_mapper(low=0, high=1, center=0.6)
# create a bokeh figure, add Rectangle glyphs mapped to the 3D data
fig = figure(width=600, height=300, tools='')
fig.rect(x='x', y='y', width=1, height=1, source=df, line_color=None,
fill_color={'field': 'z', 'transform': mapper})
# create and add a colorbar object, then show
cbar = ColorBar(color_mapper=mapper, location=(0, 0), label_standoff=10)
cbar.major_label_text_font_size = '12pt'
fig.add_layout(cbar, place='right')
show(fig)
mapper = bokeh_diverging_asymmetric_color_mapper(low=0, high=1, center=0.3,
cmaps=[cm.Purples, cm.Blues])