当前位置:   article > 正文

基于条形图的世界杯数据可视化_阿里云世界杯可视化分析

阿里云世界杯可视化分析

1 前言

要说时下最热门的活动,非2022卡塔尔世界杯莫属了。正好借此次机会,回顾一下过往的世界杯,就其历史数据做一些数据的呈现和分析工作。根据对世界杯历史数据的简单观察,发现条形图能更直观地展示数据。同时,本次论文的选题和数据是来自于“阿里云天池平台”的可视化大赛“世界杯数据可视化分析”,该文章也将作为参赛作品同步到“天池平台”上。

2 导入模块和数据

第一步是导入所需要的包。为此,我们需要:

  • pandas和它的DataFrame类来做数据读取和处理;
  • numpy在图表中进行一些基于数据的科学运算;
  • plotnine来获取数据并执行可视化操作。

除此之外,还使用了 plotnine 的 figure_size 函数来调整图形的大小,使它们显示得更加美观、整洁。

import numpy as np
import pandas as pd
import plotnine
plotnine.options.figure_size=(12, 4.2)
from plotnine import *
from plotnine import data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

然后导入世界杯历史比赛的信息,文件为“WorldCupMatches.csv”。

# 导入数据并查看
# 注意要加encoding='gbk',直接读取会显示
# UnicodeDecodeError: 'utf-8' codec can't decode bytes in position 18508-18509: invalid continuation byte
# 这是由于数据中有一些非英语国家的语言,utf-8无法处理的编码导致的
matches = pd.read_csv('WorldCupMatches.csv',encoding='gbk')
matches
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
YearDatetimeStageStadiumCityHome Team NameHome Team GoalsAway Team GoalsAway Team NameAttendanceHalf-time Home GoalsHalf-time Away GoalsRefereeAssistant 1Assistant 2RoundIDMatchIDHome Team InitialsAway Team Initials
0193013 Jul 1930 - 15:00Group 1PocitosMontevideoFrance41Mexico4444.030LOMBARDI Domingo (URU)CRISTOPHE Henry (BEL)REGO Gilberto (BRA)2011096FRAMEX
1193013 Jul 1930 - 15:00Group 4Parque CentralMontevideoUSA30Belgium18346.020MACIAS Jose (ARG)MATEUCCI Francisco (URU)WARNKEN Alberto (CHI)2011090USABEL
2193014 Jul 1930 - 12:45Group 2Parque CentralMontevideoYugoslavia21Brazil24059.020TEJADA Anibal (URU)VALLARINO Ricardo (URU)BALWAY Thomas (FRA)2011093YUGBRA
3193014 Jul 1930 - 14:50Group 3PocitosMontevideoRomania31Peru2549.010WARNKEN Alberto (CHI)LANGENUS Jean (BEL)MATEUCCI Francisco (URU)2011098ROUPER
4193015 Jul 1930 - 16:00Group 1Parque CentralMontevideoArgentina10France23409.000REGO Gilberto (BRA)SAUCEDO Ulises (BOL)RADULESCU Constantin (ROU)2011085ARGFRA
............................................................
847201405 Jul 2014 - 17:00Quarter-finalsArena Fonte NovaSalvadorNetherlands00Costa Rica51179.000Ravshan IRMATOV (UZB)RASULOV Abduxamidullo (UZB)KOCHKAROV Bakhadyr (KGZ)255953300186488NEDCRC
848201408 Jul 2014 - 17:00Semi-finalsEstadio MineiraoBelo HorizonteBrazil17Germany58141.005RODRIGUEZ Marco (MEX)TORRENTERA Marvin (MEX)QUINTERO Marcos (MEX)255955300186474BRAGER
849201409 Jul 2014 - 17:00Semi-finalsArena de Sao PauloSao PauloNetherlands00Argentina63267.000C眉neyt 脟AKIR (TUR)DURAN Bahattin (TUR)ONGUN Tarik (TUR)255955300186490NEDARG
850201412 Jul 2014 - 17:00Play-off for third placeEstadio NacionalBrasiliaBrazil03Netherlands68034.002HAIMOUDI Djamel (ALG)ACHIK Redouane (MAR)ETCHIALI Abdelhak (ALG)255957300186502BRANED
851201413 Jul 2014 - 16:00FinalEstadio do MaracanaRio De JaneiroGermany10Argentina74738.000Nicola RIZZOLI (ITA)Renato FAVERANI (ITA)Andrea STEFANI (ITA)255959300186501GERARG

852 rows × 19 columns

