Mathematica Plot對象解析
引言
從一個簡單的問題談起。怎么樣畫這么一個圖像?

恩,Rotate一下應該就可以了
Rotate[Plot[Sin[x], {x, 0, 4 \[Pi]}], 90 Degree]
但是仔細觀察就會發現一個問題了,x軸是反的。怎么辦呢?
想到的一個方法是Scale,把x軸Scale到-1倍就可以了。但列位試試,不論怎么把Scale作用到Plot上都是報錯。以前也曾經試圖把Plot對象和Circle,Point畫在同一個Graphics里面,但是同樣也失敗了。這說明 Plot對象和Point, Line 這些 Graphics Primitives很不同, 因此我們有必要研究一下Plot對象的結構。
探索
首先使用TreeForm查看一個簡單的 Plot[Sin[x],{x,-1,1}]

不難發現結果是以Graphics作為根的,這個很容易理解,畢竟Plot出來的結果既含有坐標軸,又含有標簽,還有數據圖像,肯定是個復雜的Graphics對象,在幫助里也說得很明確,“Plot normally returns Graphics[{Line[...],...}]. ”。因此,我們就不能夠把Plot結果像Disk,Arrow一樣插入到Graphics中,因為它自己本身就是Graphics對象。同時,針對graphics primitive的函數也都不能直接作用在Plot結果上,比如上面提到的Scale。
往下看,Graphics包含了兩個List,前者包含著很多Primitive對象,后者是屬性列表,這和我們平時生成Graphics的方法是一致的,因為它本來就是Graphics嘛。

如上圖,我們只看第一個List。它本身也只包含一個List。再往下一層就可以看到我們的圖線了,處于第三層的List包含了Hue和Line兩個元素。我們試著同時繪制兩條圖線,TreeForm@Plot[{x, Sin[x]}, {x, -1, 1}],會發現新添加的圖線也是處于第三層,第二層依然是只有一個孤零零的List。因此我們就可以知道,為了得到 Plot的圖線數據,只需要把第3層的Line集合提取出來就行了。
Plot[{Sin[x], Cos[x]}, {x, 0, 2 \[Pi]}][[1, 1]] //
Cases[#, Line[___], Infinity] &
使用 Cases, 我們可以提取出以Line開頭的子表達式。
一鼓作氣
至此,我們基本了解Plot結果的大致結構了,Plot可以看作是一種特殊的Graphics求值器,先根據函數式求出散點序列,轉換為Line對象,然后填充到一個Graphics對象里。Plot的那些Axes,Epilog,PlotRange屬性,其實是來自于Graphics而已。如果想要把Plot和Circle放到一起,就不能夠想當然的把Plot放到Graphics里面了,因為Graphics是不支持嵌套的,可行方法有以下幾種
Plot[Sin[x], {x, -1, 1}, Epilog -> Circle[{0, 0}, 0.1]]
Show[Plot[Sin[x], {x, -1, 1}], Graphics[Circle[{0, 0}, 0.1]]]
Graphics[{Circle[{0, 0}, 0.1],
Inset[Plot[Sin[x], {x, -1, 1}], {0, 0}, {0, 0}, {1, 1}]}]
如果只是想獲得Plot圖形的數據,以便進一步處理,直接一層層剝皮即可
Plot[Sin[x], {x, 0, 4 \[Pi]}] // First // First // Last // Last
或者使用模式匹配
Plot[Sin[x], {x, 0, 4 \[Pi]}] // Cases[#, Line[___], Infinity] &
功德圓滿
現在再來畫文章開頭展示的圖片是不是就很簡單了?
a = Plot[Sin[x], {x, -4 \[Pi], 4 \[Pi]}] //
Cases[#, Line[___], Infinity] &;
Graphics[{Blue, Thick, Rotate[a, 90 Degree, {0, 0}]}, Axes -> True,
Ticks -> {{-\[Pi], \[Pi]}, Range[-4 \[Pi], 4 \[Pi], \[Pi]]},
PlotRange -> {{-\[Pi], \[Pi]}, Automatic}]
浙公網安備 33010602011771號