🧇 Make Waffle Charts in Python.

Overview

PyWaffle

PyPI version ReadTheDocs Binder

PyWaffle is an open source, MIT-licensed Python package for plotting waffle charts.

It provides a Figure constructor class Waffle, which could be passed to matplotlib.pyplot.figure and generates a matplotlib Figure object.

PyPI Page: https://pypi.org/project/pywaffle/

Documentation: http://pywaffle.readthedocs.io/

Installation

pip install pywaffle

Requirements

  • Python 3.5+
  • Matplotlib

Examples

1. Value Scaling

import matplotlib.pyplot as plt
from pywaffle import Waffle
fig = plt.figure(
    FigureClass=Waffle, 
    rows=5, 
    columns=10, 
    values=[48, 46, 6],
    figsize=(5, 3)
)
plt.show()

basic

The values are automatically scaled to 24, 23 and 3 to fit 5 * 10 chart size.

2. Values in dict & Auto-sizing

data = {'Democratic': 48, 'Republican': 46, 'Libertarian': 3}
fig = plt.figure(
    FigureClass=Waffle, 
    rows=5, 
    values=data, 
    legend={'loc': 'upper left', 'bbox_to_anchor': (1.1, 1)}
)
plt.show()

Use values in dictionary; use absolute value as block number, without defining columns

In this example, since only rows is specified and columns is empty, absolute values in values are used as block numbers. Similarly, rows could also be optional if columns is specified.

If values is a dict, its keys are used as labels.

3. Title, Legend, Colors, Background Color, Block Color, Direction and Style

data = {'Democratic': 48, 'Republican': 46, 'Libertarian': 3}
fig = plt.figure(
    FigureClass=Waffle, 
    rows=5, 
    values=data, 
    colors=["#232066", "#983D3D", "#DCB732"],
    title={'label': 'Vote Percentage in 2016 US Presidential Election', 'loc': 'left'},
    labels=[f"{k} ({v}%)" for k, v in data.items()],
    legend={'loc': 'lower left', 'bbox_to_anchor': (0, -0.4), 'ncol': len(data), 'framealpha': 0},
    starting_location='NW',
    block_arranging_style='snake'
)
fig.set_facecolor('#EEEEEE')
plt.show()

Add title, legend and background color; customize the block color

Many parameters, like title and legend, accept the same parameters as in Matplotlib.

4. Plot with Icons - Pictogram Chart

data = {'Democratic': 48, 'Republican': 46, 'Libertarian': 3}
fig = plt.figure(
    FigureClass=Waffle, 
    rows=5, 
    values=data, 
    colors=["#232066", "#983D3D", "#DCB732"],
    legend={'loc': 'upper left', 'bbox_to_anchor': (1, 1)},
    icons='child', 
    font_size=12, 
    icon_legend=True
)
plt.show()

Use Font Awesome icons

PyWaffle supports Font Awesome icons in the chart.

5. Multiple Plots in One Chart

import pandas as pd
data = pd.DataFrame(
    {
        'labels': ['Hillary Clinton', 'Donald Trump', 'Others'],
        'Virginia': [1981473, 1769443, 233715],
        'Maryland': [1677928, 943169, 160349],
        'West Virginia': [188794, 489371, 36258],
    },
).set_index('labels')

# A glance of the data:
#                  Maryland  Virginia  West Virginia
# labels                                            
# Hillary Clinton   1677928   1981473         188794
# Donald Trump       943169   1769443         489371
# Others             160349    233715          36258


fig = plt.figure(
    FigureClass=Waffle,
    plots={
        '311': {
            'values': data['Virginia'] / 30000,
            'labels': [f"{k} ({v})" for k, v in data['Virginia'].items()],
            'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.05, 1), 'fontsize': 8},
            'title': {'label': '2016 Virginia Presidential Election Results', 'loc': 'left'}
        },
        '312': {
            'values': data['Maryland'] / 30000,
            'labels': [f"{k} ({v})" for k, v in data['Maryland'].items()],
            'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.2, 1), 'fontsize': 8},
            'title': {'label': '2016 Maryland Presidential Election Results', 'loc': 'left'}
        },
        '313': {
            'values': data['West Virginia'] / 30000,
            'labels': [f"{k} ({v})" for k, v in data['West Virginia'].items()],
            'legend': {'loc': 'upper left', 'bbox_to_anchor': (1.3, 1), 'fontsize': 8},
            'title': {'label': '2016 West Virginia Presidential Election Results', 'loc': 'left'}
        },
    },
    rows=5,  # outside parameter applied to all subplots
    colors=["#2196f3", "#ff5252", "#999999"],  # outside parameter applied to all subplots
    figsize=(9, 5)
)
plt.show()

