Python: pyecharts visualization

Introduction

(This is a 20-year note, so the pyecharts version used may seem outdated now, for reference)
A brief introduction on how to use pyecharts to draw, mainly about the drawing of geographical maps.

pyecharts is the python version of the well-known drawing tool echarts, which uses the output HTML as a carrier to draw interactive display diagrams.

When I read it in 20 years, it was still divided into two series of versions, v0.5 and v1.0. Version 1.0 was a subversive update to 0.5. Then I looked at it now and it has been updated to version v2.x. .

There are relatively few introductions on the use of v1.0 on the Internet. The best explanation in this regard is the official document of pyecharts, link: official document , which is very comprehensive, and each explanation is followed by a demo.

Take a look at the references on the official website, especially the Gallery section, and basically finish drawing a lot of pictures.

Geo geographic map drawing

from pyecharts import options as opts
from pyecharts.charts import Geo
from pyecharts.faker import Faker
from pyecharts.globals import ChartType
import pandas as pd
from pyecharts.charts import Map

from pyecharts.render import make_snapshot

from snapshot_selenium import snapshot

def draw(zz_cors, custom_cors, agent_cors):
	g = Geo(init_opts=opts.InitOpts(width="1200px", height="950px"))	# 设置HTML中画布的大小
	coors = {
    
    }	# 待加入的所有坐标,key=每个坐标的name,value是坐标的组合,在这里就是'[经度,纬度]'
	value_pairs = []	# 为所有坐标分段,即为每个坐标加入一个段标识,这样以后可以对相同段的数据做一些集中处理,比如说采用同一种颜色标注等。
	i = 0

	for j in range(len(custom_cors)):
		coors[str(i)] = custom_cors[j]
		value_pairs.append([str(i), 3])
		i += 1

	for j in range(len(zz_cors)):       # 
		coors[str(i)] = zz_cors[j]
		value_pairs.append([str(i), 4])
		i+=1

	coors[str(i)] = [114.2265222, 30.52285061]
	value_pairs.append([str(i), 2])
	i+=1
	coors[str(i)] = [114.4879442, 30.56922194]      # 
	value_pairs.append([str(i), 1])

	for key, value in coors.items():
		g.add_coordinate(key, value[0], value[1])	# 将所有自定义坐标加入Geo中

	#  ECharts 提供的标记类型包括
	#     # 'circle', 'rect', 'roundRect', 'triangle', 'diamond', 'pin', 'arrow', 'none'
	#     # 可以通过 'image://url' 设置为图片,其中 URL 为图片的链接,或者 dataURI。
	#     # 可以通过 'path://' 将图标设置为任意的矢量路径。
	pieces = [		# 对不同的分段进行具体的设置
		{
    
    'value': '1', 'label': '名字_1', 'color': '#8A2BE2', 'symbolSize': 20, 'symbol':'pin', 'colorAlpha':1},
		{
    
    'value': '2', 'label': '名字_2', 'color': 'red', 'symbolSize': 20, 'symbol': 'pin', 'colorAlpha':1},
		{
    
    'value': '3', 'label': '名字_3', 'color': 'cyan', 'symbolSize': 2, 'symbol': 'circle'},
		{
    
    'value': '4', 'label': '名字_4', 'color': '#002CFF', 'symbolSize': 5, 'symbol': 'roundRect'},
	]
	c = (
			# g.add_schema(maptype="china")
			g.add_schema(maptype="湖北")
			# g.add_schema(maptype="武汉")
			.add(
			"",
			# [list(z) for z in zip(names, values)],
			value_pairs,
			type_=ChartType.SCATTER,
			symbol_size=5,
			color='#00FFF3',
			is_large=True,
		)
			.set_series_opts(label_opts=opts.LabelOpts(is_show=False)) 	# is_show=FALSE,默认不显示每个点对应的value 
			.set_global_opts(
			visualmap_opts=opts.VisualMapOpts(is_piecewise=True, pieces=pieces),
			# legend_opts = opts.LegendOpts(pos_top='top'),
			title_opts=opts.TitleOpts(title=""),
		)
	)

	c.render('test.html')

def read_zhongzhi():
	file = '../data/机构地址规范版本.csv'
	data = pd.read_csv(file, encoding='gbk')
	cors = []
	values = []
	for idx, row in data.iterrows():
		if row['PROVINCE'] == '湖北省':
			cors.append([row[11], row[12]])
	return cors

