import matplotlib
# 关键:设置无交互后端,适配 ideone 云端环境
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
from io import BytesIO
# 适配Linux环境中文字体
plt.rcParams["font.family"] = ["DejaVu Sans"]
plt.rcParams['axes.unicode_minus'] = False
cities = [
"Nanning", "Liuzhou", "Guilin", "Wuzhou", "Beihai", "Fangchenggang", "Qinzhou",
"Guigang", "Yulin", "Baise", "Hezhou", "Hechi", "Laibin", "Chongzuo"
]
out_contract = np.array([16.18, 31.03, 20.19, 0.64, 2.38, 0.25, 2.01,
5.16, 1.88, 0.29, 6.15, 4.92, 7.13, 1.11])
in_contract = np.array([162.52, 20.02, 6.89, 12.80, 4.66, 4.09, 57.62,
10.42, 13.73, 3.78, 1.66, 8.31, 6.69, 2.27])
total = out_contract + in_contract
finish_rate = np.array([46, 43, 46, 35, 5, 7, 70, 22, 22, 8, 30, 24, 36, 7])
def save_fig(name):
buf = BytesIO()
plt.tight_layout()
plt.savefig(buf, format='png', dpi=100, bbox_inches="tight")
print(f"{name}‑plot generated (bytes length: {len(buf.getvalue())})")
buf.close()
# 1. Pie chart
plt.figure(figsize=(10, 10))
plt.pie(total, labels=cities, autopct="%.1f%%", startangle=90)
plt.title("City Total‑Contract Proportion")
save_fig("pie")
plt.close()
# 2. Group bar chart
x = np.arange(len(cities))
width = 0.35
plt.figure(figsize=(14, 7))
plt.bar(x - width/2, out_contract, width, label="Output Contract")
plt.bar(x + width/2, in_contract, width, label="Absorb Contract")
plt.xticks(x, cities, rotation=45, ha="right")
plt.xlabel("City")
plt.ylabel("Amount")
plt.title("Output & Absorb Contract Comparison")
plt.legend()
save_fig("bar_group")
plt.close()
# 3. Finish‑rate bar
plt.figure(figsize=(14, 7))
bars = plt.bar(cities, finish_rate)
plt.xticks(rotation=45, ha="right")
plt.ylabel("Finish‑rate %")
plt.title("City Task Completion Rate")
for bar in bars:
h = bar.get_height()
plt.text(bar.get_x() + bar.get_width() / 2, h, f"{h}%", ha="center", va="bottom")
save_fig("bar_rate")
plt.close()
print("All three charts have been rendered successfully.")
aW1wb3J0IG1hdHBsb3RsaWIKIyDlhbPplK7vvJrorr7nva7ml6DkuqTkupLlkI7nq6/vvIzpgILphY0gaWRlb25lIOS6keerr+eOr+WigwptYXRwbG90bGliLnVzZSgnQWdnJykKCmltcG9ydCBtYXRwbG90bGliLnB5cGxvdCBhcyBwbHQKaW1wb3J0IG51bXB5IGFzIG5wCmZyb20gaW8gaW1wb3J0IEJ5dGVzSU8KCiMg6YCC6YWNTGludXjnjq/looPkuK3mloflrZfkvZMKcGx0LnJjUGFyYW1zWyJmb250LmZhbWlseSJdID0gWyJEZWphVnUgU2FucyJdCnBsdC5yY1BhcmFtc1snYXhlcy51bmljb2RlX21pbnVzJ10gPSBGYWxzZQoKY2l0aWVzID0gWwogICAgIk5hbm5pbmciLCAiTGl1emhvdSIsICJHdWlsaW4iLCAiV3V6aG91IiwgIkJlaWhhaSIsICJGYW5nY2hlbmdnYW5nIiwgIlFpbnpob3UiLAogICAgIkd1aWdhbmciLCAiWXVsaW4iLCAiQmFpc2UiLCAiSGV6aG91IiwgIkhlY2hpIiwgIkxhaWJpbiIsICJDaG9uZ3p1byIKXQpvdXRfY29udHJhY3QgPSBucC5hcnJheShbMTYuMTgsIDMxLjAzLCAyMC4xOSwgMC42NCwgMi4zOCwgMC4yNSwgMi4wMSwKICAgICAgICAgICAgICAgICAgICAgICAgICA1LjE2LCAxLjg4LCAwLjI5LCA2LjE1LCA0LjkyLCA3LjEzLCAxLjExXSkKaW5fY29udHJhY3QgPSBucC5hcnJheShbMTYyLjUyLCAyMC4wMiwgNi44OSwgMTIuODAsIDQuNjYsIDQuMDksIDU3LjYyLAogICAgICAgICAgICAgICAgICAgICAgICAgIDEwLjQyLCAxMy43MywgMy43OCwgMS42NiwgOC4zMSwgNi42OSwgMi4yN10pCnRvdGFsID0gb3V0X2NvbnRyYWN0ICsgaW5fY29udHJhY3QKZmluaXNoX3JhdGUgPSBucC5hcnJheShbNDYsIDQzLCA0NiwgMzUsIDUsIDcsIDcwLCAyMiwgMjIsIDgsIDMwLCAyNCwgMzYsIDddKQoKCmRlZiBzYXZlX2ZpZyhuYW1lKToKICAgIGJ1ZiA9IEJ5dGVzSU8oKQogICAgcGx0LnRpZ2h0X2xheW91dCgpCiAgICBwbHQuc2F2ZWZpZyhidWYsIGZvcm1hdD0ncG5nJywgZHBpPTEwMCwgYmJveF9pbmNoZXM9InRpZ2h0IikKICAgIHByaW50KGYie25hbWV94oCRcGxvdCBnZW5lcmF0ZWQgKGJ5dGVzIGxlbmd0aDoge2xlbihidWYuZ2V0dmFsdWUoKSl9KSIpCiAgICBidWYuY2xvc2UoKQoKCiMgMS4gUGllIGNoYXJ0CnBsdC5maWd1cmUoZmlnc2l6ZT0oMTAsIDEwKSkKcGx0LnBpZSh0b3RhbCwgbGFiZWxzPWNpdGllcywgYXV0b3BjdD0iJS4xZiUlIiwgc3RhcnRhbmdsZT05MCkKcGx0LnRpdGxlKCJDaXR5IFRvdGFs4oCRQ29udHJhY3QgUHJvcG9ydGlvbiIpCnNhdmVfZmlnKCJwaWUiKQpwbHQuY2xvc2UoKQoKIyAyLiBHcm91cCBiYXIgY2hhcnQKeCA9IG5wLmFyYW5nZShsZW4oY2l0aWVzKSkKd2lkdGggPSAwLjM1CnBsdC5maWd1cmUoZmlnc2l6ZT0oMTQsIDcpKQpwbHQuYmFyKHggLSB3aWR0aC8yLCBvdXRfY29udHJhY3QsIHdpZHRoLCBsYWJlbD0iT3V0cHV0IENvbnRyYWN0IikKcGx0LmJhcih4ICsgd2lkdGgvMiwgaW5fY29udHJhY3QsIHdpZHRoLCBsYWJlbD0iQWJzb3JiIENvbnRyYWN0IikKcGx0Lnh0aWNrcyh4LCBjaXRpZXMsIHJvdGF0aW9uPTQ1LCBoYT0icmlnaHQiKQpwbHQueGxhYmVsKCJDaXR5IikKcGx0LnlsYWJlbCgiQW1vdW50IikKcGx0LnRpdGxlKCJPdXRwdXQgJiBBYnNvcmIgQ29udHJhY3QgQ29tcGFyaXNvbiIpCnBsdC5sZWdlbmQoKQpzYXZlX2ZpZygiYmFyX2dyb3VwIikKcGx0LmNsb3NlKCkKCiMgMy4gRmluaXNo4oCRcmF0ZSBiYXIKcGx0LmZpZ3VyZShmaWdzaXplPSgxNCwgNykpCmJhcnMgPSBwbHQuYmFyKGNpdGllcywgZmluaXNoX3JhdGUpCnBsdC54dGlja3Mocm90YXRpb249NDUsIGhhPSJyaWdodCIpCnBsdC55bGFiZWwoIkZpbmlzaOKAkXJhdGUgJSIpCnBsdC50aXRsZSgiQ2l0eSBUYXNrIENvbXBsZXRpb24gUmF0ZSIpCmZvciBiYXIgaW4gYmFyczoKICAgIGggPSBiYXIuZ2V0X2hlaWdodCgpCiAgICBwbHQudGV4dChiYXIuZ2V0X3goKSArIGJhci5nZXRfd2lkdGgoKSAvIDIsIGgsIGYie2h9JSIsIGhhPSJjZW50ZXIiLCB2YT0iYm90dG9tIikKc2F2ZV9maWcoImJhcl9yYXRlIikKcGx0LmNsb3NlKCkKCnByaW50KCJBbGwgdGhyZWUgY2hhcnRzIGhhdmUgYmVlbiByZW5kZXJlZCBzdWNjZXNzZnVsbHkuIik=