Tornado,Bottle,Flask比较

转自博客园_朝晖

         最近接手一个Tornado项目代码,项目要在原有基础上做很大扩展,为了更好地吃透并扩展好这个项目,就对Tornado以及比较轻型的Bottle、Flask这些框架一一作了调研。其实若干年前做第一个PythonWeb项目的时候,也对很多框架作了横向调研,不过当时的调研比较表面,这次的调研对各框架的文档作了比较细致的通读。Django不在其列,是因为对Django比较熟悉,不需要调研,不过Django可能作为标杆来对以上三者作为评判

        第一个:原先代码使用的框架Tornado,首先Tornado的定位:Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. By using non-blocking network I/O, Tornado can scale to tens of thousands of open connections, making it ideal for long pollingWebSockets, and other applications that require a long-lived connection to each user.,这个是官文档的原文,事实文档内容比例也说明其asynchronous networking library的内容比例还是很大的。这样下来其Web Framework的比例就相对很小了,于是其Library的特性导致它的Web框架玩法与其他框架比起来相对比较原始。再就是官方文档中的By using non-blocking network I/O, Tornado can scale to tens of thousands of open connections, making it ideal for long pollingWebSockets 这一句说明了Tornado真正的个性强项,一个异步Web库勉为其难做Web Framework和Django比起来真是太原始粗糙了。

     第二个:Bottle,Tornado文档pdf是200来页,Bottle是100来页,flask是300多页,Bottle is amicroframework designed for prototyping and building small web applications and services.Bottle的特性对于它这个定位来说是足够了。

     第三个:Flask,Flask号称微内核框架,他的文档中有一段对micro的解释,充分表明他的设计方向:“Micro” does not mean that your whole web application has to fit into a single python file (although it certainly can), nor does it mean that Flask is lacking in functionality. The “micro” in microframework means Flask aims to keep the core simple but extensible. Flask won’t make many decisions for you, such as what database to use. Those decisions that it does make, such as what templating engine to use, are easy to change. Everything else is up to you, so that Flask can be everything you need and nothing you don’t. 这种设计风格正好和Django截然反之,Django是All in one,在技术设施层所需要的工作和决策非常少,Flask却给开发者敞开了扩展的空间。

WordPress使用Redis缓存提高速度

缓存

给 WordPress 博客换了一个缓存插件 —— WP Redis,使用 Redis 缓存给博客提高速度和性能,之前用的插件 WP Super Cache 是基于文件缓存的,虽然也很不错,但是用 Redis 应该是更好的选择。

体验地址:https://blog.tanteng.me

安装 PhpRedis 扩展

由于我的服务器是阿里云的,各种服务如 PHP,MySQL,Nginx 等都是用 yum install 的方式安装的,因此安装 PhpRedis 也用 yum install 的方式。

先用 yum serach phpredis 查找一下可用的版本,选用跟服务器 php 版本匹配的安装。过程省略。

扩展安装完成后需要重启 php-fpm 服务,通过 phpinfo() 或者 php -m 命令的方式可以看到多了一个 redis 的扩展。

安装 WP Redis 插件

在 WordPress 后台插件管理安装 WP Redis 插件,安装完后,需要做以下必须步骤(复制自插件官网页面):

1.Install object-cache.php to wp-content/object-cache.phpwith a symlink or by copying the file.

2.If you’re not running on Pantheon, edit wp-config.php to add your cache credentials, e.g.

$redis_server = array(
    'host'     => '127.0.0.1',
    'port'     => 6379,
    'auth'     => '12345',
    'database' => 0, // Optionally use a specific numeric Redis database. Default is 0.
);

这里 database 配置我使用的是数据库 1,因为主站用的是默认的 0,这里 database 可以根据情况选择。

刷新页面,看看 redis 数据库有没有新的缓存数据:

[root@iZ94r80gdghZ blog.tanteng.me]# redis-cli
127.0.0.1:6379> select 1
OK

使用 keys * 命令可以显示所有缓存数据。

