Jacky Liu's Blog

Python + 股票: 个股资讯表

 

---- 以上是 Vim 在全屏模式下的截图。全屏模式下 Vim 没有了程序标签栏,并且覆盖了 OS 的系统任务栏。用来切换全屏模式的按键定义:

    nnoremap <S-F10> :silent !wmctrl -r :ACTIVE: -b toggle,fullscreen<CR>

需要外部命令 wmctrl 可用。感谢 闲耘,是从他的 vimrc 里抄来的。

 

---- 基本搞定了个股资讯表。内容包括新闻动态、重大事项、公司公告。

 

---- 表的结构:<代码> <日期> <时间> <类型> <来源> <序号> <内容> <属性>。下面一条查询语句:

SELECT t1.代码, t1.日期, t1.时间, t1.类型, t1.来源, t1.序号, t1.内容, t1.属性 FROM 个股资讯 AS t1
JOIN (
	SELECT 代码, 类型, MAX(日期) AS 最大日期 FROM 个股资讯 GROUP BY 类型, 代码
) AS t2
ON t1.代码=t2.代码 AND t1.类型=t2.类型 AND t1.日期=t2.最大日期;

耗时 20 多秒,读出 12000 多条记录。不知道是否设计有问题,怎么会这么慢。眼下没时间深究,先这样吧。

 

---- Plotting 模块改用多进程也基本搞定,结果比预想的还要好。我的电脑是双核的,所以在主进程之外又建立两个工作进程来执行绘图任务。粗略统计,与单进程相比的速度提升在 120% ~ 130% 之间,现在绘制一幅图形大概只需要 3 到 4 秒。

 

---- 但是遇到一个神秘 bug,好久才搞定。好像必须给进程对象的建立留有足够的时间,否则进程跑起来会出问题。目前在程序里加了一个延时语句 sleep(0.3),看上去是好了。因为程序结构比较复杂,没心思去重现它了,能用就行,也先这样吧。

 

---- 接下来要把图形再优化一下,新的内容加进去。差不多了以后开始建日线统计表。

 

让 Python 在下载的时候使用 IPv4 域名解析

---- 这个话题由来于我想从深交所的网站扒些信息下来,发现用 Python 下载时,每次都要 30 秒才能连上,浏览器访问却正常。于是查找原因,最后用抓包分析,发现问题出在域名解析阶段。浏览器访问时,向 DNS 服务器发送的是 A 型查询,要求做 IPv4 地址解析; 而 Python 的 urllib.request 模块发送的却是 AAAA 型查询,要求做 IPv6 地址解析,对深交所网址进行 IPv6 解析居然要花 30 秒,不知道为什么。

---- 然后就是各种 Google + 查看代码,追根溯源。不细说了,只贴结果:

 

def Resolver_IPv4(hostname):
	return socket.gethostbyname(hostname)    # 此函数返回 IPv4 地址
													
class HTTPConnection_IPv4(http.client.HTTPConnection):
	def connect(self):
		self.sock= socket.create_connection((Resolver_IPv4(self.host), self.port), self.timeout)

class HTTPHandler_IPv4(urllib.request.HTTPHandler):
	def http_open(self, req):
		return self.do_open(HTTPConnection_IPv4, req)
													
urlopen_IPv4= urllib.request.build_opener(HTTPHandler_IPv4).open

 

如此以后,用这个 urlopen_IPv4() 函数来取代平常用的 urllib.request.urlopen() 函数,就可以用 IPv4 地址解析的方式来下载:

 

webfile= urlopen_IPv4(fullurl='http://www.szse.cn/', timeout=3)


---- 最后说一下,抓包感觉就跟作弊一样,爽!

在 Vim 里控制外部程序,Vim 与 Emacs 与 Conque

---- 上一篇里说的想拿 Vim 当自编程序的 UI,基本已经做到了:



---- 底部的那个 buffer 属于 CSA 模块,这个新写的 Vim 插件就是负责充当外部程序在 Vim 里的界面,buffer 里显示的是外部程序的输出。关于用 Vim 来当 UI 的话题在 第一篇 里讲过。

---- 果然即使用 Python 接口建立了多个线程,也是没有办法让这些线程自动刷新 Vim buffer 里的显示的,况且还有上一篇里说的那个大 Bug。最后采用比较妥协的办法,负责监听的辅助线程还是建的,但是不产生任何输出,只修改后台数据。而主线程每次向外部程序发送输入之后,就 sleep 0.3 秒然后根据后台数据刷新显示,一般情况下都能即时显示外部程序的输出。另外再定义一个手动刷新的按键。

---- 要点记一下:

1. 上一篇里说的那个 bug,是 GUI 的问题,用终端版的 Vim 没事。GUI 版如果在后台建多个线程的话,只允许其中一个线程有可见的输出(也就是造成 Gvim 窗口内显示内容改变),其它线程只能修改后台数据。

2. 如上,即使多线程也不可能自动刷新 Vim buffer 的内容,但可以显示消息(不考虑 bug 的情况下)。自动刷新 Vim buffer 目前已知的只有一个办法:用 VimScript 的 feedkeys() 函数,但是有严重局限,相当于屏蔽了用户的其它输入。这个绝对不用。

3. 辅助线程监听外部程序的输出用的是 Python 的 select.select() 函数,可以监听一个 file descriptor 列表并返回其中有内容可读的 descriptor,但有一点要注意:在产生输出的外部程序已经终止以后,会出现 file descriptor 一直有效但读不到内容的情况,如果不注意这一点就有可能让监听过程陷入死循环,知道的话只要稍微处理一下就可以了。

---- 下一步打算升级程序的 Plotting 模块。现在这个模块还是测试性质的,上次试着画了 2000 多只股票自 2010 年以来的走势,全部单线程运行,花了两个多小时。现在打算改用 Python 的 multiprocessing 模块实现。据文档里说,这个模块与 threading 模块的接口十分类似,这就好了,以前那些关于 threading 的代码可以直接拿过来抄。以后批量执行绘图任务的时候,应该能省不少时间。

 

----------------------------------------------------- <以下补记> -------------------------------------------------------



---- 重大发现,感谢 依云 在回复里的提醒。以上要点第 2 条其实是不成立的。Vim 本身虽然是单线程的,但是通过 Python 完全能够实现多线程的特性。上面所说的辅助线程在监听到外部程序输出以后,就可以操作 vim.buffer 对象,这时 Vim buffer 实际上已经更新了,所缺的只是刷新显示的步骤而已。只要在刷新过程的最后添上一条 Vim 命令: "redraw!" 就可以了,出来的效果实在是 nice!

---- 这样一来,我完全想不到有什么是 Vim + Python 不能做的了。想起来在去年的时候,我想拿 Vim 当自编程序的界面,因为在 Vim 里找不到与外部进程交流的办法而被逼到去看 Emacs 。。。 如今看来,Vim + Python 真是个无敌组合,我忍不住要恶心一把。。。Emacs 你去 Shǐ 吧,哈哈,你的 Elisp 再强,能强得过 Python 吗?速度比不过 Vim,功能又比不过 Python。再想想 Elisp 里头那无数个括号,是要蛋疼到怎样啊?你那 N 个窗口,图片显示功能或许很酷,可是搁不住它慢啊!这事情一慢起来还有什么意思?好在 Emacs 早就顾及这一点,于是定义了更加蛋疼的操作方式,用 Emacs 的人,想快也快不起来,啊哈哈哈 ...

---- 以上讲笑,请浮云看待。如有用 Emacs 的看到,请先冷静 10 秒开骂 。。。

---- 既然这样,Conque 这个 Vim 插件就好拿出来再说一下了。确实像 依云 说的那样,它的实现可以有重大改进。Conque 是在 Vim 里模拟 Shell 终端的一个很流行的插件,它不同版本的实现曾经有过很大改变,但都使用了 Python 接口,插件负责底层交流的部分是 Python 写的。我在去年 7 月左右看过当时最新版的代码,学习了很多。首先,知道使用 Python 接口来编写 Vim 插件就是来自 Conque 的启发,这个还要感谢当时在 Vim-cn 群里跟我提起这个插件的网友 “Strange”。另外,Conque 使用了 Python 语言里负责底层系统操作的标准模块,比如 tty、select 这些,来与外部 Shell 进程交流,这些模块直接对应于底层的 Unix 系统调用,效率高而且可靠,我在自己写的程序里也用 select.select() 来监听外部进程,这也是从 Conque 里学来的。

---- 从当时的 Conque 的代码来看,它是单线程的,从键盘接收用户输入发送给 Shell 进程,而接收靠的是 Vim 函数 feedkeys(),以这个函数作为触发,不停地监听和提取 Shell 输出,经过格式、颜色处理以后发送到 Vim buffer 里。就像上面说的,用 feedkeys() 有严重局限,因为它完全模拟了用户的按键操作。这样一来,真正的用户就只能进行一个键的操作了。如果按键输入多于一个键,后面的键就会被 feedkeys() 冲掉。而 Conque 的解决办法,就是把键盘上几乎每一个键都做了映射,使得 Conque 能通过这些映射来区分是真正的用户输入,还是 feedkeys() 的输入,从而做不同处理。我觉得,这是个很无奈的做法。如果它对速度的影响还不那么糟糕的话,实际上它还屏蔽了 Vim 强大的编辑功能。如果只是把 Shell 原样不动地搬进 Vim 的窗口里是没多大意思的,能够在 Vim 里操作 Shell 的最大好处在于,在编辑那些火星文的 Shell 语句的时候,要能够毫无保留地使用 Vim 的强大编辑功能,这样才真正有意义。

