<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 關于本書的編寫 為了編寫此書,我評價了許多寫書的軟件,最終決定使用Sphinx和reStructuredText作為寫書的工具。隨著章節的逐漸增加,我越來越覺得當初的選擇是正確的。 ## 本書的編寫工具 本書采用[reStructuredText](http://docutils.sourceforge.net/rst.html)(rst) 格式的文本編寫,然后用[Sphinx](http://sphinx.pocoo.org)將reStructuredText文件自動轉換為html格式的文件。采用[Leo](http://webpages.charter.net/edreamleo/front.html)管理和組織所有的文檔。用[proTeXt](http://www.tug.org/protext)將latex格式的數學公式轉換為PNG圖片。 * **reStructuredText** : 一種結構化文本格式,它提供了對寫書所需的各種元素的支持。例如章節、鏈接、格式、圖片以及語法高亮等等。 * **Sphinx** : 將一系列reStructuredText文本轉換成各種不同的輸出格式,并自動制作交叉引用(cross-references)、索引等。也就是說,如果某目錄中有一系列的reStructuredText格式的文檔, Sphinx可以制作一份組織得非常完美的HTML文件。 * **Leo** : 以樹狀結構管理文本、代碼的編輯器,可以用它來進行數據組織和項目管理。我使用它管理構成本書的所有rst文檔、python程序以及圖片和筆記。下面是使用Leo編寫本書時的一個例子: > ![](https://box.kancloud.cn/2016-03-19_56ed1bbc096c6.png) > > 編寫本書所使用的Leo編輯器的界面 * **PicPick**, **Greenshot** : 界面截圖工具。 ## 問題與解決方案 在使用上述工具編寫本書時,為了達到完美的效果,我對這些工具做了一些配置和修改的工作。 ### 代碼中的注釋 Sphinx使用Pygments進行代碼高亮的處理,在Pygments的缺省樣式中,代碼注釋部分是采用斜體字表示的,斜體的漢字看起來十分別扭,因此需要將缺省樣式的斜體改為正體。在conf.py文件中有如下配置: ``` # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' ``` 它指定pygments使用sphinx樣式對代碼進行高亮處理,我沒有弄明白如何添加自己定義的樣式,因此直接手工修改定義此樣式的文件: ``` %Python安裝目錄%\Lib\site-packages\sphinx\highlighting.py ``` 將其中的Comment的樣式改為noitalic: ``` ... styles.update({ Generic.Output: '#333', Comment: 'noitalic #408090', Number: '#208050', }) ... ``` ### 修改Sphinx的主題 為了給文檔添加評論功能,必須添加一部分javascript代碼,因此需要修改Shpinx的主題。 * 首先編輯conf.py文件中如下的兩個配置: ``` # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. html_theme = 'pydoc' # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ["./theme"] ``` * 然后在conf.py文件所在的目錄下創建一個子目錄theme,將sphinx安裝目錄下的themes\sphinxdoc文件夾復制到theme文件夾下,并重命名為pydoc,目錄結構如下圖所示: > ![](https://box.kancloud.cn/2016-03-19_56ed1bbc29188.png) > > theme文件夾的結構 * 編輯layout.html文件。此文件是一個模板,Sphinx最終使用此模板生成每個rst文件所對應的html文件。因此我在其中添加了對我自己的css和js文件的引用: ``` <link type="text/css" href="_static/jquery-ui-1.7.2.custom.css" rel="stylesheet" /> <link type="text/css" href="_static/comments.css" rel="stylesheet" /> <script type="text/javascript" src="_static/jquery-ui-1.7.2.custom.min.js"></script> <script type="text/javascript" src="_static/pydoc.js"></script> ``` * 在theme\pydoc\static目錄下添加相應的css和js文件。為了固定html頁面左側的目錄欄,可以配置theme\pydoc\theme.conf中的stickysidebar=True,不過好像IE7.0下無法正常顯示,因此在css文件中添加如下代碼,除了IE6.0以外其它的瀏覽器(Firefox,IE7, Chrome)都能夠正常固定目錄欄: > ``` > div.sphinxsidebar{ > position : fixed; > left : 0px; > top : 30px; > margin-left : 0px !important; > } > > ``` ### 關閉引號自動轉換 在輸出html的時候,如果使用Sphinx缺省的配置,會對引號進行自動轉換:將標準的單引號和雙引號轉換為unicode中的全角引號。為了關閉此項功能,需要編輯 conf.py,進行如下設置: ``` html_use_smartypants = False ``` ### 用latex編寫數學公式 Sphinx支持將latex編寫的數學公式轉換為png圖片。為了在windows下使用latex,我下載了[proTeXt](http://www.tug.org/protext),這個tex軟件包的大小有700M左右,安裝之后占用1.3G。為了告訴Sphinx工具latex的安裝位置,如下修改make.bat文件: ``` %SPHINXBUILD% -D pngmath_latex="..\latex.exe" -b html %ALLSPHINXOPTS% build/html ``` 然后就可以如下使用latex: ``` X_k = \sum_{n=0}^{N-1} x_n e^{-{i 2\pi k \frac{n}{N}}} \qquad k = 0,\dots,N-1. ``` 得到的輸出圖片如下: ![](https://box.kancloud.cn/2016-03-19_56ed1bbc3947e.png) ### Leo的配置 Leo的缺省配置用起來很不習慣:它的樹狀目錄在上方,而且字體很小。下面是對Leo的一些修改和配置: * Leo現在可以使用tk和qt兩個庫。使用tk庫的界面用起來不習慣,因此通過在啟動Leo時添加參數強制使用qt庫的界面:launchLeo.py --gui=qt 。 * 我個人很喜歡微軟雅黑的漢字字體,但是由于雅黑字體的英文不是等寬的,因此用它來編輯代碼的話就很不爽了。于是上網找到了一個雅黑和Consolas的復合字體: > YaHei Mono字體下載地址: [http://hyry.dip.jp/files/yahei_mono.7z](http://hyry.dip.jp/files/yahei_mono.7z) * 復制一份leo\config\leoSettings.leo到同一目錄,改名為myLeoSettings.leo。用Leo編輯此文件,在目錄樹中找到節點:qtGui plugin--&gt;@data qt-gui-plugin-style-sheet,修改此樣式表中的字體的定義,使用新安裝的Yahei Mono字體。 > ``` > QTextEdit#richTextEdit { > ... > font-family: Yahei Mono; > font-size: 17px; > ... > } > > ``` * 修改@settings--&gt;Window--&gt;@string initial_split_orientation節點和@settings--&gt;Window--&gt;Options for new windows--&gt;@strings[vertical,horizontal] initial_splitter_orientation節點的值為horizontal。這樣目錄樹和編輯框就是左右分欄的了。 * 在Leo中用@auto-rst輸出rst文件時,會自動的將目錄樹中的節點名轉換為rst文件中的標題。在rst中標題都是由下劃線標出的。下劃線的長度要求和文本的長度一致。由于Leo采用unicode表示文本,因此漢字的長度為1,但是rst編譯器似乎要求漢字的長度為2,因此對于 **Leo的配置** 這樣的標題,rst要求用9個下劃線符號標識,而Leo只用6個,造成在編譯時出現許多警告信息,為了解決這個問題,編輯leo\core\leoRst.py文件中的underline函數如下,并且將其后的所有len(s)都改為len(ss): ``` def underline (self,s,p): ... try: ss = s.encode("gbk") except: try: ss = s.encode("shiftjis") except: ss = s trace = False and not g.unitTesting ... ``` ### 讓Matplotlib顯示中文 將中文字體文件復制到: ``` %PythonPath%\Lib\site-packages\matplotlib\mpl-data\fonts\ttf\ ``` 下,這里以上一節介紹的Yahei Mono字體為例。 找到Matplotlib的配置文件matplotlibrc,全局配置文件的路徑: ``` %PythonPath%\Lib\site-packages\matplotlib\mpl-data\matplotlibrc ``` 用戶配置文件路徑: ``` c:\Documents and Settings\%UserName%\.matplotlib\matplotlibrc ``` 用文本編輯器打開此文件,進行如下編輯: * 找到設置font.family的行,改為font.family : monospace,注意去掉前面的#號。 * 在下面添加一行:font.monospace : Yahei Mono。 在matplotlib中使用中文字符串時記住要用unicode格式,例如:u"測試中文顯示"。 ### 用Matplotlib生成圖片 matplotlib提供了一個Sphinx的擴展插件,可以使用..plot命令自動生成圖片。可是這個插件生成的圖片的路徑和本書所采用的路徑不符合,無法在HTML文件中顯示最終生成的圖。因此我直接復制下面兩個文件: ``` c:\Python26\Lib\site-packages\matplotlib\sphinxext\plot_directive.py c:\Python26\Lib\site-packages\matplotlib\sphinxext\only_directives.py ``` 到sourceexts下,命名為plot_directive.py。然后編輯conf.py,修改下面兩行: ``` sys.path.append(os.path.abspath('exts')) extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.pngmath', 'plot_directive'] ``` 這樣就可以載入extsplot_directive.py擴展插件了。然后編輯plot_directive.py文件,使得它的輸出符合本書的路徑,并且除去大圖和PDF輸出。 在rst文件中使用: ``` import matplotlib.pyplot as plt import numpy as np x = np.random.randn(1000) plt.hist( x, 20) plt.grid() plt.title(r'Normal: $\mu=%.2f, \sigma=%.2f$'%(x.mean(), x.std())) plt.show() ``` ![](https://box.kancloud.cn/2016-03-19_56ed1bbc49a9a.png) ### 用Graphviz繪圖 Sphinx可以調用Graphviz繪制流程圖,首先下載Graphviz的Windows安裝包進行安裝,假設安裝目錄為c:\graphviz。 Graphviz的下載地址: [http://www.graphviz.org](http://www.graphviz.org) 編輯conf.py配置文件,在 extensions 列表定義的最后添加一項:'sphinx.ext.graphviz'。 如下編輯make.bat文件,配置dot.exe的執行路徑: ``` .. graphviz:: digraph GraphvizDemo{ node [fontname="Yahei Mono" shape="rect"]; edge [fontname="Yahei Mono" fontsize=10]; node1[label="開始"]; node2[label="正常"]; node1->node2[label="測試"]; } ``` 輸出圖為: ![digraph GraphvizDemo{ node [fontname="Yahei Mono" shape="rect"]; edge [fontname="Yahei Mono" fontsize=10]; node1[label="開始"]; node2[label="正常"]; node1-&gt;node2[label="測試"]; }](img/graphviz-691597b9de6125817b93aaad942bf30f1e3d5346.png) ### 制作CHM文檔 Sphinx支持輸出為CHM文檔格式,只需要運行make htmlhelp即可。但是此命令輸出的目錄文件(擴展名為.hhc),卻不支持中文。為了解決這個問題,我進行了如下修改: * sphinx的安裝目錄下找到buildershtmlhelp.py,將其復制一份,改名為htmlhelpcn.py。輸出CHM文檔的程序都在這里面。 * 修改builders\_\_init\_\_.py文件,在其最后的BUILTIN_BUILDERS字典定義中添加一行: > ``` > 'htmlhelpcn': ('htmlhelpcn', 'HTMLHelpBuilder') > > ``` * 修改make.bat文件,在其中添加: > ``` > if "%1" == "htmlhelpcn" ( > %SPHINXBUILD% -b htmlhelpcn %ALLSPHINXOPTS% build/htmlhelpcn > echo. > echo.Build finished; now you can run HTML Help Workshop with the ^ > .hhp project file in build/htmlhelpcn. > goto end > ) > > ``` * 編輯htmlhelpcn.py文件,找到project_template字符串的定義,修改其中的Language定義為Language=0x804。 * 反復運行make.bat htmlhelpcn命令,根據輸出的錯誤提示修改htmlhelpcn.py,將其中幾處編碼錯誤的地方都添加.encode("gb2312")。其中有一處: > ``` > f.write(item.encode('ascii', 'xmlcharrefreplace')) > > # 改為--&gt; > > f.write(item.encode('gb2312')) > > ``` * 如果在rst文檔中給圖片添加了中文說明的話,有可能輸出的CHM文件中看不到圖片。 * make.bat htmlhelpcn正常運行之后,運行下面的命令輸出制作CHM文件: > ``` > "C:\Program Files\HTML Help Workshop\hhc.exe" htmlhelpcn\scipydoc.hhp > > ``` ### CHM中嵌入Flash動畫 用如下的reStructuredText的 raw 指令可以在html中嵌入Flash動畫: ``` <OBJECT CLASSID="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" WIDTH="589" HEIGHT="447" CODEBASE="http://active.macromedia.com/flash5/cabs/swflash.cab#version=7,0,0,0"> <PARAM NAME="movie" VALUE="img/fft_study_04.swf"> <PARAM NAME="play" VALUE="true"> <PARAM NAME="loop" VALUE="false"> <PARAM NAME="wmode" VALUE="transparent"> <PARAM NAME="quality" VALUE="high"> <EMBED SRC="img/fft_study_04.swf" width="589" HEIGHT="447" quality="high" loop="false" wmode="transparent" TYPE="application/x-shockwave-flash" PLUGINSPAGE= "http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"> </EMBED> </OBJECT> ``` 由于Html Help Workshop不會將swf文件打包進CHM,因此CHM中看不到flash動畫,只需要在嵌入flash動畫的html之后添加一條: ``` <img src="img/fft_study_04.swf" style="visibility:hidden"/> ``` 這樣Html Help Workshop就會把fft_study_04.swf文件添加進去,由于使用隱藏的CSS,頁面中也不會把它當作圖片顯示出來。 ### 制作PDF文檔 調用make latex命令可以輸出為latex格式的文件,然后調用 xelatex scipydoc.tex 即可將其轉換為PDF文件,xelatex是proTeXt自帶的命令。制作PDF文檔時同樣有中文無法顯示的問題,按照以下步驟解決: * 編輯文檔的配置文件conf.py,在最后的 Options for LaTeX output 定義處,添加如下代碼,這段文字將添加到最終輸出的tex文件中,這里的Yahei Mono可以修改為你想要的中文字體名: ``` latex_preamble = r""" \usepackage{float} \textwidth 6.5in \oddsidemargin -0.2in \evensidemargin -0.2in \usepackage{ccaption} \usepackage{fontspec,xunicode,xltxtra} \setsansfont{Microsoft YaHei} \setromanfont{Microsoft YaHei} \setmainfont{Microsoft YaHei} \setmonofont{Yahei Mono} \XeTeXlinebreaklocale "zh" \XeTeXlinebreakskip = 0pt plus 1pt \renewcommand{\baselinestretch}{1.3} \setcounter{tocdepth}{3} \captiontitlefont{\small\sffamily} \captiondelim{ - } \renewcommand\today{\number\year年\number\month月\number\day日} \makeatletter \renewcommand*\l@subsection{\@dottedtocline{2}{2.0em}{4.0em}} \renewcommand*\l@subsubsection{\@dottedtocline{3}{3em}{5em}} \makeatother \titleformat{\chapter}[display] {\bfseries\Huge} {\filleft \Huge 第 \hspace{2 mm} \thechapter \hspace{4 mm} 章} {4ex} {\titlerule \vspace{2ex}% \filright} [\vspace{2ex}% \titlerule] %\definecolor{VerbatimBorderColor}{rgb}{0.2,0.2,0.2} \definecolor{VerbatimColor}{rgb}{0.95,0.95,0.95} """.decode("utf-8") ``` 通過renewcommand命令將輸出的PDF文檔中的一部分英文修改為中文。 不知何故,在latex_preamble中添加修改插圖標題前綴的命令沒有作用,因此通過下面的命令在正文中添加轉換前綴的renewcommand: ``` .. raw:: latex \renewcommand\partname{部分} \renewcommand{\chaptermark}[1]{\markboth{第 \thechapter\ 章 \hspace{4mm} #1}{}} \fancyhead[LE,RO]{用Python做科學計算} \renewcommand{\figurename}{\textsc{圖}} ``` * 調整conf.py中的其它選項: > ``` > latex_paper_size = 'a4' > latex_font_size = '11pt' > latex_use_modindex = False > > ``` * 運行下面的命令輸出PDF文檔,使用nonstopmode,即使出現錯誤也不暫停運行。 > ``` > xelatex -interaction=nonstopmode scipydoc.tex > > ``` 還有一些latex配置沒有找到如何使用reStructuredText進行設置,因此寫了一個Python的小程序讀取輸出的tex文件,替換其中的一些latex命令: * 將begin{figure}[htbp]改為begin{figure}[H},這樣能保證圖和文字保持tex中的前后關系,而不會對圖進行自動排版 * 在\tableofcontents之前添加\renewcommand\contentsname{目 錄},將目錄標題的英文改為中文,此段配置在latex_preamble中定義無效 ### 添加PDF封面 使用作圖軟件設計封面圖片之后,使用圖片轉PDF工具將其轉換為一個只有一頁的PDF文檔cover.pdf: 圖片轉PDF工具下載地址: [http://www.softinterface.com](http://www.softinterface.com) 然后使用PDF合并工具將cover.pdf和正文的PDF文件進行合并。我在網絡上找了很久,終于找到了下面這個能夠維持內部鏈接和書簽的免費的合并工具: PDF工具PDFsam下載地址: [http://www.pdfsam.org](http://www.pdfsam.org) PDFsam提供了界面和命令行方式,界面方式很容易使用,但是為了一個批處理產生最終PDF文檔我需要使用命令行方式,下面是使用命令行進行PDF文檔合并的批處理程序: ``` set MERGE=java -jar "c:\Program Files\pdfsam\lib\pdfsam-console-2.2.0e.jar" %MERGE% -f cover.pdf -f scipydoc.pdf -o %CD%\scipydoc2.pdf concat ``` * -f參數指定輸入的PDF文件名 * -o參數指定輸出的PDF文件名,注意必須使用絕對路徑,因此這里使用%CD%將相對路徑轉換為絕對路徑。 ### 輸出打包的批處理 下面是同時輸出zip, chm, pdf文件的批處理命令: ``` rename html scipydoc "c:\Program Files\7-Zip\7z.exe" a scipydoc.zip scipydoc rename scipydoc html "C:\Program Files\HTML Help Workshop\hhc.exe" htmlhelpcn\scipydoc.hhp copy htmlhelpcn\scipydoc.chm . /y cd latex xelatex -interaction=nonstopmode scipydoc.tex cd .. copy latex\scipydoc.pdf . /y ``` ### HTML的中文搜索 由于Sphinx不懂中文分詞,因此它所生成的搜索索引文件searchindex.js中的中文單詞分的不正確。為了修正這個問題,我寫了一個Sphinx擴展chinese_search.py,使用中文分詞庫smallseg生成索引文件中的中文單詞。 smallseg中文分詞庫地址: [http://code.google.com/p/smallseg](http://code.google.com/p/smallseg) 下面是這個擴展的完整源程序: ``` from os import path import re import cPickle as pickle from docutils.nodes import comment, Text, NodeVisitor, SkipNode from sphinx.util.stemmer import PorterStemmer from sphinx.util import jsdump, rpartition from smallseg import SEG DEBUG = False word_re = re.compile(r'\w+(?u)') stopwords = set(""" a and are as at be but by for if in into is it near no not of on or such that the their then there these they this to was will with """.split()) if DEBUG: testfile = file("testfile.txt", "wb") class _JavaScriptIndex(object): """ The search index as javascript file that calls a function on the documentation search object to register the index. """ PREFIX = 'Search.setIndex(' SUFFIX = ')' def dumps(self, data): return self.PREFIX + jsdump.dumps(data) + self.SUFFIX def loads(self, s): data = s[len(self.PREFIX):-len(self.SUFFIX)] if not data or not s.startswith(self.PREFIX) or not \ s.endswith(self.SUFFIX): raise ValueError('invalid data') return jsdump.loads(data) def dump(self, data, f): f.write(self.dumps(data)) def load(self, f): return self.loads(f.read()) js_index = _JavaScriptIndex() class Stemmer(PorterStemmer): """ All those porter stemmer implementations look hideous. make at least the stem method nicer. """ def stem(self, word): word = word.lower() return word #return PorterStemmer.stem(self, word, 0, len(word) - 1) class WordCollector(NodeVisitor): """ A special visitor that collects words for the `IndexBuilder`. """ def __init__(self, document): NodeVisitor.__init__(self, document) self.found_words = [] def dispatch_visit(self, node): if node.__class__ is comment: raise SkipNode if node.__class__ is Text: words = seg.cut(node.astext().encode("utf8")) words.reverse() self.found_words.extend(words) class IndexBuilder(object): """ Helper class that creates a searchindex based on the doctrees passed to the `feed` method. """ formats = { 'jsdump': jsdump, 'pickle': pickle } def __init__(self, env): self.env = env self._stemmer = Stemmer() # filename -> title self._titles = {} # stemmed word -> set(filenames) self._mapping = {} # desctypes -> index self._desctypes = {} def load(self, stream, format): """Reconstruct from frozen data.""" if isinstance(format, basestring): format = self.formats[format] frozen = format.load(stream) # if an old index is present, we treat it as not existing. if not isinstance(frozen, dict): raise ValueError('old format') index2fn = frozen['filenames'] self._titles = dict(zip(index2fn, frozen['titles'])) self._mapping = {} for k, v in frozen['terms'].iteritems(): if isinstance(v, int): self._mapping[k] = set([index2fn[v]]) else: self._mapping[k] = set(index2fn[i] for i in v) # no need to load keywords/desctypes def dump(self, stream, format): """Dump the frozen index to a stream.""" if isinstance(format, basestring): format = self.formats[format] format.dump(self.freeze(), stream) def get_modules(self, fn2index): rv = {} for name, (doc, _, _, _) in self.env.modules.iteritems(): if doc in fn2index: rv[name] = fn2index[doc] return rv def get_descrefs(self, fn2index): rv = {} dt = self._desctypes for fullname, (doc, desctype) in self.env.descrefs.iteritems(): if doc not in fn2index: continue prefix, name = rpartition(fullname, '.') pdict = rv.setdefault(prefix, {}) try: i = dt[desctype] except KeyError: i = len(dt) dt[desctype] = i pdict[name] = (fn2index[doc], i) return rv def get_terms(self, fn2index): rv = {} for k, v in self._mapping.iteritems(): if len(v) == 1: fn, = v if fn in fn2index: rv[k] = fn2index[fn] else: rv[k] = [fn2index[fn] for fn in v if fn in fn2index] return rv def freeze(self): """Create a usable data structure for serializing.""" filenames = self._titles.keys() titles = self._titles.values() fn2index = dict((f, i) for (i, f) in enumerate(filenames)) return dict( filenames=filenames, titles=titles, terms=self.get_terms(fn2index), descrefs=self.get_descrefs(fn2index), modules=self.get_modules(fn2index), desctypes=dict((v, k) for (k, v) in self._desctypes.items()), ) def prune(self, filenames): """Remove data for all filenames not in the list.""" new_titles = {} for filename in filenames: if filename in self._titles: new_titles[filename] = self._titles[filename] self._titles = new_titles for wordnames in self._mapping.itervalues(): wordnames.intersection_update(filenames) def feed(self, filename, title, doctree): """Feed a doctree to the index.""" self._titles[filename] = title visitor = WordCollector(doctree) doctree.walk(visitor) def add_term(word, prefix='', stem=self._stemmer.stem): word = stem(word) word = word.strip(u"!@#$%^&*()_+-*/\\\";,.[]{}<>") if len(word) <= 1: return if word.encode("utf8").isalpha() and len(word) < 3: return if word.isdigit(): return if word in stopwords: return try: float(word) return except: pass if DEBUG: testfile.write("%s\n" % word.encode("utf8")) self._mapping.setdefault(prefix + word, set()).add(filename) words = seg.cut(title.encode("utf8")) for word in words: add_term(word) for word in visitor.found_words: add_term(word) def load_indexer(self): def func(docnames): print "############### CHINESE INDEXER ###############" self.indexer = IndexBuilder(self.env) keep = set(self.env.all_docs) - set(docnames) try: f = open(path.join(self.outdir, self.searchindex_filename), 'rb') try: self.indexer.load(f, self.indexer_format) finally: f.close() except (IOError, OSError, ValueError): if keep: self.warn('search index couldn\'t be loaded, but not all ' 'documents will be built: the index will be ' 'incomplete.') # delete all entries for files that will be rebuilt self.indexer.prune(keep) return func def builder_inited(app): if app.builder.name == 'html': print "****************************" global seg seg = SEG() app.builder.load_indexer = load_indexer(app.builder) def setup(app): app.connect('builder-inited', builder_inited) ``` ### PDF的頁碼和圖編號參照 Sphinx生成的tex文件沒有使用\label和\ref進行編號引用,而是生成一些鏈接,這些鏈接雖然方便電子版的閱讀,可是打印出來之后就毫無用處了,因此我寫了一個擴展latex_ref.py為最終生成的PDF添加編號引用功能,這個擴展添加了三個role:tlabel, tref, tpageref,分別對應tex的\label, \ref, \pageref。 下面是完整的源程序: ``` # -*- coding: utf-8 -*- from docutils import nodes, utils class tref(nodes.Inline, nodes.TextElement): pass class tlabel(nodes.Inline, nodes.TextElement): pass class tpageref(nodes.Inline, nodes.TextElement): pass def tref_role(role, rawtext, text, lineno, inliner, options={}, content=[]): data = text.split(",") if u"圖" in data[0]: name = u"圖" pos = data[0][0] ref = data[1] return [tref(name=name, ref=ref, pos=pos)], [] return [],[] def tlabel_role(role, rawtext, text, lineno, inliner, options={}, content=[]): return [tlabel(latex=text)], [] def tpageref_role(role, rawtext, text, lineno, inliner, options={}, content=[]): return [tpageref(latex=text)], [] def latex_visit_ref(self, node): self.body.append(r"%s\ref{%s}" % (node['name'], node['ref'])) raise nodes.SkipNode def html_visit_ref(self, node): self.body.append(r'<a href="#%s">%s%s</a>' % (node['ref'], node['pos'], node['name'])) raise nodes.SkipNode def latex_visit_label(self, node): self.body.append(r"\label{%s}" % node['latex']) raise nodes.SkipNode def latex_visit_pageref(self, node): self.body.append(r"\pageref{%s}" % node['latex']) raise nodes.SkipNode def empty_visit(self, node): raise nodes.SkipNode def setup(app): app.add_node(tref,latex=(latex_visit_ref, None),text=(empty_visit, None),html=(html_visit_ref, None)) app.add_node(tlabel,latex=(latex_visit_label, None),text=(empty_visit, None),html=(empty_visit, None)) app.add_node(tpageref,latex=(latex_visit_pageref, None),text=(empty_visit, None),html=(empty_visit, None)) app.add_role('tref', tref_role) app.add_role('tlabel', tlabel_role) app.add_role('tpageref', tpageref_role) ``` ## ReST使用心得 ### 添加圖的編號和標題 使用figure命令插入帶編號和標題的插圖: ``` .. _pythonxyhome: .. figure:: images/pythonxy_home.png Python(x,y)的啟動畫面 ``` ### PDF文字包圍圖片 當給figure添加figwidth和align屬性之后,在生成的latex文檔中,將使用wrapfigure生成圖。為了和前面的段落之間添加一個換行符,使用一個斜杠空格。 ``` .. literalinclude:: examples/tvtk_cone.example.py .. literalinclude:: example.c :language: c ``` ## 未解決的問題 **數學公式輸出不正確** 有時候數學公式的輸出不正確,某些數學符號不能顯示,可是多試幾次之后就正常了,不知道是什么原因。 **Leo不能配置目錄樹和編輯框的寬度比例** 每次Leo開啟之后目錄樹和編輯框的寬度是相等的,看上去很不協調。而且修改mySettings.leo中的相關配置也不能解決,不明白是什么問題。目前的解決方法是添加兩個工具按鈕:show-tree和hide-tree,這樣點擊一下show-tree就會將目錄樹和編輯框改為1:3的比例;而點擊hide-tree則能隱藏目錄樹: ``` # -*- coding: utf-8 -*- from enthought.traits.api import \ Str, Float, HasTraits, Property, cached_property, Range, Instance, on_trait_change, Enum from enthought.chaco.api import Plot, AbstractPlotData, ArrayPlotData, VPlotContainer from enthought.traits.ui.api import \ Item, View, VGroup, HSplit, ScrubberEditor, VSplit from enthought.enable.api import Component, ComponentEditor from enthought.chaco.tools.api import PanTool, ZoomTool import numpy as np # 鼠標拖動修改值的控件的樣式 scrubber = ScrubberEditor( hover_color = 0xFFFFFF, active_color = 0xA0CD9E, border_color = 0x808080 ) # 取FFT計算的結果freqs中的前n項進行合成,返回合成結果,計算loops個周期的波形 def fft_combine(freqs, n, loops=1): length = len(freqs) * loops data = np.zeros(length) index = loops * np.arange(0, length, 1.0) / length * (2 * np.pi) for k, p in enumerate(freqs[:n]): if k != 0: p *= 2 # 除去直流成分之外,其余的系數都*2 data += np.real(p) * np.cos(k*index) # 余弦成分的系數為實數部 data -= np.imag(p) * np.sin(k*index) # 正弦成分的系數為負的虛數部 return index, data class TriangleWave(HasTraits): # 指定三角波的最窄和最寬范圍,由于Range似乎不能將常數和traits名混用 # 所以定義這兩個不變的trait屬性 low = Float(0.02) hi = Float(1.0) # 三角波形的寬度 wave_width = Range("low", "hi", 0.5) # 三角波的頂點C的x軸坐標 length_c = Range("low", "wave_width", 0.5) # 三角波的定點的y軸坐標 height_c = Float(1.0) # FFT計算所使用的取樣點數,這里用一個Enum類型的屬性以供用戶從列表中選擇 fftsize = Enum( [(2**x) for x in range(6, 12)]) # FFT頻譜圖的x軸上限值 fft_graph_up_limit = Range(0, 400, 20) # 用于顯示FFT的結果 peak_list = Str # 采用多少個頻率合成三角波 N = Range(1, 40, 4) # 保存繪圖數據的對象 plot_data = Instance(AbstractPlotData) # 繪制波形圖的容器 plot_wave = Instance(Component) # 繪制FFT頻譜圖的容器 plot_fft = Instance(Component) # 包括兩個繪圖的容器 container = Instance(Component) # 設置用戶界面的視圖, 注意一定要指定窗口的大小,這樣繪圖容器才能正常初始化 view = View( HSplit( VSplit( VGroup( Item("wave_width", editor = scrubber, label=u"波形寬度"), Item("length_c", editor = scrubber, label=u"最高點x坐標"), Item("height_c", editor = scrubber, label=u"最高點y坐標"), Item("fft_graph_up_limit", editor = scrubber, label=u"頻譜圖范圍"), Item("fftsize", label=u"FFT點數"), Item("N", label=u"合成波頻率數") ), Item("peak_list", style="custom", show_label=False, width=100, height=250) ), VGroup( Item("container", editor=ComponentEditor(size=(600,300)), show_label = False), orientation = "vertical" ) ), resizable = True, width = 800, height = 600, title = u"三角波FFT演示" ) # 創建繪圖的輔助函數,創建波形圖和頻譜圖有很多類似的地方,因此單獨用一個函數以 # 減少重復代碼 def _create_plot(self, data, name, type="line"): p = Plot(self.plot_data) p.plot(data, name=name, title=name, type=type) p.tools.append(PanTool(p)) zoom = ZoomTool(component=p, tool_mode="box", always_on=False) p.overlays.append(zoom) p.title = name return p def __init__(self): # 首先需要調用父類的初始化函數 super(TriangleWave, self).__init__() # 創建繪圖數據集,暫時沒有數據因此都賦值為空,只是創建幾個名字,以供Plot引用 self.plot_data = ArrayPlotData(x=[], y=[], f=[], p=[], x2=[], y2=[]) # 創建一個垂直排列的繪圖容器,它將頻譜圖和波形圖上下排列 self.container = VPlotContainer() # 創建波形圖,波形圖繪制兩條曲線: 原始波形(x,y)和合成波形(x2,y2) self.plot_wave = self._create_plot(("x","y"), "Triangle Wave") self.plot_wave.plot(("x2","y2"), color="red") # 創建頻譜圖,使用數據集中的f和p self.plot_fft = self._create_plot(("f","p"), "FFT", type="scatter") # 將兩個繪圖容器添加到垂直容器中 self.container.add( self.plot_wave ) self.container.add( self.plot_fft ) # 設置 self.plot_wave.x_axis.title = "Samples" self.plot_fft.x_axis.title = "Frequency pins" self.plot_fft.y_axis.title = "(dB)" # 改變fftsize為1024,因為Enum的默認缺省值為枚舉列表中的第一個值 self.fftsize = 1024 # FFT頻譜圖的x軸上限值的改變事件處理函數,將最新的值賦值給頻譜圖的響應屬性 def _fft_graph_up_limit_changed(self): self.plot_fft.x_axis.mapper.range.high = self.fft_graph_up_limit def _N_changed(self): self.plot_sin_combine() # 多個trait屬性的改變事件處理函數相同時,可以用@on_trait_change指定 @on_trait_change("wave_width, length_c, height_c, fftsize") def update_plot(self): # 計算三角波 global y_data x_data = np.arange(0, 1.0, 1.0/self.fftsize) func = self.triangle_func() # 將func函數的返回值強制轉換成float64 y_data = np.cast["float64"](func(x_data)) # 計算頻譜 fft_parameters = np.fft.fft(y_data) / len(y_data) # 計算各個頻率的振幅 fft_data = np.clip(20*np.log10(np.abs(fft_parameters))[:self.fftsize/2+1], -120, 120) # 將計算的結果寫進數據集 self.plot_data.set_data("x", np.arange(0, self.fftsize)) # x坐標為取樣點 self.plot_data.set_data("y", y_data) self.plot_data.set_data("f", np.arange(0, len(fft_data))) # x坐標為頻率編號 self.plot_data.set_data("p", fft_data) # 合成波的x坐標為取樣點,顯示2個周期 self.plot_data.set_data("x2", np.arange(0, 2*self.fftsize)) # 更新頻譜圖x軸上限 self._fft_graph_up_limit_changed() # 將振幅大于-80dB的頻率輸出 peak_index = (fft_data > -80) peak_value = fft_data[peak_index][:20] result = [] for f, v in zip(np.flatnonzero(peak_index), peak_value): result.append("%s : %s" %(f, v) ) self.peak_list = "\n".join(result) # 保存現在的fft計算結果,并計算正弦合成波 self.fft_parameters = fft_parameters self.plot_sin_combine() # 計算正弦合成波,計算2個周期 def plot_sin_combine(self): index, data = fft_combine(self.fft_parameters, self.N, 2) self.plot_data.set_data("y2", data) # 返回一個ufunc計算指定參數的三角波 def triangle_func(self): c = self.wave_width c0 = self.length_c hc = self.height_c def trifunc(x): x = x - int(x) # 三角波的周期為1,因此只取x坐標的小數部分進行計算 if x >= c: r = 0.0 elif x < c0: r = x / c0 * hc else: r = (c-x) / (c-c0) * hc return r # 用trifunc函數創建一個ufunc函數,可以直接對數組進行計算, 不過通過此函數 # 計算得到的是一個Object數組,需要進行類型轉換 return np.frompyfunc(trifunc, 1, 1) if __name__ == "__main__": triangle = TriangleWave() triangle.configure_traits() ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看