我正在使用python和matplotlib构建AWS的PDF成本报告,该报告每周发送一次。我正在尝试通过饼图添加按成本细分的服务,以显示每种服务在总成本中所占的比例。但是,显示的饼图实际上并不会自动显示百分比。饼形图的所有值都位于相同的12点位置,并且没有价差。
不确定我在做什么错。尺寸,标签和颜色的列表大小相同。大小或值列表是整数,我尝试了浮点数和字符串。不会引发错误,只是无法正确形成图表。
代码:
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
答案 0 :(得分:0)
我最终找到了解决方案,那就是在创建新图表之前添加plt.close()。