Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: superpung/tju-expense
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.2.0
Choose a base ref
...
head repository: superpung/tju-expense
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.3.0
Choose a head ref
  • 1 commit
  • 3 files changed
  • 1 contributor

Commits on Dec 24, 2024

  1. feat: new layout

    superpung committed Dec 24, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    superpung Sᴜᴘᴇʀ Lᴇᴇ
    Copy the full SHA
    280ab36 View commit details
Showing with 101 additions and 27 deletions.
  1. BIN docs/example.png
  2. +2 −2 pyproject.toml
  3. +99 −25 src/tju_expense/analyze.py
Binary file modified docs/example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[project]
name = "tju-expense"
version = "0.2.0"
description = "Add your description here"
version = "0.3.0"
description = "天津大学校园卡年度消费报告"
authors = [
{ name = "SUPER", email = "hi@repus.me" }
]
124 changes: 99 additions & 25 deletions src/tju_expense/analyze.py
Original file line number Diff line number Diff line change
@@ -29,9 +29,9 @@ def analyze(df_file, title, save_to):
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
plt.rcParams['font.size'] = 14 # 设置全局字体大小为14(可以根据需要调整)

# 创建纵向图表布局 (3行2列的网格,但热力图和趋势图分别占一整行)
fig = plt.figure(figsize=(12, 15))
gs = plt.GridSpec(3, 3)
# 创建纵向图表布局
fig = plt.figure(figsize=(12, 16))
gs = plt.GridSpec(4, 3, figure=fig) # 必须要加 figure=fig

# 1. 消费热力图 (第一行,跨越所有列)
ax1 = fig.add_subplot(gs[0, :])
@@ -41,14 +41,26 @@ def analyze(df_file, title, save_to):
ax2 = fig.add_subplot(gs[1, :])
plot_daily_trend(df, ax2)

# 3. 消费类型饼图 (第三行,第一列)
# 3. 绘制每日消费散点图 (第三行,第一列)
ax3 = fig.add_subplot(gs[2, 0])
plot_type_pie_chart(df, ax3)
plot_daily_scatter(df, ax3)

# 4. 消费地点统计 (第三行,第二列)
ax4 = fig.add_subplot(gs[2, 1:])
plot_place_statistics(df, ax4)

# 5. 消费类型饼图 (第四行,第一列)
ax5 = fig.add_subplot(gs[3, 0])
plot_type_pie_chart(df, ax5)

# 6. 每月消费统计饼图 (第四行,第二列)
ax6 = fig.add_subplot(gs[3, 1])
plot_monthly_pie_chart(df, ax6)

# 7. 时段消费统计饼图 (第四行,第三列)
ax7 = fig.add_subplot(gs[3, 2])
plot_time_slot_pie_chart(df, ax7)

plt.tight_layout()
plt.savefig(save_to, dpi=300, bbox_inches='tight')
return True
@@ -115,6 +127,43 @@ def plot_daily_trend(df, ax):
# 旋转x轴日期标签
plt.setp(ax.get_xticklabels(), rotation=45, ha='right')

def plot_daily_scatter(df, ax):
"""绘制每日消费散点图"""
ax.scatter(df['time'].dt.hour + df['time'].dt.minute / 60, df['amount'], color='#6baed6', alpha=0.6) # 修改为时间(0:00-24:00)

# 设置x轴刻度
ax.set_xticks([0, 4, 8, 12, 16, 20, 24]) # 设置x轴刻度为0, 4, 8, 12, 16, 20, 24
ax.set_xticklabels(['0', '4', '8', '12', '16', '20', '24']) # 设置x轴标签

# 设置标签
ax.set_title('消费时间分布')
ax.set_xlabel('时间')
ax.set_ylabel('')

def plot_place_statistics(df, ax):
"""绘制消费地点统计柱状图"""
df = df[~df['type'].str.contains('水|电', na=False)]

# 统计每个地点的消费总额并取前10
place_stats = df.groupby('place')['amount'].sum()
place_stats = place_stats.nlargest(10).sort_values(ascending=True)

# 绘制横向柱状图
bars = place_stats.plot(
kind='barh',
ax=ax,
color='#6baed6'
)

# 设置标签
ax.set_title('消费地点TOP10')
ax.set_xlabel('消费金额')
ax.set_ylabel('')

# 在柱状图上添加数值标签
for i, v in enumerate(place_stats):
ax.text(v, i, f'{v:.2f}', va='center', fontsize=7)

def plot_type_pie_chart(df, ax):
"""绘制消费类型饼图"""
# 统计每种类型的消费总额
@@ -136,37 +185,62 @@ def plot_type_pie_chart(df, ax):
startangle=90,
pctdistance=0.85,
explode=explode,
colors=sns.color_palette("pastel")
colors=sns.color_palette("Blues")
)

# 设置标题和样式
ax.set_title('消费类型占比', pad=20)
plt.setp(autotexts, size=8, weight="bold")
plt.setp(texts, size=8)

def plot_place_statistics(df, ax):
"""绘制消费地点统计柱状图"""
df = df[~df['type'].str.contains('水|电', na=False)]
def plot_monthly_pie_chart(df, ax):
"""绘制每月消费统计饼图"""
# 统计每月消费总额
monthly_stats = df.groupby(df['time'].dt.to_period('M'))['amount'].sum()

# 统计每个地点的消费总额并取前10
place_stats = df.groupby('place')['amount'].sum()
place_stats = place_stats.nlargest(10).sort_values(ascending=True)

# 绘制横向柱状图
bars = place_stats.plot(
kind='barh',
ax=ax,
color='#a1c9f4'
# 绘制饼图
wedges, texts, autotexts = ax.pie(
monthly_stats,
labels=[f"{month.month}月" for month in monthly_stats.index], # 修改为X月的形式
autopct='%1.1f%%',
startangle=90,
pctdistance=0.85,
colors=sns.color_palette("Blues")
)

# 设置标签
ax.set_title('消费地点TOP10')
ax.set_xlabel('消费金额')
ax.set_ylabel('')
# 设置标题和样式
ax.set_title('每月消费占比', pad=20)
plt.setp(autotexts, size=8, weight="bold")
plt.setp(texts, size=8)

# 在柱状图上添加数值标签
for i, v in enumerate(place_stats):
ax.text(v, i, f'{v:.2f}', va='center', fontsize=7)
def plot_time_slot_pie_chart(df, ax):
"""绘制时段消费统计饼图"""
time_slots = {
'早餐': (5, 11), # 5点到11点
'午餐': (11, 17), # 11点到17点
'晚餐': (17, 24) # 17点到24点
}

time_slot_stats = {}
filtered_df = df[~df['type'].str.contains('水|电', na=False)]
for slot, (start, end) in time_slots.items():
mask = (filtered_df['time'].dt.hour >= start) & (filtered_df['time'].dt.hour < end)
time_slot_stats[slot] = filtered_df[mask]['amount'].sum()

# 绘制饼图
wedges, texts, autotexts = ax.pie(
time_slot_stats.values(),
labels=time_slot_stats.keys(),
autopct='%1.1f%%',
startangle=90,
pctdistance=0.85,
colors=sns.color_palette("Blues")
)

# 设置标题和样式
ax.set_title('时段消费占比', pad=20)
plt.setp(autotexts, size=8, weight="bold")
plt.setp(texts, size=8)

def print_statistics(df_file):
"""打印基本统计信息"""