---- 今天这个突破应该能够让以上成为现实,或许一半成为现实。。。因为还有 GUI 的那个大 Bug 在。是不是 Conque 的作者没有用多线程是因为,他当时就知道这个 bug 啊?为了顾及到插件的通用性,就只好放弃这个几近完美的解决方案了。因为这是 X 系统的 bug,我就叫你 X-bug 吧,万事具备,只欠踩死这只 bug!哈哈!

关于通过 vim 的 python 接口使用多线程特性的问题

    ---- Vim Bug 第三弹,以下代码:

python3 << EOF

import threading
import time

print('xxx')

def print_to_vim():
	print('yyy')

threading.Thread(name='test', target=print_to_vim).start()

print('xxx')

time.sleep(3)

EOF

    ---- source 以后 gvim 窗口神奇蒸发,得到如下结果:

    ---- 结论: 通过 python 接口开了多个线程的话,只容许其中一个线程使用 print() 函数。不过这看起来像是 Gnome 或者 X 的问题,不是 Vim 的问题。
   
    ---- 我就是想拿 Vim 当我自编程序的用户界面而已,这至于吗。

    ---- 设计目标:

    1. 从 Vim 窗口里通过自定义命令和按键控制外部程序,不需要进 Shell。
    2. 程序输出通过 Vim 窗口来显示。利用 Python 的多线程特性,主线程处理日常功能,辅助线程专门监听程序的输出,一有输出就刷新 buffer 显示。

    ---- 以上。再配合用新写的 FSE 模块来浏览和管理程序文件,别的什么都不需要了。

    ---- 要是一切如常的话,搞定这些是完全没有问题的,就是怕这些层出不穷的 bug。我容易吗我。

 

FileSystemExplorer 写好了

        ---- 感谢 依云 解决了 Py3 接口内存泄漏的问题。已经下了 firefox 的源码来测试,一共 11 级目录 45000 多个节点,用扩展输出形式,一次打开花费 13 秒左右,反复关闭打开最多用 350 MB 内存,不会一直增加。

        ---- 左边是收藏夹功能,右边是文件结构浏览功能。可以建多个实例浏览不同路径,收藏夹只有一个。


        ---- 收藏夹界面里的操作:

  'O':   添加同级标题
  'o':   添加下级标题
  '\a':  将当前主窗口内的路径加入收藏
  '\s':  显示当前条目的信息
  '\d':  删除当前光标下的标题(recursive)或节点
  '\r':  修改当前标题


        ---- 浏览界面里的操作:

设置属性:
	:Set hidden	不显示隐藏文件(默认)
	:Set nohidden	显示隐藏文件
	:Set byname	按名称排序(默认)
	:Set bysize	按大小排序
	:Set bymtime	按修改时间排序
	:Set byatime	按访问时间排序
	:Set desc	逆序
	:Set asc	正序(默认)
	:Set basic	显示基本信息(只有文件或目录名)
	:Set extend	显示扩展信息(默认,包括大小、修改时间、访问时间)
	:Set lock	锁定当前根节点,只能在其内部浏览
	:Set unlock	解除根节点锁定(默认)
浏览:
	:CD {dir}	切换到指定节点
	"Enter":	打开/关闭目录,打开文件。
	"Shift-Enter":	递归式打开/关闭目录,打开文件。
	"\r":		刷新显示。原来打开的节点仍打开,原来关闭的仍关闭
	"\f":		显示当前节点的信息。
	"\s":		把根节点切换到指定节点。
	"\c":		关闭所有目录节点,除了当前节点和它的上级节点以外
	"Alt-i, Alt-k" 定位到上一个/下一个节点。
		1. 当前光标位于缩进部分的第 i 个 Tab 上时,定位到上一个/下一个 i 级节点。
		2. 当光标位于其它位置时,定位到上一个/下一个同级节点。
文件操作:
	"o":		在指定目录下新建一个节点。
	"O":		建立一个指定节点的同级节点。
	"\d":		删除指定的节点。
	"\t":		在指定目录或指定文件所在的目录下开启一个终端。 


        ---- 源文件在 “Vim 插件” 页面里。但是自用插件写的时候完全没考虑通用性,所以换一台电脑八成是不能用的,只给感兴趣的人作参考。

Gvim7.3 + Python3 接口的内存使用完全失控

    ---- 为什么会有这种鸟事,为什么为什么。一度以为 Vim 已经很熟不需要再搞了,谁知道风平浪静的日子是没有的。快抓狂了。Vim 是这么成熟的编辑器,这种事难道该发生么。

    ---- 原本以为是 Python 代码写的有问题,对 Python 不熟,内存泄漏什么的。逐渐排除了以后开始锁定到 Python 接口上面,具体讲就是 vim.buffer 这个东西。这个是测试代码:
 

lcd %:h
tabedit tmpbuffer
setlocal buftype=nofile

python3 << EOF
for i in range(3):
	flines= ['x'*200] * 50000
	vim.command("%s+\\_.*++g")
	for fl in flines:
		vim.current.buffer.append(fl)
	del flines[:]
EOF


    ---- 而这个是结果:

        在 gvim7.2 + Python2 接口下面:
            第 1 次 source:    46.8 MB    内存,关闭 tmpbuffer 后不变
            第 2 次 source:    59.2 MB    内存,关闭 tmpbuffer 后 58.1
            第 3 次 source:    61.6 MB    内存,关闭 tmpbuffer 后 60.4
            第 4 次 source:    63.9 MB    内存,关闭 tmpbuffer 后 63.6
            第 5 次 source:    66.3 MB    内存,关闭 tmpbuffer 后 65.1
       
        在 gvim7.3 + Python3 接口下面:
            第 1 次 source:    142.6 MB 内存,关闭 tmpbuffer 后不变
            第 2 次 source:    238.5 MB 内存,关闭 tmpbuffer 后不变
            第 3 次 source:    334.5 MB 内存,关闭 tmpbuffer 后不变

    ---- buftype 选项其实对结果无影响。第一个看上去还好。第二个,好像 gvim7.3 的 Python3 接口是没有任何内存回收的,就这么任由它增长。另外初次运行的内存消耗也是 gvim7.2 的三倍。这没问题么? 问题大了。后来索性一直运行,这个是最后的结果:

    ---- 我表示这不是我的问题。考虑把这个贴到 vim-use 群里面。

    ---- 这个很打击我写插件的热情。不过还是要写,不写就亏大了,尼玛感觉就跟炒股被套一样。昨天新加的:

        1. 丰富了颜色

        2. 添加了功能: 除当前节点和它的上级节点之外,关闭其它所有打开的节点。

        3. 添加了功能: 锁定根节点,只能在根节点内部浏览。

Vim 的 Python 接口的内存回收机制有问题 !!!!!

    ---- 续写 FileSystemExplorer 这个插件,现在写好的:
        1. 能刷新
        2. 能设置属性:
            a. 是否显示隐藏文件
            b. 显示基本输出(只有名称)还是扩展输出(包括大小,修改时间与访问时间)
            c. 设置根据名称 / 大小 / 修改时间 / 访问时间排序,设置正序或逆序。
        3. 能递归式打开节点(但是结果恐怖,后述。)
   
    ---- 几个要点记一下:

        1. 数据结构内部不要形成引用回路(reference cycle)。让文件节点同时保持对上级和下级节点的引用可以方便操作,但是对上级的引用要用 weakref 实现。如果形成引用回路就会产生没法析构的对象,以及内存泄漏。

        2. 怎样定义一个类似 list 的对象: 直接继承 list 类型不是个好主意,应该继承 Abstract Base Classes(ABC)里面的 MutableSequence,然后覆盖掉以下 “虚函数”: __init__(), __len__(), __getitem__(), __del__(), __setitem__(), insert()。

        3. 类 list 对象的读取操作与 list 形式一样,可以用 slicing,也可以用 comprehension。但是赋值不一样,不能直接
           

                self= 另一个sequence


        ,需要注意。

        4. 可以使用 del[:] 清除一个 类 list 对象,但是操作之前要先清除成员之间的引用关系。否则即使没有引用回路存在,Python 也不知道先清除哪个成员,结果又是一堆没法析构的对象。(对这一点还不是十分确定,有可能是太过谨慎了,回头写个程序验证一下。)

        5. 在函数的默认参数里不要使用可变值类型(mutable type)。比如:
           
            def my_function(arg=[]):
                pass

        这样是不对的,第二次调用时那个值就会变掉。应该这样:

            def my_function(arg=None):
                if arg is None: arg= []

    ---- 测试: 使用基本输出形式,显示隐藏文件,用 recursive 方式打开我的根目录(但是产生输出内容用的是线性处理方式),将近 49000 个节点(垃圾文件触目惊心),时间大概 8 秒。记得以前用 NerdTree 递归式打开 firefox 源文件的目录,也是几万个节点,花了两分钟以上。用扩展输出形式,多用 10 秒。我的电脑是 07 年的双核笔记本。所以 Python 接口的速度还是不错的,跟 VimScript 相比。

    ---- 最后一个大要点必须单独写:

                    Vim 的 Python 接口的内存回收机制有问题 !!!!!

    如上。虽然已经通过定义 __del__() 等方式确认所建立的 Python 数据对象都能被正确析构,但是内存占用还是一路彪升。用 recursive 方式打开一次根目录会增加几十 MB 内存,但是这些对象析构的时候内存却不减少。试着来回打开关闭了十几次,内存就到了 400 MB 以上,通过资源管理器来看,gvim 成了最耗内存的程序。

    后来把 Python 代码搬出来,改成一般的 Python 测试程序,通过 Shell 运行,没出现这种情况。递归式建立 49000 个节点会耗用 160MB 内存,但是后面无论怎样销毁再建立,内存都不再增加,可见内存回收在起作用。所以不是我代码写的有问题,有可能是 Vim 与 Python 的 garbage collector 通气不畅所致。

    [补记]:

    ---- 又想了个办法,在原来的 Vim 与 Python 混合代码里定义了一个测试命令,模拟其它所有内部操作但只是不往 Vim Buffer 做任何输出。通过此命令反复进行大量数据结构的建立与销毁操作,结果与上面的测试程序一样,内存占用是固定的,不会一直增加。所以问题出在 Python 接口上面。

    ---- 先不想这么多,内存问题绝对是我能力以外的事情。只要平时不会二到用 recursive 方式打开几万个节点的目录再关闭,再打开再关闭,再打开再关闭 ... 这个插件还是能用的。

    ---- 关于 Reference Cycle 的测试代码如下,如果两个对象互相硬指向对方的话,析构函数 __del__() 不会被调用,于是内存泄漏。

 

