'sns.barplot from dict with tuple keys

I can successfully create a pandas barplot based off of a groupy as follows:

df.groupby('stop_duration')['violation_raw'].value_counts().plot(kind="barh")

It works fine.

But I like to use sns.barplot because I have certain aesthetics I like to adhere to.

I use this general structure to print dicts to sns.barplots all the time:

plt.figure(figsize=(7, 7))
gbsdvrvc = df.groupby('stop_duration')['violation_raw'].value_counts().to_dict()

cc = sns.barplot(x=list(gbsdvrvc.values()), y=list(gbsdvrvc.keys()), orient='h', palette="dark:salmon_r")
for item in cc.get_xticklabels():
    cc.bar_label(cc.containers[0])
plt.xlabel("Count", labelpad=12)
plt.ylabel("Stop Duration, Violation Raw", labelpad=12, fontdict={'fontsize': 16, 'fontweight': 'bold'})
plt.tight_layout()
plt.show()

However, this exact code generates a KeyError:

Traceback (most recent call last):
  File "C:/Users/Mark/PycharmProjects/main/main.py", line 348, in <module>
    cc = sns.barplot(x=list(gbsdvrvc.values()), y=list(gbsdvrvc.keys()), orient='h', palette="dark:salmon_r")
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\seaborn\_decorators.py", line 46, in inner_f
    return f(**kwargs)
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\seaborn\categorical.py", line 3182, in barplot
    plotter = _BarPlotter(x, y, hue, data, order, hue_order,
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\seaborn\categorical.py", line 1584, in __init__
    self.establish_variables(x, y, hue, data, orient,
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\seaborn\categorical.py", line 206, in establish_variables
    plot_data, value_label = self._group_longform(vals, groups,
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\seaborn\categorical.py", line 253, in _group_longform
    grouped_vals = vals.groupby(grouper)
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\series.py", line 1884, in groupby
    return SeriesGroupBy(
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\groupby\groupby.py", line 889, in __init__
    grouper, exclusions, obj = get_grouper(
  File "C:\Users\Mark\AppData\Local\Programs\Python\Python38\lib\site-packages\pandas\core\groupby\grouper.py", line 862, in get_grouper
    raise KeyError(gpr)
KeyError: ('0-15 Min', 'Speeding')

I guess it does not like the tuples as keys?

The dict (gbsdvrvc) is created just fine:

enter image description here

As mentioned above, I can do this with the pandas bar plot just fine (.plot(kind="barh")).

Why am I unable to create the desired sns.barplot from this dictionary (gbsdvrvc)?

Here is a working example using the same code. The keys in the dict used for this output were not tuples:

enter image description here



Solution 1:[1]

@JohanC let me know (see above) that Seaborn does NOT expect tuples as keys.

Based on that, I wrote the following code to convert each tuple of strings into a list of strings, the strings being a single string representation of each tuple.

gbsdvrvc = df.groupby('stop_duration')['violation_raw'].value_counts().to_dict()
# pprint(gbsdvrvc)
y = list(gbsdvrvc.keys())

def convertTuple(list_of_tup):
    # initialize an empty string
    los = []
    for tup in list_of_tup:
        str_ = ''
        for item_ in tup:
            str_ = str_ + item_
            if str_ not in los:
                los.append(str_)
    return los

merged_keys = convertTuple(y)

# items to be removed
unwanted = {'0-15 Min', '16-30 Min', '30+ Min'}
filtered = [ele for ele in merged_keys if ele not in unwanted]

This solved my problem.

Only odd thing is that the dict has 36 unique key\value pairs. After running convertTuple I end up with 39 items in my list??

The extras are in the above set 'unwanted'.

No idea why they are appearing.

I simply get rid of them and then it works.

{('0-15 Min', 'APB'): 37,
 ('0-15 Min', 'Call for Service'): 547,
 ('0-15 Min', 'Equipment/Inspection Violation'): 9173,
 ('0-15 Min', 'Motorist Assist/Courtesy'): 119,
 ('0-15 Min', 'Other Traffic Violation'): 11763,
 ('0-15 Min', 'Registration Violation'): 2421,
 ('0-15 Min', 'Seatbelt Violation'): 2665,
 ('0-15 Min', 'Special Detail/Directed Patrol'): 1622,
 ('0-15 Min', 'Speeding'): 41014,
 ('0-15 Min', 'Suspicious Person'): 32,
 ('0-15 Min', 'Violation of City/Town Ordinance'): 144,
 ('0-15 Min', 'Warrant'): 6,
 ('16-30 Min', 'APB'): 24,
 ('16-30 Min', 'Call for Service'): 435,
 ('16-30 Min', 'Equipment/Inspection Violation'): 1373,
 ('16-30 Min', 'Motorist Assist/Courtesy'): 59,
 ('16-30 Min', 'Other Traffic Violation'): 3150,
 ('16-30 Min', 'Registration Violation'): 804,
 ('16-30 Min', 'Seatbelt Violation'): 249,
 ('16-30 Min', 'Special Detail/Directed Patrol'): 613,
 ('16-30 Min', 'Speeding'): 6848,
 ('16-30 Min', 'Suspicious Person'): 13,
 ('16-30 Min', 'Violation of City/Town Ordinance'): 61,
 ('16-30 Min', 'Warrant'): 6,
 ('30+ Min', 'APB'): 18,
 ('30+ Min', 'Call for Service'): 316,
 ('30+ Min', 'Equipment/Inspection Violation'): 474,
 ('30+ Min', 'Motorist Assist/Courtesy'): 25,
 ('30+ Min', 'Other Traffic Violation'): 1310,
 ('30+ Min', 'Registration Violation'): 207,
 ('30+ Min', 'Seatbelt Violation'): 38,
 ('30+ Min', 'Special Detail/Directed Patrol'): 220,
 ('30+ Min', 'Speeding'): 600,
 ('30+ Min', 'Suspicious Person'): 11,
 ('30+ Min', 'Violation of City/Town Ordinance'): 6,
 ('30+ Min', 'Warrant'): 3}

enter image description here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MarkS