Multiple plots

In this chart, 1 block = 30000 votes.

Data source https://en.wikipedia.org/wiki/United_States_presidential_election,_2016.

Demo

Wanna try it yourself? There is Online Demo!

What's New

See CHANGELOG

License

  • PyWaffle is under MIT license, see LICENSE file for the details.
  • The Font Awesome font is licensed under the SIL OFL 1.1: http://scripts.sil.org/OFL
Comments
  • Blocks of a single colour are not always contiguous

    Blocks of a single colour are not always contiguous

    In this example output, the yellow block is split up, unnecessarily:

    zf7kX (from example at https://stackoverflow.com/questions/41400136/how-to-do-waffle-charts-in-python-square-piechart )

    Shouldn't the rolling out of blocks go down one column, then up the next, then down the next, and so on, in order to ensure that coloured regions remain contiguous?

    opened by cpbl 11
  • Display labels in the same order as grids when plotting in vertical mode

    Display labels in the same order as grids when plotting in vertical mode

    This PR changes the order of the legend to match the order of the plotted grids when plotting with vertical=True

    Before this PR:

    before

    After this PR:

    test

    Signed-off-by: Alex Couture-Beil [email protected]

    opened by alexcb 6
  • UserWarning: This figure includes Axes that are not compatible with tight_layout

    UserWarning: This figure includes Axes that are not compatible with tight_layout

    First of all, incredibly awesome and fun package. Thanks a lot!

    I'm getting this warning in all the plots:

    UserWarning: This figure includes Axes that are not compatible with tight_layout, so results might be incorrect. warnings.warn("This figure includes Axes that are not compatible ").

    It seems a false positive in this context, right?

    opened by lincolnfrias 4
  • missing corner squares with automatic scaling

    missing corner squares with automatic scaling

    I'm making 50×20 grids, so each block is 0.1%. I've found that with some data, the top right corner ends up empty. Here's a real-world example:

    #!/usr/bin/python3
    
    import matplotlib as m
    m.use("Agg")
    import matplotlib.pyplot as plt
    import matplotlib.dates as dates
    from pywaffle import Waffle
    
    m.style.use('seaborn-whitegrid')
    m.rcParams['font.size'] = 12
    
    fig = plt.figure( 
    FigureClass=Waffle, 
     rows=20,
     columns=50,
     values={'32': 192,'33': 76,'34':59},
     figsize=[16, 9],
    )              
    
    fig.savefig('test.png',dpi=300)
    
                
    plt.close()   
    

    This results in:

    test

    ... with an empty square in the top right -- a total of 999 squares instead of 1000.

    I assume this is because all values are getting rounded down.

    opened by mattdm 3
  • cant specify columns

    cant specify columns

    Each chart I create (python 3.7.4, PyWaffle 0.2.3) is coming out square regardless of what is passed in the columns parameter. Its as if the columns parameter is being overwritten by what is passed to rows

        plt.figure(
            FigureClass=Waffle,
            rows=5,
            columns=10,
            values=[150, 75, 25],
            figsize=(16, 9)
        );
        plt.savefig('example.png')
    

    example

    opened by rtphokie 3
  • ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

    ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

    When using a pandas DataFrame, I keep getting this error, no matter what DataFrame I use:

    Traceback (most recent call last):
      File "clean_input_file.py", line 177, in <module>
        main()
      File "clean_input_file.py", line 172, in main
        plot_res(data_FSW)
      File "clean_input_file.py", line 149, in plot_res
        title={'label': 'Vote Percentage in 2016 US Presidential Election', 'loc': 'left'}
      File "C:\Users\Pez Amaury\AppData\Local\Programs\Python\Python36-32\lib\site-packages\matplotlib\pyplot.py", line 548, in figure
        **kwargs)
      File "C:\Users\Pez Amaury\AppData\Local\Programs\Python\Python36-32\lib\site-packages\matplotlib\backend_bases.py", line 160, in new_figure_manager
        fig = fig_cls(*args, **kwargs)
      File "C:\Users\Pez Amaury\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pywaffle\waffle.py", line 158, in __init__
        if (not self.fig_args['values'] or not self.fig_args['rows']) and not self.plots:
      File "C:\Users\Pez Amaury\AppData\Local\Programs\Python\Python36-32\lib\site-packages\pandas\core\generic.py", line 1573, in __nonzero__
        .format(self.__class__.__name__))
    ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
    

    I understand this is due to using operators or/and in waffle.py, so changing them to np.logical_and and np.logical_or would probably solve the problem.

    Here's the dataFrame I'm using:

    Variables ART last 12 months 0.0 Access to condoms last 12 months 0.0 Any STI treatment last 12 months 0.0 Clean needles/syringes at last injection 0.0 Condom use at last time they had sex 0.0 Condom use when had anal sex last time with a male partner 0.0 Condom use when had sex last time with a commercial client 0.0 HBV Prevalence 0.0 HCV Prevalence 0.0 HIV Prevalence 0.0 HIV incidence 0.0 HIV test history 0.0 HIV test in last 12 months 0.0 HIV-1 Prevalence 0.0 HIV-2 Prevalence 0.0 OST/MMT last 6 months 0.0 Other STI Prevalence 0.0 Received HIV test results 0.0 STI test last 12 months 0.0 Syphilis Prevalence 0.0 Name: 2001, dtype: float64

    opened by ghost 3
  • Bump Font Awesome to v6

    Bump Font Awesome to v6

    Hi there! Firstly, just wanted to say I absolutely love this package - it works so seamlessly, and you've really thought of everything in terms of how people might want to tweak things to make some beautiful visualisations!

    I noticed that Font Awesome released v6 (in Feb 2022) which have quite a few new icons, so I thought I'd bump the version to their latest. Do let me know if it's not just a matter of bumping the version here!

    opened by jennynz 2
  • Font awesome license

    Font awesome license

    I notice that files from the Font Awesome project are being used. The project's license requires attribution. IANAL, and I am not affiliated with that project, but I think there probably needs to be a license file for these files, and this needs to be in the MANIFEST.in file (see #18) so it is included in sdists.

    opened by toddrme2178 2
  • Make mapping global variable, use builtin ceil

    Make mapping global variable, use builtin ceil

    I made METHOD_MAPPING global so that it is only created one time during loading time. Also math.ceil is used to replace the ceil function you wrote. :) block_iter is a generator now.

    opened by tweakimp 2
  • Update to FontAwesome v5

    Update to FontAwesome v5

    Hello,

    Thanks for creating this module, it's really useful and pretty straightforward to use.

    One thing I've noticed is that the module currently uses FontAwesome v4.7.0, with the latest version of FA being v5.5.0. It'd be nice to be able to use the latest set of icons and updating the equivalence should be relatively straightforward through the cheatsheet they provide, but the download is now (I believe since 5.0) split into three .otf files - "solid", "regular" and "brands". I see there being two ways to deal with this:

    1. Pick one of the new three to have as the main reference. The "regular" is I think meant to be the most similar to the old icons, but the "solid" is the most complete.
    2. Keep all three and either:
      1. Add an extra parameter to choose which of the three icon sets to use (e.g. icon_set as a string).
      2. Rename the icon lookups to include which set they come from, and ensure the user only uses icons from one set.

    I am happy to work on a PR for this based on your preference. I think 2i would work best (and might start looking at implementing it), but will defer to your judgement. There may also be some compatibility issues with name changes, but I think it's worth it for the wider set of icons available.

    Thanks,

    Adam

    opened by asongtoruin 2
  • KeyError: 'rows' in waffle.py

    KeyError: 'rows' in waffle.py

    Hi, I tried your last example Multiple plot and had the following error

    figsize=(9, 5) # figsize is a parameter of plt.figure File "/usr/local/lib/python3.6/dist-packages/matplotlib/pyplot.py", line 533, in figure **kwargs) File "/usr/local/lib/python3.6/dist-packages/matplotlib/backend_bases.py", line 160, in new_figure_manager fig = fig_cls(*args, **kwargs) File "/usr/local/lib/python3.6/dist-packages/pywaffle/waffle.py", line 165, in init self._waffle(loc, **copy.deepcopy(setting)) File "/usr/local/lib/python3.6/dist-packages/pywaffle/waffle.py", line 174, in _waffle if len(self._pa['values']) == 0 or not self._pa['rows']: KeyError: 'rows'

    opened by cecilebraun 2
  • Fractional blocks

    Fractional blocks

    Is there a way to enable fractional blocks, so that there is no rounding? I'm especially running into issues where the rounding causes the total number of blocks to fluctuate, as in the example below. Both datasets total to 87.46 but the top plot has an extra block. It'd be great if the last block could have fractional size, and if the intermediate blocks could have split colors.

    output

    Code to reproduce:

    plot1 = {'Net income': 18.46, 'Income tax': 1.64, 'MG&A': 7.52, 'R&D': 15.3, 'Cost of sales': 44.54}
    plot2 = {'Misc income': 1.2, 'Revenue': 86.26}
    fig = plt.figure(
        FigureClass=Waffle,
        plots={
            311: {'values':plot1},
            312: {'values':plot2}
        },
        rows=5,
        figsize=(9, 7),
        legend={'loc': 'upper left', 'bbox_to_anchor': (1.1, 1)},
        block_arranging_style='snake',
    )
    
    Feature Request 
    opened by riley-x 1
  • Request: ability to use system-packaged Fontawesome if found?

    Request: ability to use system-packaged Fontawesome if found?

    In Fedora, we have FontAwesome as an included package, and our packaging guidelines require bundled fonts to be ... debundled.

    I've patched this in to my package build scripts (see https://mattdm.org/misc/fedora/pywaffle/python-pywaffle.spec), but it would be ideal if the library just noticed and used those. I guess this could be a "build time" thing, but I'm thinking maybe if

    /usr/share/fonts/fontawesome5-free-fonts/Font Awesome 5 Free-Regular-400.otf
    /usr/share/fonts/fontawesome5-free-fonts/Font Awesome 5 Free-Solid-900.otf
    /usr/share/fonts/fontawesome5-brands-fonts/Font Awesome 5 Brands-Regular-400.otf
    

    are installed, those could be automatically used -- with the mappings created at runtime from /usr/share/fontawesome5/metadata/icons.json.

    That'd also benefit people who install via pip or whatever.

    What do you think?

    Feature Request 
    opened by mattdm 3
  • characters argument and plt.savefig

    characters argument and plt.savefig

    There seem to be a problem when saving figures as pdf with matplotlib.pyplot.savefig and using the characters argument in Waffle: some characters are replaced by others.

    list_character = ["🖳", "🐍"]
    
    from pywaffle import Waffle
    from matplotlib import pyplot as plt
    
    n_row = 4
    n_column = 5
    
    import numpy as np
    list_value = np.ones(len(list_character))
    
    fig = plt.figure(
        FigureClass=Waffle,
        rows=1,
        columns=len(list_character),
        values=list_value,
        characters=list_character,
        font_file="~/.fonts/Symbola.ttf",
        font_size=50
        )
    
    plt.savefig("replaced_character.pdf")
    plt.close("all")
    

    yields the attached file (two snakes instead of a computer and a snake). The computer alone is correctly printed. Inverting the order yields two snakes.

    replaced_character.pdf

    opened by SG-phimeca 7
  • width problems with a thousand blocks

    width problems with a thousand blocks

    When plotting a larger number of blocks, the width of the white space between them become unstable:

    plt.figure(
        FigureClass=Waffle,
        rows=20,
        columns=80,
        values=[300, 700],
        figsize=(18, 10)
    );
    plt.savefig('example.png')
    
    

    image

    This is probably outside the original scope of the package and maybe should even be discouraged, but sometimes is useful to give the reader the impression of dealing with a large population. Feel free to close this issue.

    opened by lincolnfrias 2