# -*- coding: utf-8 -*-

import weakref

class Child:
	
	def __init__(self, parent):
		
		# 这里切换使用软指向还是硬指向
		#	self._parent= parent	# XXX: 硬指向上级对象
		self._parent= weakref.ref(parent)	# XXX: 软指向上级对象
		
		print('Child.__init__() -- called !')

	def __del__(self):
		print('Child.__del__() -- called !')


class Parent:
	
	def __init__(self):
		self._child= None
		print('Parent.__init__() -- called !')

	def add_child(self, child):
		self._child= child			# XXX: 硬指向下级对象

	def __del__(self):
		print('Parent.__del__() -- called !')
		


parent= Parent()
child= Child(parent=parent)
parent.add_child(child=child)

del parent
del child

 

FileSystemExplorer 终于成形了

---- 外部的 Vim 插件我基本都是装上试试然后就卸掉,用到的基本都自己写。在文件操作方面,因为自带的 Netrw 实在不够用,一些 VimScript 写的外部插件(比如 NerdTree)又有慢的问题。自己写的 FileSystemExplorer 这个插件自从起个头以后名不副实了很久,现在终于成形了。

---- 主体还是 Python 写的(通过 Vim 的 Python 接口),纯 VimScript 写的太慢。但是目前还是很菜。以下是设想中,准备逐步添加的功能:

1. 刷新(也可以用于删除、新建操作之后)

2. 改变排序方式(也可以用于递归式打开目录之后)

3. 删除目录或文件

4. 批量删除

5. 转移目录或文件

6. 改名

7. 递归式打开目录

8. 新建目录或文件

9. 快速定位(到同级上一个/下一个节点,到上级节点)

10. 智能化开启文件(通过后台调用其它程序)

---- 基本上 Vim 和 Python 折腾到现在,不确定性已经越来越少。接下来的事可能跟工厂做工差不多。继续开工 。。。

用 Python / Matplotlib 画出来的股票 K线图 (二)

 

---- 最新的在这里: 用 Python / Matplotlib 画出来的股票 K线图 (四)

 

---- 下一篇在这里: 用 Python / Matplotlib 画出来的股票 K线图 (三)

 

---- 上一版的改进,双股同列 + 无数细小改进,如下图。dpi= 300。明的一条是个股走势,暗的是同期的指数走势。这大概是近期最强的一只。

 

---- 要想培养对走势的感觉,采用固定比例尺的图形是必须的。一般股票软件里的图形都为显示方便而做了变形处理,用处不大。

 

---- 图形感觉差不多了,告一段落。接下来的目标是 股本结构、历史分配、行业板块、股东研究 这些信息,还包括个股资讯。实时的数据仍然暂时不碰。

 

 

---- 源码贴出来。因为 Matplotlib 还不支持 Python3, 所以单写了一个 Python2 脚本。注意绘图数据是用 pickle file 传递的。

[补记:我决定放弃线性坐标了。这个脚本只支持对数坐标。]

 

# -*- coding: utf-8 -*-

import os
import sys
import pickle
import math
import datetime
import matplotlib

matplotlib.use("WXAgg", warn=True)	# 这个要紧跟在 import matplotlib 之后,而且必须安装了 wxpython 2.8 才行。

import matplotlib.pyplot as pyplot
import matplotlib.font_manager as font_manager 

import numpy
from matplotlib.ticker import FixedLocator, MultipleLocator, FuncFormatter, NullFormatter



__font_properties__=font_manager.FontProperties(fname='/usr/share/fonts/truetype/wqy/wqy-zenhei.ttc')
__color_lightsalmon__= '#ffa07a'
__color_pink__= '#ffc0cb'
__color_navy__= '#000080'