def read_custom():
	file = '../data/20201102_202011031827.csv'
	data = pd.read_csv(file, encoding='utf8')
	cors = []
	values = []
	for idx, row in data.iterrows():
		cors.append([row['GIS_LNG'], row['GIS_LAT']])
	return cors

def read_agent():
	file = '../data/query-hive-48766.csv'
	data = pd.read_csv(file, encoding='gbk')
	cors = []
	values = []
	for idx, row in data.iterrows():
		cors.append([row['tmp_tsales_agnt_loc_all_last.gis_lng'], row['tmp_tsales_agnt_loc_all_last.gis_lat']])
	return cors


if __name__ == '__main__':
	zz_cors = read_zhongzhi()
	custom_cors = read_custom()
	agent_cors = read_agent()
	draw(zz_cors, custom_cors, agent_cors)

map download

It should be noted that since v0.3.2, in order to reduce the size of the project itself and maintain the lightweight operation of the pyecharts project, pyecharts will no longer have its own map js file. If users need to use maps and charts, they can install the corresponding map file package by themselves. Here's how to install it.

  • Global country map: echarts-countries-pypkg (1.9MB): world map and 213 countries, including China map
  • China Provincial Map: echarts-china-provinces-pypkg (730KB): 23 provinces, 5 autonomous regions
  • Chinese city-level map: echarts-china-cities-pypkg (3.8MB): 370 Chinese cities
  • China county-level map: echarts-china-counties-pypkg (4.1MB): 2882 Chinese counties and districts
  • Maps of China regions: echarts-china-misc-pypkg (148KB): 11 maps of China regions, such as South China and North China.
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple echarts-countries-pypkg

 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple echarts-china-provinces-pypkg

 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple echarts-china-cities-pypkg

 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple echarts-china-counties-pypkg

 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple echarts-china-misc-pypkg

 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple echarts-united-kingdom-pypkg#如果提示缺少这个就安装一下

pip  install pyecharts_snapshot

line chart

area highlighting

insert image description here

The example code is on the pyecharts official website: line chart Line/Line-Distribution_of_electricity;

Abscissa with selection display

insert image description here

The interval below can be selected at will. The example code is on the pyecharts official website: line chart Line/Line-Beijing_aqi;

add

There is a maptype parameter, and there are many options. For details, please refer to the datasets/map_filenames.json file in the pyecharts package directory

MapMap

The map type is different from the Geo type,

Let's start with a small example:

from pyecharts import options as opts
from pyecharts.charts import Map
from pyecharts.faker import Faker
import pandas as pd
from pyecharts.globals import CurrentConfig

def draw(datas):
	canvas = Map(init_opts=opts.InitOpts(width="1200px", height="950px"))
	# 分段图例,数据小于该值会自动归入某段
	pieces = [
		{
    
    'min': 0, 'max': 1000, 'label': '0 - 1000', 'color': '#FFFACD'},
		{
    
    'min': 1000, 'max': 2000, 'label': '1000 - 2000', 'color': '#FFD700'},
		{
    
    'min': 2000, 'max': 5000, 'label': '2000 - 5000', 'color': '#FFA54F'},
		{
    
    'min': 5000, 'max': 10000, 'label': '5000 - 10000', 'color': '#FF6347'},
		{
    
    'min': 10000, 'max': 1000000, 'label': '> 10000', 'color': '#A52A2A'},
	]
	canvas.add(
	        "",
			datas,
			'china',	# 定义映射的地图文件,省级,
        	#'china-cities',	# 定义映射的地图文件,市级,
	        label_opts=opts.LabelOpts(is_show=True),
			is_map_symbol_show=False,       # 是否显示标记图形
	    )

	canvas.set_global_opts(
	        title_opts=opts.TitleOpts(title="各省分布"),
	        visualmap_opts=opts.VisualMapOpts(min_=0,
	                                          max_=100000,
	                                          # range_color=['#FFFFFF', '#FFEC8B', '#FFA500', '#FF3030'],
	                                          is_piecewise=True,
	                                          pieces=pieces,
                                              textstyle_opts=opts.TextStyleOpts(font_size=20)	# 设置分段图例的文本大小
                                             ),  # 视觉映射配置项
	    )
    # 配置系列项
	canvas.set_series_opts(label_opts=opts.LabelOpts(
		position='Bottom',
		is_show= True       # 是否显示系列值
	),
	)

	canvas.render("province_kehu.html")

