如何创建堆积条形图?
How to Create A Stacked Bar Chart?
我正在编写一个程序来监视和记录前台应用程序的使用时间,并将它们保存在 SQL 数据库中。然后我想检索前几天的数据并将它们全部编译成堆叠条形图。此处,x-axis 将记录使用情况的不同日期,每个栏中的各种堆栈将代表使用的每个应用程序。
在我的程序中,我创建了 2 个 table,一个用于记录每天的应用程序使用情况(每个新的一天的数据具有不同的主键 ID),另一个 table 用于记录每天的主键。
Table 1:
_id
Application
usage_time
0
Google Chrome
245.283942928347
0
Finder
123.384234239734
0
PyCharm
100.484829432934
1
PyCharm
1646.46116232872
1
SQLiteStudio
160.25696277618408
1
Google Chrome
1756.8145654201508
1
Microsoft Teams
150.2583293914795
Table 2:
Date
daily_id
2021-07-18 07:25:25.376734
0
2021-07-18 07:27:57.419574
1
在我的堆积条形图程序中,我想出了这段代码来优化要放入堆积条形图中的数据:
conn = sqlite3.connect('daily_usage_monitor.sqlite', detect_types=sqlite3.PARSE_DECLTYPES)
all_app_data = conn.execute('SELECT all_usage_information.date, monitor.application, monitor.usage_time '
'FROM all_usage_information '
'INNER JOIN monitor ON all_usage_information.daily_id = monitor._id '
'ORDER BY all_usage_information.date, monitor.usage_time ASC').fetchall()
for date, app, usage_time in all_app_data:
print(f'{date} - {app}: {usage_time}')
conn.close()
daily_data = {}
# Create nested dictionary - key = each date, value = dictionary of different apps & their time usage durations
for date, app, time in all_app_data:
conditions = [date not in daily_data, app != 'loginwindow']
if all(conditions):
daily_data[date] = {app: time}
elif not conditions[0] and conditions[1]:
daily_data[date].update({app: time})
print(daily_data) # TODO: REMOVE AFTER TESTING
total_time = 0
# Club any applications that account for <5% of total time into 1 category called 'Other'
for date, app_usages in daily_data.items():
total_time = sum(time for app, time in app_usages.items())
refined_data = {}
for key, value in app_usages.items():
if value/total_time < 0.05:
refined_data['Others'] = refined_data.setdefault('Others', 0) + value
else:
refined_data[key] = value
daily_data[date] = refined_data
print(daily_data) # TODO: REMOVE AFTER TESTING
# Add key:value pairs initializing apps to 0 which are either used in past and never used again
# or used in future but not in past
used_apps = set()
counter = 0
for date, app_usages in reversed(daily_data.items()):
for app, time in app_usages.items():
used_apps.add(app)
counter += 1
if counter != 1:
for used_app in used_apps:
if used_app not in app_usages.keys():
app_usages[used_app] = 0
used_apps = set()
counter = 0
for date, app_usages in daily_data.items():
for app, time in app_usages.items():
used_apps.add(app)
counter += 1
if counter != 1:
for used_app in used_apps:
if used_app not in app_usages.keys():
app_usages[used_app] = 0
print(daily_data) # TODO: REMOVE AFTER TESTING
# Takes the nested dictionary and breaks it into a labels list and a dictionary with apps & time usages for each day
# Sorts data so it can be used to create composite bar chart
final_data = {}
labels = []
for date, app_usages in daily_data.items():
labels.append(date.strftime('%d/%m/%Y'))
for app, time in app_usages.items():
# time = datetime.timedelta(seconds=time) # TODO: CHECK WHAT TO DO
if app not in final_data:
final_data[app] = [time]
else:
final_data[app].append(time)
print(final_data)
final_data = dict(sorted(final_data.items(), key=lambda x: x[1], reverse=True))
print(final_data) # TODO: REMOVE AFTER TESTING
这个处理给出了这个输出:
{'Google Chrome':[245.283942928347,1756.8145654201508],'Finder':[123.3842342397347,0],[= 43 = 43 =]: =15=]
然后,为了创建堆叠条形图,这是我编写的代码:
width = 0.5
counter = 0
fig, ax = plt.subplots()
for key, value in final_data.items():
if counter == 0:
ax.bar(labels, value, width=width, label=key)
else:
ax.bar(labels, value, width=width, bottom=bottom, label=key)
bottom = value
counter += 1
ax.set_ylabel('Time usage on applications')
ax.set_xlabel('Dates (DD-MM-YYYY)')
ax.set_title('Time Usage Trend')
ax.legend()
plt.show()
但是,这是我得到的输出:
如您所见,第一个条有重叠,第二个堆叠条中缺少 Google Chrome 条,Finder 条非常小,即使它不是与其他数据相比很小。
关于如何修复此堆积条形图的任何想法?也将感谢有关如何改进数据处理的建议
matplotlib 堆积条形图疑难解答
看来你的问题是 for 循环。您正在遍历键和值,并绘制每次迭代的值。
for key, value in final_data.items():
print(key, value)
Google Chrome [245.283942928347, 1756.8145654201508]
Finder [123.3842342397347, 0]
PyCharm [100.4848294329348, 1646.46116232872]
Others [0, 310.5152921676636]
您打算做的是在每次迭代中绘制每个 LABEL。您可以更改 for 循环,但我建议您将字典放入 pandas 数据框并使用 pandas DataFrame.plot.bar(stacked=True)。为堆叠条形图设置 'bottom' 或 'left' 需要很多麻烦。
final_data = pd.DataFrame({
'Google Chrome': [245.283942928347, 1756.8145654201508],
'Finder': [123.3842342397347, 0],
'PyCharm': [100.4848294329348, 1646.46116232872],
'Others': [0, 310.5152921676636]}
)
final_data.plot.bar(stacked=True)
我正在编写一个程序来监视和记录前台应用程序的使用时间,并将它们保存在 SQL 数据库中。然后我想检索前几天的数据并将它们全部编译成堆叠条形图。此处,x-axis 将记录使用情况的不同日期,每个栏中的各种堆栈将代表使用的每个应用程序。
在我的程序中,我创建了 2 个 table,一个用于记录每天的应用程序使用情况(每个新的一天的数据具有不同的主键 ID),另一个 table 用于记录每天的主键。
Table 1:
_id | Application | usage_time |
---|---|---|
0 | Google Chrome | 245.283942928347 |
0 | Finder | 123.384234239734 |
0 | PyCharm | 100.484829432934 |
1 | PyCharm | 1646.46116232872 |
1 | SQLiteStudio | 160.25696277618408 |
1 | Google Chrome | 1756.8145654201508 |
1 | Microsoft Teams | 150.2583293914795 |
Table 2:
Date | daily_id |
---|---|
2021-07-18 07:25:25.376734 | 0 |
2021-07-18 07:27:57.419574 | 1 |
在我的堆积条形图程序中,我想出了这段代码来优化要放入堆积条形图中的数据:
conn = sqlite3.connect('daily_usage_monitor.sqlite', detect_types=sqlite3.PARSE_DECLTYPES)
all_app_data = conn.execute('SELECT all_usage_information.date, monitor.application, monitor.usage_time '
'FROM all_usage_information '
'INNER JOIN monitor ON all_usage_information.daily_id = monitor._id '
'ORDER BY all_usage_information.date, monitor.usage_time ASC').fetchall()
for date, app, usage_time in all_app_data:
print(f'{date} - {app}: {usage_time}')
conn.close()
daily_data = {}
# Create nested dictionary - key = each date, value = dictionary of different apps & their time usage durations
for date, app, time in all_app_data:
conditions = [date not in daily_data, app != 'loginwindow']
if all(conditions):
daily_data[date] = {app: time}
elif not conditions[0] and conditions[1]:
daily_data[date].update({app: time})
print(daily_data) # TODO: REMOVE AFTER TESTING
total_time = 0
# Club any applications that account for <5% of total time into 1 category called 'Other'
for date, app_usages in daily_data.items():
total_time = sum(time for app, time in app_usages.items())
refined_data = {}
for key, value in app_usages.items():
if value/total_time < 0.05:
refined_data['Others'] = refined_data.setdefault('Others', 0) + value
else:
refined_data[key] = value
daily_data[date] = refined_data
print(daily_data) # TODO: REMOVE AFTER TESTING
# Add key:value pairs initializing apps to 0 which are either used in past and never used again
# or used in future but not in past
used_apps = set()
counter = 0
for date, app_usages in reversed(daily_data.items()):
for app, time in app_usages.items():
used_apps.add(app)
counter += 1
if counter != 1:
for used_app in used_apps:
if used_app not in app_usages.keys():
app_usages[used_app] = 0
used_apps = set()
counter = 0
for date, app_usages in daily_data.items():
for app, time in app_usages.items():
used_apps.add(app)
counter += 1
if counter != 1:
for used_app in used_apps:
if used_app not in app_usages.keys():
app_usages[used_app] = 0
print(daily_data) # TODO: REMOVE AFTER TESTING
# Takes the nested dictionary and breaks it into a labels list and a dictionary with apps & time usages for each day
# Sorts data so it can be used to create composite bar chart
final_data = {}
labels = []
for date, app_usages in daily_data.items():
labels.append(date.strftime('%d/%m/%Y'))
for app, time in app_usages.items():
# time = datetime.timedelta(seconds=time) # TODO: CHECK WHAT TO DO
if app not in final_data:
final_data[app] = [time]
else:
final_data[app].append(time)
print(final_data)
final_data = dict(sorted(final_data.items(), key=lambda x: x[1], reverse=True))
print(final_data) # TODO: REMOVE AFTER TESTING
这个处理给出了这个输出: {'Google Chrome':[245.283942928347,1756.8145654201508],'Finder':[123.3842342397347,0],[= 43 = 43 =]: =15=]
然后,为了创建堆叠条形图,这是我编写的代码:
width = 0.5
counter = 0
fig, ax = plt.subplots()
for key, value in final_data.items():
if counter == 0:
ax.bar(labels, value, width=width, label=key)
else:
ax.bar(labels, value, width=width, bottom=bottom, label=key)
bottom = value
counter += 1
ax.set_ylabel('Time usage on applications')
ax.set_xlabel('Dates (DD-MM-YYYY)')
ax.set_title('Time Usage Trend')
ax.legend()
plt.show()
但是,这是我得到的输出:
如您所见,第一个条有重叠,第二个堆叠条中缺少 Google Chrome 条,Finder 条非常小,即使它不是与其他数据相比很小。
关于如何修复此堆积条形图的任何想法?也将感谢有关如何改进数据处理的建议
matplotlib 堆积条形图疑难解答
看来你的问题是 for 循环。您正在遍历键和值,并绘制每次迭代的值。
for key, value in final_data.items():
print(key, value)
Google Chrome [245.283942928347, 1756.8145654201508]
Finder [123.3842342397347, 0]
PyCharm [100.4848294329348, 1646.46116232872]
Others [0, 310.5152921676636]
您打算做的是在每次迭代中绘制每个 LABEL。您可以更改 for 循环,但我建议您将字典放入 pandas 数据框并使用 pandas DataFrame.plot.bar(stacked=True)。为堆叠条形图设置 'bottom' 或 'left' 需要很多麻烦。
final_data = pd.DataFrame({
'Google Chrome': [245.283942928347, 1756.8145654201508],
'Finder': [123.3842342397347, 0],
'PyCharm': [100.4848294329348, 1646.46116232872],
'Others': [0, 310.5152921676636]}
)
final_data.plot.bar(stacked=True)