可以看到 Redis 有 WordPress 的缓存数据了,说明 WP Redis 插件运行正常。(原文地址:https://blog.tanteng.me/)

网站架构变化

出处:http://blog.csdn.net/anxpp/article/details/51614973

大型网站架构演化过程

1、初始阶段的网站架构

网站一开始,使用的人并不多,访问量比较小,使用一台服务器就已经完全满足要求的。我们的个人主页、博客,都可以使用如下架构:

01 
应用程序、数据库和文件等资源,都在同一台服务器上。通常也使用一些开源免费的软件来将成本最低化。

2.2、应用服务于数据服务分离
随着业务的发展,一台服务器终将不能满足需求。这是,可以按需将应用服务和数据服务分离:应用服务器、数据库服务器和文件服务器。
他们根据各自的特性,对cpu、内存和硬盘等的需求也各不相同:

02 
应用服务于数据服务分离后,不同特性的服务器担任不同的角色, 系统整体性能将大大提高。

2.3、使用缓存改善性能
我们很清楚,并不是所有的资源都被平均访问到,刚好相反,一部分资源可能会被非常频繁的访问,而另外一些则几乎不会被访问。
如果我们将最常被访问的资源直接放到内存中(或其他的缓存方式),由于不再需要从数据库(硬盘)中读取,速度将会大大提高,不过也会增加对内存的需求。
而缓存一般分两种,应用服务器本地缓存和远程缓存。本地缓存因内存原因,不适合放太多,所以可以专门部署大内存的服务器,当远程缓存服务器(速度比本地缓存会慢些)。而目前的缓存技术也比较多,常见的NoSQL数据库也常被用来当缓存工具使用,本地缓存也能借助一些框架实现,这时的架构如下:

03 
使用缓存后,数据访问压力会大大减小。

2.4、使用服务器集群
业务继续发展后,高并发的访问不可避免,使用服务器集群是比较常用的有效手段。
这相当于将一台应用服务器复制多个,然后通过负载均衡服务器,将请求分发到不同的应用服务器,他们干的是相同的事,不过压力会大大减小:

04 
根据高并发的情况,可以增加或者减少其中的应用服务器,从而使系统有较好的伸缩性。

2.5、数据库读写分离
虽然缓存能一定程度上优化数据访问,但是当业务发展一定程度时,数据库的负载压力可能还是会过高,从而成为瓶颈。
目前主流的数据库,都支持配置主从数据库,利用这一特性,我们可以部署两台数据库服务器,一台用于写操作,这是主数据库,而从数据库用于读,主数据库会将数据以数据库提供的机制,增量同步到从数据库,这样就改善了数据库的负载压力:

06 
为了便于应用服务器的扩展以及更容易的访问主从两个数据库,通常会从应用服务器中独立出来一个专门用来访问数据库的数据访问模块。

2.6、使用反向代理和CDN加速访问
CND和反向代理都是使用缓存的原理,区别在于前者部署与网络提供商的机房,使用户咋请求资源时,从就近的机房获取数据;后者部署于应用服务器前端,用户请求到达后,会有限返回服务器中缓存的可用资源。

07 
这两种技术主要目的就是加速用户的访问,使数据返回更快,同时还能减轻后端服务器的负载压力。

2.7、分布式文件服务器和分布式数据库
随着业务的日益增长,任何单个强大的服务器都不能满足业务的需求,这时可以使用分布式数据库和分布式文件服务器。
在数据已经达到服务器不能支持的时候,就可以拆分业务,让他们使用的数据库服务器部署在不同的物理服务器上:

09

2.8、使用NoSQL和搜索引擎
通常使用NoSQL和搜索引擎技术来处理复杂的数据存储和检索:

10

2.9、业务拆分
随着业务的进一步发展,也使其变得更加复杂,导致整个系统难以维护。
这时就可以将整个业务拆分成不同的产品线,再按需将各个产品线拆分成不同的应用,并对这些应用单独部署维护,然后以超链接、消息队列数据分发和访问统一的数据存储系统来关联这个完整的系统:

09

2.10、分布式服务
随着业务的拆分得越来越小,整个系统的关联上也变得日益复杂,部署维护依然是一件非常困难的事。
这时可以将这些业务中一些通用的地方提取出来独立部署加以复用,提供统一的服务:

什么是Python?

Python是一种计算机程序设计语言。你可能已经听说过很多种流行的编程语言,比如非常难学的C语言,非常流行的Java语言,适合初学者的Basic语言,适合网页编程的JavaScript语言等。

那Python是一种什么语言?

首先,我们普及一下编程语言的基础知识。用任何编程语言来开发程序,都是为了让计算机干活,比如下载一个MP3,编写一个文档等等,而计算机干活的CPU只认识机器指令,所以,尽管不同的编程语言差异极大,最后都得“翻译”成CPU可以执行的机器指令。而不同的编程语言,干同一个活,编写的代码量,差距也很大。

比如,完成同一个任务,C语言要写1000行代码,Java只需要写100行,而Python可能只要20行。

所以Python是一种相当高级的语言。

你也许会问,代码少还不好?代码少的代价是运行速度慢,C程序运行1秒钟,Java程序可能需要2秒,而Python程序可能就需要10秒。

那是不是越低级的程序越难学,越高级的程序越简单?表面上来说,是的,但是,在非常高的抽象计算中,高级的Python程序设计也是非常难学的,所以,高级程序语言不等于简单。

但是,对于初学者和完成普通任务,Python语言是非常简单易用的。连Google都在大规模使用Python,你就不用担心学了会没用。

用Python可以做什么?可以做日常任务,比如自动备份你的MP3;可以做网站,很多著名的网站包括YouTube就是Python写的;可以做网络游戏的后台,很多在线游戏的后台都是Python开发的。总之就是能干很多很多事啦。

Python当然也有不能干的事情,比如写操作系统,这个只能用C语言写;写手机应用,只能用Swift/Objective-C(针对iPhone)和Java(针对Android);写3D游戏,最好用C或C++。

如果你是小白用户,满足以下条件:

  • 会使用电脑,但从来没写过程序;
  • 还记得初中数学学的方程式和一点点代数知识;
  • 想从编程小白变成专业的软件架构师;
  • 每天能抽出半个小时学习。

不要再犹豫了,这个教程就是为你准备的!

准备好了吗?

challenge-accepted

关于作者

廖雪峰,十年软件开发经验,业余产品经理,精通Java/Python/Ruby/Scheme/Objective C等,对开源框架有深入研究,著有《Spring 2.0核心技术与最佳实践》一书,多个业余开源项目托管在GitHub,欢迎微博交流:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

 

 

 

转自微信“菜鸟学Python”

继3.7版本之后Python再次发布了新版本,虽然新版本带来了不少调整,但是其中很大一部分都是对代码底层设计的修改,又或是typing、pickle等不常用的功能,对多数用户而言影响不大,今天我想重点聊一聊那些将对我们的代码编写产生较大影响的新功能。

在体验开始前先说下准备工作,由于Python3.8还没有正式发布,因此通过Anaconda的多版本管理搭建Python3.8新环境的方法是行不通的,我的做法是到官网下载对应的最新版本后单独安装。

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

为了避免与现有环境冲突,将其更名为Python38(下图),下文中的Python如无特殊说明均为Python3.6, Python38为Python3.8接下来就正式开始新特性体验。

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

1.字典逆序

 

我们都知道Python中的字典是无序的,Python3.6对这一问题进行了修订,默认情况下会按照键的创建顺序进行排序,但也仅限于此,你无法像列表那样对字典直接进行排序操作。

这一情况在Python3.8中进一步得到改善,Python3.8中reversed()方法增加了对字典对象的支持,可以对字典进行逆序操作

在下面这段代码中,对字典进行简单的迭代,将会按照顺序输出字典的键。

来尝个鲜,Python3.8几大新功能体验,冲鸭!

现在改变一下代码,加入reversed()方法:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

先来看使用Python3.6的运行结果(下图),可以看到在Python3.6中,字典是不支持recersed()方法的。

 

来尝个鲜,Python3.8几大新功能体验,冲鸭!

然后用Python3.8运行结果如下可以看到,字典按照键创建顺序的逆序进行了输出。虽然只是非常小的一点功能提升,但是在某些场景下对于字典对象的应用可能会起到非常关键的作用。

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

 

2.位置参数

 

在Python3.8中的参数传递方面引入了一个新的特性:PEP 570 Positional-Only Argument——限定位置参数,下面就详细聊聊这究竟是怎么回事。

一般来说,Python中的参数传递有三种形式:位置参数、关键字参数和可变参数,为了避免不必要的麻烦,规定在可变参数之后只允许使用关键字参数。可是即便如此还是给程序员们留下了很大的自由空间,比如在可变参数之前,位置参数和关键字参数的使用几乎不受限制。这样就出现了一个问题,假如一个团队中很多人进行合作开发,函数的定义形式和调用模式是很难规范和统一的

因此Python3.8就引入了一个“Positional-Only Argument”的概念和分隔符“/”,在分隔符“/”左侧的参数,只允许使用位置参数的形式进行传递。

举个例子来进行说明,首先建立下面这样一个函数,由于函数中使用了分隔符“/”,因此只能使用Python3.8运行。

def add_num(x, y, z=100, /, a=100):
    print(x + y + z + a)

 

尝试以下面这种方式调用函数:

add_num(1, 2, z=4, a=5)

结果在运行的时候发生了报错:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

接着尝试全部以位置参数的形式调用函数(如下),结果顺利执行。可见“Positional-Only Argument”对分隔符“/”右侧的参数形式并没有限制

# 输入
add_num(1, 2, 4, 5)
# 输出
12

那么如果只给定前两个参数,后面两个参数使用默认值又如何呢?通过下面的调用可以发现,也是可以正常运行的。

# 输入
add_num(1, 2)
# 输出
203

通过上面这个例子我们发现Python3.8对于参数传递的限制仅仅作用于分隔符“/”的左侧,而且只是在函数调用时发生作用。

 

3.赋值表达式

 

Python3.8中新增了赋值表达式“:=”操作符,简单来说就是把运算操作和赋值操作放在了一起,有点类似于“a+=b”这种表达方式,我想赋值表达式的出现应该是python追求简洁的传统理念所致。

来看下面这段代码,在func函数的if语句中,运算、赋值、判断操作在同一条语句中完成,即使变量a原本不存在也没关系。

# 输入
def func(x, y, z):
    if (a := x + y) != z:
        print(a)
    else:
        print(z)
func(1, 2, 5)
# 输出
3

当然,就上面这段代码本身来看,将 x+y 的结果进行赋值似乎意义不大,但是如果运算表达式的计算量非常大或者要进行大规模独写等操作的话,重复执行对代码的效率将造成大的影响;而如果事先对运算表达式赋值则需要多写一行代码。

 

目前来看,赋值表达式最重要的作用就是使代码变得更加简洁,至于运行效率的差异,目前还没有验证。

 

4.快速调试

 

在之前的Python版本中,“f表达式”——f'{expr}’的作用与eval()函数基本相同,例如:

  • f'{[1, 2, 3, 4, 5, 6]}’的结果是列表[1, 2, 3, 4, 5, 6];

  • f'{3 + 2}’的结果是运算后的值5。

Python3.8中对该功能进行了优化,f'{expr}’语句中增加了对等号“=”的支持,在保留原来功能的基础上,还能够同时输出运算表达式本身。

例如执行先面这段代码,除了计算并输出运算结果外,还会将“=”和其左侧的算式一并输出:

x = 3
print(f'{x * 2 = }')

执行结果:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

f'{expr}’不仅适用于基本的算术运算,还能够进行其他对象的操作,以列表为例,令lst=[1, 2, 3, 4, 5, 6],现在对其进行扩展操作:

lst = eval('[1, 2, 3, 4, 5, 6]')
print(f'{lst = }')
print(f'{lst + [7] = }')

运行结果如下:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

函数运算同样适用,例如对两个列表求交集,执行下面这段代码:

lst1 = [1, 2, 3, 4, 5]
lst2 = [3, 5, 7]
print(f'{list(set(lst1).intersection(set(lst2))) = }')

运行结果:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

相比仅输出结果,连带运算表达式一起输出有助于定位检查,在调试代码的时候使用真的是快捷又方便

 

5.共享内存

 

进程是系统进行资源分配的独立单位,在以前的python版本中,进程间的数据交互只能通过Queue、Pipes等方式来实现,数据无法直接共享。

在Python 3.8中,multiprocessing模块提供了SharedMemory类,可以在不同的Python进程之间创建共享的内存block。目前支持int、float、str、bytes、bool、None、numpy.ndarray等一部分Python对象。

还是举个例子来进行说明,在下面这段代码中建立了2个进程,在进程1中对列表中的每个元素执行+10操作,进程1结束后执行进程2,输出列表内容。

来尝个鲜,Python3.8几大新功能体验,冲鸭!

由于进程之间数据无法共享,因此进程2中输出的列表是没有进行过+10操作的内容:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

 

现在我们对代码进行一下小小的修改,nums不是作为一个普通的list,而是作为一个共享内存对象来创建,代码如下:

来尝个鲜,Python3.8几大新功能体验,冲鸭!

由于shared_memory是Python3.8中的新增内容,因此在Python3.6下运行会出错,我们还是用Python3.8来运行这段代码(结果如下)可以看到,进程2中输出的结果与进程1中是一样的,两个进程之间通过shared_memory实现了数据共享。

来尝个鲜,Python3.8几大新功能体验,冲鸭!

当然,shared_memory在实际应用中肯定不会如此简单,

  • 比如SharedMemory.ShareableList和SharedMemory.SharedMemory的使用本身有很多规则和限制、

  • 比如需要考虑数据锁的问题等等,

  • 但是共享内存确实为进程间通讯提供了一个新的解决方案,而且据说其通讯效率也是非常之高的。

Python3.8发布的新特性和新功能还有很多,对一些内置模块的改进和优化则更多,想尝鲜的同学可以点击阅读原文,了解Python3.8详情!你对Python3.8新特性怎么看,欢迎吱一声留言!

往期热门:

值得收藏|菜鸟学Python【入门文章大全】

 

学习群:

小密圈人气很高的两个实战项目

小密圈的趣味实战-微信主题

3个月还没入门Python,看这100名小密圈的同学3周学Python的杰作

Python爬虫框架

1.ScrapyScrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。。用这个框架可以轻松爬下来如亚马逊商品信息之类的数据。项目地址:https://scrapy.org/

2.PySpiderpyspider 是一个用python实现的功能强大的网络爬虫系统,能在浏览器界面上进行脚本的编写,功能的调度和爬取结果的实时查看,后端使用常用的数据库进行爬取结果的存储,还能定时设置任务与任务优先级等。项目地址:https://github.com/binux/pyspider

3.CrawleyCrawley可以高速爬取对应网站的内容,支持关系和非关系数据库,数据可以导出为JSON、XML等。项目地址:http://project.crawley-cloud.com/

4.PortiaPortia是一个开源可视化爬虫工具,可让您在不需要任何编程知识的情况下爬取网站!简单地注释您感兴趣的页面,Portia将创建一个蜘蛛来从类似的页面提取数据。项目地址:https://github.com/scrapinghub/portia

5.NewspaperNewspaper可以用来提取新闻、文章和内容分析。使用多线程,支持10多种语言等。项目地址:https://github.com/codelucas/newspaper

6.Beautiful SoupBeautiful Soup 是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间。项目地址:https://www.crummy.com/software/BeautifulSoup/bs4/doc/

7.GrabGrab是一个用于构建Web刮板的Python框架。借助Grab,您可以构建各种复杂的网页抓取工具,从简单的5行脚本到处理数百万个网页的复杂异步网站抓取工具。Grab提供一个API用于执行网络请求和处理接收到的内容,例如与HTML文档的DOM树进行交互。项目地址:http://docs.grablib.org/er-user-manual8.ColaCola是一个分布式的爬虫框架,对于用户来说,只需编写几个特定的函数,而无需关注分布式运行的细节。任务会自动分配到多台机器上,整个过程对用户是透明的。项目地址:https://github.com/chineking/cola

转载源:https:/www.toutiao.com/i6560240315519730190/

Python 3D绘图

转自tedu.cn

在一些大型的科幻片中,常常能看到这样的场景,需要地图的时候,往往不是拿出一张纸,而是出现非常炫酷的3d投影地图,一目了然。在如今,3d技术早已经被人们所熟知,并且熟练地应用。网购鞋子的时候,出现的3d鞋子图片,可以全方位的了解鞋子的样式,还有3D网络广告,3D电影等等。

我们今天就一起来学习用python建一个3D的模型图。老规矩,先导入功能库:

import numpy as np

import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d.axes3d import Axes3D

#用matplotlib绘制的图显示在页面里而不是弹出一个窗口

%matplotlib inline

先生成3D坐标轴来看看效果吧

fig1=plt.figure()#创建一个绘图对象  

ax=Axes3D(fig1)#用这个绘图对象创建一个Axes对象(有3D坐标)  

plt.show()#显示模块中的所有绘图对象  

然后设置算法,不同的算法会生成不同的3D模型图。

#系数,有X,Y生成Z

a = 0.7

#将圆周率赋值给b

b = np.pi          

#计算Z轴的值

def mk_Z(X,Y):

    return 2+a-2*np.cos(X)*np.cos(Y)-a*np.cos(b-2*X)

生成X,Y,Z的数据

 #生成X,Y,Z

#numpy.linspace(start, stop, num=xxx, endpoint=True, retstep=False, dtype=None)

#在指定的间隔内返回均匀间隔的100个数字

x = np.linspace(0,2*np.pi,100)

y = np.linspace(0,2*np.pi,100)

##用这两个对象中的可能取值一一映射去扩充为所有可能的取样点

X,Y = np.meshgrid(x,y)

Z = mk_Z(X,Y)

查看数据类型

生成3D图形

 #创建绘图对象,设置对象大小

fig = plt.figure(figsize=(14,6))

#创建3d的视图,使用属性projection

#add_subplot在一块画布上确定图形分布,1行,2列,占据第一列

ax = fig.add_subplot(1, 2, 1, projection=’3d’)

#rstride和cstride表示行列隔多少个取样点建一个小面

ax.plot_surface(X,Y,Z,rstride = 5,cstride = 5)

生成带有颜色的3D图像

 #创建3d视图,使用colorbar,添加颜色柱

#add_subplot在一块画布上确定图形分布,1行,2列,占据第二列

ax = fig.add_subplot(1, 2, 2, projection=’3d’)

#rstride和cstride表示行列隔多少个取样点建一个小面,cmap表示绘制曲面的颜色,rainbow代表彩虹色

p = ax.plot_surface(X, Y, Z, rstride=5, cstride=5, cmap=’rainbow’, antialiased=True)

cb = fig.colorbar(p, shrink=0.5)

图像显示

如果不喜欢这种图片呢,我们还可以换一种算法来创建不同的3D图形,

 #网兜图形

def fun(x,y):  

    return np.power(x,2)+np.power(y,2)

怎么样,小伙伴们快来试一试吧!

matplotlib用法

1、matplotlib-绘制精美的图表

matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入GUI应用程序中。

它的文档相当完备,并且 Gallery页面 中有上百幅缩略图,打开之后都有源程序。因此如果你需要绘制某种类型的图,只需要在这个页面中浏览/复制/粘贴一下,基本上都能搞定。

本章节作为matplotlib的入门介绍,将较为深入地挖掘几个例子,从中理解和学习matplotlib绘图的一些基本概念。

1.1 快速绘图

matplotlib的pyplot子库提供了和matlab类似的绘图API,方便用户快速绘制2D图表。让我们先来看一个简单的例子:

# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0, 10, 1000)
y = np.sin(x)
z = np.cos(x**2)

plt.figure(figsize=(8,4))
plt.plot(x,y,label="$sin(x)$",color="red",linewidth=2)
plt.plot(x,z,"b--",label="$cos(x^2)$")
plt.xlabel("Time(s)")
plt.ylabel("Volt")
plt.title("PyPlot First Example")
plt.ylim(-1.2,1.2)
plt.legend()
plt.show()
_images/pyplot_simple_plot.png

图1.1 调用pyplot库快速将数据绘制成曲线图

matplotlib中的快速绘图的函数库可以通过如下语句载入:

import matplotlib.pyplot as plt

pylab模块

matplotlib还提供了名为pylab的模块,其中包括了许多numpy和pyplot中常用的函数,方便用户快速进行计算和绘图,可以用于IPython中的快速交互式使用。

接下来调用figure创建一个绘图对象,并且使它成为当前的绘图对象。

plt.figure(figsize=(8,4))

也可以不创建绘图对象直接调用接下来的plot函数直接绘图,matplotlib会为我们自动创建一个绘图对象。如果需要同时绘制多幅图表的话,可以是给figure传递一个整数参数指定图标的序号,如果所指定序号的绘图对象已经存在的话,将不创建新的对象,而只是让它成为当前绘图对象。

通过figsize参数可以指定绘图对象的宽度和高度,单位为英寸;dpi参数指定绘图对象的分辨率,即每英寸多少个像素,缺省值为80。因此本例中所创建的图表窗口的宽度为8*80 = 640像素。

但是用工具栏中的保存按钮保存下来的png图像的大小是800*400像素。这是因为保存图表用的函数savefig使用不同的DPI配置,savefig函数也有一个dpi参数,如果不设置的话,将使用matplotlib配置文件中的配置,此配置可以通过如下语句进行查看,关于配置文件将在后面的章节进行介绍:

>>> import matplotlib
>>> matplotlib.rcParams["savefig.dpi"]
100

下面的两行程序通过调用plot函数在当前的绘图对象中进行绘图:

plt.plot(x,y,label="$sin(x)$",color="red",linewidth=2)
plt.plot(x,z,"b--",label="$cos(x^2)$")

plot函数的调用方式很灵活,第一句将x,y数组传递给plot之后,用关键字参数指定各种属性:

  • label : 给所绘制的曲线一个名字,此名字在图示(legend)中显示。只要在字符串前后添加”$”符号,matplotlib就会使用其内嵌的latex引擎绘制的数学公式。
  • color : 指定曲线的颜色
  • linewidth : 指定曲线的宽度

第二句直接通过第三个参数”b–“指定曲线的颜色和线型,这个参数称为格式化参数,它能够通过一些易记的符号快速指定曲线的样式。其中b表示蓝色,”–“表示线型为虚线。在IPython中输入 “plt.plot?” 可以查看格式化字符串的详细配置。

接下来通过一系列函数设置绘图对象的各个属性:

plt.xlabel("Time(s)")
plt.ylabel("Volt")
plt.title("PyPlot First Example")
plt.ylim(-1.2,1.2)
plt.legend()
  • xlabel : 设置X轴的文字
  • ylabel : 设置Y轴的文字
  • title : 设置图表的标题
  • ylim : 设置Y轴的范围
  • legend : 显示图示

最后调用plt.show()显示出我们创建的所有绘图对象。

1.1.1 配置属性

matplotlib所绘制的图的每个组成部分都对应有一个对象,我们可以通过调用这些对象的属性设置方法set_*或者pyplot的属性设置函数setp设置其属性值。例如plot函数返回一个 matplotlib.lines.Line2D 对象的列表,下面的例子显示如何设置Line2D对象的属性:

>>> import numpy as np
>>> import matplotlib.pyplot as plt
>>> x = np.arange(0, 5, 0.1)
>>> line, = plt.plot(x, x*x) # plot返回一个列表,通过line,获取其第一个元素
>>> # 调用Line2D对象的set_*方法设置属性值
>>> line.set_antialiased(False)
>>> # 同时绘制sin和cos两条曲线,lines是一个有两个Line2D对象的列表
>>> lines = plt.plot(x, np.sin(x), x, np.cos(x)) #
>>> # 调用setp函数同时配置多个Line2D对象的多个属性值
>>> plt.setp(lines, color="r", linewidth=2.0)

这段例子中,通过调用Line2D对象line的set_antialiased方法,关闭对象的反锯齿效果。或者通过调用plt.setp函数配置多个Line2D对象的颜色和线宽属性。

同样我们可以通过调用Line2D对象的get_*方法,或者plt.getp函数获取对象的属性值:

>>> line.get_linewidth()
1.0
>>> plt.getp(lines[0], "color") # 返回color属性
'r'
>>> plt.getp(lines[1]) # 输出全部属性
alpha = 1.0
animated = False
antialiased or aa = True
axes = Axes(0.125,0.1;0.775x0.8)
... ...

注意getp函数只能对一个对象进行操作,它有两种用法:

  • 指定属性名:返回对象的指定属性的值
  • 不指定属性名:打印出对象的所有属性和其值

matplotlib的整个图表为一个Figure对象,此对象在调用plt.figure函数时返回,我们也可以通过plt.gcf函数获取当前的绘图对象:

>>> f = plt.gcf()
>>> plt.getp(f)
alpha = 1.0
animated = False
...

Figure对象有一个axes属性,其值为AxesSubplot对象的列表,每个AxesSubplot对象代表图表中的一个子图,前面所绘制的图表只包含一个子图,当前子图也可以通过plt.gca获得:

>>> plt.getp(f, "axes")
[<matplotlib.axes.AxesSubplot object at 0x05CDD170>]
>>> plt.gca()
<matplotlib.axes.AxesSubplot object at 0x05CDD170>

用plt.getp可以发现AxesSubplot对象有很多属性,例如它的lines属性为此子图所包括的 Line2D 对象列表:

>>> alllines = plt.getp(plt.gca(), "lines")
>>> alllines
<a list of 3 Line2D objects>
>>> alllines[0] == line # 其中的第一条曲线就是最开始绘制的那条曲线
True

通过这种方法我们可以很容易地查看对象的属性和它们之间的包含关系,找到需要配置的属性。

1.2 绘制多轴图

一个绘图对象(figure)可以包含多个轴(axis),在Matplotlib中用轴表示一个绘图区域,可以将其理解为子图。上面的第一个例子中,绘图对象只包括一个轴,因此只显示了一个轴(子图)。我们可以使用subplot函数快速绘制有多个轴的图表。subplot函数的调用形式如下:

subplot(numRows, numCols, plotNum)

subplot将整个绘图区域等分为numRows行 * numCols列个子区域,然后按照从左到右,从上到下的顺序对每个子区域进行编号,左上的子区域的编号为1。如果numRows,numCols和plotNum这三个数都小于10的话,可以把它们缩写为一个整数,例如subplot(323)和subplot(3,2,3)是相同的。subplot在plotNum指定的区域中创建一个轴对象。如果新创建的轴和之前创建的轴重叠的话,之前的轴将被删除。

下面的程序创建3行2列共6个轴,通过axisbg参数给每个轴设置不同的背景颜色。

for idx, color in enumerate("rgbyck"):
    plt.subplot(320+idx+1, axisbg=color)
plt.show()
_images/pyplot_subplot01.png

图1.2 用subplot函数将Figure分为六个子图区域

如果希望某个轴占据整个行或者列的话,可以如下调用subplot:

plt.subplot(221) # 第一行的左图
plt.subplot(222) # 第一行的右图
plt.subplot(212) # 第二整行
plt.show()
_images/pyplot_subplot02.png

图1.3 将Figure分为三个子图区域

当绘图对象中有多个轴的时候,可以通过工具栏中的Configure Subplots按钮,交互式地调节轴之间的间距和轴与边框之间的距离。如果希望在程序中调节的话,可以调用subplots_adjust函数,它有left, right, bottom, top, wspace, hspace等几个关键字参数,这些参数的值都是0到1之间的小数,它们是以绘图区域的宽高为1进行正规化之后的坐标或者长度。

1.3 配置文件

一幅图有许多需要配置的属性,例如颜色、字体、线型等等。我们在绘图时,并没有一一对这些属性进行配置,许多都直接采用了Matplotlib的缺省配置。Matplotlib将缺省配置保存在一个文件中,通过更改这个文件,我们可以修改这些属性的缺省值。

Matplotlib 使用配置文件 matplotlibrc 时的搜索顺序如下:

  • 当前路径 : 程序的当前路径
  • 用户配置路径 : 通常为 HOME/.matplotlib/,可以通过环境变量MATPLOTLIBRC修改
  • 系统配置路径 : 保存在 matplotlib的安装目录下的 mpl-data 下

通过下面的语句可以获取用户配置路径:

>>> import matplotlib
>>> matplotlib.get_configdir()
'C:\\Documents and Settings\\zhang\\.matplotlib'

通过下面的语句可以获得目前使用的配置文件的路径:

>>> import matplotlib
>>> matplotlib.matplotlib_fname()
'C:\\Python26\\lib\\site-packages\\matplotlib\\mpl-data\\matplotlibrc'

由于在当前路径和用户配置路径中都没有找到位置文件,因此最后使用的是系统配置路径下的配置文件。如果你将matplotlibrc复制一份到脚本的当前目录下:

>>> import os
>>> os.getcwd()
'C:\\zhang\\doc'

复制配置文件之后再运行:

>>> matplotlib.matplotlib_fname()
'C:\\zhang\\doc\\matplotlibrc'

如果你用文本编辑器打开此配置文件的话,你会发现它实际上是定义了一个字典。为了对众多的配置进行区分,关键字可以用点分开。

配置文件的读入可以使用 rc_params 函数,它返回一个配置字典:

>>> matplotlib.rc_params()
{'agg.path.chunksize': 0,
 'axes.axisbelow': False,
 'axes.edgecolor': 'k',
 'axes.facecolor': 'w',
 ... ...

在matplotlib模块载入的时候会调用rc_params,并把得到的配置字典保存到rcParams变量中:

>>> matplotlib.rcParams
{'agg.path.chunksize': 0,
'axes.axisbelow': False,
... ...

matplotlib将使用rcParams中的配置进行绘图。用户可以直接修改此字典中的配置,所做的改变会反映到此后所绘制的图中。例如下面的脚本所绘制的线将带有圆形的点标识符:

>>> matplotlib.rcParams["lines.marker"] = "o"
>>> import pylab
>>> pylab.plot([1,2,3])
>>> pylab.show()

为了方便配置,可以使用rc函数,下面的例子同时配置点标识符、线宽和颜色:

>>> matplotlib.rc("lines", marker="x", linewidth=2, color="red")

如果希望恢复到缺省的配置(matplotlib载入时从配置文件读入的配置)的话,可以调用 rcdefaults 函数。

>>> matplotlib.rcdefaults()

如果手工修改了配置文件,希望重新从配置文件载入最新的配置的话,可以调用:

>>> matplotlib.rcParams.update( matplotlib.rc_params() )

1.4 Artist对象

matplotlib API包含有三层:

  • backend_bases.FigureCanvas : 图表的绘制领域
  • backend_bases.Renderer : 知道如何在FigureCanvas上如何绘图
  • artist.Artist : 知道如何使用Renderer在FigureCanvas上绘图

FigureCanvas和Renderer需要处理底层的绘图操作,例如使用wxPython在界面上绘图,或者使用PostScript绘制PDF。Artist则处理所有的高层结构,例如处理图表、文字和曲线等的绘制和布局。通常我们只和Artist打交道,而不需要关心底层的绘制细节。

Artists分为简单类型和容器类型两种。简单类型的Artists为标准的绘图元件,例如Line2D、 Rectangle、 Text、AxesImage 等等。而容器类型则可以包含许多简单类型的Artists,使它们组织成一个整体,例如Axis、 Axes、Figure等。

直接使用Artists创建图表的标准流程如下:

  • 创建Figure对象
  • 用Figure对象创建一个或者多个Axes或者Subplot对象
  • 调用Axies等对象的方法创建各种简单类型的Artists

下面首先调用pyplot.figure辅助函数创建Figure对象,然后调用Figure对象的add_axes方法在其中创建一个Axes对象,add_axes的参数是一个形如[left, bottom, width, height]的列表,这些数值分别指定所创建的Axes对象相对于fig的位置和大小,取值范围都在0到1之间:

>>> import matplotlib.pyplot as plt
>>> fig = plt.figure()
>>> ax = fig.add_axes([0.15, 0.1, 0.7, 0.3])

然后我们调用ax的plot方法绘图,创建一条曲线,并且返回此曲线对象(Line2D)。

>>> line, = ax.plot([1,2,3],[1,2,1])
>>> ax.lines
[<matplotlib.lines.Line2D object at 0x0637A3D0>]
>>> line
<matplotlib.lines.Line2D object at 0x0637A3D0>

ax.lines是一个为包含ax的所有曲线的列表,后续的ax.plot调用会往此列表中添加新的曲线。如果想删除某条曲线的话,直接从此列表中删除即可。

Axes对象还包括许多其它的Artists对象,例如我们可以通过调用set_xlabel设置其X轴上的标题:

>>> ax.set_xlabel("time")

如果我们查看set_xlabel的源代码的话,会发现它是通过调用下面的语句实现的:

self.xaxis.set_label_text(xlabel)

如果我们一直跟踪下去,会发现Axes的xaxis属性是一个XAxis对象:

>>> ax.xaxis
<matplotlib.axis.XAxis object at 0x06343230>

XAxis的label属性是一个Text对象:

>>> ax.xaxis.label
<matplotlib.text.Text object at 0x06343290>

而Text对象的_text属性为我们设置的值:

>>> ax.xaxis.label._text
'time'

这些对象都是Artists,因此也可以调用它们的属性获取函数来获得相应的属性:

>>> ax.xaxis.label.get_text()
'time'

1.4.1 Artist的属性

图表中的每个元素都用一个matplotlib的Artist对象表示,而每个Artist对象都有一大堆属性控制其显示效果。例如Figure对象和Axes对象都有patch属性作为其背景,它的值是一个Rectangle对象。通过设置此它的一些属性可以修改Figrue图表的背景颜色或者透明度等属性,下面的例子将图表的背景颜色设置为绿色:

>>> fig = plt.figure()
>>> fig.show()
>>> fig.patch.set_color("g")
>>> fig.canvas.draw()

patch的color属性通过set_color函数进行设置,属性修改之后并不会立即反映到图表的显示上,还需要调用fig.canvas.draw()函数才能够更新显示。

下面是Artist对象都具有的一些属性:

  • alpha : 透明度,值在0到1之间,0为完全透明,1为完全不透明
  • animated : 布尔值,在绘制动画效果时使用
  • axes : 此Artist对象所在的Axes对象,可能为None
  • clip_box : 对象的裁剪框
  • clip_on : 是否裁剪
  • clip_path : 裁剪的路径
  • contains : 判断指定点是否在对象上的函数
  • figure : 所在的Figure对象,可能为None
  • label : 文本标签
  • picker : 控制Artist对象选取
  • transform : 控制偏移旋转
  • visible : 是否可见
  • zorder : 控制绘图顺序

Artist对象的所有属性都通过相应的 get_* 和 set_* 函数进行读写,例如下面的语句将alpha属性设置为当前值的一半:

>>> fig.set_alpha(0.5*fig.get_alpha())

如果你想用一条语句设置多个属性的话,可以使用set函数:

>>> fig.set(alpha=0.5, zorder=2)

使用前面介绍的 matplotlib.pyplot.getp 函数可以方便地输出Artist对象的所有属性名和值。

>>> plt.getp(fig.patch)
    aa = True
    alpha = 1.0
    animated = False
    antialiased or aa = True
    ... ...

1.4.2 Figure容器

现在我们知道如何观察和修改已知的某个Artist对象的属性,接下来要解决如何找到指定的Artist对象。前面我们介绍过Artist对象有容器类型和简单类型两种,这一节让我们来详细看看容器类型的内容。

最大的Artist容器是matplotlib.figure.Figure,它包括组成图表的所有元素。图表的背景是一个Rectangle对象,用Figure.patch属性表示。当你通过调用add_subplot或者add_axes方法往图表中添加轴(子图时),这些子图都将添加到Figure.axes属性中,同时这两个方法也返回添加进axes属性的对象,注意返回值的类型有所不同,实际上AxesSubplot是Axes的子类。

>>> fig = plt.figure()
>>> ax1 = fig.add_subplot(211)
>>> ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3])
>>> ax1
<matplotlib.axes.AxesSubplot object at 0x056BCA90>
>>> ax2
<matplotlib.axes.Axes object at 0x056BC910>
>>> fig.axes
[<matplotlib.axes.AxesSubplot object at 0x056BCA90>,
<matplotlib.axes.Axes object at 0x056BC910>]

为了支持pylab中的gca()等函数,Figure对象内部保存有当前轴的信息,因此不建议直接对Figure.axes属性进行列表操作,而应该使用add_subplot, add_axes, delaxes等方法进行添加和删除操作。但是使用for循环对axes中的每个元素进行操作是没有问题的,下面的语句打开所有子图的栅格。

>>> for ax in fig.axes: ax.grid(True)

Figure对象可以拥有自己的文字、线条以及图像等简单类型的Artist。缺省的坐标系统为像素点,但是可以通过设置Artist对象的transform属性修改坐标系的转换方式。最常用的Figure对象的坐标系是以左下角为坐标原点(0,0),右上角为坐标(1,1)。下面的程序创建并添加两条直线到fig中:

>>> from matplotlib.lines import Line2D
>>> fig = plt.figure()
>>> line1 = Line2D([0,1],[0,1], transform=fig.transFigure, figure=fig, color="r")
>>> line2 = Line2D([0,1],[1,0], transform=fig.transFigure, figure=fig, color="g")
>>> fig.lines.extend([line1, line2])
>>> fig.show()
_images/pyplot_artist01.png

图1.4 在Figure对象中手工绘制直线

注意为了让所创建的Line2D对象使用fig的坐标,我们将fig.TransFigure赋给Line2D对象的transform属性;为了让Line2D对象知道它是在fig对象中,我们还设置其figure属性为fig;最后还需要将创建的两个Line2D对象添加到fig.lines属性中去。

Figure对象有如下属性包含其它的Artist对象:

  • axes : Axes对象列表
  • patch : 作为背景的Rectangle对象
  • images : FigureImage对象列表,用来显示图片
  • legends : Legend对象列表
  • lines : Line2D对象列表
  • patches : patch对象列表
  • texts : Text对象列表,用来显示文字

1.4.3 Axes容器

Axes容器是整个matplotlib库的核心,它包含了组成图表的众多Artist对象,并且有许多方法函数帮助我们创建、修改这些对象。和Figure一样,它有一个patch属性作为背景,当它是笛卡尔坐标时,patch属性是一个Rectangle对象,而当它是极坐标时,patch属性则是Circle对象。例如下面的语句设置Axes对象的背景颜色为绿色:

>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> ax.patch.set_facecolor("green")

当你调用Axes的绘图方法(例如plot),它将创建一组Line2D对象,并将所有的关键字参数传递给这些Line2D对象,并将它们添加进Axes.lines属性中,最后返回所创建的Line2D对象列表:

>>> x, y = np.random.rand(2, 100)
>>> line, = ax.plot(x, y, "-", color="blue", linewidth=2)
>>> line
<matplotlib.lines.Line2D object at 0x03007030>
>>> ax.lines
[<matplotlib.lines.Line2D object at 0x03007030>]

注意plot返回的是一个Line2D对象的列表,因为我们可以传递多组X,Y轴的数据,一次绘制多条曲线。

与plot方法类似,绘制直方图的方法bar和绘制柱状统计图的方法hist将创建一个Patch对象的列表,每个元素实际上都是Patch的子类Rectangle,并且将所创建的Patch对象都添加进Axes.patches属性中:

>>> ax = fig.add_subplot(111)
>>> n, bins, rects = ax.hist(np.random.randn(1000), 50, facecolor="blue")
>>> rects
<a list of 50 Patch objects>
>>> rects[0]
<matplotlib.patches.Rectangle object at 0x05BC2350>
>>> ax.patches[0]
<matplotlib.patches.Rectangle object at 0x05BC2350>

一般我们不会直接对Axes.lines或者Axes.patches属性进行操作,而是调用add_line或者add_patch等方法,这些方法帮助我们完成许多属性设置工作:

>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> rect = matplotlib.patches.Rectangle((1,1), width=5, height=12)
>>> print rect.get_axes() # rect的axes属性为空
None
>>> rect.get_transform() # rect的transform属性为缺省值
BboxTransformTo(Bbox(array([[  1.,   1.],
       [  6.,  13.]])))
>>> ax.add_patch(rect) # 将rect添加进ax
<matplotlib.patches.Rectangle object at 0x05C34E50>
>>> rect.get_axes() # 于是rect的axes属性就是ax
<matplotlib.axes.AxesSubplot object at 0x05C09CB0>
>>> # rect的transform属性和ax的transData相同
>>> rect.get_transform()
... # 太长,省略
>>> ax.transData
... # 太长,省略
>>> ax.get_xlim() # ax的X轴范围为0到1,无法显示完整的rect
(0.0, 1.0)
>>> ax.dataLim._get_bounds() # 数据的范围和rect的大小一致
(1.0, 1.0, 5.0, 12.0)
>>> ax.autoscale_view() # 自动调整坐标轴范围
>>> ax.get_xlim() # 于是X轴可以完整显示rect
(1.0, 6.0)
>>> plt.show()

通过上面的例子我们可以看出,add_patch方法帮助我们设置了rect的axes和transform属性。

下面详细列出Axes包含各种Artist对象的属性:

  • artists : Artist对象列表
  • patch : 作为Axes背景的Patch对象,可以是Rectangle或者Circle
  • collections : Collection对象列表
  • images : AxesImage对象列表
  • legends : Legend对象列表
  • lines : Line2D对象列表
  • patches : Patch对象列表
  • texts : Text对象列表
  • xaxis : XAxis对象
  • yaxis : YAxis对象

下面列出Axes的创建Artist对象的方法:

Axes的方法所创建的对象添加进的列表
annotateAnnotatetexts
barsRectanglepatches
errorbarLine2D, Rectanglelines,patches
fillPolygonpatches
histRectanglepatches
imshowAxesImageimages
legendLegendlegends
plotLine2Dlines
scatterPolygonCollectionCollections
textTexttexts

下面以绘制散列图(scatter)为例,验证一下:

>>> fig = plt.figure()
>>> ax = fig.add_subplot(111)
>>> t = ax.scatter(np.random.rand(20), np.random.rand(20))
>>> t # 返回值为CircleCollection对象
<matplotlib.collections.CircleCollection object at 0x06004230>
>>> ax.collections # 返回的对象已经添加进了collections列表中
[<matplotlib.collections.CircleCollection object at 0x06004230>]
>>> fig.show()
>>> t.get_sizes() # 获得Collection的点数
20
_images/pyplot_artist02.png

图1.5 用scatter函数绘制散列图

1.4.4 Axis容器

Axis容器包括坐标轴上的刻度线、刻度文本、坐标网格以及坐标轴标题等内容。刻度包括主刻度和副刻度,分别通过Axis.get_major_ticks和Axis.get_minor_ticks方法获得。每个刻度线都是一个XTick或者YTick对象,它包括实际的刻度线和刻度文本。为了方便访问刻度线和文本,Axis对象提供了get_ticklabels和get_ticklines方法分别直接获得刻度线和刻度文本:

>>> pl.plot([1,2,3],[4,5,6])
[<matplotlib.lines.Line2D object at 0x0AD3B670>]
>>> pl.show()
>>> axis = pl.gca().xaxis
>>> axis.get_ticklocs() # 获得刻度的位置列表
array([ 1. ,  1.5,  2. ,  2.5,  3. ])
>>> axis.get_ticklabels() # 获得刻度标签列表
<a list of 5 Text major ticklabel objects>
>>> [x.get_text() for x in axis.get_ticklabels()] # 获得刻度的文本字符串
[u'1.0', u'1.5', u'2.0', u'2.5', u'3.0']
>>> axis.get_ticklines() # 获得主刻度线列表,图的上下刻度线共10条
<a list of 10 Line2D ticklines objects>
>>> axis.get_ticklines(minor=True) # 获得副刻度线列表
<a list of 0 Line2D ticklines objects>

获得刻度线或者刻度标签之后,可以设置其各种属性,下面设置刻度线为绿色粗线,文本为红色并且旋转45度:

>>> for label in axis.get_ticklabels():
...     label.set_color("red")
...     label.set_rotation(45)
...     label.set_fontsize(16)
...
>>> for line in axis.get_ticklines():
...     line.set_color("green")
...     line.set_markersize(25)
...     line.set_markeredgewidth(3)

最终的结果图如下:

_images/pyplot_axis01.png

图1.6 手工配置X轴的刻度线和刻度文本的样式

上面的例子中,获得的副刻度线列表为空,这是因为用于计算副刻度的对象缺省为NullLocator,它不产生任何刻度线;而计算主刻度的对象为AutoLocator,它会根据当前的缩放等配置自动计算刻度的位置:

>>> axis.get_minor_locator() # 计算副刻度的对象
<matplotlib.ticker.NullLocator instance at 0x0A014300>
>>> axis.get_major_locator() # 计算主刻度的对象
<matplotlib.ticker.AutoLocator instance at 0x09281B20>

我们可以使用程序为Axis对象设置不同的Locator对象,用来手工设置刻度的位置;设置Formatter对象用来控制刻度文本的显示。下面的程序设置X轴的主刻度为pi/4,副刻度为pi/20,并且主刻度上的文本以pi为单位:

# -*- coding: utf-8 -*-
import matplotlib.pyplot as pl
from matplotlib.ticker import MultipleLocator, FuncFormatter
import numpy as np
x = np.arange(0, 4*np.pi, 0.01)
y = np.sin(x)
pl.figure(figsize=(8,4))
pl.plot(x, y)
ax = pl.gca()

def pi_formatter(x, pos):
    """
    比较罗嗦地将数值转换为以pi/4为单位的刻度文本
    """
    m = np.round(x / (np.pi/4))
    n = 4
    if m%2==0: m, n = m/2, n/2
    if m%2==0: m, n = m/2, n/2
    if m == 0:
        return "0"
    if m == 1 and n == 1:
        return "$\pi$"
    if n == 1:
        return r"$%d \pi$" % m
    if m == 1:
        return r"$\frac{\pi}{%d}$" % n
    return r"$\frac{%d \pi}{%d}$" % (m,n)

# 设置两个坐标轴的范围
pl.ylim(-1.5,1.5)
pl.xlim(0, np.max(x))

# 设置图的底边距
pl.subplots_adjust(bottom = 0.15)

pl.grid() #开启网格

# 主刻度为pi/4
ax.xaxis.set_major_locator( MultipleLocator(np.pi/4) )

# 主刻度文本用pi_formatter函数计算
ax.xaxis.set_major_formatter( FuncFormatter( pi_formatter ) )

# 副刻度为pi/20
ax.xaxis.set_minor_locator( MultipleLocator(np.pi/20) )

# 设置刻度文本的大小
for tick in ax.xaxis.get_major_ticks():
    tick.label1.set_fontsize(16)
pl.show()

关于刻度的定位和文本格式的东西都在matplotlib.ticker中定义,程序中使用到如下两个类:

  • MultipleLocator : 以指定值的整数倍为刻度放置刻度线
  • FuncFormatter : 使用指定的函数计算刻度文本,他会传递给所指定的函数两个参数:刻度值和刻度序号,程序中通过比较笨的办法计算出刻度值所对应的刻度文本

此外还有很多预定义的Locator和Formatter类,详细内容请参考相应的API文档。

_images/pyplot_axis02.png

图1.7 手工配置X轴的刻度线的位置和文本,并开启副刻度

转载:http://old.sebug.net/paper/books/scipydoc/matplotlib_intro.html#figure

Python Bottle路由

原文地址:http://www.linuxyw.com/566.html

静态路由

注:以下很多文字说明,我直接是用文档上的bottle开发从hello写起,用vim创建新的py文件:vim main.py#/usr/bin/env python#coding=utf-8from bottle import route, run@route(‘/hello’) #定义路由,即浏览器访问的地址def hello(): #函数名根据功能随意定义吧,只要不使用系统关键字便可,一般推荐按功能命名吧 return “Hellowww.linuxyw.com” #浏览器返回的内容run(host=’0.0.0.0′, port=8080) #开启服务,端口是8080,授受任何IP地址访问 现在这个教程,是直接这台博客服务器下跑的,所以,我只要输入我网站的域名(一般来说,都是在自己电脑上,或虚拟机中跑的程序,那么就应该输入该IP,如:http://192.168.1.22:8080/hello),就可以访问上面的程序在浏览器输入地址:http://linuxyw.com:8080/hellopython bottle框架基础教程:路由(route)hello linuxyw.com 就这么简单!保存为 py 文件并执行:python main.py[root@linuxyw bottle]# python main.py Bottle v0.12.8 server starting up (using WSGIRefServer())…Listening on http://0.0.0.0:8080/Hit Ctrl-C to quit. 用浏览器访问 http://linuxyw.com:8080/hello 就可以看到”Hello www.linuxyw.com”。它的执行流程大致如下:route() 函数将一段代码绑定到一个 URL,在这个例子中, 我们将 hello() 函数绑定给了 /hello 。我们称之为 route (也是该修饰器的函数名) ,这是 Bottle 框架最重要的开发理念。你可以根据需要定义任意多的 route 。在浏览器请求一个 URL 的时候,框架自动调用与之相应的函数,接着将函数的返回值发送给浏览器。就这么简单!最后一行调用的 run() 函数启动了内置的开发服务器。它监听它的 8080 端口并响应请求,Control-c 可将其关闭。到目前为止,这个内置的开发服务器已经足够用于日常的开发测试了。它根本不需要安装,就可以让你的应用跑起来。在教程的后面,你将学会如何让你的应用跑在其他服务器上面 (译者注:内置服务器不能满足生产环境的要求) 调试模式 在早期开发的时候非常有用,但请务必记得,在生产环境中将其关闭。毫无疑问,这是一个十分简单例子,但它展示了用 Bottle 做应用开发的基本理念。接下来你将了解到其他开发方式。

动态路由

动态路由简单的就是说,url地址是可以传递不同的内容到网页内容上去,这样就不需要写很多的静态路由了,用以下的代码示例吧

  1. @route(‘/hello/<name>’)
  2. def helloName(name):
  3. return “hello:%s” % name

在url中,输入不同的值,就会出现不同的内容,

如果我输入http://linuxyw.com:8080/hello/jianjian,那网页就会显示:hello:jianjian

如果我输入http://linuxyw.com:8080/hello/python,那网页就会显示:hello:python

包含通配符的 route,我们称之为动态 route(与之对应的是静态 route),它能匹配多个 URL 地址。一个通配符包含在一对尖括号里面 (像这样 <name> ),通配符之间用”/” 分隔开来。如果我们将 URL 定义为/hello/<name> 这样,那么它就能匹配 /hello/alice 和 /hello/bob 这样的浏览器请求,但不能匹配/hello , /hello/ 和 /hello/mr/smith 。URL 中的通配符都会当作参数传给回调函数,直接在回调函数中使用。这样可以漂亮地实现 RESTful形式的 URL。

用python web框架 bottle 开发网站

python有很多web开发框架,django,bottle,flask,pylons,Tornado,webpy,web2py, Quixote,Pyramid,aiohttp,sani……还有其它各种出名的不出名的框架,但是微框架却不多,抛开语言,最早最有名的sinatra,webpy,直到现在还有不少用户。

python web入门有人推荐学习django或者flask,其实bottle比二者更轻,更小,更容易上手和被初学者接受,bottle不依赖于任何第三方的python模块,单文件,容易部署,性能高,内置web开发基本需要的东西(route,request等等),甚至不亚于Tornado。

用python web框架 bottle 开发网站(一)
性能测试图片

接下来的我们用bottle实现一个简单的无数据库用户登录注册系统,添加螺丝帽验证,即使你没有任何python web基础,跟着流程走一遍,也是能理解用bottle做web开发究竟是怎么回事,其它框架则大同小异。

开发要求:

  • 安装了最新的python(推荐python 版本 3.x)
  • 安装时勾选了添加环境变量
  • 下载bottle.py到本地,或者pip install bottle安装bottle
  • 使用一个简单的编辑器,例如notepad++,visual studio code,不推荐使用记事本
  • 安装cmder(可选)

接下来,我们开始使用bottle做一个简单的了解

from bottle import route,run
@route('/')
def index():
    return 'hello, bottle'
run(host = 'localhost', port = 80)

在你的编辑器中键入以上代码,保存为main.py,然后在命令行中运行python main.py,你会看到一个服务器已经运行了

用python web框架 bottle 开发网站(一)
image.png

打开浏览器,访问localhost或者http://127.0.0.1,显示欢迎页面

用python web框架 bottle 开发网站(一)
image.png

第一节,我们先做一个简单的了解,知道bottle是一个web微框架,然后用短短5行代码,构建并运行一个服务器。

来源:简书