Я использую python и matplotlib для создания отчета о стоимости PDF для AWS, который отправляется еженедельно.Я пытаюсь добавить разбивку услуг по стоимости с помощью круговой диаграммы, чтобы показать, сколько каждая услуга составляет общую стоимость.Тем не менее, круговая диаграмма, которую я показываю, на самом деле не выполняет автоматические проценты.На круговой диаграмме все значения находятся в одинаковых 12-часовых позициях и спред для них отсутствует.
Не совсем уверен, что я делаю здесь неправильно.Списки размеров, меток и цветов имеют одинаковый размер.Размеры или список значений являются целыми числами, я пробовал float и strings.Не выдает ошибку, просто неправильно формирует график.
Пустая круговая диаграмма. 
Список значений, которые пытается использовать диаграмма: 
Список цветов, которые пытается использовать диаграмма: 
Список меток, которые пытается использовать диаграмма. 
Код:
labels = []
sizes = []
colors = []
for cost in cost_dict:
if cost_dict[cost]["UnblendedCost"] >= 0.1:
labels.append(cost)
sizes.append(int(cost_dict[cost]["UnblendedCost"]))
number_of_colors = len(sizes)
colors = []
color_choices = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue', 'yellowgreen', 'lightcoral', 'lightskyblue', 'purple', 'grey']
count = 0
for color in range(0,number_of_colors):
colors.append(color_choices[count])
count += 1
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=90)
plt.axis('equal')
plt.savefig("cost-pie2.png")
Полный скрипт:
import boto3
import datetime
from fpdf import FPDF
import calendar
from dateutil.relativedelta import relativedelta
import collections
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
import operator
import sys
#number_of_months = sys.argv[1]
number_of_months = 4
def get_aws_data(first_date, current_date):
client = boto3.client('ce')
Dimensions = client.get_dimension_values(
TimePeriod={
'Start': first_date,
'End': current_date
},
Dimension='SERVICE',
Context='COST_AND_USAGE'
)
cost_dict = {}
for dimension in Dimensions["DimensionValues"]:
dimension_to_search = str(dimension["Value"])
response = client.get_cost_and_usage(
TimePeriod={
'Start': first_date,
'End': current_date
},
Granularity='MONTHLY',
Filter={"Dimensions": {
"Key": "SERVICE",
"Values": [
dimension_to_search
]
}},
Metrics=[
'BlendedCost',
'UnblendedCost',
'UsageQuantity',
],
GroupBy=[
{
"Type": "DIMENSION",
"Key": "SERVICE"
},
]
)
for result in response["ResultsByTime"]:
for cost in result["Groups"]:
if cost["Metrics"]["BlendedCost"]["Amount"] > 0 or cost["Metrics"]["UnblendedCost"]["Amount"] > 0:
if cost_dict.has_key(cost["Keys"][0]):
cost_dict[cost["Keys"][0]]["BlendedCost"] = float(cost["Metrics"]["BlendedCost"]["Amount"]) + float(cost_dict[cost["Keys"][0]]["BlendedCost"])
cost_dict[cost["Keys"][0]]["UnblendedCost"] = float(cost["Metrics"]["UnblendedCost"]["Amount"]) + float(cost_dict[cost["Keys"][0]]["UnblendedCost"])
cost_dict[cost["Keys"][0]]["Usage"] = float(cost["Metrics"]["UsageQuantity"]["Amount"]) + float(cost_dict[cost["Keys"][0]]["Usage"])
else:
cost_dict[cost["Keys"][0]] = {}
cost_dict[cost["Keys"][0]]["BlendedCost"] = {}
cost_dict[cost["Keys"][0]]["UnblendedCost"] = {}
cost_dict[cost["Keys"][0]]["Usage"] = {}
cost_dict[cost["Keys"][0]]["BlendedCost"] = float(cost["Metrics"]["BlendedCost"]["Amount"])
cost_dict[cost["Keys"][0]]["UnblendedCost"] = float(cost["Metrics"]["UnblendedCost"]["Amount"])
cost_dict[cost["Keys"][0]]["Usage"] = float(cost["Metrics"]["UsageQuantity"]["Amount"])
return cost_dict
def generate_monthly_cost_report(months):
dates_dict = collections.OrderedDict()
starting_and_end_days = []
months = int(months)
print months
for month_count in range(months,0,-1):
six_months = datetime.datetime.today() + relativedelta(months=-month_count)
last_day_of_month = calendar.monthrange(six_months.year, six_months.month)[1]
six_month = six_months.month
if six_month != 10 and six_month != 11 and six_month != 12:
six_month = "0" + str(six_month)
sixth_months_first = str(six_months.year) + "-" + str(six_month) + "-" + "01"
sixth_months_last = str(six_months.year) + "-" + str(six_month) + "-" + str(last_day_of_month)
starting_and_end_days.append((sixth_months_first, sixth_months_last))
months_dict = collections.OrderedDict()
last_month_total = 0
for first_day, last_day in starting_and_end_days:
old_month = int(last_day.split("-")[1]) - 1
if len(str(old_month)) < 2:
old_month = "0" + str(old_month)
#if str(last_day.split("-")[2]) == "28":
# first_day = last_day.split("-")[0] + "-" + old_month + "-31"
#else:
# if str(last_day.split("-")[2]) == "30":
# first_day = last_day.split("-")[0] + "-" + old_month + "-31"
# else:
# first_day = last_day.split("-")[0] + "-" + old_month + "-30"
one_month_forward = int(last_day.split("-")[1]) + 1
if len(str(one_month_forward)) < 2:
one_month_forward = "0" + str(one_month_forward)
year = last_day.split("-")[0]
if str(one_month_forward) == "01":
year = int(year) + 1
year = str(year)
last_day = year + "-" + one_month_forward + "-01"
cost_dict = get_aws_data(first_day, last_day)
total_cost = 0.0
time_frame = str(first_day) + ":" + str(last_day)
if time_frame not in months_dict.keys():
months_dict[time_frame] = {}
for cost in cost_dict:
if cost_dict[cost]["UnblendedCost"] >= 0.1:
total_cost = cost_dict[cost]["UnblendedCost"] + total_cost
last_month_total = total_cost
dates_dict[first_day] = total_cost
days = int(str(last_day).split("-")[2]) - int(str(first_day).split("-")[2]) + 1
average_by_day = total_cost / float(days)
months_dict[time_frame]["cost"] = {}
months_dict[time_frame]["cost"] = cost_dict
months_dict[time_frame]["total"] = {}
months_dict[time_frame]["total"] = total_cost
months_dict[time_frame]["average"] = {}
months_dict[time_frame]["average"] = str(average_by_day)
return dates_dict, months_dict, round(last_month_total, 2)
def generate_month_cost_report():
todays_date = datetime.datetime.now()
day = todays_date.day
year = todays_date.year
month = todays_date.month
first_day = "01"
if month != "10" and month != "11" and month != "12":
first_date = str(year) + "-0" + str(month) + "-" + str(first_day)
if len(str(day)) < 2:
day = "0" + str(day)
current_date = str(year) + "-0" + str(month) + "-" + str(day)
else:
first_date = str(year) + "-" + str(month) + "-" + str(first_day)
if len(str(day)) < 2:
day = "0" + str(day)
current_date = str(year) + "-" + str(month) + "-" + str(day)
cost_dict = get_aws_data(first_date, current_date)
time_frame = str(first_date) + ":" + str(current_date)
total_cost = 0.0
for cost in cost_dict:
if cost_dict[cost]["UnblendedCost"] >= 0.1:
total_cost = cost_dict[cost]["UnblendedCost"] + total_cost
average_by_day = total_cost / float(day)
last_day_of_month = calendar.monthrange(datetime.datetime.now().year, datetime.datetime.now().month)[1]
number_of_days_left_in_month = last_day_of_month - datetime.datetime.now().day
total_left_for_month = average_by_day * number_of_days_left_in_month
return cost_dict, total_left_for_month, total_cost, first_date, time_frame, average_by_day
class PDF(FPDF):
def header(self):
# Logo
self.image('logo_pb.png', 10, 8, 33)
# Arial bold 15
self.set_font('Arial', 'BI', 10)
# Move to the right
self.cell(80)
# Title
self.cell(30, 10, 'Title', 0, 0, 'C')
# Line break
self.ln(20)
# Page footer
def footer(self):
# Position at 1.5 cm from bottom
self.set_y(-15)
# Arial italic 8
self.set_font('Arial', 'I', 8)
# Page number
self.cell(0, 10, 'Page ' + str(self.page_no()) + '/{nb}', 0, 0, 'C')
pdf = PDF()
pdf.alias_nb_pages()
pdf.add_page()
cost_dict, total_left_for_month, total_cost, first_date, time_frame_this_month, average_by_day = generate_month_cost_report()
predicted_total_cost = total_cost + total_left_for_month
predicted_total_cost = round(predicted_total_cost, 2)
predicted_total_cost_string = " $" + str(predicted_total_cost)
number_of_months = str(number_of_months).strip()
number_of_months = int(number_of_months)
dates_dict, months_dict, last_month_total = generate_monthly_cost_report(number_of_months)
dates_dict[first_date] = predicted_total_cost
plot_data = []
month_data = []
for item in dates_dict:
plot_data.append(int(dates_dict[item]))
year = str(item).split("-")[0]
month = str(item).split("-")[1]
month_item = month + "/" + year
month_data.append(month_item)
#import time
#epoch_months = []
#for month in month_data:
# pattern = '%Y-%m-%d'
# epoch = int(time.mktime(time.strptime(month, pattern)))
# epoch_months.append(epoch)
sns.set_style("darkgrid")
plt.xticks(rotation=20)
plt.plot(month_data,plot_data)
plt.savefig("cost-trend.png")
spacer_string = """
"""
pdf.multi_cell(0, 5, spacer_string, 0, 1)
labels = []
sizes = []
colors = []
for cost in cost_dict:
if cost_dict[cost]["UnblendedCost"] >= 0.1:
labels.append(cost)
sizes.append(int(cost_dict[cost]["UnblendedCost"]))
number_of_colors = len(sizes)
colors = []
color_choices = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue', 'yellowgreen', 'lightcoral', 'lightskyblue', 'purple', 'grey']
count = 0
for color in range(0,number_of_colors):
colors.append(color_choices[count])
count += 1
plt.pie(sizes, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=90)
plt.axis('equal')
plt.savefig("cost-pie2.png")
pdf.set_font('Times', 'B', 10)
pdf.image('cost-trend.png', 0, 30, 200, 120)
pdf.set_font('Times', 'B', 10)
pdf.cell(0,5, time_frame_this_month, 0, 1)
for cost in cost_dict:
if cost_dict[cost]["UnblendedCost"] >= 0.1:
pdf.set_font('Times', 'B', 10)
cost_string = " " + cost + ": "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
cost_new_string = "$" + str(round(cost_dict[cost]["UnblendedCost"], 2)).strip()
pdf.cell(40, 5, cost_new_string, 0, 1)
pdf.ln(5)
pdf.line(10, 30, 200, 30)
pdf.set_font('Times', 'B', 10)
cost_string = "Total: "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
total_cost_string = " $" + str(round(total_cost, 2))
pdf.cell(0, 5, total_cost_string, 0, 1)
pdf.set_font('Times', 'B', 10)
cost_string = "Predicted Total: "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
pdf.cell(0, 5, predicted_total_cost_string, 0, 1)
next_thirty_days = average_by_day * 30
next_thirty_days = " $" + str(round(next_thirty_days, 2))
pdf.set_font('Times', 'B', 10)
cost_string = "Predicted Total Next 30 Days: "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
pdf.cell(0, 5, str(next_thirty_days), 0, 1)
pdf.set_font('Times', 'B', 10)
cost_string = "Last Month Total: "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
pdf.cell(0, 5, " $"+str(last_month_total), 0, 1)
net_change = (last_month_total / predicted_total_cost) * 100
net_change = net_change - 100
net_change = abs(net_change)
net_change = round(net_change, 2)
pdf.set_font('Times', 'B', 10)
cost_string = "Net Change: "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
pdf.cell(0, 5, " "+str(net_change) + "%", 0, 1)
pdf.ln(5)
pdf.set_font('Times', 'B', 10)
pdf.cell(0, 10, "Historical "+str(number_of_months)+" Month Cost Analysis", 0, 1)
for timeframe in sorted(months_dict, reverse=True):
total_cost = 0.00
time_frame = timeframe
time_frame_string = timeframe
pdf.set_font('Times', 'B', 10)
pdf.cell(0, 5, time_frame_string, 0, 1)
pdf.set_font('Times', '', 10)
for cost in months_dict[timeframe]["cost"]:
if months_dict[timeframe]["cost"][cost]["UnblendedCost"] >= 0.1:
pdf.set_font('Times', 'B', 10)
cost_string = " " + cost + ": "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
cost_string = " $" + str(round(months_dict[timeframe]["cost"][cost]["UnblendedCost"], 2)).strip()
pdf.cell(0, 5, cost_string, 0, 1)
months_dict[timeframe]["cost"][cost]["TimeFrame"] = time_frame
total_cost = months_dict[timeframe]["cost"][cost]["UnblendedCost"] + total_cost
pdf.ln(5)
pdf.set_font('Times', 'B', 10)
cost_string = "Total: "
pdf.cell(80, 5, cost_string, 0, 0)
pdf.set_font('Times', '', 10)
total_cost_string = " $" + str(round(total_cost, 2))
pdf.cell(0, 5, total_cost_string, 0, 1)
pdf.ln(10)
pdf.cell(0, 10, " ", 0, 1)
pdf.set_font('Arial', 'I', 8)
pdf.cell(5, 10, " * EC2 - Other: Cost not asscoiated with ELB or EC2 Instance. Examples would be: EBS volumes or Elastic IP addresses.", 0, 1)
pdf.output('AWSCost.pdf', 'F')
print "Report generated."
#better formatting
#trendline
#move the graphic to the top middle