3

I'm learning Python via Jupyter lab and I'm facing a problem with Waffle chart.

I have the following dictionary, which I want to display as a Waffle chart:

import pandas as pd 
import matplotlib.pyplot as plt
from pywaffle import Waffle

dic = {'Xemay':150,'Xedap':20,'Oto':180,'Maybay':80,'Tauthuy':135,'Xelua':5}
df = pd.DataFrame.from_dict(dic, orient='index')

plt.figure(FigureClass=Waffle,rows=5,values=dic,legend={'loc': 'upper left', 'bbox_to_anchor': (1, 1)})
plt.title('Số lượng xe bán được của một công ty')
plt.show()

The result, however, is unexpected:

Screenshot1

Instead, the chart should look like this instead. What am I doing wrong?

Screenshot2

normanius
  • 8,629
  • 7
  • 53
  • 83
  • 3
    To be clear are you using `PyWaffle` to create the chart? Would help people answer if you included your import explicitly – Robert King Jan 10 '20 at 10:48
  • Yes I did import: import numpy as np import pandas as pd import seaborn as sns from matplotlib import pyplot as plt from pywaffle import Waffle import collections from wordcloud import WordCloud, STOPWORDS from PIL import Image import folium import geopandas as gpd import math import re from folium import plugins – Tuyen Duong Jan 10 '20 at 11:00
  • 2
    Does this answer your question? [How to do waffle charts in python? (square piechart)](https://stackoverflow.com/questions/41400136/how-to-do-waffle-charts-in-python-square-piechart) – rpanai Jan 10 '20 at 11:36
  • 1
    Also see the nice introduction at the [project's page](https://github.com/gyli/PyWaffle). – JohanC Jan 10 '20 at 15:09

2 Answers2

3

Actually, your code is correct and Waffle properly shows your data (zoom inside your plot to see the squares...)

However, to achieve the desired output, you have to play with the parameters "rows" and "columns", which specify the dimensions of your waffle chart.

nRows=5
countsPerBlock=10  # 1 block = 10 counts
plt.figure(FigureClass=Waffle,
           rows=nRows,
           columns=int(np.ceil(sum(dic.values())/nRows/countsPerBlock)),
           values=dic,
           legend={'loc': 'upper left', 'bbox_to_anchor': (1, 1.1)})
plt.show()

Screenshot solution 2

Note that waffle internally applies some rounding (see parameter rounding_rule), which is why countsPerBlock is not exactly true unless you scale the data yourself. To exactly reproduce the desired output, use the following code:

nRows = 5
countsPerBlock = 10
keys = ['Xemay', 'Xedap', 'Oto', 'Maybay', 'Tauthuy', 'Xelua']
vals = np.array([150, 20, 180, 80, 135, 5])
vals = np.ceil(vals/countsPerBlock)
data = dict(zip(keys, vals))

plt.figure(FigureClass=Waffle,
           rows=5,
           values=data,
           legend={'loc': 'upper left', 'bbox_to_anchor': (1, 1)})
plt.show()

Screenshot solution final

Alternatively, you could normalize your data such that the sum of values is 100. In a 5x20 square, one square will represent 1% of your data.

# Create a dict of normalized data. There are plenty of 
# ways to do this. Here is one approach:
keys = ['Xemay', 'Xedap', 'Oto', 'Maybay', 'Tauthuy', 'Xelua']
vals = np.array([150, 20, 180, 80, 135, 5])
vals = vals/vals.sum()*100
data = dict(zip(keys, vals))
nRows = 5
# ...

Screenshot solution final

normanius
  • 8,629
  • 7
  • 53
  • 83
0

These 2 code options can solve my problem:

1. Contribution from Mr.Normanius:

nRows = 5
countsPerBlock = 10
keys = ['Xemay', 'Xedap', 'Oto', 'Maybay', 'Tauthuy', 'Xelua']
vals = np.array([150, 20, 180, 80, 135, 5])
vals = np.ceil(vals/countsPerBlock)
data = dict(zip(keys, vals))

plt.figure(FigureClass=Waffle,
           rows=5,
           values=data,
           legend={'loc': 'upper left', 'bbox_to_anchor': (1, 1)})
plt.show()

2. From what I've learned:

fig = plt.figure(
    FigureClass=Waffle, 
    rows=5, 
    values=df[0]/10, 
    title={'label': 'So luong xe duoc ban cua mot cong ty', 'loc': 'left'},
    labels=df.index.tolist(),
    legend={'loc': 'lower right', 'bbox_to_anchor': (1, 0.5)}
)
plt.show()

The result as below: enter image description here