Bullet Charts in Python/v3

How to create Stephen Few Bullet Charts in Python with Plotly.


Note: this page is part of the documentation for version 3 of Plotly.py, which is not the most recent version.
See our Version 4 Migration Guide for information about how to upgrade.
The version 4 version of this page is here.

New to Plotly?¶

Plotly's Python library is free and open source! Get started by downloading the client and reading the primer.
You can set up Plotly to work in online or offline mode, or in jupyter notebooks.
We also have a quick-reference cheatsheet (new!) to help you get started!

Version Check¶

Note: Bullet Charts are available in version 2.2.2+
Run pip install plotly --upgrade to update your Plotly version

In [1]:
import plotly
plotly.__version__
Out[1]:
'2.2.2'

Simple Bullet Chart¶

Stephen Few's Bullet Chart was invented to replace dashboard gauges and meters, combining both types of charts into simple bar charts with qualitative bars (ranges), quantitiative bars (measures) and performance points (markers) all into one simple layout. ranges typically are broken into three values: bad, okay, good, the measures are the darker bars that represent the actual values that a particular variable reached, and the points or markers usually indicate a goal point relative to the value achieved by the measure bar.

To use this figure factory, you can input either a pandas DataFrame as your data, or a sequence (ex. list, tuple, np.array, etc.) of dictionaries. You must map the column to the name of the particular column or key in your data. For example, if you want column A in your DataFrame to be the measures column, your function call will look like:

ff.create_bullet(data, measures='A', ...)

The valid params to set your DataFrame columns or dictionary keys to are titles, subtitles, ranges, measures and markers. The variable for titles and subtitles must contain strings as its elements and the rest lists.

In [2]:
import plotly.plotly as py
import plotly.figure_factory as ff

import pandas as pd

data = pd.read_json('https://cdn.rawgit.com/plotly/datasets/master/BulletData.json')

fig = ff.create_bullet(
    data, markers='markers', measures='measures',
    ranges='ranges', subtitles='subtitle', titles='title',
)
py.iplot(fig, filename='bullet chart from a dataframe')
Out[2]:

Vertical Bullet Chart¶

This example uses a tuple of dictionaries as its data input.

In [3]:
import plotly.plotly as py
import plotly.figure_factory as ff

data = (
  {"label": "Revenue", "sublabel": "US$, in thousands",
   "range": [150, 225, 300], "performance": [220,270], "point": [250]},
  {"label": "Profit", "sublabel": "%", "range": [20, 25, 30],
   "performance": [21, 23], "point": [26]},
  {"label": "Order Size", "sublabel":"US$, average","range": [350, 500, 600],
   "performance": [100,320],"point": [550]},
  {"label": "New Customers", "sublabel": "count", "range": [1400, 2000, 2500],
   "performance": [1000, 1650],"point": [2100]},
  {"label": "Satisfaction", "sublabel": "out of 5","range": [3.5, 4.25, 5],
   "performance": [3.2, 4.7], "point": [4.4]}
)

fig = ff.create_bullet(
    data, titles='label', subtitles='sublabel', markers='point',
    measures='performance', ranges='range', orientation='v',
)
py.iplot(fig, filename='bullet chart from dict')
Out[3]:

Use Your Own Colors¶

You can use different colors for the range and the measure columns. Set range_colors and measure_colors to a 2-item list of two colors to interpolate between.

In [4]:
import plotly.plotly as py
import plotly.figure_factory as ff

import pandas as pd

data = pd.read_json('https://cdn.rawgit.com/plotly/datasets/master/BulletData.json')

measure_colors=['rgb(63,102,153)', 'rgb(120,194,195)']
range_colors=['rgb(245,225,218)', 'rgb(241,241,241)']


fig = ff.create_bullet(
    data, orientation='h', markers='markers', measures='measures',
    ranges='ranges', subtitles='subtitle', titles='title',
    range_colors=range_colors,
    measure_colors=measure_colors
)
py.iplot(fig, filename='bullet chart - custom colors')
Out[4]:

Custom Kwargs¶

In [5]:
import plotly.plotly as py
import plotly.figure_factory as ff

import pandas as pd

data = pd.read_json('https://cdn.rawgit.com/plotly/datasets/master/BulletData.json')

fig = ff.create_bullet(
    data, orientation='v', markers='markers', measures='measures',
    ranges='ranges', subtitles='subtitle', titles='title',
    title='lots of kwargs', width=600, showlegend=True,
    scatter_options={'marker': {'size': 30,
                                'color': 'rgb(21, 166, 20)',
                                'symbol': 'hourglass'}}

)

