分级统计地图,或许在以前大家还不常见,但是疫情期间,借助分级地图向我们呈现全国各省市风险地区情况、确诊或死亡人数情况等的应用还是数不胜数的,效果也让人一目了然。显然,分级地图即是在我们整个制图区域内利用地理行政规划(或其它规划单位)划分若干个小单元,再对各单元按数据分级,利用不同的颜色(饱和度或晕线等等)进行呈现。
分级地图可以向我们呈现各区现象的一个集中程度,所以在应用上,我们可以用来展现人口普查结果、城市发展结果、疫情严重程度、选举票数情况等等相关数据的可视化。
但一定要注意,分级地图稍有不慎会带来错误地信息传导。经典的案例即为美国选举地图。
因为美国大选的规则是,获得该选区过半选票的候选人将获得选区所有的选票,对应区域在地图上填充颜色。从可视化的角度,颜色只代表了候选人维度的分组,比较数值大小只能靠面积,那么单看上面这张地图,我们可以马上得出结论:应该是红色方赢得大选,然而事实与我们的结论相悖。
为什么会这样呢?这源于数据分布和地理区域不对称的问题。通常情况下,人口稀疏的地区反而地理面积大,占据了大幅屏幕;而人口密集,数据量大的区域地理面积相对小,就有了劣势。在这里我仍然要重提可视化的宗旨,必须是保证正确的信息传递,美化都是其次!!!!
本来也没想好要画什么数据,就先随机生成模拟数据来实现全国各省市分级地图的绘制。
excel中的数据如下:
数据导入:
import pandas as pd
data = pd.read_excel('地图数据.xlsx',sheet_name=[0,1,2])
datamap = data[0]
#现存确诊
datamap_xc = list(zip(datamap['地区'],datamap['模拟数据']))
我们要绘制图形的数据结构如下:
如题,我们使用的是python语言,借助pyecharts包实现。
from pyecharts.charts import Map
from pyecharts import options as opts
map_xc = (
Map()
.add("模拟数据",datamap_xc,maptype='china')
.set_global_opts(title_opts=opts.TitleOpts(title="pyecharts地图示例",subtitle="2020年12月07日"),
visualmap_opts=opts.VisualMapOpts(max_=100,is_piecewise=True,
pieces=[
{"min": 10000, "label": '>10000', "color": "#801C1B"},
{"min": 1000, "max": 9999,"label": '1000-9999', "color": "#FF3030"},
{"min": 500, "max": 999, "label": '500-999', "color": "#FF4500"},
{"min": 100, "max": 499, "label": '100-499', "color": "#FF7F50"},
{"min": 10, "max": 99, "label": '10-99', "color": "#FFA500"},
{"min": 1, "max": 9, "label": '1-9', "color": "#FFDEAD"},
{"max": 0,"label": '0', "color": "white"}
]))
.set_series_opts(label_opts=opts.LabelOpts(is_show=True,position='leftBottom'))
)
map_xc.render("./分级地图-示例1.html")
绘制结果如下:(颜色选的不是特别好)
(1) opts.VisualMapOpts是我们的视觉映射配置项
def __init__(
self,
is_show: bool = True,
type_: str = "color",
min_: Numeric = 0,
max_: Numeric = 100,
range_text: Optional[Sequence] = None,
range_color: Optional[Sequence[str]] = None,
range_size: Optional[Sequence[int]] = None,
range_opacity: Optional[Numeric] = None,
orient: str = "vertical",
pos_left: Optional[str] = None,
pos_right: Optional[str] = None,
pos_top: Optional[str] = None,
pos_bottom: Optional[str] = None,
split_number: int = 5,
series_index: Union[Numeric, Sequence, None] = None,
dimension: Optional[Numeric] = None,
is_calculable: bool = True,
is_piecewise: bool = False,
is_inverse: bool = False,
precision: Optional[int] = None,
pieces: Optional[Sequence] = None,
out_of_range: Optional[Sequence] = None,
item_width: int = 0,
item_height: int = 0,
background_color: Optional[str] = None,
border_color: Optional[str] = None,
border_width: int = 0,
textstyle_opts: Union[TextStyleOpts, dict, None] = None,
)
①is_show=True : 是否显示映射条,默认是True,即显示我们左下角的这个分级label。
②type_='color' : 默认是color,即颜色映射。还有一个可选项是‘size’,即大小映射,此时地图上不显示颜色。我们如果把is_piecewise和pieces都去掉,选择大小映射得到的结果如下:
③min_=0,max_=100 : 【0,100】区间是默认值,可以调整,结合两张图,我们可以发现其只在不分段型地图中有效,注意上下的两个小三角形是默认可移动的,自定义显示区间(如下下图),如果不需要,则增加is_calculable =False 。
④range_text=None : 表明程度的文本,只能从高到低标注,并且只能标注首尾的text。比如我们在type_='color'下增加range_text=['高’,‘低’],得到的结果如下:
⑤range_color : 默认如上图,当然也可以自定义,要求填入的颜色顺序是从浅色到深色对应由小到大的数值即可,色彩种类数没有限制,尽量三个以上,保持同色系。这样的话,实现蓝色系列、黄色系列或者红色系列都行。
⑥orient : 映射条的放置方式,默认为‘vertical’,竖直方向;还可以选择水平,如果我们设置orient=‘horizontal’,得到的结果如下:
⑦pos_left : 指的是映射条左边离画布左侧边缘的距离,自定义的话可以填x%(画布宽的百分比),或者填像素值,又或者选择”left“,“right”,“center”其一。pos_right同理,一般情况下上述两者选择其一来进行水平位置的定位。
⑧pos_top : 指的是映射条上边离画布顶部边缘的距离,数值填法如上;文本填法可以选择“top”,“middle”或者“bottom”其一。在定位过程中,如果映射条消失,比如pos_top='100%',此时映射条是隐藏在了显示画布的下方,所以没显示。在使用过程中,我们常常是一水平一数值搭配,比如pos_left='10%',pos_top='5%'。
⑨split_number : 分段区间数,默认为5,具体定多少,根据数据的极差来选择。
⑩is_piecewise : 是否为分段型,默认为False,如果按照我们的案例为True,一般增加pieces,自定义每一段的范围和text,颜色等。对于pieces中的min/max,若不指定 max,表示 max 为正无穷(Infinity),若不指定min,表示min为负无穷(-Infinity)。
另:background_color : 映射条区域的背景颜色,border_color : 该区域的边界颜色border_width :区域边界的宽度,举例如下:
background_color='#ff967c',border_color = 'blue',border_width = 1
(2)如何更改地图所在整个画布的背景颜色或主题呢?
在map的配置项中,我们可以增加画布主体theme选项更改图像主题,通过bg
_color更改背景颜色。举例如下所示:
map_xc = (
Map(init_opts=opts.InitOpts(theme='essos',bg_color='#fefcaf'))
.add("模拟数据",datamap_xc,maptype='china')
.set_global_opts(title_opts=opts.TitleOpts(title="pyecharts地图示例",subtitle="林老头ss"),
visualmap_opts=opts.VisualMapOpts(is_piecewise=False,max_=100))
.set_series_opts(label_opts=opts.LabelOpts(is_show=True,position='leftBottom'))
)
map_xc.render("./分级地图-示例1.html")
theme的可选项如下,大家可以自配:
class _ThemeType:
BUILTIN_THEMES = ["light", "dark", "white"]
LIGHT = "light"
DARK = "dark"
WHITE = "white"
CHALK: str = "chalk"
ESSOS: str = "essos"
INFOGRAPHIC: str = "infographic"
MACARONS: str = "macarons"
PURPLE_PASSION: str = "purple-passion"
ROMA: str = "roma"
ROMANTIC: str = "romantic"
SHINE: str = "shine"
VINTAGE: str = "vintage"
WALDEN: str = "walden"
WESTEROS: str = "westeros"
WONDERLAND: str = "wonderland"
HALLOWEEN: str = "halloween"
(3)如何绘制区县地图或者世界地图呢?
注意到我们add中有个参数为maptype,默认为’china‘,即中国地图。如果要画世界地图,则对于’world‘,如果要画某个省的区县地图,则maptype='城市名',我们以深圳市为例:
from pyecharts.charts import Map
from pyecharts import options as opts
data_sz = [('南山区',5096),('福田区',5000),('罗湖区',4500),('盐田区',3500),
('宝安区',2500),('龙岗区',2200),('龙华区',1500),('坪山区',900)]
counties = (
Map()
.add(
'深圳',
data_sz,
maptype='深圳',
label_opts=opts.LabelOpts(is_show= False),
)
.set_global_opts(
title_opts=opts.TitleOpts(),
visualmap_opts=opts.VisualMapOpts(is_piecewise=True,
pieces=[
{"min": 5000, "label": '>5000', "color": "#fc5a50"},
{"min": 4000, "max": 4999,"label": '4000-4999', "color": "#fea993"},
{"min": 3000, "max": 3999, "label": '3000-3999', "color": "#ffb07c"},
{"min": 2000, "max": 2999, "label": '2000-2099', "color": "#f1da7a"},
{"min": 1000, "max": 1999, "label": '1000-1999', "color": "#8ab8fe"},
{"min": 1, "max": 999, "label": '1-999', "color": "#c1c6fc"},
{"max": 0,"label": '其它区县', "color": "white"}
]))
.set_series_opts(label_opts=opts.LabelOpts(is_show=False,position='leftBottom'))
.render("./地图示例2.html")
)
注意,我们set_series_opts中is_show= False,所以区县名称没有显示出来,这么做是因为对某些省份,区县的标签容易挤在一起显示,非常混乱,但在交互中我们仍然可以很容易知道各区县的信息。绘图结果如下所示:
希望对您有所帮助~