我正在绘制一个函数y = a*x^2
,其中 a 是变量常数。我想以交互方式控制 a,但我谷歌了一下,似乎 TikZ 不支持交互式操作。
另外,我想知道是否有任何方法可以在函数内绘制一些点并随机移动?
答案1
实际上,恕我直言,这可以看作是两个不同的问题。
那么,让我们从第一个开始:
我正在绘制一个函数
y = a*x^2
,其中 a 是变量常数。我想以交互方式控制 a,但我谷歌了一下,似乎 TikZ 不支持交互式操作。
我会用这个奇妙的ocgx
包装与pgfplots
;在网站上你已经可以找到一些例子:
代码:
\documentclass{article}
\usepackage{pgfplots}
\usetikzlibrary{ocgx}
\tikzset{ocg button/.style={circle,inner sep=.25em,switch ocg with mark on={#1}{}}}
\tikzset{base/.style={baseline=-0.5ex}}
\newcommand{\function}{\x^2}
\newcommand{\button}[2]{\tikz[base]\node[fill=#2!30,ocg button=#1]{};}
\newcommand{\plotit}[2]{\addplot+[ocg={name=#2,ref=#2}]{#1};\label{#2}}
\newcommand{\legendit}[3]{\item[\ref{#1}] #2$x^2$ \button{#1}{#3}}
\begin{document}
\begin{minipage}[b][0.4\textheight][l]{0.7\textwidth}
\begin{tikzpicture}
\begin{axis}[grid= major,xlabel=$x$,
ylabel =$y$,
ylabel style={rotate=-90},
cycle list={blue,red,green!50!lime,orange,cyan!50!blue},
]
\plotit{\function}{first}
\plotit{1.5*\function}{second}
\plotit{2.25*\function}{third}
\plotit{3*\function}{fourth}
\plotit{5*\function}{fifth}
\end{axis}
\end{tikzpicture}
\end{minipage}%
\begin{minipage}[b][0.5\textheight][c]{0.2\textwidth}
\begin{itemize}
\legendit{first}{}{blue}
\legendit{second}{1.5}{red}
\legendit{third}{2.25}{green!50!lime}
\legendit{fourth}{3}{orange}
\legendit{fifth}{5}{cyan!50!blue}
\end{itemize}
\end{minipage}%
\end{document}
结果(点击第二和第四个按钮):
免责声明
这对我来说在 Evince(Ubuntu 12.10 附带的标准版本)和 Acrobat Reader 下有效。
现在我们来谈谈第二个问题:
另外,我想知道是否有任何方法可以在函数内绘制一些点并随机移动?
为此,我将使用standalone
带有选项的类tikz
,并按顺序将点沿着图放置,并带有设施
node[<some opitons>, pos=<position along the plot>]
其中<position along the plot>
应该是 0 到 1 之间的某个数字。
一个例子:
\documentclass[tikz]{standalone}
\usepackage{pgfplots}
\begin{document}
\foreach \pos in {0,0.05,...,1.05}{
\begin{tikzpicture}
\begin{axis}[grid= major,xlabel=$x$,
ylabel =$y$,
ylabel style={rotate=-90},
no marks,
]
\addplot{\x^2}
node[fill=orange,draw=blue,circle,inner sep=1pt, pos=\pos]{}
;
\end{axis}
\end{tikzpicture}
}
\end{document}
结果:
如果你想要随机点,只需更改里面的列表
\foreach \pos in {0,0.05,...,1.05}
其中改变我的意思是你必须打乱顺序(为了简单起见我没有这样做)。
一条注释:列表以 结束1.05
,但未1
正确显示最终点。
要在图中拥有随机点,基本上有两种方法:第一种方法是通过独立类(在以下答案中有几个例子使用 TikZ 绘制封闭的液滴形曲线),而第二个利用 Beamer 类;其样式定义在使用 TikZ 节点在 Beamer 中突出显示可以根据某些节点出现的时刻来定位它们:这会产生一种随机性。
代码:
\documentclass{beamer}
\usepackage{lmodern}
\usepackage{pgfplots}
\tikzset{
invisible/.style={opacity=0,text opacity=0},
visible on/.style={alt=#1{}{invisible}},
alt/.code args={<#1>#2#3}{%
\alt<#1>{\pgfkeysalso{#2}}{\pgfkeysalso{#3}}
},
}
% https://tex.stackexchange.com/questions/84513/highlighting-in-beamer-using-tikz-nodes/84608#84608
\tikzset{
background filldraw/.style args={#1 and #2}{draw=#1, fill=#2},
background filldraw/.default={white and white},
filldraw on/.style={alt=#1{}{background filldraw}},
}
\begin{document}
\begin{frame}{}
\begin{tikzpicture}
\begin{axis}[grid= major,xlabel=$x$,
ylabel =$y$,
ylabel style={rotate=-90},
no marks,
]
\addplot{\x^2};
\end{axis}
\foreach \pos/\moment in {{(4,4)}/{1,3,5,6},{(2,2)}/{2,3,4,8},
{(1.5,4)}/{2,4,5,7},{(5,3)}/{1,2,3,5,8},{(2.5,1.5)}/{2,4,5,6},
{(1.75,3.5)}/{1,3,6,8},{(3.75,2.5)}/{2,5,7,8},{(3.75,1.25)}/{2,3,4,5,6}}{
\node[circle, inner sep=1.5pt,
background filldraw={blue and orange},
filldraw on=<\moment>] at \pos {};
}
\end{tikzpicture}
\end{frame}
\end{document}
结果:
答案2
真正的交互性(即您可以顺利修改绘制函数的参数)超出了 PDF 标准的可能性。但是,PDF 标准允许将交互元素嵌入文档中,即 RichMedia Annotation,它将显示和用户交互委托给插件。目前只有 AdobeReader 实现了 RichMedia Annotation,它使用 FlashPlayer 来渲染注释区域内的图形材料。
因此,交互式应用程序必须采用 Flash (SWF) 格式。例如,可以使用现在开源的Flex-SDK. 生成的 SWF 可以使用 media9 包嵌入到 PDF 中。
该示例使用了 Flex 的 LineChart 和 HSlider 组件。
\documentclass[12pt]{article}
\usepackage{media9}
\begin{document}
\section{Interactive function plot example}
\begin{equation}
y=a x^2
\end{equation}
\noindent\includemedia[
width=\linewidth,height=1.1\linewidth,
activate=pageopen
]{}{bec.swf}
\end{document}
嵌入的 Flash 文件bec.swf
(按照主题发布者的要求,可视化类似于 Bose-Einstein 凝聚态的东西)是使用Flex-SDK 中的编译器从bec.mxml
下面列出的Flex 源文件编译而来的。mxmlc
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="init();">
<mx:Script><![CDATA[
import mx.collections.ArrayCollection;
import flash.utils.Timer;
import flash.events.TimerEvent;
[Bindable] private var quadFunc:ArrayCollection = new ArrayCollection();
[Bindable] private var atoms:ArrayCollection = new ArrayCollection();
private var xMax:Number=10;
private var yMax:Number=300;
private var updateTimer:Timer;
public function atomPositions(e:TimerEvent):void {
atoms.removeAll();
var yM:Number=aSlider.value*xMax*xMax;
for (var i:Number = 0; i<50; i++){
var y:Number=Math.random()*yM;
var x:Number=(Math.random()*2-1)*Math.sqrt(y/aSlider.value);
atoms.addItem({xPos:x, yPos:y});
}
}
public function change():void {
quadFunc.removeAll();
for (var i:Number = -xMax; i<=xMax; i+=0.1){
var yVal:Number=aSlider.value*i*i;
quadFunc.addItem({xVal:i, yVal:yVal});
}
atomPositions(null);
}
public function init():void {
haxis.minimum=-xMax;
haxis.maximum=xMax;
vaxis.maximum=yMax;
change();
updateTimer = new Timer(50,0);
updateTimer.addEventListener("timer", atomPositions);
updateTimer.start();
}
]]></mx:Script>
<mx:LineChart id="chart" width="100%" height="100%"
showDataTips="true">
<mx:horizontalAxis>
<mx:LinearAxis id="haxis"/>
</mx:horizontalAxis>
<mx:verticalAxis>
<mx:LinearAxis id="vaxis" minimum="-2"/>
</mx:verticalAxis>
<mx:series>
<mx:LineSeries xField="xVal" yField="yVal" form="curve"
dataProvider="{quadFunc}"/>
<mx:PlotSeries xField="xPos" yField="yPos" dataProvider="{atoms}"
itemRenderer="mx.charts.renderers.CircleItemRenderer"/>
</mx:series>
</mx:LineChart>
<mx:HSlider id="aSlider" width="100%"
minimum="0.1" maximum="3" value="0.1"
dataTipPlacement="top"
snapInterval="0.01" tickInterval="0"
labels="[a=0.1,3]"
allowTrackClick="true"
liveDragging="true"
change="change();"/>
</mx:Application>