再查看一下数据描述,用以选取合适的数据x轴和y轴来进行可视化

matches.describe()
  • 1
YearHome Team GoalsAway Team GoalsAttendanceHalf-time Home GoalsHalf-time Away GoalsRoundIDMatchID
count852.000000852.000000852.000000850.000000852.000000852.0000008.520000e+028.520000e+02
mean1985.0892021.8110331.02230045164.8000000.7089200.4284041.066177e+076.134687e+07
std22.4488251.6102551.08757323485.2492470.9374140.6912522.729613e+071.110572e+08
min1930.0000000.0000000.0000002000.0000000.0000000.0000002.010000e+022.500000e+01
25%1970.0000001.0000000.00000030000.0000000.0000000.0000002.620000e+021.188750e+03
50%1990.0000002.0000001.00000041579.5000000.0000000.0000003.370000e+022.191000e+03
75%2002.0000003.0000002.00000061374.5000001.0000001.0000002.497220e+054.395006e+07
max2014.00000010.0000007.000000173850.0000006.0000005.0000009.741060e+073.001865e+08

3 具体可视化数据的选取

通过观察表中的数据以及结合比赛实际情况,我发现了评价一届足球比赛的两项重要指标。一个就是当届世界杯的观众人数,这反映了这届比赛的受欢迎程度;另一个则是当届世界杯总的进球数,这反映了这届比赛的激烈程度。这两项指标分别从主观层面和客观层面反映了某届世界杯的精彩程度,是较为全面和有意义的数据分析。

同时,由于数据过多,无法对全部的比赛进行展示,故此次作业仅展示两项指标加权后排名靠前的几届世界杯。

4 数据预处理以便可视化

数据预处理的主要涉及到数据清洗,以及针对要分析的内容进行特定字段的转化。具体到该表,主要需要对每届世界杯的数据进行整合,求出当年的观众总数和进球总数,并计算出两项指标的得分,选取前面的比赛进行条形图的绘制。

# 先将空值补为0
matches.fillna(0)
# 使用聚集函数groupby求相同的‘Year’下的‘Attendance’的和
# 并设置as_index=False使‘Year’放弃列索引,让‘Year’和‘Attendance’处于同一列
att_matches=matches.groupby(['Year'],as_index=False)['Attendance'].sum()
# 使用apply函数将每场比赛两队的得分加起来,设置axis=1保证是列操作
matches['Goals']=matches.apply(lambda x: x['Home Team Goals'] + x['Away Team Goals'], axis=1)
score_matches=matches.groupby(['Year'],as_index=False)['Goals'].sum()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

考虑到ggplot直方图绘制对数据格式有所要求,故需先按对应格式将数据进行转化。简单来说,就是将att_matches和score_matches拼在一起,然后加一列‘Index’表明具体是什么指标,用于fill参数。

# 创建新DataFrame
dic = {"Year": [],
       "y": [],
       "Index": []}
data = pd.DataFrame(dic)
# 做行遍历,将数据填到新的DataFrame中,并用int转换保证年份是整数
for index, row in att_matches.iterrows():
    data.loc[len(data.index)] = [int(row['Year']),
                                 row['Attendance'], 'Attendance']
for index, row in score_matches.iterrows():
    data.loc[len(data.index)] = [int(row['Year']), row['Goals'], 'Goals']
# 查看新数据
data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
YearyIndex
01930590549.0Attendance
11934363000.0Attendance
21938375700.0Attendance
319501045246.0Attendance
41954768607.0Attendance
51958819810.0Attendance
61962893172.0Attendance
719661563135.0Attendance
819701603975.0Attendance
919741865753.0Attendance
1019781545791.0Attendance
1119822109723.0Attendance
1219862394031.0Attendance
1319902516215.0Attendance
1419943587538.0Attendance
1519982785100.0Attendance
1620022705197.0Attendance
1720063359439.0Attendance
1820103178856.0Attendance
1920144319243.0Attendance
20193070.0Goals
21193470.0Goals
22193884.0Goals
23195088.0Goals
241954140.0Goals
251958126.0Goals
26196289.0Goals
27196689.0Goals
28197095.0Goals
29197497.0Goals
301978102.0Goals
311982146.0Goals
321986132.0Goals
331990115.0Goals
341994141.0Goals
351998171.0Goals
362002161.0Goals
372006147.0Goals
382010145.0Goals
392014206.0Goals

