基于Python和Pandas优化学生课程表可视化的方案咨询
课程表可视化:重叠课程堆叠显示问题
问题背景与需求
我用Pandas DataFrame存储课程表数据,想要将其可视化成重叠课程堆叠显示的样式。目前基于ChatGPT 3.5生成并修改的Matplotlib条形图代码,仅能勉强处理周一上午的部分重叠,完全遗漏周一下午的重叠情况,无法达到理想的堆叠效果。
我设想了两种修复方案,但都觉得过于繁琐:
- 从周五(图表底部)开始计算每日重叠课程数,设置Y轴位置后依次处理其他日期;
- 忽略重叠判断,按每日课程数量统一偏移所有课程条,该方案虽会导致非重叠课程无法对齐,但可接受。
希望找到更简便的实现方式,比如适配的图表类型、第三方库或编码技巧,同时满足以下补充需求:
- 重叠课程不常见,尽量保持非重叠课程水平对齐;
- 支持2门及以上课程同时重叠的场景。
现有代码
import pandas as pd import matplotlib.pyplot as plt import numpy as np # Sample DataFrame data = { 'CCode': ['BABM701','BABM701', 'DCFE700', 'MG6051', 'DCFE700', 'MG6051'], 'SG': ['All','All', 'All', 'A', 'All','A'], 'StartTime': ['09:00:00','13:00:00', '09:00:00','09:00:00', '13:00:00','10:00:00'], 'EndTime': ['12:00:00', '14:30:00','14:30:00','12:00:00', '14:30:00','12:00:00'], 'Day': ['Mon', 'Mon','Mon', 'Thu', 'Thu','Fri'], 'Room': ['X310','X310', 'K312','K225', 'K312','K225'] } df = pd.DataFrame(data) # Convert the 'StartTime' and 'EndTime' to datetime format df['StartTime'] = pd.to_datetime(df['StartTime'], format='%H:%M:%S').dt.time df['EndTime'] = pd.to_datetime(df['EndTime'], format='%H:%M:%S').dt.time # Get unique CCode values and assign colors automatically unique_ccodes = df['CCode'].unique() colors = plt.cm.Spectral(np.linspace(0, 1, len(unique_ccodes))) # Using tab20 colormap color_map = {ccode: colors[i] for i, ccode in enumerate(unique_ccodes)} # Create the plot plt.figure(figsize=(12, 6)) # Set the y-position for the bars y_positions = {'Mon': 4, 'Tue': 3, 'Wed': 2, 'Thu': 1, 'Fri': 0} # Find the earliest start time and latest end time earliest_start = min(9, df['StartTime'].apply(lambda x: x.hour + x.minute/60).min()) latest_end = max(17, df['EndTime'].apply(lambda x: x.hour + x.minute/60).max()) # Adjust y-positions based on overlaps for day in df['Day'].unique(): day_df = df[df['Day'] == day].sort_values(by='StartTime') overlap_count = np.zeros(len(day_df)) for i in range(len(day_df)): for j in range(i + 1, len(day_df)): if day_df.iloc[i]['EndTime'] > day_df.iloc[j]['StartTime'] and day_df.iloc[i]['StartTime'] < day_df.iloc[j]['EndTime']: overlap_count[j] += 1 day_df['Overlap'] = overlap_count # Plot bars for the day with adjusted height for overlapping courses for idx, row in day_df.iterrows(): duration = (pd.Timestamp.combine(pd.Timestamp.today(), row['EndTime']) - pd.Timestamp.combine(pd.Timestamp.today(), row['StartTime'])).seconds/3600 x_position = row['StartTime'].hour + row['StartTime'].minute/60 y_position = y_positions[day] - row['Overlap'] * 0.5 # Adjusting y position based on overlap plt.barh(y=y_position, width=duration, left=x_position, color=color_map[row['CCode']], alpha=0.7, edgecolor='grey', label=row['CCode']) # Annotate the bar with CCode and SG label = f"{row['CCode']} {row['SG']}" plt.text(x=x_position + duration/2, y=y_position, s=label, color='black', va='center', ha='center') # Customize the plot plt.xlabel('Time') plt.ylabel('Day') plt.title('Course Schedule') plt.xlim(earliest_start, latest_end) plt.xticks(np.arange(earliest_start, latest_end + 1, 1)) plt.yticks([0, 1, 2, 3, 4], ['Fri', 'Thu', 'Wed', 'Tue', 'Mon']) plt.grid(axis='x', linestyle='--', alpha=0.7) plt.legend(loc='upper right') plt.tight_layout() # Show the plot plt.show()
内容的提问来源于stack exchange,提问作者ic198
相关产品推荐
相关产品推荐

