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}]

 

 

 

 

posted on 2012-08-17 14:03  大宝pku  阅读(2983)  评论(0编辑  收藏  举报

导航