我发现数据较多,全部绘制出来可能会不太美观与整洁,故选取其中较为“精彩”的几届比赛。至于评分权重,不妨两个指标五五开。具体的评分是以该届的指标除以该项指标的最大值,求和后取总分大于1的那几届比赛。

# 求指标最值
att_max = att_matches.loc[:, 'Attendance'].max()
score_max = score_matches.loc[:, 'Goals'].max()
# 分类求得分
data['Grade'] = data.apply(lambda x: x['y']/att_max if x['Index']
                           == 'Attendance' else x['y']/score_max, axis=1)

data
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
YearyIndexGrade
01930590549.0Attendance0.136725
11934363000.0Attendance0.084043
21938375700.0Attendance0.086983
319501045246.0Attendance0.241997
41954768607.0Attendance0.177949
51958819810.0Attendance0.189804
61962893172.0Attendance0.206789
719661563135.0Attendance0.361900
819701603975.0Attendance0.371356
919741865753.0Attendance0.431963
1019781545791.0Attendance0.357885
1119822109723.0Attendance0.488447
1219862394031.0Attendance0.554271
1319902516215.0Attendance0.582559
1419943587538.0Attendance0.830594
1519982785100.0Attendance0.644812
1620022705197.0Attendance0.626313
1720063359439.0Attendance0.777784
1820103178856.0Attendance0.735975
1920144319243.0Attendance1.000000
20193070.0Goals0.339806
21193470.0Goals0.339806
22193884.0Goals0.407767
23195088.0Goals0.427184
241954140.0Goals0.679612
251958126.0Goals0.611650
26196289.0Goals0.432039
27196689.0Goals0.432039
28197095.0Goals0.461165
29197497.0Goals0.470874
301978102.0Goals0.495146
311982146.0Goals0.708738
321986132.0Goals0.640777
331990115.0Goals0.558252
341994141.0Goals0.684466
351998171.0Goals0.830097
362002161.0Goals0.781553
372006147.0Goals0.713592
382010145.0Goals0.703883
392014206.0Goals1.000000
df = pd.DataFrame({"Year": [], "y": [], "Index": [], "Grade": []})
# 循环查找各届比赛并计算对应的分数,选出大于等于1的放到df中
i = 1930
while i <= 2014:
    ans = data.query('Year=='+str(i))
    if (len(ans) > 1):
        if (ans.loc[:, 'Grade'].sum() >= 1):
            insertRow = ans[0: 2]
            # 采用concat进行添加,append会有后续不支持的提示
            df = pd.concat([df, ans])
    i += 4
#  对‘Year’和‘y’进行取整操作,以便图中显示
df['Year'] = data['Year'].astype(int)
df['y'] = data['y'].astype(int)
df
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
YearyIndexGrade
1119822109723Attendance0.488447
311982146Goals0.708738
1219862394031Attendance0.554271
321986132Goals0.640777
1319902516215Attendance0.582559
331990115Goals0.558252
1419943587538Attendance0.830594
341994141Goals0.684466
1519982785100Attendance0.644812
351998171Goals0.830097
1620022705197Attendance0.626313
362002161Goals0.781553
1720063359439Attendance0.777784
372006147Goals0.713592
1820103178856Attendance0.735975
382010145Goals0.703883
1920144319243Attendance1.000000
392014206Goals1.000000

5 基本视图绘制

根据ggplot的要求,需要有x轴、y轴和分组变量放到aes审美映射中。
并且,为实现直方图的功能,还需要添加geoms的具体原语。如下图所示,为实现直方图的绘制,我使用的是使用geom_col()原语。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col()
)
p
  • 1
  • 2
  • 3
  • 4
  • 5


在这里插入图片描述

<ggplot: (156870788628)>
  • 1

相比于堆叠的直方图,此处我们采用双直方图的效果可能会更好,故需要在geom_col()中加入position="dodge"的代码。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge")
)
p
  • 1
  • 2
  • 3
  • 4
  • 5


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WMIBUAE-1677066339115)(WorldCupVisualization_files/WorldCupVisualization_17_0.png)]

<ggplot: (156873574352)>
  • 1

6 添加数据标签

完成了基本底图的绘制,接下来需要在图上加一些数据,让图中信息变得更丰富。首先,在各条形图上贴上数值标签,具体值取‘y’即可,分别表示观众总数和进球总数。以上可通过geom-geom_text()–并在其aes()参数中添加 label="y"来实现。为方便数据的显示,我们可对直方图的宽度进行调整,通过设置width属性来实现。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(label="y"))
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GN9TldfL-1677066339115)(WorldCupVisualization_files/WorldCupVisualization_19_0.png)]