def read_gaoke_data():
	file = '../data/客户-省级分布.xlsx'
	data = pd.read_excel(file, )
	values = []
	for idx, row in data.iterrows():
		values.append([row['FIL_NAME'], row['N_TOTAL']])
	return values

if __name__ == '__main__':
	v_gaoke = read_gaoke_data()
	draw(v_gaoke)

formatter control value display

This is basically the same as the purpose of the following section "Displaying the value in the graph". When I wrote the following section, I didn't know much about the formatter parameter of the graph label, so the solution was tortuous and limited. However, there was a sudden need today, and the following section could not solve the problem, so I expanded and explored the role of formatter.

The requirement is this:

Still draw a city map, but the data is not limited to the two columns of city name and number of users in the city, but also a column of "proportion of users in the city". It is required to use "number of users" to draw the map, but the "proportion of users in the city" should be displayed near the marker point, similar
insert image description here

I couldn't complete it with the following sections, so I started to explore the formatter by accident.

See reference 1 in this section for details

The formatter parameter in pyecharts supports two forms of string template and callback function.

The string template is actually the method in the next section, that is, the options of abcd,

Let me first explain the formatter on the official website:

 # 标签内容格式器,支持字符串模板和回调函数两种形式,字符串模板与回调函数返回的字符串均支持用 \n 换行。
    # 模板变量有 {a}, {b},{c},{d},{e},分别表示系列名,数据名,数据值等。 
    # 在 trigger 为 'axis' 的时候,会有多个系列的数据,此时可以通过 {a0}, {a1}, {a2} 这种后面加索引的方式表示系列的索引。 
    # 不同图表类型下的 {a},{b},{c},{d} 含义不一样。 其中变量{a}, {b}, {c}, {d}在不同图表类型下代表数据含义为:

    # 折线(区域)图、柱状(条形)图、K线图 : {a}(系列名称),{b}(类目值),{c}(数值), {d}(无)
    # 散点图(气泡)图 : {a}(系列名称),{b}(数据名称),{c}(数值数组), {d}(无)
    # 地图 : {a}(系列名称),{b}(区域名称),{c}(合并数值), {d}(无)
    # 饼图、仪表盘、漏斗图: {a}(系列名称),{b}(数据项名称),{c}(数值), {d}(百分比)
    # 示例:formatter: '{b}: {@score}'
    # 
    # 回调函数,回调函数格式:
    # (params: Object|Array) => string
    # 参数 params 是 formatter 需要的单个数据集。格式如下:
    # {
    
    
    #    componentType: 'series',
    #    // 系列类型
    #    seriesType: string,
    #    // 系列在传入的 option.series 中的 index
    #    seriesIndex: number,
    #    // 系列名称
    #    seriesName: string,
    #    // 数据名,类目名
    #    name: string,
    #    // 数据在传入的 data 数组中的 index
    #    dataIndex: number,
    #    // 传入的原始数据项
    #    data: Object,
    #    // 传入的数据值
    #    value: number|Array,
    #    // 数据图形的颜色
    #    color: string,
    # }
    formatter: Optional[str] = None,

However, the string form is too rigid and the scalability is not high, so you can also choose a callback function, namely:

from pyecharts.commons.utils import JsCode
# then
.add(   
        type_="effectScatter",
        series_name="",         
        data_pair=data,        
        symbol_size=10,
        effect_opts=opts.EffectOpts(),
        label_opts=opts.LabelOpts(
            position="top",
            is_show=True,   #is_show是否显示标签,点上面的内容
            formatter=JsCode(                  #formatter为标签内容格式器{a}:系列名;{b}:数据名;{c}:数值数组也可以是回调函数    
                    """function(params) {
                    if ('value' in params.data) {
                        return params.data.value[2];
                    }
                }"""
                ),#显示数据,可以去掉经纬度只显示数值return params.data.value[2] + ': ' + params.data.value[0]+': ' + params.data.value[1];
            ), 
        itemstyle_opts=opts.ItemStyleOpts(),
        is_selected=True,  #选中图例
    )

The value corresponding to the array can be displayed through params.data.value[i], and value[0] represents the first value.

In the above requirement, my dataset format is:

[
	['北京', [20, '3%']],
	['武汉', [56, '2%']],
	....
]