def Plot(pfile, figpath):
	'''
	pfile 指明存放绘图数据的 pickle file,figpath 指定图片需存放的路径
	'''

	fileobj= open(name=pfile, mode='rb')
	pdata= pickle.load(fileobj)
	fileobj.close()
	os.remove(pfile)

	#	计算图片的尺寸(单位英寸)
	#	注意:Python2 里面, "1 / 10" 结果是 0, 必须写成 "1.0 / 10" 才会得到 0.1
	#==================================================================================================================================================
	length= len(pdata[u'日期'])		# 所有数据的长度,就是天数

	open_price_pri= pdata[u'开盘'][0]	# int 类型
	open_price_sec= pdata[u'开盘二'][0]	# 同上

	highest_price_pri= max( [phigh for phigh in pdata[u'最高'] if phigh != None] )		# 第一个行情的最高价
	highest_price_sec= max( [phigh for phigh in pdata[u'最高二'] if phigh != None] )	# 第二个行情的最高价
	highest_price= max(highest_price_pri, highest_price_sec*open_price_pri/open_price_sec)	# 以第一个行情为基准修正出的总最高价
	
	lowest_price_pri= min( [plow for plow in pdata[u'最低'] if plow != None] )	# 最低价
	lowest_price_sec= min( [plow for plow in pdata[u'最低二'] if plow != None] )	# 最低价
	lowest_price= min(lowest_price_pri, lowest_price_sec*open_price_pri/open_price_sec)	# 以第一个行情为基准修正出的总最低价



	yhighlim_price= int(highest_price * 1.1)	# K线子图 Y 轴最大坐标
	ylowlim_price=  int(lowest_price / 1.1)		# K线子图 Y 轴最小坐标



	xfactor= 10.0/230.0	# 一条 K 线的宽度在 X 轴上所占距离(英寸)
	yfactor= 0.3	# Y 轴上每一个距离单位的长度(英寸),这个单位距离是线性坐标和对数坐标通用的

	expbase= 1.1	# 底数,取得小一点,比较接近 1。股价 3 元到 4 元之间有大约 3 个单位距离
	
	# XXX: 价格在 Y 轴上的 “份数”。注意,虽然最高与最低价是以第一个行情为基准修正出来的,但其中包含的倍数因子对结果无影响,即:
	#	log(base, num1) - log(base, num2) == 
	#	log(base, num1/num2) ==
	#	log(base, k*num1/k*num2) ==
	#	log(base, k*num1) - log(base, k*num2)
	# ,这是对数运算的性质。
	ymulti_price= math.log(yhighlim_price, expbase)	- math.log(ylowlim_price, expbase)	
	
	ymulti_vol= 3.0		# 成交量部分在 Y 轴所占的 “份数”
	ymulti_top= 1.2		# 顶部空白区域在 Y 轴所占的 “份数”
	ymulti_bot= 1.2		# 底部空白区域在 Y 轴所占的 “份数”

	xmulti_left= 12.0	# 左侧空白区域所占的 “份数”
	xmulti_right= 12.0	# 右侧空白区域所占的 “份数”

	xmulti_all= length + xmulti_left + xmulti_right
	xlen_fig= xmulti_all * xfactor		# 整个 Figure 的宽度
	ymulti_all= ymulti_price + ymulti_vol + ymulti_top + ymulti_bot
	ylen_fig= ymulti_all * yfactor		# 整个 Figure 的高度
	
	rect_1= (xmulti_left/xmulti_all, (ymulti_bot+ymulti_vol)/ymulti_all, length/xmulti_all, ymulti_price/ymulti_all)	# K线图部分
	rect_2= (xmulti_left/xmulti_all, ymulti_bot/ymulti_all, length/xmulti_all, ymulti_vol/ymulti_all)	# 成交量部分



	#	建立 Figure 对象
	#==================================================================================================================================================
	figfacecolor= __color_pink__
	figedgecolor= __color_navy__
	figdpi= 300
	figlinewidth= 1.0

	figobj= pyplot.figure(figsize=(xlen_fig, ylen_fig), dpi=figdpi, facecolor=figfacecolor, edgecolor=figedgecolor, linewidth=figlinewidth)	# Figure 对象

	# 整个 figure 的标题
	title_pri= (pdata[u'代码'] + ' ' if u'代码' in pdata else '') + pdata[u'简称']
	title_sec= (pdata[u'代码二'] + '   ' if u'代码二' in pdata else '') + pdata[u'简称二']
	
	figobj.suptitle(title_pri + ' / ' + title_sec, fontsize=12, fontproperties=__font_properties__)



	#==================================================================================================================================================
	#==================================================================================================================================================
	#=======	
	#=======	XXX: 第一只:成交量部分
	#=======	
	#==================================================================================================================================================
	#==================================================================================================================================================

	#	第一只:添加 Axes 对象
	#==================================================================================================================================================
	axes_2= figobj.add_axes(rect_2, axis_bgcolor='black')
	axes_2.set_axisbelow(True)	# 网格线放在底层

	#	第一只:改变坐标线的颜色
	#==================================================================================================================================================
	for child in axes_2.get_children():
		if isinstance(child, matplotlib.spines.Spine):
			child.set_color('lightblue')

	#	第一只:得到 X 轴 和 Y 轴 的两个 Axis 对象
	#==================================================================================================================================================
	xaxis_2= axes_2.get_xaxis()
	yaxis_2= axes_2.get_yaxis()

	#	第一只:设置两个坐标轴上的 grid
	#==================================================================================================================================================
	xaxis_2.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	xaxis_2.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)

	yaxis_2.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	yaxis_2.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)



	#==================================================================================================================================================
	#=======	第一只:成交量绘图
	#==================================================================================================================================================
	xindex= numpy.arange(length)	# X 轴上的 index,一个辅助数据

	zipoc= zip(pdata[u'开盘'], pdata[u'收盘'])
	up=   numpy.array( [ True if po < pc and po != None else False for po, pc in zipoc] )		# 标示出该天股价日内上涨的一个序列
	down= numpy.array( [ True if po > pc and po != None else False for po, pc in zipoc] )		# 标示出该天股价日内下跌的一个序列
	side= numpy.array( [ True if po == pc and po != None else False for po, pc in zipoc] )		# 标示出该天股价日内走平的一个序列



	if u'成交额' in pdata:
		volume= pdata[u'成交额']
	else:
		volume= pdata[u'成交量']

	rarray_vol= numpy.array(volume)
	volzeros= numpy.zeros(length)	# 辅助数据

	# XXX: 如果 up/down/side 各项全部为 False,那么 vlines() 会报错。
	if True in up:
		axes_2.vlines(xindex[up], volzeros[up], rarray_vol[up], edgecolor='red', linewidth=3.0, label='_nolegend_')
	if True in down:
		axes_2.vlines(xindex[down], volzeros[down], rarray_vol[down], edgecolor='green', linewidth=3.0, label='_nolegend_')
	if True in side:
		axes_2.vlines(xindex[side], volzeros[side], rarray_vol[side], edgecolor='0.7', linewidth=3.0, label='_nolegend_')
	


	#	第一只:设定 X 轴坐标的范围 
	#==================================================================================================================================================
	axes_2.set_xlim(-1, length)



	#	第一只:设定 X 轴上的坐标
	#==================================================================================================================================================
	datelist= [ datetime.date(int(ys), int(ms), int(ds)) for ys, ms, ds in [ dstr.split('-') for dstr in pdata[u'日期'] ] ]

	# 确定 X 轴的 MajorLocator
	mdindex= []	# 每个月第一个交易日在所有日期列表中的 index
	years= set([d.year for d in datelist])	# 所有的交易年份

	for y in sorted(years):		
		months= set([d.month for d in datelist if d.year == y])		# 当年所有的交易月份
		for m in sorted(months):
			monthday= min([dt for dt in datelist if dt.year==y and dt.month==m])	# 当月的第一个交易日
			mdindex.append(datelist.index(monthday))

	xMajorLocator= FixedLocator(numpy.array(mdindex))

	# 第一只:确定 X 轴的 MinorLocator
	wdindex= {}	# value: 每周第一个交易日在所有日期列表中的 index; key: 当周的序号 week number(当周是第几周)
	
	for d in datelist:
		isoyear, weekno= d.isocalendar()[0:2]
		dmark= isoyear*100 + weekno
		if dmark not in wdindex:
			wdindex[dmark]= datelist.index(d)

	xMinorLocator= FixedLocator(numpy.array( sorted(wdindex.values()) ))

	# 第一只:确定 X 轴的 MajorFormatter 和 MinorFormatter
	def x_major_formatter_2(idx, pos=None):
		return datelist[idx].strftime('%Y-%m-%d')

	def x_minor_formatter_2(idx, pos=None):
		return datelist[idx].strftime('%m-%d')

	xMajorFormatter= FuncFormatter(x_major_formatter_2)
	xMinorFormatter= FuncFormatter(x_minor_formatter_2)

	# 第一只:设定 X 轴的 Locator 和 Formatter
	xaxis_2.set_major_locator(xMajorLocator)
	xaxis_2.set_major_formatter(xMajorFormatter)

	xaxis_2.set_minor_locator(xMinorLocator)
	xaxis_2.set_minor_formatter(xMinorFormatter)

	# 第一只:设定 X 轴主要坐标点与辅助坐标点的样式
	for malabel in axes_2.get_xticklabels(minor=False):
		malabel.set_fontsize(4)
		malabel.set_horizontalalignment('right')
		malabel.set_rotation('45')

	for milabel in axes_2.get_xticklabels(minor=True):
		milabel.set_fontsize(4)
		milabel.set_color('blue')
		milabel.set_horizontalalignment('right')
		milabel.set_rotation('45')



	#	第一只:设定成交量 Y 轴坐标的范围 
	#==================================================================================================================================================
	maxvol= max(volume)	# 注意是 int 类型
	axes_2.set_ylim(0, maxvol)



	#	第一只:设定成交量 Y 轴上的坐标
	#==================================================================================================================================================
	vollen= len(str(maxvol))
	
	volstep_pri= int(round(maxvol/10.0+5000, -4))
	
	yMajorLocator_2= MultipleLocator(volstep_pri)



	# 第一只:确定 Y 轴的 MajorFormatter
	dimsuffix= u'元' if u'成交额' in pdata else u'股'
	def y_major_formatter_2(num, pos=None):
		if num >= 10**8:	# 大于 1 亿
			return (str(round(num/10.0**8, 2)) + u'亿' + dimsuffix) if num != 0 else '0'
		else:
			return (str(num/10.0**4) + u'万' + dimsuffix) if num != 0 else '0'

	#	def y_major_formatter_2(num, pos=None):
	#		return int(num)
	yMajorFormatter_2= FuncFormatter(y_major_formatter_2)

	# 确定 Y 轴的 MinorFormatter
	#	def y_minor_formatter_2(num, pos=None):
	#		return int(num)
	#	yMinorFormatter_2= FuncFormatter(y_minor_formatter_2)
	yMinorFormatter_2= NullFormatter()

	# 第一只:设定 X 轴的 Locator 和 Formatter
	yaxis_2.set_major_locator(yMajorLocator_2)
	yaxis_2.set_major_formatter(yMajorFormatter_2)

	#	yaxis_2.set_minor_locator(yMinorLocator_2)
	yaxis_2.set_minor_formatter(yMinorFormatter_2)

	# 第一只:设定 Y 轴主要坐标点与辅助坐标点的样式
	for malab in axes_2.get_yticklabels(minor=False):
		malab.set_font_properties(__font_properties__)
		malab.set_fontsize(4.5)	# 这个必须放在前一句后面,否则作用会被覆盖
	


	#	第一只:成交量数值在图中间的显示
	#==================================================================================================================================================
	for iy in range(volstep_pri, maxvol, volstep_pri):
		for ix in mdindex[1:-1:3]:
			newlab= axes_2.text(ix+8, iy, y_major_formatter_2(iy))
			newlab.set_font_properties(__font_properties__)
			newlab.set_color('0.3')
			newlab.set_fontsize(3)
			newlab.set_zorder(0)		# XXX: 放在底层
			#	newlab.set_verticalalignment('center')



	#==================================================================================================================================================
	#==================================================================================================================================================
	#=======	
	#=======	XXX: 第二条成交量图线
	#=======	
	#==================================================================================================================================================
	#==================================================================================================================================================

	#	添加 Axes 对象
	#==================================================================================================================================================
	axes_2_sec= axes_2.twinx()
	#	axes_2_sec.set_axisbelow(True)	# 网格线放在底层
	
	axes_2_sec.set_axisbelow(True)	# 网格线放在底层

	#	改变坐标线的颜色
	#==================================================================================================================================================
	#	for child in axes_2_sec.get_children():
	#		if isinstance(child, matplotlib.spines.Spine):
	#			child.set_color('lightblue')

	#	得到 X 轴 和 Y 轴 的两个 Axis 对象
	#==================================================================================================================================================
	xaxis_2_sec= axes_2_sec.get_xaxis()
	yaxis_2_sec= axes_2_sec.get_yaxis()

	#	设置两个坐标轴上的 grid
	#==================================================================================================================================================
	#	xaxis_2_sec.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	#	xaxis_2_sec.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)

	#	yaxis_2_sec.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	#	yaxis_2_sec.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)



	#==================================================================================================================================================
	#=======	绘图
	#==================================================================================================================================================

	if u'成交额二' in pdata:
		volume_sec= pdata[u'成交额二']
	else:
		volume_sec= pdata[u'成交量二']

	zipoc_sec= zip(pdata[u'开盘二'], pdata[u'收盘二'])
	up_sec=   numpy.array( [ True if po < pc and po != None else False for po, pc in zipoc_sec] )		# 标示出该天股价日内上涨的一个序列
	down_sec= numpy.array( [ True if po > pc and po != None else False for po, pc in zipoc_sec] )		# 标示出该天股价日内下跌的一个序列
	side_sec= numpy.array( [ True if po == pc and po != None else False for po, pc in zipoc_sec] )		# 标示出该天股价日内走平的一个序列
	
	rarray_vol_sec= numpy.array(volume_sec)
	volzeros_sec= numpy.zeros(length)	# 辅助数据

	# XXX: 如果 up_sec/down_sec/side_sec 各项全部为 False,那么 vlines() 会报错。
	if True in up_sec:
		axes_2_sec.vlines(xindex[up_sec], volzeros_sec[up_sec], rarray_vol_sec[up_sec], edgecolor='pink', linewidth=1.0, label='_nolegend_', alpha=0.3)
	if True in down_sec:
		axes_2_sec.vlines(xindex[down_sec], volzeros_sec[down_sec], rarray_vol_sec[down_sec], edgecolor='lightgreen', linewidth=1.0, label='_nolegend_', alpha=0.3)
	if True in side_sec:
		axes_2_sec.vlines(xindex[side_sec], volzeros_sec[side_sec], rarray_vol_sec[side_sec], edgecolor='0.7', linewidth=1.0, label='_nolegend_', alpha=0.3)
	


	#	设定 X 轴坐标的范围 
	#==================================================================================================================================================
	#	XXX: 不用了,与 axes_2 共用。


	#	设定 Y 轴坐标的范围 
	#==================================================================================================================================================
	maxvol_sec= max(volume_sec)	# 注意是 int 类型
	axes_2_sec.set_ylim(0, maxvol_sec)



	#	设定 Y 轴上的坐标
	#==================================================================================================================================================
	
	volstep_sec= volstep_pri*maxvol_sec/float(maxvol)
	yMajorLocator_2_sec= MultipleLocator(volstep_sec)

	# 确定 Y 轴的 MajorFormatter
	dimsuffix_sec= u'元' if u'成交额二' in pdata else u'股'
	def y_major_formatter_2_sec(num, pos=None):
		if num >= 10**8:	# 大于 1 亿
			print(('num= ' + str(num) + ', result= ' + str(round(num/10.0**8, 3)) + u'亿' + dimsuffix_sec).encode('utf8'))
			
			return (str(round(num/10.0**8, 3)) + u'亿' + dimsuffix_sec) if num != 0 else '0'
		else:
			return (str(round(num/10.0**4, 2)) + u'万' + dimsuffix_sec) if num != 0 else '0'

	#	def y_major_formatter_2_sec(num, pos=None):
	#		return int(num)
	yMajorFormatter_2_sec= FuncFormatter(y_major_formatter_2_sec)

	# 确定 Y 轴的 MinorFormatter
	#	def y_minor_formatter_2(num, pos=None):
	#		return int(num)
	#	yMinorFormatter_2_sec= FuncFormatter(y_minor_formatter_2)
	yMinorFormatter_2_sec= NullFormatter()

	# 设定 X 轴的 Locator 和 Formatter
	yaxis_2_sec.set_major_locator(yMajorLocator_2_sec)
	yaxis_2_sec.set_major_formatter(yMajorFormatter_2_sec)

	#	yaxis_2_sec.set_minor_locator(yMinorLocator_2_sec)
	yaxis_2_sec.set_minor_formatter(yMinorFormatter_2_sec)

	# 设定 Y 轴主要坐标点与辅助坐标点的样式
	for malab in axes_2_sec.get_yticklabels(minor=False):
		malab.set_font_properties(__font_properties__)
		malab.set_fontsize(4.5)	# 这个必须放在前一句后面,否则作用会被覆盖
	




	#==================================================================================================================================================
	#==================================================================================================================================================
	#=======	
	#=======	XXX: K 线图部分
	#=======	
	#==================================================================================================================================================
	#==================================================================================================================================================

	#	添加 Axes 对象
	#==================================================================================================================================================
	axes_1= figobj.add_axes(rect_1, axis_bgcolor='black', sharex=axes_2)
	axes_1.set_axisbelow(True)	# 网格线放在底层
	
	axes_1.set_yscale('log', basey=expbase)		# 使用对数坐标
	
	#	改变坐标线的颜色
	#==================================================================================================================================================
	for child in axes_1.get_children():
		if isinstance(child, matplotlib.spines.Spine):
			child.set_color('lightblue')

	#	得到 X 轴 和 Y 轴 的两个 Axis 对象
	#==================================================================================================================================================
	xaxis_1= axes_1.get_xaxis()
	yaxis_1= axes_1.get_yaxis()

	#	设置两个坐标轴上的 grid
	#==================================================================================================================================================
	xaxis_1.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	xaxis_1.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)

	yaxis_1.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	yaxis_1.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)



	#==================================================================================================================================================
	#=======	绘图
	#==================================================================================================================================================

	#	绘制 K 线部分
	#==================================================================================================================================================
	
	#	对开收盘价进行视觉修正
	for idx, poc in enumerate( zip(pdata[u'开盘'], pdata[u'收盘']) ):
		if poc[0] == poc[1] and None not in poc:
			variant= round((poc[1]+1000)/2000, 0)
			pdata[u'开盘'][idx]= poc[0] - variant		# 稍微偏离一点,使得在图线上不致于完全看不到
			pdata[u'收盘'][idx]= poc[1] + variant

	rarray_open= numpy.array(pdata[u'开盘'])
	rarray_close= numpy.array(pdata[u'收盘'])
	rarray_high= numpy.array(pdata[u'最高'])
	rarray_low= numpy.array(pdata[u'最低'])

	# XXX: 如果 up, down, side 里有一个全部为 False 组成,那么 vlines() 会报错。
	# XXX: 可以使用 alpha 参数调节透明度
	if True in up:
		axes_1.vlines(xindex[up], rarray_low[up], rarray_high[up], edgecolor='red', linewidth=0.6, label='_nolegend_')		
		axes_1.vlines(xindex[up], rarray_open[up], rarray_close[up], edgecolor='red', linewidth=3.0, label='_nolegend_')

	if True in down:
		axes_1.vlines(xindex[down], rarray_low[down], rarray_high[down], edgecolor='green', linewidth=0.6, label='_nolegend_')
		axes_1.vlines(xindex[down], rarray_open[down], rarray_close[down], edgecolor='green', linewidth=3.0, label='_nolegend_')

	if True in side:
		axes_1.vlines(xindex[side], rarray_low[side], rarray_high[side], edgecolor='0.7', linewidth=0.6, label='_nolegend_')
		axes_1.vlines(xindex[side], rarray_open[side], rarray_close[side], edgecolor='0.7', linewidth=3.0, label='_nolegend_')

	#	绘制均线部分
	#==================================================================================================================================================
	if u'5日均' in pdata:
		rarray_5dayave= numpy.array(pdata[u'5日均'])
		axes_1.plot(xindex, rarray_5dayave, 'o-', color='white', linewidth=0.1, label='ave_5', \
			markersize=0.7, markeredgecolor='white', markeredgewidth=0.1)	# 5日均线
	
	if u'10日均' in pdata:
		rarray_10dayave= numpy.array(pdata[u'10日均'])
		axes_1.plot(xindex, rarray_10dayave, 'o-', color='yellow', linewidth=0.1, label='ave_10', \
			markersize=0.7, markeredgecolor='yellow', markeredgewidth=0.1)	# 10日均线
	
	if u'30日均' in pdata:
		rarray_30dayave= numpy.array(pdata[u'30日均'])
		axes_1.plot(xindex, rarray_30dayave, 'o-', color='cyan', linewidth=0.1, label='ave_30', \
			markersize=0.7, markeredgecolor='cyan', markeredgewidth=0.1)	# 30日均线



	#	绘制 复权提示
	#==================================================================================================================================================
	if u'复权' in pdata:
		adjdict= dict(pdata[u'复权'])
		
		for idx, dstr in enumerate(pdata[u'日期']):
			if dstr in adjdict:
				axes_1.plot([idx, idx], [ylowlim_price, yhighlim_price], '-', color='purple', linewidth=0.3)
	




	#	设定 X 轴坐标的范围 
	#==================================================================================================================================================
	axes_1.set_xlim(-1, length)



	#	先设置 label 位置,再将 X 轴上的坐标设为不可见。因为与 成交量子图 共用 X 轴
	#==================================================================================================================================================

	# 设定 X 轴的 Locator 和 Formatter
	xaxis_1.set_major_locator(xMajorLocator)
	xaxis_1.set_major_formatter(xMajorFormatter)

	xaxis_1.set_minor_locator(xMinorLocator)
	xaxis_1.set_minor_formatter(xMinorFormatter)

	# 将 X 轴上的坐标设为不可见。
	for malab in axes_1.get_xticklabels(minor=False):
		malab.set_visible(False)

	for milab in axes_1.get_xticklabels(minor=True):
		milab.set_visible(False)

	# 用这一段效果也一样
	#	pyplot.setp(axes_1.get_xticklabels(minor=False), visible=False)
	#	pyplot.setp(axes_1.get_xticklabels(minor=True), visible=False)



	#	设定 Y 轴坐标的范围 
	#==================================================================================================================================================
	axes_1.set_ylim(ylowlim_price, yhighlim_price)



	#	设定 Y 轴上的坐标
	#==================================================================================================================================================
	
	# XXX: 不用 LogLocator 了,因为不能控制坐标点的位置。

	#	主要坐标点
	#----------------------------------------------------------------------------
	yticks_major_pri= []
	for i in range(1, 999):
		newloc= ylowlim_price * (expbase**i)
		if newloc <= yhighlim_price:
			yticks_major_pri.append(newloc)
		else:
			break

	yMajorLocator_1= FixedLocator(numpy.array(yticks_major_pri))

	# 确定 Y 轴的 MajorFormatter
	def y_major_formatter_1(num, pos=None):
		return str(round(num/1000.0, 2))
	
	yMajorFormatter_1= FuncFormatter(y_major_formatter_1)

	# 设定 X 轴的 Locator 和 Formatter
	yaxis_1.set_major_locator(yMajorLocator_1)
	yaxis_1.set_major_formatter(yMajorFormatter_1)

	# 设定 Y 轴主要坐标点与辅助坐标点的样式
	for mal in axes_1.get_yticklabels(minor=False):
		mal.set_fontsize(6)
	
	

	#	辅助坐标点
	#----------------------------------------------------------------------------
	yticks_minor_pri= []
	mtstart= ylowlim_price * (1.0+(expbase-1.0)/2)
	for i in range(999):
		newloc= mtstart * (expbase**i)
		if newloc <= yhighlim_price:
			yticks_minor_pri.append(newloc)
		else:
			break

	yMinorLocator_1= FixedLocator(numpy.array(yticks_minor_pri))		# XXX minor ticks 已经在上面一并设置,这里不需要了。

	# 确定 Y 轴的 MinorFormatter
	def y_minor_formatter_1(num, pos=None):
		return str(round(num/1000.0, 2))
		
	yMinorFormatter_1= FuncFormatter(y_minor_formatter_1)
	
	# 设定 X 轴的 Locator 和 Formatter
	yaxis_1.set_minor_locator(yMinorLocator_1)
	yaxis_1.set_minor_formatter(yMinorFormatter_1)
	# 设定 Y 轴主要坐标点与辅助坐标点的样式
	for mal in axes_1.get_yticklabels(minor=True):
		mal.set_fontsize(5)
		mal.set_color('blue')



	#	第一只:价格数值在图中间的显示
	#==================================================================================================================================================
	for iy in yticks_major_pri:
		for ix in mdindex[1:-1:3]:
			newlab= axes_1.text(ix+8, iy*1.001, y_major_formatter_1(iy))
			newlab.set_font_properties(__font_properties__)
			newlab.set_color('0.3')
			newlab.set_fontsize(3)
			newlab.set_zorder(0)		# XXX: 放在底层
			#	newlab.set_verticalalignment('center')



	#	第一只:日期在图中间的显示
	#==================================================================================================================================================
	for iy in yticks_minor_pri[1:-1:5]:
		for ix in mdindex:
			newlab= axes_1.text(ix-1, iy, pdata[u'日期'][ix])
			newlab.set_font_properties(__font_properties__)
			newlab.set_color('0.3')
			newlab.set_fontsize(4)
			newlab.set_rotation('vertical')
			#	newlab.set_horizontalalignment('left')
			#	newlab.set_verticalalignment('bottom')
			newlab.set_zorder(0)		# XXX: 放在底层
			#	newlab.set_verticalalignment('center')



	#==================================================================================================================================================
	#==================================================================================================================================================
	#=======	
	#=======	XXX: 第二条 K 线图
	#=======	
	#==================================================================================================================================================
	#==================================================================================================================================================

	#	添加 Axes 对象
	#==================================================================================================================================================
	axes_1_sec= axes_1.twinx()
	#	axes_1_sec.set_axisbelow(True)	# 网格线放在底层
	
	axes_1_sec.set_yscale('log', basey=expbase)	# 使用对数坐标


	#	得到 X 轴 和 Y 轴 的两个 Axis 对象
	#==================================================================================================================================================
	xaxis_1_sec= axes_1_sec.get_xaxis()
	yaxis_1_sec= axes_1_sec.get_yaxis()



	#==================================================================================================================================================
	#=======	绘图
	#==================================================================================================================================================

	#	绘制 K 线部分
	#==================================================================================================================================================
	
	#	对开收盘价进行视觉修正
	for idx, poc in enumerate( zipoc_sec ):
		if poc[0] == poc[1] and None not in poc:
			pdata[u'开盘二'][idx]= poc[0] - 5		# 稍微偏离一点,使得在图线上不致于完全看不到
			pdata[u'收盘二'][idx]= poc[1] + 5		
	
	rarray_open= numpy.array(pdata[u'开盘二'])
	rarray_close= numpy.array(pdata[u'收盘二'])
	rarray_high= numpy.array(pdata[u'最高二'])
	rarray_low= numpy.array(pdata[u'最低二'])

	# XXX: 如果 up_sec, down_sec, side_sec 里有一个全部为 False 组成,那么 vlines() 会报错。
	# XXX: 可以使用 alpha 参数调节透明度
	if True in up_sec:
		axes_1_sec.vlines(xindex[up_sec], rarray_low[up_sec], rarray_high[up_sec], edgecolor='red', linewidth=0.6, label='_nolegend_', alpha=0.3)
		axes_1_sec.vlines(xindex[up_sec], rarray_open[up_sec], rarray_close[up_sec], edgecolor='red', linewidth=3.0, label='_nolegend_', alpha=0.3)

	if True in down_sec:
		axes_1_sec.vlines(xindex[down_sec], rarray_low[down_sec], rarray_high[down_sec], edgecolor='green', linewidth=0.6, label='_nolegend_', alpha=0.3)
		axes_1_sec.vlines(xindex[down_sec], rarray_open[down_sec], rarray_close[down_sec], edgecolor='green', linewidth=3.0, label='_nolegend_', alpha=0.3)

	if True in side_sec:
		axes_1_sec.vlines(xindex[side_sec], rarray_low[side_sec], rarray_high[side_sec], edgecolor='0.7', linewidth=0.6, label='_nolegend_', alpha=0.3)
		axes_1_sec.vlines(xindex[side_sec], rarray_open[side_sec], rarray_close[side_sec], edgecolor='0.7', linewidth=3.0, label='_nolegend_', alpha=0.3)



	#	设定 X 轴坐标的范围 
	#==================================================================================================================================================
	axes_1_sec.set_xlim(-1, length)



	#	先设置 label 位置,再将 X 轴上的坐标设为不可见。因为与 成交量子图 共用 X 轴
	#==================================================================================================================================================

	# 设定 X 轴的 Locator 和 Formatter
	xaxis_1_sec.set_major_locator(xMajorLocator)
	xaxis_1_sec.set_major_formatter(xMajorFormatter)

	xaxis_1_sec.set_minor_locator(xMinorLocator)
	xaxis_1_sec.set_minor_formatter(xMinorFormatter)

	# 将 X 轴上的坐标设为不可见。
	for malab in axes_1_sec.get_xticklabels(minor=False):
		malab.set_visible(False)

	for milab in axes_1_sec.get_xticklabels(minor=True):
		milab.set_visible(False)



	#	设定 Y 轴坐标的范围 
	#==================================================================================================================================================
	axes_1_sec.set_ylim(ylowlim_price*open_price_sec/open_price_pri, yhighlim_price*open_price_sec/open_price_pri)



	#	设定 Y 轴上的坐标
	#==================================================================================================================================================
	
	#	主要坐标点
	#----------------------------------------------------------------------------
	yticks_major_sec= []
	ylowlim_price_sec=  ylowlim_price*open_price_sec/open_price_pri
	yhighlim_price_sec= yhighlim_price*open_price_sec/open_price_pri
	
	for i in range(1, 999):
		newloc= ylowlim_price_sec * (expbase**i)
		if newloc <= yhighlim_price_sec:
			yticks_major_sec.append(newloc)
		else:
			break

	yMajorLocator_1_sec= FixedLocator(numpy.array(yticks_major_sec))

	# 确定 Y 轴的 MajorFormatter
	def y_major_formatter_1_sec(num, pos=None):
		return str(round(num/1000.0, 2))
	
	yMajorFormatter_1_sec= FuncFormatter(y_major_formatter_1_sec)

	# 设定 X 轴的 Locator 和 Formatter
	yaxis_1_sec.set_major_locator(yMajorLocator_1_sec)
	yaxis_1_sec.set_major_formatter(yMajorFormatter_1_sec)

	# 设定 Y 轴主要坐标点与辅助坐标点的样式
	for mal in axes_1_sec.get_yticklabels(minor=False):
		mal.set_fontsize(6)
	
	

	#	辅助坐标点
	#----------------------------------------------------------------------------
	yticks_minor_sec= []
	mtstart_sec= ylowlim_price_sec * (1.0+(expbase-1.0)/2)
	for i in range(999):
		newloc= mtstart_sec * (expbase**i)
		if newloc <= yhighlim_price_sec:
			yticks_minor_sec.append(newloc)
		else:
			break

	yMinorLocator_1_sec= FixedLocator(numpy.array(yticks_minor_sec))		# XXX minor ticks 已经在上面一并设置,这里不需要了。

	# 确定 Y 轴的 MinorFormatter
	def y_minor_formatter_1_sec(num, pos=None):
		return str(round(num/1000.0, 2))
		
	yMinorFormatter_1_sec= FuncFormatter(y_minor_formatter_1_sec)
	
	# 设定 X 轴的 Locator 和 Formatter
	yaxis_1_sec.set_minor_locator(yMinorLocator_1_sec)
	yaxis_1_sec.set_minor_formatter(yMinorFormatter_1_sec)
	# 设定 Y 轴主要坐标点与辅助坐标点的样式
	for mal in axes_1_sec.get_yticklabels(minor=True):
		mal.set_fontsize(5)
		mal.set_color('blue')



	#	显示图片
	#==================================================================================================================================================
	#	pyplot.show()

	#	保存图片
	#==================================================================================================================================================
	figobj.savefig(figpath, dpi=figdpi, facecolor=figfacecolor, edgecolor=figedgecolor, linewidth=figlinewidth)