# group legends
chart_elements = 6  # 3 grey bars, 2 blue bars, 1 marker
for cols, title in enumerate(data['title']):
    for ele in range(chart_elements):
        if ele == 0:
            showlegend = True
        else:
            showlegend = False
        fig['data'][cols * 6 + ele].update(
            {
                'legendgroup': '{}'.format(title),
                'name': title,
                'showlegend': showlegend
            }
        )

py.iplot(fig, filename='bullet chart - custom kwargs')
Out[5]:

Reference¶

In [6]:
help(ff.create_bullet)
Help on function create_bullet in module plotly.figure_factory._bullet:

create_bullet(data, markers=None, measures=None, ranges=None, subtitles=None, titles=None, orientation='h', range_colors=('rgb(200, 200, 200)', 'rgb(245, 245, 245)'), measure_colors=('rgb(31, 119, 180)', 'rgb(176, 196, 221)'), horizontal_spacing=None, vertical_spacing=None, scatter_options={'marker': {'color': 'rgb(0, 0, 0)', 'size': 12, 'symbol': 'diamond-tall'}}, **layout_options)
    Returns figure for bullet chart.

    :param (pd.DataFrame | list | tuple) data: either a list/tuple of
        dictionaries or a pandas DataFrame.
    :param (str) markers: the column name or dictionary key for the markers in
        each subplot.
    :param (str) measures: the column name or dictionary key for the measure
        bars in each subplot. This bar usually represents the quantitative
        measure of performance, usually a list of two values [a, b] and are
        the blue bars in the foreground of each subplot by default.
    :param (str) ranges: the column name or dictionary key for the qualitative
        ranges of performance, usually a 3-item list [bad, okay, good]. They
        correspond to the grey bars in the background of each chart.
    :param (str) subtitles: the column name or dictionary key for the subtitle
        of each subplot chart. The subplots are displayed right underneath
        each title.
    :param (str) titles: the column name or dictionary key for the main label
        of each subplot chart.
    :param (bool) orientation: if 'h', the bars are placed horizontally as
        rows. If 'v' the bars are placed vertically in the chart.
    :param (list) range_colors: a tuple of two colors between which all
        the rectangles for the range are drawn. These rectangles are meant to
        be qualitative indicators against which the marker and measure bars
        are compared.
        Default=('rgb(200, 200, 200)', 'rgb(245, 245, 245)')
    :param (list) measure_colors: a tuple of two colors which is used to color
        the thin quantitative bars in the bullet chart.
        Default=('rgb(31, 119, 180)', 'rgb(176, 196, 221)')
    :param (float) horizontal_spacing: see the 'horizontal_spacing' param in
        plotly.tools.make_subplots. Ranges between 0 and 1.
    :param (float) vertical_spacing: see the 'vertical_spacing' param in
        plotly.tools.make_subplots. Ranges between 0 and 1.
    :param (dict) scatter_options: describes attributes for the scatter trace
        in each subplot such as name and marker size. Call
        help(plotly.graph_objs.Scatter) for more information on valid params.
    :param layout_options: describes attributes for the layout of the figure
        such as title, height and width. Call help(plotly.graph_objs.Layout)
        for more information on valid params.

    Example 1: Use a Dictionary
    ```
    import plotly
    import plotly.plotly as py
    import plotly.figure_factory as ff

    data = [
      {"label": "Revenue", "sublabel": "US$, in thousands",
       "range": [150, 225, 300], "performance": [220,270], "point": [250]},
      {"label": "Profit", "sublabel": "%", "range": [20, 25, 30],
       "performance": [21, 23], "point": [26]},
      {"label": "Order Size", "sublabel":"US$, average","range": [350, 500, 600],
       "performance": [100,320],"point": [550]},
      {"label": "New Customers", "sublabel": "count", "range": [1400, 2000, 2500],
       "performance": [1000, 1650],"point": [2100]},
      {"label": "Satisfaction", "sublabel": "out of 5","range": [3.5, 4.25, 5],
       "performance": [3.2, 4.7], "point": [4.4]}
    ]

    fig = ff.create_bullet(
        data, titles='label', subtitles='sublabel', markers='point',
        measures='performance', ranges='range', orientation='h',
        title='my simple bullet chart'
    )
    py.iplot(fig)
    ```

    Example 2: Use a DataFrame with Custom Colors
    ```
    import plotly.plotly as py
    import plotly.figure_factory as ff

    import pandas as pd

    data = pd.read_json('https://cdn.rawgit.com/plotly/datasets/master/BulletData.json')

    fig = ff.create_bullet(
        data, titles='title', markers='markers', measures='measures',
        orientation='v', measure_colors=['rgb(14, 52, 75)', 'rgb(31, 141, 127)'],
        scatter_options={'marker': {'symbol': 'circle'}}, width=700

    )
    py.iplot(fig)
    ```