Owner
Guangyang Li
Guangyang Li
`charts.css.py` brings `charts.css` to Python. Online documentation and samples is available at the link below.

charts.css.py charts.css.py provides a python API to convert your 2-dimension data lists into html snippet, which will be rendered into charts by CSS,

Ray Luo 3 Sep 23, 2021
Farhad Davaripour, Ph.D. 1 Jan 5, 2022
Simple plotting for Python. Python wrapper for D3xter - render charts in the browser with simple Python syntax.

PyDexter Simple plotting for Python. Python wrapper for D3xter - render charts in the browser with simple Python syntax. Setup $ pip install PyDexter

D3xter 31 Mar 6, 2021
Python library that makes it easy for data scientists to create charts.

Chartify Chartify is a Python library that makes it easy for data scientists to create charts. Why use Chartify? Consistent input data format: Spend l

Spotify 3.2k Jan 4, 2023
Python library that makes it easy for data scientists to create charts.

Chartify Chartify is a Python library that makes it easy for data scientists to create charts. Why use Chartify? Consistent input data format: Spend l

Spotify 2.8k Feb 18, 2021
Python library that makes it easy for data scientists to create charts.

Chartify Chartify is a Python library that makes it easy for data scientists to create charts. Why use Chartify? Consistent input data format: Spend l