<ggplot: (156875705741)>
  • 1

尽管数据标签已经添加上去了,但还不够美观,这主要体现在标签的大小、位置和内容上。首先标签的位置应该居于各条形图的中间(宽度和高度两方面);然后是‘Attendance’的数值过大,不太好显示,可约算为多少W的形式;最后调整完以上内容,可适当对文字的大小做一些改动。

# y的坐标比较好确定,取‘Grade’的一半即可
df["y_pos"] = df["Grade"]/2
# x的坐标则要麻烦一点,需要根据它的Index而定,是‘Attendance’则在‘Year’基础上前移,‘Goals’则后移
df['x_pos'] = df.apply(lambda x: x['Year']-0.7 if x['Index']
                       == 'Attendance' else x['Year']+0.7, axis=1)
# 用类似的方式再加一列,转换标签为‘Attendance’的数据,不过此处转换并没有进行四舍五入,直接通过‘//’的除法来实现
df['y_show'] = df.apply(lambda x: str(x['y']//10000)+'w' if x['Index']
                        == 'Attendance' else x['y'], axis=1)
# 然后添加geom_text()原语通过aes()映射将求得的坐标赋上去
# 文字大小的调整则可设置size属性,此处设置为7
p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16


在这里插入图片描述

<ggplot: (156875769532)>
  • 1

7 调整轴的刻度

观察已画出的图,我发现‘Year’没有显示出具体的年份,就无法知道具体是那届世界杯,故需要改变X轴的刻度线,可使用scale_x_continuous选项。这里将X轴改为每四年,因为世界杯是每四年一届。正好筛选出来的年份是1982年到2014年所有的世界杯,没有中间某届不在范围内的情况出现,故不需要再对x轴做进一步处理。可使用的参数如下:break选项来设置断点,它需要一个数值的列表作为参数。 可以使用numpy的range函数来生成这样一个列表,可设置开始、结束和步长。注意,由于 Python 的索引,在使用 np.range 的范围是[,)。同样地,如果想改变Y轴,可以使用scale_y_continuous选项。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7


在这里插入图片描述

<ggplot: (156875797514)>
  • 1

8 设置轴标签和标题

为了改变轴的标签,可以使用xlab和ylab方法添加所需的名称,分别对应的是x轴和y轴。添加标题,则要设置ggtitle选项,并将要设置的内容作为一个字符串参数传入。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10


在这里插入图片描述

<ggplot: (156875691678)>
  • 1

9 调整调色板

plotnine支持matplotlib中的调色板,通过scale_fill_manual选项可以设置,里面需要的参数是关于颜色的列表。先尝试把条形区域设为青绿色和橘黄色。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_manual(["mediumturquoise", "orange"])
)
p

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述

<ggplot: (156875907379)>
  • 1

除此之外,还可以使用HEX代码来表示颜色,如以上区域的颜色可改为#F0FF00、#58CFFB。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_manual(["#F0FF00", "#58CFFB"])
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11


在这里插入图片描述

<ggplot: (156875963152)>
  • 1

除了手动的调颜色,还可以使用现成的配色方案,plotnine提供了scale_colour_brewer的选项,需要的参数主要是type和palette。type指数据的类型,有[‘seq’, ‘div’, ‘qual’]三个选择,分别是连续、离散、定性,其实不一定要严格按照这个来,只要配色适合就可以。palette可以是str和int类型,如果是前者,则按该命名选取;如果是后者,因每个值都有对应的str,索引即可,默认为1。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_brewer(type='qual', palette=2)
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11


在这里插入图片描述

<ggplot: (156876241752)>
  • 1

10 调整图例

目前的图例处于默认位置,即整体的右侧,较为割裂,这可以添加一个theme选项来做调整。具体来说,可设置legend_position选项指定其位于底部,并设置legend_direction="horizontal"让图例水平排布,当然这是底部的默认选项,可不写出。同时,‘Index’作为图例的标题有点冗余,可以用legend_title=element_blank()将它隐藏。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_brewer(type='qual', palette=2)
    + theme(
        legend_position="bottom",
        legend_title=element_blank(),
    )
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15


在这里插入图片描述

<ggplot: (156875917736)>
  • 1

但有点问题的就是,图例把X轴的标题以及部分数据遮住了。这时需要在theme中使用 legend_box_spacing 选项来解决这个问题,它可以将图例的位置向下移动。具体的值要由具体情况而定,可以反复调整取最佳的位置。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_brewer(type='qual', palette=2)
    + theme(
        legend_position="bottom",
        legend_title=element_blank(),
        legend_box_spacing=0.4,
    )
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16