if __name__ == '__main__':
	Plot(pfile=sys.argv[1], figpath=sys.argv[2])







 

用来画股票 K线图 的 Python 脚本

    ---- <补记>:

        最新的在这里: 用 Python / Matplotlib 画出来的股票 K线图 (四)

        下一篇在这里: 用 Python / Matplotlib 画出来的股票 K线图 (三)

 

    ---- 花了 20 个小时左右的时间才从新浪下载完复权日线数据,把复权日线表建起来。这速度也太慢了,还有首次下载网页失败的比例居然这么高,一定有问题,印象中以前不是这么慢的,下载几千只股票的数据也只有几十个页面会首次下载失败吧。但昨天晚上更新最新数据的时候把下载任务之间的延迟扩大了一些,好像好一些,速度还可以,而且失败率不高。我开的是 5 个线程,下载页面之间的间隔是 0.2 ~ 0.3 秒。

    ---- 另外,把那个画 K 线图的脚本贴出来。这个脚本是通过研究 Matplotlib 官网里的示例并且借助 Google,用大概 1 周的时间改出来的。简单介绍一下:

    1. 由两个子图(subplot)构成,上面一个显示价格(K 线),下面一个显示成交量。
   
    2. K 线子图可以使用线性坐标或者对数坐标(由 Plot() 函数第三个参数控制)。使用线性坐标的时候,每个单位价格区间所占高度是固定的;使用对数坐标的时候,每个单位涨幅区间(比如 10%)所占高度是固定的。成交量子图的高度总是固定,不论成交量数值大小。
   
    3. 对 X 轴来说,每根 K 线的宽度固定,整个图形的宽度决定于行情的天数。只要把行情数据文件作为参数传递过去就可以,图片尺寸由程序自主计算。
   
    4. 另外,figdpi 这个变量控制图片的分辨率(解析度),可以随意调大调小。上一篇文章里贴的图使用的 dpi 值是 300。另外,X 轴和 Y 轴上的坐标点也是程序自主决定的。

    ---- 整个脚本还是一个 work-in-progress,目前的局限主要在于使用对数坐标时,Y 轴坐标点的确定。前一篇里所贴的那个图,可以看见价格上限在 20 块左右,如果换一只价格 90 块上下的股票,或者用来画几千点的指数行情,那 Y 轴的坐标点就会太密集。解决办法是根据取值区间来自主选择合适的 Y 轴坐标间距,但是这个目前还没有做。

    ---- 任何意见或建议都许多欢迎 !

 

    ---- <补记>:已经有了大幅改进的版本,在下一篇里。

 