Spotify 3.2k Jan 1, 2023
Drag’n’drop Pivot Tables and Charts for Jupyter/IPython Notebook, care of PivotTable.js

pivottablejs: the Python module Drag’n’drop Pivot Tables and Charts for Jupyter/IPython Notebook, care of PivotTable.js Installation pip install pivot

Nicolas Kruchten 512 Dec 26, 2022
Drag’n’drop Pivot Tables and Charts for Jupyter/IPython Notebook, care of PivotTable.js

pivottablejs: the Python module Drag’n’drop Pivot Tables and Charts for Jupyter/IPython Notebook, care of PivotTable.js Installation pip install pivot

Nicolas Kruchten 419 Feb 11, 2021
Streamlit dashboard examples - Twitter cashtags, StockTwits, WSB, Charts, SQL Pattern Scanner

streamlit-dashboards Streamlit dashboard examples - Twitter cashtags, StockTwits, WSB, Charts, SQL Pattern Scanner Tutorial Video https://ww

null 122 Dec 21, 2022
mysql relation charts

sqlcharts 自动生成数据库关联关系图 复制settings.py.example 重命名为settings.py 将数据库配置信息填入settings.DATABASE,目前支持mysql和postgresql 执行 python build.py -b,-b是读取数据库表结构,如果只更新匹