在这里插入图片描述

<ggplot: (156875735251)>
  • 1

可以看到,图例在下方单独拿一部分来显示会感觉有点冗余,希望其放在与‘Year’平行靠右的位置。这里可以使用legend_position的另一种参数传入形式,即坐标形式(x,y),范围在(0,0)到(1,1)对应左下角到右上角。需反复调整,得到好的位置,此处坐标选的是(0.7,0)。然后发现还需对‘Year’,即x轴标题做下移操作,可使用theme中的axis_title_x选项,参数格式需用element_text()的格式,在里面使用margin这个参数。值得一提的是,这个参数的赋值比较怪,类似于{‘t’: 15}的格式,前面可选项为[‘t’,‘r’,‘b’,‘l’],表示top、right、bottom、left;后面为移动的数值。为对称考虑,也对y轴标题做相同移动。至于标题,留到下一节处理。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_brewer(type='qual', palette=2)
    + theme(
        axis_title_x = element_text(margin={'t': 15}),
        axis_title_y = element_text(margin={'r': 15}),
        legend_position=(0.7,0),
        legend_direction="horizontal",
        legend_title=element_blank(),
    )
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18


在这里插入图片描述

<ggplot: (156876171643)>
  • 1

11 调整标题

类似于x轴标题的调整,theme中的plot_title选项可对标题样式做更改,同样也是在element_text()中进行参数赋值。具体用法可见下方注释。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_brewer(type='qual', palette=2)
    + theme(
        plot_title=element_text(face="bold.italic",  # 字体
                                color="#223C5F",  # 颜色
                                size=24,  # 大小
                                vjust=0),  # 垂直位置,相对于图,0为远离,1为靠近。
        axis_title_x=element_text(margin={'t': 15}),
        axis_title_y=element_text(margin={'r': 15}),
        legend_position=(0.7, 0),
        legend_direction="horizontal",
        legend_title=element_blank(),
    )
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22


在这里插入图片描述

<ggplot: (156875716521)>
  • 1

12 选用主题

以上都是对一些细节进行改动,如果相对整体的样式进行改动,可在在ggplot()后面添加对应的主题函数。主要有以下几种:

  • theme_grey():默认主题,灰色背景,不带x、y轴线,带白色网格线等
  • theme_bw():变色背景,带全方位x、y轴线(上下左右),带灰色网格线
  • theme_classic():无网格线,有轴线,类似excel风格
  • theme_linedraw():白色背景黑色线条,带黑框
  • theme_light():和theme_linedraw()很像,区别是线条为灰色
  • theme_dark():黑色背景的theme_light(),可以用来画薄彩色线条
  • theme_minimal():简约主题,无框
  • theme_void():空白主题
  • theme_xkcd():XKCD风格的主题
  • theme_538():538主题,灰色背景,无框,带线
    还有一些以其他可视化工具为格式的主题,如theme_matplotlib()、theme_seaborn。
p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"), size=7)
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_brewer(type='qual', palette=2)
    + theme_classic()
    + theme(
        plot_title=element_text(face="bold.italic",  # 字体
                                color="#223C5F",  # 颜色
                                size=24,  # 大小
                                vjust=0),  # 垂直位置,相对于图,0为远离,1为靠近。
        axis_title_x=element_text(margin={'t': 15}),
        axis_title_y=element_text(margin={'r': 15}),
        legend_position=(0.7, 0),
        legend_direction="horizontal",
        legend_title=element_blank(),
    )
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述

<ggplot: (156876533097)>
  • 1

13 创建自定义主题

首先,自定义一个主题就要选定使用的字体,由于内置的字体有限,可从外部导入下载好的字体。再通过matplotlib.font_manager中的FontProperties选项以创建对象的形式把该字体加载到Python以供使用,并可以对该对象进行格式的设置。
具体到本次作业,我力图创建一个科技感的主题,使用的字体为赛博朋克风格的“Qualy_Bold.ttf”。

# 导入模块
import matplotlib.font_manager as fm
# 读取字体
fpath = "Qualy_Bold.ttf"
# 创建字体对象
title_text = fm .FontProperties(fname=fpath)
body_text = fm .FontProperties(fname=fpath)
# 设置字体大小和样式,标题要设得大和粗一点
title_text .set_size(24)
title_text .set_weight("bold")
body_text.set_size(12)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

