Matplotlib Piechart自动百分比无法正常工作

时间:2018-06-25 21:47:26

标签: python matplotlib charts

我正在使用python和matplotlib构建AWS的PDF成本报告,该报告每周发送一次。我正在尝试通过饼图添加按成本细分的服务,以显示每种服务在总成本中所占的比例。但是,显示的饼图实际上并不会自动显示百分比。饼形图的所有值都位于相同的12点位置,并且没有价差。

不确定我在做什么错。尺寸,标签和颜色的列表大小相同。大小或值列表是整数,我尝试了浮点数和字符串。不会引发错误,只是无法正确形成图表。

空饼图。 Pie Chart

图表尝试使用的值列表: Sizes List

图表尝试使用的颜色列表: Colors List

图表尝试使用的标签列表。 List of Labels

代码:

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

1 个答案:

答案 0 :(得分:0)

我最终找到了解决方案,那就是在创建新图表之前添加plt.close()。