null 6 Aug 22, 2022
Altair extension for saving charts in a variety of formats.

Altair Saver This packge provides extensions to Altair for saving charts to a variety of output types. Supported output formats are: .json/.vl.json: V

Altair 85 Dec 9, 2022
🐞 📊 Ladybug extension to generate 2D charts

ladybug-charts Ladybug extension to generate 2D charts. Installation pip install ladybug-charts QuickStart import ladybug_charts API Documentation Loc

Ladybug Tools 3 Dec 30, 2022
GitHub English Top Charts

Help you discover excellent English projects and get rid of the interference of other spoken language.

kon9chunkit 529 Jan 2, 2023
Data-FX is an addon for Blender (2.9) that allows for the visualization of data with different charts

Data-FX Data-FX is an addon for Blender (2.9) that allows for the visualization of data with different charts Currently, there are only 2 chart option

Landon Ferguson 20 Nov 21, 2022
Make sankey, alluvial and sankey bump plots in ggplot

The goal of ggsankey is to make beautiful sankey, alluvial and sankey bump plots in ggplot2

David Sjoberg 156 Jan 3, 2023
GitHubPoster - Make everything a GitHub svg poster

GitHubPoster Make everything a GitHub svg poster 支持 Strava 开心词场 扇贝 Nintendo Switch GPX 多邻国 Issue

yihong 1.3k Jan 2, 2023
Make your BSC transaction simple.

bsc_trade_history Make your BSC transaction simple. 中文ReadMe Background: inspired by debank ,Practice my hands on this small project Blog:Crypto-BscTr

foolisheddy 7 Jul 6, 2022
Make visual music sheets for thatskygame (graphical representations of the Sky keyboard)

sky-python-music-sheet-maker This program lets you make visual music sheets for Sky: Children of the Light. It will ask you a few questions, and does

null 21 Aug 26, 2022
Make scripted visualizations in blender

Scripted visualizations in blender The goal of this project is to script 3D scientific visualizations using blender. To achieve this, we aim to bring

Praneeth Namburi 10 Jun 1, 2022