为了让图表看起来更科技感,作如下改动:

  • 改变各项文字的颜色,具体包括geom_text(colour=‘black’);plot_title、axis_title_x、axis_title_y、axis_text_x、axis_text_y中的element_text(color=“#EAF7F7”)
  • 通过改变 axis_line_x 和 axis_line_y 的参数可以改变轴线的厚度和颜色,传值需用element_line()映射。
  • 摆脱网格线,需要设置四个参数为空(element_blank()):panel_grid_major, panel_grid_minor, panel_border 和 panel_background。
  • 使用刚刚导入的科技感字体,需改变plot_title和text的值,传值也要进行映射:element_text(fontproperties=body_text)。
  • 去除图例的背景色,设置legend_background为空。
p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"),
                size=9, colour='black', fontstyle='oblique')
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_manual(["#07a793", "#84ff94"])
    + theme(
        plot_background=element_rect(fill='#05171b', colour='#05171b'),
        plot_title=element_text(color="#EAF7F7",  # 颜色
                                size=24,  # 大小
                                vjust=0,
                                fontproperties=title_text
                                ),  # 垂直位置,相对于图,0为远离,1为靠近。
        axis_title_x=element_text(margin={'t': 15}, colour="#EAF7F7"),
        axis_title_y=element_text(margin={'r': 15}, colour="#EAF7F7"),
        legend_position=(0.7, 0),
        legend_direction="horizontal",
        legend_title=element_blank(),
        legend_text=element_text(colour="#EAF7F7"),
        axis_line_x=element_line(size=2, colour="#EAF7F7"),
        axis_line_y=element_line(size=2, colour="#EAF7F7"),
        legend_background=element_blank(),
        panel_grid_major=element_blank(),
        panel_grid_minor=element_blank(),
        panel_border=element_blank(),
        panel_background=element_blank(),
        text=element_text(fontproperties=body_text),
        axis_text_x=element_text(colour="#EAF7F7"),
        axis_text_y=element_text(colour="#EAF7F7"),
    )
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36


在这里插入图片描述

<ggplot: (156876500176)>
  • 1

14 添加图片

最后,为在标题中展现足球的元素,可以通过watermark(水印)来导入本地图片。具体设置为filename为图片路径, xo、yo为图片的位置,可随具体情况调整。

p = (
    ggplot(df, aes(x='Year', y='Grade', fill='Index'))
    + geom_col(position="dodge", width=3)
    + geom_text(df, aes(x="x_pos", y="y_pos", label="y_show"),
                size=9, colour='black', fontstyle='oblique')
    + scale_x_continuous(breaks=np .arange(1982, 2015, 4))
    + ggtitle("Top exciting World Cup matches")
    + xlab("Year")
    + ylab("Measure of excitement")
    + scale_fill_manual(["#07a793", "#84ff94"])
    + theme(
        plot_background=element_rect(fill='#05171b', colour='#05171b'),
        plot_title=element_text(color="#EAF7F7",  # 颜色
                                size=24,  # 大小
                                vjust=0,
                                fontproperties=title_text
                                ),  # 垂直位置,相对于图,0为远离,1为靠近。
        axis_title_x=element_text(margin={'t': 15}, colour="#EAF7F7"),
        axis_title_y=element_text(margin={'r': 15}, colour="#EAF7F7"),
        legend_position=(0.7, 0),
        legend_direction="horizontal",
        legend_title=element_blank(),
        legend_text=element_text(colour="#EAF7F7"),
        axis_line_x=element_line(size=2, colour="#EAF7F7"),
        axis_line_y=element_line(size=2, colour="#EAF7F7"),
        legend_background=element_blank(),
        panel_grid_major=element_blank(),
        panel_grid_minor=element_blank(),
        panel_border=element_blank(),
        panel_background=element_blank(),
        text=element_text(fontproperties=body_text),
        axis_text_x=element_text(colour="#EAF7F7"),
        axis_text_y=element_text(colour="#EAF7F7"),
    )
    + watermark(filename='soccer.png', xo=190, yo=417)
)
p
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37


在这里插入图片描述

<ggplot: (156875740413)>
  • 1

总结

本文对时下热点内容进行了可视化。先对数据按ggplot的要求读入格式进行了预处理,再依次进行了基本视图绘制,并在此基础上做了一系列的优化,包括数据标签、轴的刻度与标签、标题、配色、图例、主题和图片的添加与调整。最后,得到了一张美观、简洁且具有科技感的世界杯精彩程度双直方图。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/753840
推荐阅读
相关标签
  

闽ICP备14008679号