一、pygal(图表类型Bar)

将使用Python可视化包Pygal来生成可缩放的矢量图形文件

**pygal官方文档:www.pygal.org/en/stable/**

1、安装pygal

pip install pygal -i https://pypi.tuna.tsinghua.edu.cn/simple

2、简单的python图表

import pygal
pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4).render()

生成svg图表

pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4).render_to_file("simple.svg")

需要查看它的源文件,才能显示图片。

3、制作多系列图标(Bar)

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.Bar()
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.render_to_file("wsd.svg")

4、堆叠图表(StackedBar)

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.StackedBar()
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.render_to_file("wsd.svg")

5、将上面的图表水平(HorizontalStackedBar)

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.HorizontalStackedBar()
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.render_to_file("wsd.svg")

二、pygal(各种图表类型)

1、基本的简单线形图(Line)

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.Line()
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.render_to_file("wsd.svg")

2、Horizontal Line

相同的图形但水平,范围为0-100。

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.HorizontalLine()
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.range = [0, 10]
py_bar.render_to_file("wsd.svg")

3、Stacked

相同的图形但具有堆叠值和填充渲染

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.StackedLine(fill=True)
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.range = [0, 10]
py_bar.render_to_file("wsd.svg")

4、Time

对于与时间相关的图,只需格式化标签或使用xy图表的一种变体

import pygal
from datetime import datetime

# x_label_rotation=20是指x轴标签右旋转20度,可负数,负数向左旋转
date_chart = pygal.Line(x_label_rotation=-20)
date_chart.x_labels = map(lambda d: d.strftime('%Y-%m-%d'), [
 datetime(2013, 1, 2),
 datetime(2013, 1, 12),
 datetime(2013, 2, 2),
 datetime(2013, 2, 22)])
date_chart.add("Visits", [300, 412, 823, 672])
date_chart.render_to_file("line-time.svg")

Lambda是一个表达式,也可以是一个匿名函数

def sum(x, y):
    return x + y

在Lambda中可以这样写

p = lambda x, y: x + y

5、Histogram

Basic

直方图是特殊条形,它为条形图取3个值:纵坐标高度,横坐标开始和横坐标结束。

import pygal

hist = pygal.Histogram()
hist.add('Wide bars', [(5, 0, 10), (4, 5, 13), (2, 0, 15)])
hist.add('Narrow bars',  [(10, 1, 2), (12, 4, 4.5), (8, 11, 13)])
hist.render_to_file("histogram-basic.svg")

6、Scatter Plot

禁用点和点之间的连线而获得散点图

import pygal
from math import cos

xy_chart = pygal.XY()
xy_chart.title = 'XY Cosinus'
xy_chart.add('x = cos(y)', [(cos(x / 10.), x / 10.) for x in range(-50, 50, 5)])
xy_chart.add('y = cos(x)', [(x / 10., cos(x / 10.)) for x in range(-50, 50, 5)])
xy_chart.add('x = 1',  [(1, -5), (1, 5)])
xy_chart.add('x = -1', [(-1, -5), (-1, 5)])
xy_chart.add('y = 1',  [(-5, 1), (5, 1)])
xy_chart.add('y = -1', [(-5, -1), (5, -1)])
xy_chart.render_to_file("xy-basic.svg")

7、Pie

简单的饼图

import pygal

pie_chart = pygal.Pie()
pie_chart.title = 'Browser usage in February 2012 (in %)'
pie_chart.add('IE', 19.5)
pie_chart.add('Firefox', 36.6)
pie_chart.add('Chrome', 36.3)
pie_chart.add('Safari', 4.5)
pie_chart.add('Opera', 2.3)
pie_chart.render_to_file("pie-basic.svg")

8、Multi-series pie

相同的饼图,但分为子类别

import pygal

pie_chart = pygal.Pie()
pie_chart.title = 'Browser usage by version in February 2012 (in %)'
pie_chart.add('IE', [5.7, 10.2, 2.6, 1])
pie_chart.add('Firefox', [.6, 16.8, 7.4, 2.2, 1.2, 1, 1, 1.1, 4.3, 1])
pie_chart.add('Chrome', [.3, .9, 17.1, 15.3, .6, .5, 1.6])
pie_chart.add('Safari', [4.4, .1])
pie_chart.add('Opera', [.1, 1.6, .1, .5])
pie_chart.render_to_file("pie-multi-series.svg")

9、Radar

简单的Kiviat图

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.Radar()
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.range = [0, 10]
py_bar.render_to_file("wsd.svg")

10、Box

Extremes (default)

import pygal

box_plot = pygal.Box()
box_plot.title = 'V8 benchmark results'
box_plot.add('Chrome', [6395, 8212, 7520, 7218, 12464, 1660, 2123, 8607])
box_plot.add('Firefox', [7473, 8099, 11700, 2651, 6361, 1044, 3797, 9450])
box_plot.add('Opera', [3472, 2933, 4203, 5229, 5810, 1828, 9013, 4669])
box_plot.add('IE', [43, 41, 59, 79, 144, 136, 34, 102])
box_plot.render_to_file("box-extremes.svg")

11、Dot

import pygal

# pygal.Bar()(1, 3, 3, 7)(1, 6, 6, 4)(5,7,8,13)(5,7,4,9).render_to_file("xgp.svg")

py_bar = pygal.Dot(x_label_rotation=30)
py_bar.add("大标题",[1, 3, 3, 7])
py_bar.add("小标题",[1, 6, 6, 4])
py_bar.range = [0, 10]
py_bar.render_to_file("wsd.svg")

12、Funnel

漏斗图

import pygal

funnel_chart = pygal.Funnel()
funnel_chart.title = 'V8 benchmark results'
funnel_chart.x_labels = ['Richards', 'DeltaBlue', 'Crypto', 'RayTrace', 'EarleyBoyer', 'RegExp', 'Splay', 'NavierStokes']
funnel_chart.add('Opera', [3472, 2933, 4203, 5229, 5810, 1828, 9013, 4669])
funnel_chart.add('Firefox', [7473, 8099, 11700, 2651, 6361, 1044, 3797, 9450])
funnel_chart.add('Chrome', [6395, 8212, 7520, 7218, 12464, 1660, 2123, 8607])
funnel_chart.render_to_file('funnel-basic.svg')

13、SolidGauge

import pygal

gauge = pygal.SolidGauge(inner_radius=0.70)
# 百分格式
percent_formatter = lambda x: '{:.10g}%'.format(x)
# 美元格式
dollar_formatter = lambda x: '{:.10g}$'.format(x)
gauge.value_formatter = percent_formatter

gauge.add('Series 1', [{'value': 225000, 'max_value': 1275000}],
          formatter=dollar_formatter)
gauge.add('Series 2', [{'value': 110, 'max_value': 100}])
gauge.add('Series 3', [{'value': 3}])
gauge.add(
    'Series 4', [
        {'value': 51, 'max_value': 100},
        {'value': 12, 'max_value': 100}])
gauge.add('Series 5', [{'value': 79, 'max_value': 100}])
gauge.add('Series 6', 99)
gauge.add('Series 7', [{'value': 100, 'max_value': 100}])
gauge.render_to_file('solidgauge-normal.svg')

14、Gauge

仪表图

import pygal

gauge_chart = pygal.Gauge(human_readable=True)
gauge_chart.title = 'DeltaBlue V8 benchmark results'
gauge_chart.range = [0, 10000]
gauge_chart.add('Chrome', 8212)
gauge_chart.add('Firefox', 8099)
gauge_chart.add('Opera', 2933)
gauge_chart.add('IE', 41)
gauge_chart.render_to_file('gauge-basic.svg')

15、Maps

World map

安装
pip install pygal_maps_world
Countries
import pygal

worldmap_chart = pygal.maps.world.World()
worldmap_chart.title = 'Some countries'
worldmap_chart.add('C countries', ['cn', 'ca', 'ch', 'cg'])
worldmap_chart.add('F countries', ['fr', 'fi'])
worldmap_chart.add('M countries', ['ma', 'mc', 'md', 'me', 'mg',
                                   'mk', 'ml', 'mm', 'mn', 'mo',
                                   'mr', 'mt', 'mu', 'mv', 'mw',
                                   'mx', 'my', 'mz'])
worldmap_chart.add('U countries', ['ua', 'ug', 'us', 'uy', 'uz'])
worldmap_chart.render_to_file('world-map-countries.svg')

16、Continents

访问各大洲

import pygal

supra = pygal.maps.world.SupranationalWorld()
supra.add('Asia', [('asia', 1)])
supra.add('Europe', [('europe', 1)])
supra.add('Africa', [('africa', 1)])
supra.add('North america', [('north_america', 1)])
supra.add('South america', [('south_america', 1)])
supra.add('Oceania', [('oceania', 1)])
supra.add('Antartica', [('antartica', 1)])
supra.render_to_file('world-map-continents.svg')

三、掷色子

分析点数概率并且绘制直方图

1、创建源文件(引用所需)

from random import randint

class Die():
    """表示一个色子的类"""
    def __init__(self,num_sides=6):
        """色子默认为6面"""
        self.num_sides=num_sides

    def roll(self):
        """返回一个位于1和色子面数之间的随机值"""
        return randint(1, self.num_sides)

2、创建一个色子

from Pygal.示例.die import Die
import pygal
# 创建一个色子
die = Die()

# 掷几次色子,并且将结果存储在一个列表中
results = []
for roll in range(1000):
    r = die.roll()
    results.append(r)

print(results)

# 分析结果
frequencies = []
for value in range(1, die.num_sides+1):
    frequency = results.count(value)
    frequencies.append(frequency)

print(frequencies)

# 对结果进行可视化
hist = pygal.Bar()
hist.title='掷色子1000次的结果'
hist.x_labels = ['1','2','3','4','5','6']
hist.x_title='Result'
hist.y_title='概率'

hist.add('D6',frequencies)
hist.render_to_file('die_visual.svg')

使用浏览器打开这个文件,鼠标指向数据,可以看到显示了标题“D6”, x轴的坐标以及y轴坐标。

可以发现,六个数字出现的频次是差不多的(理论上概率是1/6, 随着实验次数的增加,趋势越来越明显)

3、同时掷两个骰子

稍微改下代码就行,再实例化一个骰子

from Pygal.示例.die import Die
import pygal
# 创建两个色子
die_1 = Die()
die_2 = Die()

# 掷几次色子,并且将结果存储在一个列表中
results = []
for roll in range(1000):
    r = die_1.roll() + die_2.roll()
    results.append(r)
print(results)

# 分析结果
frequencies = []
max_result= die_1.num_sides + die_2.num_sides
for value in range(2, max_result + 1):
    frequency = results.count(value)
    frequencies.append(frequency)

print(frequencies)

# 对结果进行可视化
hist = pygal.Bar()
hist.title='掷色子1000次的结果'
hist.x_labels = ['2','3','4','5','6','7','8','9','10','11','12']
hist.x_title='Result'
hist.y_title='概率'

hist.add('D6 + D6',frequencies)
hist.render_to_file('die_visualc.svg')****

从图中可以看出,两个骰子之和为7的次数最多,和为2的次数最少。因为能掷出2的只有一种情况 -> (1, 1);而掷出7的情况有(1, 6) , (2, 5), (3, 4), (4, 3), (5, 2), (6, 1)共6种情况,其余数字的情况都没有7的多,故掷得7得概率最大。

4、同时掷两个骰子(六和十的)

from Pygal.示例.die import Die
import pygal
# 创建两个色子
die_1 = Die()
die_2 = Die(10)

# 掷几次色子,并且将结果存储在一个列表中
results = []
for roll in range(50000):
    r = die_1.roll() + die_2.roll()
    results.append(r)
print(results)

# 分析结果
frequencies = []
max_result= die_1.num_sides + die_2.num_sides
for value in range(2, max_result + 1):
    frequency = results.count(value)
    frequencies.append(frequency)

print(frequencies)

# 对结果进行可视化
hist = pygal.Bar()
hist.title='掷色子1000次的结果'
# hist.x_labels = ['2','3','4','5','6','7','8','9','10','11','12','13','14','15','16']
hist.x_labels = [i for i in range(2,max_result+1)]
hist.x_title='Result'
hist.y_title='概率'
hist.add('D6 + D6',frequencies)
hist.render_to_file('die_visualcc.svg')

四、Python处理csv文件

CSV(Comma-Separated Values)即逗号分隔值,可以用Excel打开查看。由于是纯文本,任何编辑器也都可打开。与Excel文件不同,CSV文件中:

  • 值没有类型,所有值都是字符串
  • 不能指定字体颜色等样式
  • 不能指定单元格的宽高,不能合并单元格
  • 没有多个工作表
  • 不能嵌入图像图表

在CSV文件中,以,作为分隔符,分隔两个单元格。像这样a,,c表示单元格a和单元格c之间有个空白的单元格。依此类推。

不是每个逗号都表示单元格之间的分界。所以即使CSV是纯文本文件,也坚持使用专门的模块进行处理。Python内置了csv模块。先看看一个简单的例子。

1、从CSV文件中读取数据

import csv

filename = 'F:/Jupyter Notebook/matplotlib_pygal_csv_json/sitka_weather_2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    print(list(reader))

**data不能直接打印,list(data)最外层是list,里层的每一行数据都在一个list中,有点像这样**

[['name', 'age'], ['Bob', '14'], ['Tom', '23'], ...]

于是我们可以这样访问到Bob的年龄reader[1][1], 在for循环中遍历如下

import csv

filename = 'F:/Jupyter Notebook/matplotlib_pygal_csv_json/sitka_weather_2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    for row in reader:
        # 行号从1开始
        print(reader.line_num, row)
截取一部分输出
1 ['AKST', 'Max TemperatureF]
2 ['2014-1-1', '46', '42', '37', '40', '38', '36', '97', 138']
...

前面的数字是行号,从1开始,可以用reader.line_num获取。

要注意的是,reader只能被遍历一次。由于reader是可迭代对象,可以使用next方法一次获取一行。

import csv

filename = 'F:/Jupyter Notebook/matplotlib_pygal_csv_json/sitka_weather_2014.csv'
with open(filename) as f:
    reader = csv.reader(f)
    # 读取一行,下面的reader中已经没有该行了
    head_row = next(reader)
    for row in reader:
        # 行号从2开始
        print(reader.line_num, row)

2、写数据到csv文件中

有reader可以读取,当然也有writer可以写入。一次写入一行,一次写入多行都可以。

import csv

# 使用数字和字符串的数字都可以
datas = [['name', 'age'],
         ['Bob', 14],
         ['Tom', 23],
        ['Jerry', '18']]

with open('example.csv', 'w', newline='') as f:
    writer = csv.writer(f)
    for row in datas:
        writer.writerow(row)
        
    # 还可以写入多行
    writer.writerows(datas)

如果不指定newline='',则每写入一行将有一空行被写入。上面的代码生成如下内容。

name,age
Bob,14
Tom,23
Jerry,18
name,age
Bob,14
Tom,23
Jerry,18

3、DictReader和DictWriter对象

使用DictReader可以像操作字典那样获取数据,把表的第一行(一般是标头)作为key。可访问每一行中那个某个key对应的数据。

import csv

filename = 'F:/Jupyter Notebook/matplotlib_pygal_csv_json/sitka_weather_2014.csv'
with open(filename) as f:
    reader = csv.DictReader(f)
    for row in reader:
        # Max TemperatureF是表第一行的某个数据,作为key
        max_temp = row['Max TemperatureF']
        print(max_temp)

使用DictWriter类,可以写入字典形式的数据,同样键也是标头(表格第一行)。

import csv

headers = ['name', 'age']

datas = [{'name':'Bob', 'age':23},
        {'name':'Jerry', 'age':44},
        {'name':'Tom', 'age':15}
        ]

with open('example.csv', 'w', newline='') as f:
    # 标头在这里传入,作为第一行数据
    writer = csv.DictWriter(f, headers)
    writer.writeheader()
    for row in datas:
        writer.writerow(row)
        
    # 还可以写入多行
    writer.writerows(datas)

4、统计每月最高温度

import csv
from matplotlib import pyplot as plt
from datetime import datetime

plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

filename = 'Python-sitka_weather_2014.csv'
with open(filename) as f:
    # 调用reader()函数,将f对象作为参数传递给它,从而创建一个与该文件相关联的阅读器对象
    reader = csv.reader(f)
    # 返回文件中的下一行
    header_row = next(reader)
    # print(header_row)

    # for index, column_header in enumerate(header_row):
    #     print(index, column_header)

    highs = []
    for row in reader:
        # 使用int()将字符串转换为数字,让matplotlib能够读取它们
        high = int(row[1])
        highs.append(high)

    print(highs)

    # 根据数据绘制图形
    fig = plt.figure(dpi=128, figsize=(16, 9))
    plt.plot(highs, c='red')

    # 设置图形格式
    plt.title('2014年最高气温', fontsize=24)
    plt.xlabel('', fontsize=16)
    plt.ylabel('最高气温', fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()

5、统计每月最高温度和最低温度

import csv
from matplotlib import pyplot as plt
from datetime import datetime

plt.rcParams['font.sans-serif'] = ['SimHei']  # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False  # 用来正常显示负号

filename = 'Python-sitka_weather_2014.csv'
with open(filename) as f:
    # 调用reader()函数,将f对象作为参数传递给它,从而创建一个与该文件相关联的阅读器对象
    reader = csv.reader(f)
    # 返回文件中的下一行
    header_row = next(reader)
    # print(header_row)

    dates, highs, lows = [], [], []
    for row in reader:
        current_date = datetime.strptime(row[0], "%Y/%m/%d")
        dates.append(current_date)
        # print(current_date)

        # 使用int()将字符串转换为数字,让matplotlib能够读取它们
        high = int(row[1])
        highs.append(high)

        low = int(row[3])
        lows.append(low)

    # print(highs)

    # 根据数据绘制图形
    fig = plt.figure(dpi=128, figsize=(16, 9))
    plt.plot(dates, highs, c='red', alpha=0.5)
    plt.plot(dates, lows, c='blue', alpha=0.5)
    plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1)

    # 设置图形格式
    plt.title('2014年最高气温', fontsize=24)
    plt.xlabel('', fontsize=16)
    # 绘制斜线标签
    fig.autofmt_xdate()
    plt.ylabel('最高气温', fontsize=16)
    plt.tick_params(axis='both', which='major', labelsize=16)

    plt.show()
    # plt.savefig('hish.png')