I am trying to apply callout labels as asked here: Python PieChart (is it possible to do CallOut labels)
However, I'm getting a number of issues trying to apply the overlapping labels.. any ideas... I am a beginner with Python.
Errors such as AttributeError: 'list' object has no attribute 'theta2' TypeError: 'function' object is not iterable AttributeError: 'numpy.int64' object has no attribute 'theta2'
here is my code:
from collections import Counter
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.cm as cm, matplotlib.font_manager as fm
import pandas as pd
import csv
import itertools
from collections import OrderedDict
import operator
# Create database of duplicates - check if the mac and os pairs have duplicates
reader = csv.reader(open('Workbook1.csv', 'r'), delimiter=',')
writer = csv.writer(open('remacos.csv', 'w'), delimiter=',')
entries = set()
for row in reader:
key = (row[1], row[2])
if key not in entries:
writer.writerow(row)
entries.add(key)
del writer #Force the writer to clean up
# Create database of duplicates - check if the mac and browser pairs have duplicates
reader = csv.reader(open('Workbook1.csv', 'r'), delimiter=',')
writer = csv.writer(open('remacbrowser.csv', 'w'), delimiter=',')
entries = set()
for row in reader:
key = (row[1], row[3])
if key not in entries:
writer.writerow(row)
entries.add(key)
del writer #Force the writer to clean up
df = pd.read_csv('remacos.csv', index_col="mac")
counteros = Counter(df['os'])
os_names = counteros.keys()
os_counts = counteros.values()
# Read Removed Duplicated entries Database and Count Values for Browsers.
df = pd.read_csv('remacbrowser.csv', index_col="mac")
counterbrowsers = Counter(df['browser'])
browser_names = counterbrowsers.keys()
browser_counts = counterbrowsers.values()
#New Bar Chart with Fonts
countdata = df['browser'].value_counts()
ax = countdata.plot(kind='bar',
figsize=[9, 6],
width=0.9,
alpha=0.6,
color='g',
edgecolor='w',
grid=False,
ylim=[0, 400])
ax.set_xticks(range(len(countdata)))
ax.set_xticklabels(countdata.index, rotation=45, rotation_mode='anchor', ha='right', fontproperties=ticks_font)
ax.yaxis.grid(True)
for label in ax.get_yticklabels():
label.set_fontproperties(ticks_font)
ax.set_title('Most Popular Browsers', fontproperties=title_font)
ax.set_xlabel('', fontproperties=label_font)
ax.set_ylabel('Number of counts', fontproperties=label_font)
plt.show()
# Make Pie Chart for Browsers
plt.figure(figsize=plt.figaspect(1))
#values = sorted(browser_counts)
#labels = browser_names
labels, values = zip(*sorted(counterbrowsers.items(), key=lambda x: x[1])) #Counteros is the Dictionary-like object we are trying to sort. This 'zip' solves the problem of sorting each of them independently. This will sort as pairs, by value.
colors = ['yellowgreen', 'gold', 'lightskyblue', 'lightcoral', '#008DB8','#00AAAA','#001CF0','#00FF80', 'c','m','r','b', '#191970','#0038E2','#0055D4','#0071C6','#00E28E', '#00C69C']
#explode = (0, 0, 0, 0.1, 0.1, 0.2, 0.3, 0.4, 0.6)
explode = list()
for k in labels:
explode.append(0.1)
#sizes = counts.values.tolist()
def make_autopct(values):
def my_autopct(pct):
total = sum(values)
val=int(round(pct*total/100))
return '{p:.2f}% ({v:d})'.format(p=pct,v=val)
return my_autopct
pie = plt.pie(values, labels=labels, explode=explode, colors=colors, shadow=True, startangle=90, autopct=make_autopct(values))
bbox_props = dict(boxstyle="square,pad=0.3", fc="w", ec="k", lw=0.72)
arrowprops=dict(arrowstyle="-",connectionstyle="angle,angleA=0,angleB=90")
kw = dict(xycoords='data',textcoords='data',arrowprops=arrowprops,
bbox=bbox_props, zorder=0, va="center")
for i, p in enumerate(pie):
ang = (p.theta2 - p.theta1)/2.+p.theta1
y = np.sin(ang/180.*np.pi)
x = 1.35*np.sign(np.cos(ang/180.*np.pi))
plt.gca().annotate(str(1+i), xy=(0, 0), xytext=( x, y), **kw )
plt.legend(labels, loc="lower right")
plt.axis('equal') # Set aspect ratio to be equal so that pie is drawn as a circle, # View the plot drop above
plt.title('Browsers Analytics', bbox={'facecolor':'0.8', 'pad':5})
plt.show()
The CSV files are displayed in a table like this: One CSV compares Mac address with Browser The other CSV links Mac and OS for the count data. In the pie chart I am just trying to get one to show I can then replicate the results (hopefully).
id mac os browser 1 fe:fe:fe:fe:fe:fe Windows 10 Chrome
2 fe:fe:fe:fe:fe:fe Mac OS X Chrome
3 fe:fe:fe:fe:fe:fe iPhone Handheld Browser
5 37:02:e6:87:FF:77 Windows 8.1 Internet Explorer
The bar chart is just one way of showing the data however displaying the data in a pie chart with callouts is the goal. I'm having trouble implemnting a solution to overlap/callout the labels. The value using here for i, p in enumerate(pie) is where i seem to be getting the errors like AttributeError: 'list' object has no attribute 'theta2'
Traceback (most recent call last):
File "csv-test.py", line 176, in <module>
ang = (p.theta2 - p.theta1)/2.+p.theta1
AttributeError: 'list' object has no attribute 'theta2'
If i change the (pie) value to (counterbrowser) I get:
Traceback (most recent call last):
File "csv-test.py", line 176, in <module>
ang = (p.theta2 - p.theta1)/2.+p.theta1
AttributeError: 'str' object has no attribute 'theta2'
Patches = pie gives me the following error (replacing (pie) with patches)
Traceback (most recent call last):
File "csv-test.py", line 176, in <module>
ang = (p.theta2 - p.theta1)/2.+p.theta1
AttributeError: 'list' object has no attribute 'theta2'