# -*- coding: utf-8 -*-

import sys
import pickle
import math
import datetime
import matplotlib

matplotlib.use("WXAgg", warn=True)	# 这个要紧跟在 import matplotlib 之后,而且必须安装了 wxpython 2.8 才行。

import matplotlib.pyplot as pyplot
import numpy
from matplotlib.ticker import FixedLocator, MultipleLocator, LogLocator, FuncFormatter, NullFormatter, LogFormatter



def Plot(pfile, figpath, useexpo=True):
	'''
	pfile 指明存放绘图数据的 pickle file,figpath 指定图片需存放的路径
	'''

	fileobj= open(name=pfile, mode='rb')
	pdata= pickle.load(fileobj)
	fileobj.close()

	#	计算图片的尺寸(单位英寸)
	#	注意:Python2 里面, "1 / 10" 结果是 0, 必须写成 "1.0 / 10" 才会得到 0.1
	#==================================================================================================================================================
	
	length= len(pdata[u'日期'])		# 所有数据的长度,就是天数

	highest_price= max(pdata[u'最高'])	# 最高价
	lowest_price= min( [plow for plow in pdata[u'最低'] if plow != None] )	# 最低价

	yhighlim_price= round(highest_price+50, -2)	# K线子图 Y 轴最大坐标
	ylowlim_price=  round(lowest_price-50, -2)	# K线子图 Y 轴最小坐标

	xfactor= 10.0/230.0	# 一条 K 线的宽度在 X 轴上所占距离(英寸)
	yfactor= 0.3	# Y 轴上每一个距离单位的长度(英寸),这个单位距离是线性坐标和对数坐标通用的
	
	if useexpo:	# 要使用对数坐标
		expbase= 1.1	# 底数,取得小一点,比较接近 1。股价 3 元到 4 元之间有大约 3 个单位距离
		ymulti_price= math.log(yhighlim_price, expbase)	- math.log(ylowlim_price, expbase)	# 价格在 Y 轴上的 “份数”

	else:
		ymulti_price= (yhighlim_price - ylowlim_price) / 100	# 价格在 Y 轴上的 “份数”
	
	ymulti_vol= 3.0		# 成交量部分在 Y 轴所占的 “份数”
	ymulti_top= 0.2		# 顶部空白区域在 Y 轴所占的 “份数”
	ymulti_bot= 0.8		# 底部空白区域在 Y 轴所占的 “份数”

	xmulti_left= 10.0	# 左侧空白区域所占的 “份数”
	xmulti_right= 3.0	# 右侧空白区域所占的 “份数”

	xmulti_all= length + xmulti_left + xmulti_right
	xlen_fig= xmulti_all * xfactor		# 整个 Figure 的宽度
	ymulti_all= ymulti_price + ymulti_vol + ymulti_top + ymulti_bot
	ylen_fig= ymulti_all * yfactor		# 整个 Figure 的高度
	
	rect_1= (xmulti_left/xmulti_all, (ymulti_bot+ymulti_vol)/ymulti_all, length/xmulti_all, ymulti_price/ymulti_all)	# K线图部分
	rect_2= (xmulti_left/xmulti_all, ymulti_bot/ymulti_all, length/xmulti_all, ymulti_vol/ymulti_all)	# 成交量部分

	#	建立 Figure 对象
	#==================================================================================================================================================
	figfacecolor= 'white'
	figedgecolor= 'black'
	figdpi= 600
	figlinewidth= 1.0

	figobj= pyplot.figure(figsize=(xlen_fig, ylen_fig), dpi=figdpi, facecolor=figfacecolor, edgecolor=figedgecolor, linewidth=figlinewidth)	# Figure 对象

	#==================================================================================================================================================
	#==================================================================================================================================================
	#=======	成交量部分
	#==================================================================================================================================================
	#==================================================================================================================================================

	#	添加 Axes 对象
	#==================================================================================================================================================
	axes_2= figobj.add_axes(rect_2, axis_bgcolor='black')
	axes_2.set_axisbelow(True)	# 网格线放在底层

	#	改变坐标线的颜色
	#==================================================================================================================================================
	for child in axes_2.get_children():
		if isinstance(child, matplotlib.spines.Spine):
			child.set_color('lightblue')

	#	得到 X 轴 和 Y 轴 的两个 Axis 对象
	#==================================================================================================================================================
	xaxis_2= axes_2.get_xaxis()
	yaxis_2= axes_2.get_yaxis()

	#	设置两个坐标轴上的 grid
	#==================================================================================================================================================
	xaxis_2.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	xaxis_2.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)

	yaxis_2.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	yaxis_2.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)



	#==================================================================================================================================================
	#=======	绘图
	#==================================================================================================================================================
	xindex= numpy.arange(length)	# X 轴上的 index,一个辅助数据

	zipoc= zip(pdata[u'开盘'], pdata[u'收盘'])
	up=   numpy.array( [ True if po < pc and po != None else False for po, pc in zipoc] )		# 标示出该天股价日内上涨的一个序列
	down= numpy.array( [ True if po > pc and po != None else False for po, pc in zipoc] )		# 标示出该天股价日内下跌的一个序列
	side= numpy.array( [ True if po == pc and po != None else False for po, pc in zipoc] )		# 标示出该天股价日内走平的一个序列



	volume= pdata[u'成交量']
	rarray_vol= numpy.array(volume)
	volzeros= numpy.zeros(length)	# 辅助数据

	# XXX: 如果 up/down/side 各项全部为 False,那么 vlines() 会报错。
	if True in up:
		axes_2.vlines(xindex[up], volzeros[up], rarray_vol[up], color='red', linewidth=3.0, label='_nolegend_')
	if True in down:
		axes_2.vlines(xindex[down], volzeros[down], rarray_vol[down], color='green', linewidth=3.0, label='_nolegend_')
	if True in side:
		axes_2.vlines(xindex[side], volzeros[side], rarray_vol[side], color='0.7', linewidth=3.0, label='_nolegend_')
	


	#	设定 X 轴坐标的范围 
	#==================================================================================================================================================
	axes_2.set_xlim(-1, length)



	#	设定 X 轴上的坐标
	#==================================================================================================================================================
	datelist= [ datetime.date(int(ys), int(ms), int(ds)) for ys, ms, ds in [ dstr.split('-') for dstr in pdata[u'日期'] ] ]

	# 确定 X 轴的 MajorLocator
	mdindex= []	# 每个月第一个交易日在所有日期列表中的 index
	years= set([d.year for d in datelist])	# 所有的交易年份

	for y in sorted(years):		
		months= set([d.month for d in datelist if d.year == y])		# 当年所有的交易月份
		for m in sorted(months):
			monthday= min([dt for dt in datelist if dt.year==y and dt.month==m])	# 当月的第一个交易日
			mdindex.append(datelist.index(monthday))

	xMajorLocator= FixedLocator(numpy.array(mdindex))

	# 确定 X 轴的 MinorLocator
	wdindex= []	# 每周第一个交易日在所有日期列表中的 index
	for d in datelist:
		if d.weekday() == 0: wdindex.append(datelist.index(d))

	xMinorLocator= FixedLocator(numpy.array(wdindex))

	# 确定 X 轴的 MajorFormatter 和 MinorFormatter
	def x_major_formatter_2(idx, pos=None):
		return datelist[idx].strftime('%Y-%m-%d')

	def x_minor_formatter_2(idx, pos=None):
		return datelist[idx].strftime('%m-%d')

	xMajorFormatter= FuncFormatter(x_major_formatter_2)
	xMinorFormatter= FuncFormatter(x_minor_formatter_2)

	# 设定 X 轴的 Locator 和 Formatter
	xaxis_2.set_major_locator(xMajorLocator)
	xaxis_2.set_major_formatter(xMajorFormatter)

	xaxis_2.set_minor_locator(xMinorLocator)
	xaxis_2.set_minor_formatter(xMinorFormatter)

	# 设定 X 轴主要坐标点与辅助坐标点的样式
	for malabel in axes_2.get_xticklabels(minor=False):
		malabel.set_fontsize(3)
		malabel.set_horizontalalignment('right')
		malabel.set_rotation('30')

	for milabel in axes_2.get_xticklabels(minor=True):
		milabel.set_fontsize(2)
		milabel.set_horizontalalignment('right')
		milabel.set_rotation('30')



	#	设定 Y 轴坐标的范围 
	#==================================================================================================================================================
	maxvol= max(volume)	# 注意是 int 类型
	axes_2.set_ylim(0, maxvol)



	#	设定 Y 轴上的坐标
	#==================================================================================================================================================
	vollen= len(str(maxvol))
	
	yMajorLocator_2= MultipleLocator(10**(vollen-1))
	yMinorLocator_2= MultipleLocator((10**(vollen-2))*5)

	# 确定 Y 轴的 MajorFormatter
	#	def y_major_formatter_2(num, pos=None):
	#		numtable= {'1':u'一', '2':u'二', '3':u'三', '4':u'四', '5':u'五', '6':u'六', '7':u'七', '8':u'八', '9':u'九', }
	#		dimtable= {3:u'百', 4:u'千', 5:u'万', 6:u'十万', 7:u'百万', 8:u'千万', 9:u'亿', 10:u'十亿', 11:u'百亿'}
	#		return numtable[str(num)[0]] + dimtable[vollen] if num != 0 else '0'

	def y_major_formatter_2(num, pos=None):
		return int(num)
	yMajorFormatter_2= FuncFormatter(y_major_formatter_2)

	# 确定 Y 轴的 MinorFormatter
	#	def y_minor_formatter_2(num, pos=None):
	#		return int(num)
	#	yMinorFormatter_2= FuncFormatter(y_minor_formatter_2)
	yMinorFormatter_2= NullFormatter()

	# 设定 X 轴的 Locator 和 Formatter
	yaxis_2.set_major_locator(yMajorLocator_2)
	yaxis_2.set_major_formatter(yMajorFormatter_2)

	yaxis_2.set_minor_locator(yMinorLocator_2)
	yaxis_2.set_minor_formatter(yMinorFormatter_2)

	# 设定 Y 轴主要坐标点与辅助坐标点的样式
	for malab in axes_2.get_yticklabels(minor=False):
		malab.set_fontsize(3)

	for milab in axes_2.get_yticklabels(minor=True):
		milab.set_fontsize(2)



	#==================================================================================================================================================
	#==================================================================================================================================================
	#=======	K 线图部分
	#==================================================================================================================================================
	#==================================================================================================================================================

	#	添加 Axes 对象
	#==================================================================================================================================================
	axes_1= figobj.add_axes(rect_1, axis_bgcolor='black', sharex=axes_2)
	axes_1.set_axisbelow(True)	# 网格线放在底层
	
	if useexpo:
		axes_1.set_yscale('log', basey=expbase)	# 使用对数坐标

	#	改变坐标线的颜色
	#==================================================================================================================================================
	for child in axes_1.get_children():
		if isinstance(child, matplotlib.spines.Spine):
			child.set_color('lightblue')

	#	得到 X 轴 和 Y 轴 的两个 Axis 对象
	#==================================================================================================================================================
	xaxis_1= axes_1.get_xaxis()
	yaxis_1= axes_1.get_yaxis()

	#	设置两个坐标轴上的 grid
	#==================================================================================================================================================
	xaxis_1.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	xaxis_1.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)

	yaxis_1.grid(True, 'major', color='0.3', linestyle='solid', linewidth=0.2)
	yaxis_1.grid(True, 'minor', color='0.3', linestyle='dotted', linewidth=0.1)



	#==================================================================================================================================================
	#=======	绘图
	#==================================================================================================================================================

	#	绘制 K 线部分
	#==================================================================================================================================================
	rarray_open= numpy.array(pdata[u'开盘'])
	rarray_close= numpy.array(pdata[u'收盘'])
	rarray_high= numpy.array(pdata[u'最高'])
	rarray_low= numpy.array(pdata[u'最低'])

	# XXX: 如果 up, down, side 里有一个全部为 False 组成,那么 vlines() 会报错。
	if True in up:
		axes_1.vlines(xindex[up], rarray_low[up], rarray_high[up], color='red', linewidth=0.6, label='_nolegend_')
		axes_1.vlines(xindex[up], rarray_open[up], rarray_close[up], color='red', linewidth=3.0, label='_nolegend_')
	if True in down:
		axes_1.vlines(xindex[down], rarray_low[down], rarray_high[down], color='green', linewidth=0.6, label='_nolegend_')
		axes_1.vlines(xindex[down], rarray_open[down], rarray_close[down], color='green', linewidth=3.0, label='_nolegend_')
	if True in side:
		axes_1.vlines(xindex[side], rarray_low[side], rarray_high[side], color='0.7', linewidth=0.6, label='_nolegend_')
		axes_1.vlines(xindex[side], rarray_open[side], rarray_close[side], color='0.7', linewidth=3.0, label='_nolegend_')

	#	绘制均线部分
	#==================================================================================================================================================
	rarray_1dayave= numpy.array(pdata[u'1日权均'])
	rarray_5dayave= numpy.array(pdata[u'5日均'])
	rarray_30dayave= numpy.array(pdata[u'30日均'])
	
	axes_1.plot(xindex, rarray_1dayave, 'o-', color='white', linewidth=0.1, markersize=0.7, markeredgecolor='white', markeredgewidth=0.1)	# 1日加权均线
	axes_1.plot(xindex, rarray_5dayave, 'o-', color='yellow', linewidth=0.1, markersize=0.7, markeredgecolor='yellow', markeredgewidth=0.1)	# 5日均线
	axes_1.plot(xindex, rarray_30dayave, 'o-', color='green', linewidth=0.1, markersize=0.7, markeredgecolor='green', markeredgewidth=0.1)	# 30日均线

	#	设定 X 轴坐标的范围 
	#==================================================================================================================================================
	axes_1.set_xlim(-1, length)



	#	先设置 label 位置,再将 X 轴上的坐标设为不可见。因为与 成交量子图 共用 X 轴
	#==================================================================================================================================================

	# 设定 X 轴的 Locator 和 Formatter
	xaxis_1.set_major_locator(xMajorLocator)
	xaxis_1.set_major_formatter(xMajorFormatter)

	xaxis_1.set_minor_locator(xMinorLocator)
	xaxis_1.set_minor_formatter(xMinorFormatter)

	# 将 X 轴上的坐标设为不可见。
	for malab in axes_1.get_xticklabels(minor=False):
		malab.set_visible(False)

	for milab in axes_1.get_xticklabels(minor=True):
		milab.set_visible(False)

	# 用这一段效果也一样
	#	pyplot.setp(axes_1.get_xticklabels(minor=False), visible=False)
	#	pyplot.setp(axes_1.get_xticklabels(minor=True), visible=False)



	#	设定 Y 轴坐标的范围 
	#==================================================================================================================================================
	axes_1.set_ylim(ylowlim_price, yhighlim_price)



	#	设定 Y 轴上的坐标
	#==================================================================================================================================================
	
	if useexpo:
		#	主要坐标点
		#-----------------------------------------------------
		yMajorLocator_1= LogLocator(base=expbase)
		
		yMajorFormatter_1= NullFormatter()

		# 设定 X 轴的 Locator 和 Formatter
		yaxis_1.set_major_locator(yMajorLocator_1)
		yaxis_1.set_major_formatter(yMajorFormatter_1)

		# 设定 Y 轴主要坐标点与辅助坐标点的样式
		#	for mal in axes_1.get_yticklabels(minor=False):
		#		mal.set_fontsize(3)

		#	辅助坐标点
		#-----------------------------------------------------
		minorticks= range(int(ylowlim_price), int(yhighlim_price)+1, 100)
		
		yMinorLocator_1= FixedLocator(numpy.array(minorticks))

		# 确定 Y 轴的 MinorFormatter
		def y_minor_formatter_1(num, pos=None):
			return str(num/100.0) + '0'

		yMinorFormatter_1= FuncFormatter(y_minor_formatter_1)

		# 设定 X 轴的 Locator 和 Formatter
		yaxis_1.set_minor_locator(yMinorLocator_1)
		yaxis_1.set_minor_formatter(yMinorFormatter_1)

		# 设定 Y 轴主要坐标点与辅助坐标点的样式
		for mil in axes_1.get_yticklabels(minor=True):
			mil.set_fontsize(3)

	else:	# 如果使用线性坐标,那么只标主要坐标点
		yMajorLocator_1= MultipleLocator(100)

		def y_major_formatter_1(num, pos=None):
			return str(num/100.0) + '0'

		yMajorFormatter_1= FuncFormatter(y_major_formatter_1)

		# 设定 Y 轴的 Locator 和 Formatter
		yaxis_1.set_major_locator(yMajorLocator_1)
		yaxis_1.set_major_formatter(yMajorFormatter_1)

		# 设定 Y 轴主要坐标点与辅助坐标点的样式
		for mal in axes_1.get_yticklabels(minor=False):
			mal.set_fontsize(3)


	#	保存图片
	#==================================================================================================================================================
	figobj.savefig(figpath, dpi=figdpi, facecolor=figfacecolor, edgecolor=figedgecolor, linewidth=figlinewidth)



if __name__ == '__main__':
	Plot(pfile=sys.argv[1], figpath=sys.argv[2], useexpo=True)










 

 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee