Rho+ documentation Rho+ Gallery
previous Welcome to Rho+’s documentation!
next Colormaps for Quantitative Data

Rho+ Gallery§

This page is a tour of what Rho+ has to offer.

Rho+ has two major parts: - An aesthetically pleasing theme, with harmonious light and dark variants, that works for matplotlib, bokeh, plotly, and altair plots. - A bunch of assorted odds and ends for making beautiful plots or exploring data, designed for ease of use for exploratory data analysis inside Jupyter.

Think of Rho+ as a nitro canister for your data visualization inside Python. This page shows all of the new tools you have at your disposal.

[1]:
# for Google Colab

%pip install rho_plus matplotlib seaborn bokeh panel
Requirement already satisfied: rho_plus in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (0.5.1)
Requirement already satisfied: matplotlib in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (3.5.2)
Requirement already satisfied: seaborn in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (0.11.2)
Requirement already satisfied: bokeh in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (2.4.3)
Requirement already satisfied: panel in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (0.13.1)
Requirement already satisfied: numpy>=1.21 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from rho_plus) (1.23.0)
Requirement already satisfied: hsluv<6.0.0,>=5.0.3 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from rho_plus) (5.0.3)
Requirement already satisfied: python-dateutil>=2.7 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (2.8.2)
Requirement already satisfied: kiwisolver>=1.0.1 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (1.4.3)
Requirement already satisfied: pyparsing>=2.2.1 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (3.0.9)
Requirement already satisfied: cycler>=0.10 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (0.11.0)
Requirement already satisfied: pillow>=6.2.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (9.1.1)
Requirement already satisfied: fonttools>=4.22.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (4.33.3)
Requirement already satisfied: packaging>=20.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from matplotlib) (21.3)
Requirement already satisfied: scipy>=1.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from seaborn) (1.9.3)
Requirement already satisfied: pandas>=0.23 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from seaborn) (1.5.2)
Requirement already satisfied: Jinja2>=2.9 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from bokeh) (3.1.2)
Requirement already satisfied: typing-extensions>=3.10.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from bokeh) (4.2.0)
Requirement already satisfied: tornado>=5.1 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from bokeh) (6.1)
Requirement already satisfied: PyYAML>=3.10 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from bokeh) (6.0)
Requirement already satisfied: param>=1.12.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (1.12.1)
Requirement already satisfied: pyviz_comms>=0.7.4 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (2.2.0)
Requirement already satisfied: markdown in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (3.3.7)
Requirement already satisfied: requests in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (2.27.1)
Requirement already satisfied: tqdm>=4.48.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (4.64.0)
Requirement already satisfied: pyct>=0.4.4 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (0.4.8)
Requirement already satisfied: bleach in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (5.0.0)
Requirement already satisfied: setuptools in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from panel) (62.3.2)
Requirement already satisfied: MarkupSafe>=2.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from Jinja2>=2.9->bokeh) (2.1.1)
Requirement already satisfied: pytz>=2020.1 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from pandas>=0.23->seaborn) (2022.7)
Requirement already satisfied: six>=1.5 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from python-dateutil>=2.7->matplotlib) (1.13.0)
Requirement already satisfied: webencodings in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from bleach->panel) (0.5.1)
Requirement already satisfied: importlib-metadata>=4.4 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from markdown->panel) (4.11.4)
Requirement already satisfied: idna<4,>=2.5 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from requests->panel) (3.4)
Requirement already satisfied: urllib3<1.27,>=1.21.1 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from requests->panel) (1.24.3)
Requirement already satisfied: certifi>=2017.4.17 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from requests->panel) (2022.5.18.1)
Requirement already satisfied: charset-normalizer~=2.0.0 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from requests->panel) (2.0.12)
Requirement already satisfied: zipp>=0.5 in /home/nicholas/anaconda3/envs/ds/lib/python3.9/site-packages (from importlib-metadata>=4.4->markdown->panel) (3.8.0)
Note: you may need to restart the kernel to use updated packages.

Rho+ “House Style”§

A quick demonstration of the Rho+ theming, as seen in Matplotlib. To set it up in your notebook, simply run

import rho_plus as rp

theme, colors = rp.mpl_setup(is_dark=True)

Now theme is an rcParams that’s been made the default, and colors is a list of 12 colors that form the new default sequence.

First, let’s show the default matplotlib theme:

[2]:
import matplotlib.pyplot as plt
import seaborn as sns
import rho_plus as rp

pg = sns.load_dataset('penguins')

def pg_plot():
    plt.scatter(data=pg, x='bill_depth_mm', y='bill_length_mm', c='body_mass_g')
    plt.colorbar()
    plt.xlabel('Bill Depth')
    plt.ylabel('Bill Length')
    plt.title('Penguin Bill Measurements')

# first: the default plot
with plt.style.context('default', after_reset=True):
    pg_plot()
_images/gallery_3_0.png

Now, the Rho+ version:

[3]:
IS_DARK = False
theme, colors = rp.mpl_setup(IS_DARK)

pg_plot()
_images/gallery_5_0.png

The highlights to notice:

  • A lot less clutter!

  • DejaVu Sans is not the default font: instead, Rho+ uses Source Sans.

  • The default colormap has been modified: note how the brightest yellows are a little bit easier to see on white.

The kicker is that, if you like to work in dark mode instead, it’s easy to switch:

[4]:
IS_DARK = True
theme, colors = rp.mpl_setup(IS_DARK)

pg_plot()
_images/gallery_7_0.png

Matplotlib/Seaborn Beyond Stylesheets§

There’s only so much Rho+ can do by modifying the stylesheet used in Matplotlib. For more, Rho+ has several functions that modify existing matplotlib plots to give them a glow-up.

Custom Lineplot Labels§

It can be very difficult to keep track of which line is which in a large line plot because, unlike a box plot, there’s no obvious place to put a label:

[5]:
flights = sns.load_dataset('flights')

sns.lineplot(data=flights, x='year', y='passengers', hue='month', lw=1.5)
[5]:
<AxesSubplot:xlabel='year', ylabel='passengers'>
_images/gallery_10_1.png

Good luck trying to figure out which month is which.

With the power of rp.line_labels(), the legend is replaced with an annotation beside each line’s final value:

[6]:
sns.lineplot(data=flights, x='year', y='passengers', hue='month', lw=1.5)

rp.line_labels()
_images/gallery_12_0.png

Note how the line labels are shifted so they don’t overlap. Doing this with minimal shifting is a hard problem that Rho+ handles pretty well. Labels are line-wrapped and given exactly as much room as they need. (If you want to change the font size or style of the labels, change the legend label styling before calling line_labels() so Rho+ knows how big everything is.)

See what a really big text label looks like:

[7]:
flights2 = flights.copy()
flights2['month'] = flights2['month'].replace(['Aug'], 'The Month of August (demonstrates line wrapping and intelligent margins)')
flights2['month'] = flights2['month'].replace(['May'], 'The Month of May (also note how this is italic now!)')
sns.lineplot(data=flights2, x='year', y='passengers', hue='month', lw=1.5)

rp.line_labels(size=14, style='italic')
_images/gallery_14_0.png

Automatic Scatterplot Labeling§

The 2D cousin of the above line labeling function is rp.scatter_labels(). Consider this scatterplot:

[8]:
import pandas as pd
def raptor_plot():
    fig, ax = plt.subplots()
    raptor = pd.read_csv('https://raw.githubusercontent.com/fivethirtyeight/data/master/nba-raptor/modern_RAPTOR_by_player.csv')
    data = raptor.query('mp > 500 and raptor_total > 7')
    labels = data['player_name'] + ' (' + data['season'].astype(str) + ')'

    fig.suptitle('The Best Modern NBA Seasons Ever\nAccording to 538')
    sns.scatterplot(data=data, x='raptor_offense', y='raptor_defense', hue='raptor_total', palette=rp.mpl_solara, ec=None, size='mp', legend=None)
    ax.set_xlabel('Offensive Impact')
    ax.set_ylabel('Defensive Impact')
    rp.ylabel_top()
    return labels

raptor_plot();
_images/gallery_16_0.png

By adding rp.scatter_labels() and a list of label texts (the same order as in the plot), we can try to add as many point labels as possible. This problem is much more computationally challenging than the line labeling, so Rho+ uses simple heuristics that give good results for most plots. If you want to publish a figure in a book, it’s probably best to lay out the labels yourself.

[9]:
labels = raptor_plot();
rp.scatter_labels(labels, size=13)
[9]:
<AxesSubplot:xlabel='Offensive Impact', ylabel='Defensive Impact'>
_images/gallery_18_1.png

Labels will be wrapped if necessary to fit them in. Rho+ will make sure the labels don’t overlap with plot elements, including the legend, but it can’t see the future: make sure you’ve plotted everything you want to plot before calling scatter_labels().

Readable Y-Axis Labels§

For space efficiency, most plotting libraries have a default y-axis label that is tilted 90 degrees. If you want your label to be how all other English text is read, you can call rp.ylabel_top(). It turns the y-axis label right side up, moves it to the top to save some space by avoiding overlap with the y-axis tick labels, and wraps it if it would be too long.

[10]:
pg_plot()
plt.ylabel('Bill Length in Millimeters')
plt.show()

pg_plot()
plt.ylabel('Bill Length in Millimeters')
rp.ylabel_top()
_images/gallery_21_0.png
_images/gallery_21_1.png

Custom Boxplot Styling§

This is what a box plot looks like using just the stylesheet. It also demonstrates the default categorical color theme.

[11]:
sns.boxplot(data=flights, x='passengers', y='month')
[11]:
<AxesSubplot:xlabel='passengers', ylabel='month'>
_images/gallery_23_1.png

The “whiskers” aren’t quite right, and it’s a bit loud with the filled colors taking up so much of the figure.

To fix the whisker styling, pass in **rp.boxstyle() into sns.boxplot or plt.boxplot.

To make the boxplot only colored on the edges, call rp.unfill_boxplot() after plotting a boxplot.

[12]:
sns.boxplot(data=flights, x='passengers', y='month', **rp.boxstyle())
plt.show()

sns.boxplot(data=flights, x='passengers', y='month', **rp.boxstyle())
rp.unfill_boxplot()
_images/gallery_25_0.png
_images/gallery_25_1.png

Smarter Tick Limits§

À la Edward Tufte, legend of data visualization, rp.smart_ticks() modifies the axis limits to show the maximium and minimum while adding negligible clutter. Pass xaxis=False or yaxis=False to only change a single axis.

[13]:
pg_plot()
plt.show()

pg_plot()
rp.smart_ticks()
_images/gallery_27_0.png
_images/gallery_27_1.png

Interactive Exploratory Widgets§

Rho+ includes some useful features for working with the holoviews ecosystem (panel, bokeh, holoviews, and hvplot). Like above, you set things up with

import rho_plus as rp

IS_DARK = True
rp.panel_setup(IS_DARK)

Data Grid§

Often, when doing data science, you just want to do basic spreadsheet operations on a DataFrame. Unfortunately, the default rendering of pandas DataFrames in VSCode or the standard notebook doesn’t offer much in the way of functionality. Enter rp.datagrid():

[14]:
import rho_plus as rp

IS_DARK = True
rp.panel_setup(IS_DARK)

rp.datagrid(pg)
[14]:

This data grid, courtesy of Perspective, has a lot of features. Drag any of the columns to the “Group By”, “Split By”, “Order By”, or “Where” fields to start slicing and dicing the data. Hit the icon next to each column to customize that field’s display.

Rho+ provides a simple wrapper that uses the current Panel dark mode setting and fills the screen horizontally.

Object Tree Viewer§

Exploring big nested objects inside a notebook can be quite challenging. Enter rp.show_json():

[15]:
rp.show_json(rp.vega_rho_dark)
[15]:

This is a simple way of looking through an object: serializing to JSON and then displaying using a widget like this one. Hovering over an object shows its nested values, and as always it matches your existing dark mode setting.

Table of Contents

  • Rho+ Gallery
    • Rho+ “House Style”
    • Matplotlib/Seaborn Beyond Stylesheets
    • Interactive Exploratory Widgets
  • Colormaps for Quantitative Data

  • General Index
previous Welcome to Rho+’s documentation!
next Colormaps for Quantitative Data
© Copyright 2022, Nicholas Miklaucic. Created using Sphinx 6.1.3. Insipid Theme. Show Source.