So use params.data.value[0] to call "number of users", and value[1] to call "proportion of users".

So formatter can be written as:

canvas.set_series_opts(label_opts=opts.LabelOpts(
		position='Bottom',
		is_show= True,       # 是否显示系列值
		formatter=JsCode(
			'''function(params){
					if('value' in params.data){
						return params.name + '\n'+ params.data.value[1]
					}
	}'''
		)
	)

Then, specify the data dimension used for drawing . In general, value is one-dimensional, so the default drawing is fine; but in the above example, value is two-dimensional, so we need to explicitly specify the data dimension used for drawing, that is, set the dimension parameter in visualmap_opts. After testing, 0 is the first column in value, and 2 and above are the second column in value.

canvas.set_global_opts(
	        title_opts=opts.TitleOpts(title="各省分布"),
	        visualmap_opts=opts.VisualMapOpts(min_=0,
	                                          max_=10000,
	                                          # range_color=['#FFFFFF', '#FFEC8B', '#FFA500', '#FF3030'],
	                                          series_index=0,   # 指定取哪个系列的数据
	                                          dimension=0, # 组件映射维度, 控制用x,y哪个维度来画图(做分段值)
	                                          is_piecewise=True,
	                                          pieces=pieces),  # 视觉映射配置项
	    )

references:

  1. How pyecharts uses formatter callback function
  2. The role of label_formatter of pyecharts

Show the value in the graph

In fact, map should have this function, and parameters can be set in map.add():

label_opts=opts.LabelOpts(is_show=True)

to enable the display, but the city name is displayed because the data we pass in for the artboard is

[
	[city_1,num_1],
	[city_2,num_2],
	....,
]

If we need to add num to the display, it seems that it cannot be realized by the provided API interface.

So we need to do the following:

After the target html is generated, modify the js script under the body, that is, add a "normal" node under the label of the series,

"series": [
        {
    
    
            "type": "map",
            "label": {
    
    
                "show": true,
                "position": "Bottom",
                "margin": 8,
                "normal": {
    
    
                    "show": true,
                    "formatter":'{b}\n{c}',	//有理由相信,这个类似形参,是按a、b、c...等的顺序依次排列的(猜错了,好像不是)
                    "textStyle": {
    
    
                        "fontSize": 12
                    },
                    "position": "bottom"
                }
            },
            "mapType": "china",
            "data": [
                {
    
    
                    "name": "\u897f\u85cf",
                    "value": 77
                },
                .....
                ]

references:

About the problem of adding data to the pyecharts map display

Parsing of target html

After the map is drawn, it will be rendered into an html file. Here is a brief introduction to the content of this html.

The first is the header, which defines the map resources required for drawing. Assuming that the maptype I declared in the Map object is "china", the js map resources introduced by the header are as follows:

 <script type="text/javascript" src="https://assets.pyecharts.org/assets/echarts.min.js"></script>
    <script type="text/javascript" src="https://assets.pyecharts.org/assets/maps/china.js"></script>

It means to specify the map resource from the remote library, the first is the layout resource, and the second is the map itself.

What you need to know is that these map resources actually exist locally (I mean the second one, but the first one was not found). For example, the second js resource is in \Lib\site-packages\echarts_countries_pypkg\resources\echarts-countries-js\ under your python installation directory, but from the html statement, pyecharts still prefers to pull warehouse resources from the cloud. Maybe if it is not connected to the Internet, it will choose to pull local map resources.

It needs to be mentioned that there is a map_filename.json in the Lib\site-packages\pyecharts\datasets directory under the python installation directory, and the content is similar:

insert image description here

It shows the mapping path of maptype in the cloud;

Theoretically, the next step is theoretically , if you want to replace the local js resources, you only need to replace the src path in the script with the local js path, and then you can use local js to draw, and you can use this to call local custom map resources. The idea is very good, (but there are some problems in the implementation, sometimes it may not be successful, I don't know why), in addition, when changing the local path, remember to use a relative path instead of an absolute path. Under the absolute path, the browser will report not allow to load local resource.

In html, there is another important component, which is the script in the body. There is a var in it, and there is an array called series in the var. There is a data array in this array, which contains the data you add when drawing points, such as:

"series": [
                {
    
    
                    "type": "map",
                    "label": {
    
    
                        "show": false,
                        "position": "Bottom",
                        "margin": 8
                    },
                    "mapType": "china-cities",
                    "data": [
                        {
    
    
                            "name": "\u594e\u5c6f",
                            "value": 2
                        },
                        {
    
    
                            "name": "\u4e09\u6c99",
                            "value": 5
                        },
                        {
    
    
                            "name": "\u5de2\u6e56",
                            "value": 13
                        },

Here I am drawing the distribution of cities in China, so name is the name of the city, and value is the value corresponding to the city. This value will cooperate with the pieces segment function I set to control the color corresponding to each city. The name here is in Unicode code format, you can search for a Unicode online conversion website on the Internet, for example, convert it into Chinese, if you want to add new data, you can also convert it into Unicode code, set the value, and stuff it into the data array;

Custom map js resources

First, you need to write the js of a new map, and then explicitly call the path of the new js in the script of the header in the generated html;

The second step refers to the previous section "Analysis of target html";

Regarding the new map js, you can directly rely on the old js. For example, I want to generate a map of Chinese provinces. This can be achieved by setting the maptype='china' of the Map. But if I want to process it on this basis, for example, I want to display several special cities on the basis of provinces, such as Dalian, which looks like this:

insert image description here

So what should we do?

The method is very simple. First find china.js, copy a copy, and name it new_china.js, then find the local Liaoning Province map js, copy the data of Dalian City (including the set of edge latitude and longitude) and put it in the corresponding location of new_china.js.

It needs to be mentioned here that it is recommended to generate html with native china.js first, and then manually modify the script of html to introduce the new map; (because I tried to generate html with new map.js before, but failed)

References: pyecharts custom map to add js file ideas refer to this document

Parsing of native map js

There is only one line of js in the native map. It is recommended to format it with a js formatting tool before viewing it. In addition, it is not recommended to format js with vscode and plug-ins, because I have not done it for a long time, and it is too laborious. It is recommended to find an online js formatting website to do it.

The following is the formatted china.js

insert image description here

The coordinates attribute in each geometry should contain the latitude and longitude of the edge of each province. The garbled appearance above is not because the encoding format is wrong. It seems that pyecharts has compressed these latitude and longitude points, which is currently irreversible ( ) 如果你实在想知道每个省的边缘经纬度集合,可以去第4个参考文献那里去下.

Although it is invisible to the naked eye, it does not affect the use. When customizing the map, just paste it directly, without affecting the use, and the program can be self-explanatory;

Solve the problem that the text on the province is not centered

By default, the location of the displayed file in each province is the capital of the province, not the center of the province, so the displayed text may look strange, for example:

insert image description here

The text is too close to affect the viewing effect.

The modification method is also very simple. Just change the center coordinates of each province in the map js to the latitude and longitude coordinates you want. The "cp" attribute under "properties" stores the default longitude and latitude of the provincial capital text position. Just adjust this;

Modify the location of the cp attribute, code snippet

Reference: Solve the problem that the text is not centered on the provinces on the Echarts Chinese map

Sankey diagram

I searched for a long time about how to set the order of the Sankey diagram, but I couldn't find a way.

Sets the color of the Sankey column

The echarts Sankey diagram sets different colors for each node . Although it is echarts, pyecharts can be used. According to the html, there may be a way to set the code directly, but it has not been found yet.

I haven't found the setting method in the code yet, but I have confirmed how to modify it in the final generated html:

 "series": [
        {
    
    
            "type": "sankey",
            "data": [
                {
    
    
                    "name": "2018\u5e74"
                    ,
                     "itemStyle": {
    
    
                        "color":"#EE7700"
                    }
                },
                {
    
    
                    "name": "2019\u5e74\u7559\u5b58"
                    ,
                     "itemStyle": {
    
    
                        "color":"#EE7700"
                    }
                },

Just add itemStyle to the series.

references

  1. pyecharts draw geo map
  2. pyecharts official website contains API documentation
  3. pyecharts gallery official website - many demos
  4. Custom map JSON resource This is a bit interesting, from here you can download the longitude and latitude collection of the edge points of the maps of various provinces and cities in China.
  5. pyecharts custom map provides a new way of customizing the map, and the coordinates are also changed.
  6. pyecharts specifies loading js path from local to modify the default remote priority pull is more interesting, but I failed

Guess you like

Origin blog.csdn.net/wlh2220133699/article/details/131400861