在Lu脚本中绘制普通XY图(折线图)
目 录
1 基础知识 | 绘制普通XY图的基础知识。 |
2 绘制多条函数曲线 | 需要自己双击窗口,或者单击右键,弹出菜单设置曲线的各种属性。 |
3 绘制多条函数曲线并用代码设置部分属性 | 多次绘制同一图形时,用代码设置属性是方便的。 |
4 用键盘动态改变绘图范围 | ←:向左移动;→:向右移动;↑:范围扩大;↓:范围缩小;Home:复原。 |
5 多线程交互动态显示数据 | 可用于数据的动态采集及显示。 |
6 由内部计时器控制的动画 | 可用于动态显示函数图形。 |
7 设置XY坐标轴范围与数据范围相同 | 设置X坐标轴或Y坐标轴范围与数据范围相同,不向两端扩展。 |
8 绘制散点图或者设置曲线点标记 | 绘制散点图或者设置曲线点标记。 |
1 基础知识
普通XY图是最常用的2D图形,绘制普通XY图的程序结构如下:
!!!using("win","math"); //使用命名空间win和math。win是必须的,而math是多数情况下要用到的。
init(... ...) = //定义初始化函数init,函数参数根据需要设置。
{
cwAttach(typeXY), //函数cwAttach用于设置图像类型,typeXY表示普通XY图。参数typeXY可以缺省,另外函数cwAttach也可以缺省,默认都是普通XY图。
... ... //添加初始化数据或属性。
};
ChartWnd[@init]; //显示窗口并调用函数init进行初始化。
由于图形数据多是数组形式,故需要学习几个来自命名空间math的数学函数 ,这些函数在绘制其他类型图像时也经常用到:
linspace(a,b,n)或者linspace(a,b,x):该函数产生一个一维数组。a、b、x为实数,n为整数。a和b是数组的第一个和最后一个元素,元素总数是n。或者,a是第一个元素,后面的元素按x递增,最后一个元素不超过b。
ra1[2, 3.5, -5]:该函数申请一维数组并初始化。
matrix(m,n:x11,x12,... ...)或者matrix(str):申请m×n矩阵并初始化。
m,n:矩阵的行和列。初始化数据
x11,x12,...,x1n,x21,x22,...,x2n,... ...,xm1,xm2,...,xmn
可以缺省部分及全部,多余的数据被忽略。
str:字符串,包含矩阵数据,数据之间可以用空格或逗号分隔。此时,将自动确定矩阵的行和列。例如以下是一个2×3矩阵字符串:
"1 1.2 3,
2.2 3, 5"
2 绘制多条函数曲线
!!!using("win","math");
init(x,k) =
{
x=linspace[-8.0, 8.0, 0.2],
k=len(x), //函数len可获得x的长度
cwAddCurve{x, sin(x), k},
cwAddCurve{x, x-sin(x), k},
cwAddCurve{x, x.*sin(x), k}
};
ChartWnd[@init];
作为重要的练习,你可以通过双击窗口,或者单击右键,弹出菜单设置曲线的各种属性如下图的样式:
!!!using("win","math");
init(x,k,k1,k2,k3) =
{
x=linspace[-8.0, 8.0, 0.2],
k=len(x),
k1=cwAddCurve{x, sin(x), k}, //函数cwAddCurve返回曲线的idData(曲线的唯一标识)
k2=cwAddCurve{x, x-sin(x), k},
k3=cwAddCurve{x, x.*sin(x), k},
cwSetTitle["自动设置绘图属性的例子"], //设置主标题。
cwSetUseLegend(true), //使用图例
cwSetDataTitle["曲线1",cwGetIndex(k1)], //函数cwSetDataTitle设置图例,函数cwGetIndex从曲线的idData(曲线的唯一标识)获得曲线的序号nIndex(序号是连续的)
cwSetDataTitle["曲线2",cwGetIndex(k2)],
cwSetDataTitle["曲线3",cwGetIndex(k3)],
cwSetAxisTitle("X轴", 1), cwSetAxisTitle("Y轴", 0), //设置坐标轴标题
cwSetGridLine[true,true,true,true] //显示网格
};
ChartWnd[@init];
!!!using("win","math");
//设置一些初值:x0Min和x0Max为X轴范围的原始值;xMin和xMax为X轴范围的当前值;kMax是绘图点数;inc是X轴范围发生变化时的增量。这些参数都是模块变量。
初值(::x0Min, x0Max, xMin, xMax, kMax, inc)= x0Min=-8.0, x0Max=8.0, xMin=x0Min, xMax=x0Max, kMax=100, inc=0.5;
f(x)=sin(x); //定义一元函数
g(x)=x-sin(x); //定义一元函数
h(x)=x.*sin(x); //定义一元函数
home(x::x0Min, x0Max, xMin, xMax, kMax) = //用户按Home键时调用的函数
{
cwAttach(typeXY), cwClearData(), //函数cwClearData用于重置数据为默认值
xMin=x0Min, xMax=x0Max,
x=linspace[xMin, xMax, kMax],
cwAddCurve{x, f(x), kMax}, cwAddCurve{x, g(x), kMax}, cwAddCurve{x, h(x), kMax}
};
left(x::xMin, xMax, kMax, inc) = //用户按←键时调用的函数
{
cwAttach(typeXY), cwClearData(),
xMin=xMin-inc, xMax=xMax-inc,
x=linspace[xMin, xMax, kMax],
cwAddCurve{x, f(x), kMax}, cwAddCurve{x, g(x), kMax}, cwAddCurve{x, h(x), kMax}
};
right(x::xMin, xMax, kMax, inc) = //用户按→键时调用的函数
{
cwAttach(typeXY), cwClearData(),
xMin=xMin+inc, xMax=xMax+inc,
x=linspace[xMin, xMax, kMax],
cwAddCurve{x, f(x), kMax}, cwAddCurve{x, g(x), kMax}, cwAddCurve{x, h(x), kMax}
};
up(x::xMin, xMax, kMax, inc) = //用户按↑键时调用的函数
{
cwAttach(typeXY), cwClearData(),
xMin=xMin-inc, xMax=xMax+inc,
x=linspace[xMin, xMax, kMax],
cwAddCurve{x, f(x), kMax}, cwAddCurve{x, g(x), kMax}, cwAddCurve{x, h(x), kMax}
};
down(x::xMin, xMax, kMax, inc) = //用户按↓键时调用的函数
{
cwAttach(typeXY), cwClearData(),
xMin=xMin+inc, xMax=xMax-inc,
which{xMin>xMax : [x=xMin, xMin=xMax, xMax=x], xMin==xMax : [xMin=-inc, xMax=inc], 0}, //which语句保证了参数xMin和xMax的合理性
x=linspace[xMin, xMax, kMax],
cwAddCurve{x, f(x), kMax}, cwAddCurve{x, g(x), kMax}, cwAddCurve{x, h(x), kMax}
};
init(x)=
cwSetVKFor[VK_HOME, @home], //cwSetVKFor用于设置虚拟键调用函数。本例中,用户按Home键时调用函数home,@表示取函数的地址。下同。
cwSetVKFor[VK_LEFT, @left], cwSetVKFor[VK_RIGHT, @right], cwSetVKFor[VK_UP, @up], cwSetVKFor[VK_DOWN, @down],
home[0]; //初始化时先调用一次函数home,参数0实际上可为任意值。
ChartWnd[@init];
下图是连续按←、→、↓、↑、Home时获得的图形:
在OpenLu代码窗口,粘贴以下代码,然后执行 菜单->计算->编译为临时模块并执行。该临时模块可通过 菜单->工具->模块管理->模块类型->临时模块:在主窗口中编译的临时模块 查看。
!!!using("win","math");
//定义全局函数AddPlot,用于设置向曲线k添加数据点(x,y)。该函数可在其他线程中调用。
:::AddPlot(x,y,k::xx,yy,kk)= xx=x, yy=y, kk=k, cwSetExeMsg(); //函数cwSetExeMsg用于发送执行消息。
ShowAdd(::xx,yy,kk)= cwAddPoint2D(xx,yy,kk); //函数cwAddPoint2D用于向曲线kk添加数据点(xx,yy)。
init() = cwSetExe[@ShowAdd]; //cwSetExe设置了函数ShowAdd,该函数可通过cwSetExeMsg发送消息执行。
ChartWnd[@init];
此时,我们看到打开了一个空窗口ChartWnd,里面什么也没有,如下图:
在OpenLu代码窗口,粘贴以下代码并运行:
AddPlot[0.0, 1.0, 0]; //使用我们自定义的全局函数AddPlot向曲线0发送一个数据点(0.0, 1.0)。
观察窗口ChartWnd里发生了什么?然后仍在OpenLu代码窗口,粘贴以下代码并运行:
AddPlot[1.0, 1.5, 0]; //使用我们自定义的全局函数AddPlot向曲线0发送一个数据点(1.0, 1.5)。
我们再用函数AddPlot依次发送以下数据,每次发送注意观察窗口ChartWnd里发生的变化:
[1.5, 2.5, 0]、[2.0, 2.0, 0]、[2.5, -1.0, 0]、[3.0, 1.0, 0] //曲线0的数据
[1.5, -.5, 1]、[2.0, 2.0, 1]、[2.5, 1.0, 1]、[3.0, 1.5, 1] //曲线1的数据
最终的图形如下图:
好了,这有什么用呢?假如Lu系统中有一个数据采集线程(例如串口采集模块),它每采集一组数据,就可以通过函数AddPlot发送到ChartWnd窗口进行显示。嗯,以后Lu系统中必将加入这样的数据采集模块!
!!!using("win","math");
f(x : max, static, k)= //关键字static指出后面的k是一个静态变量,静态变量总是初始化为0。
{
max=500,
x=linspace[-9.0, 9.0, max],
cwClearData(), cwAddCurve[x.*sin(x), x.*cos(x).^2.0, ++k%(max+1)] //++k%(max+1)中的运算符%表示求模
};
//函数cwSetTimer设置了一个通过计时器触发调用的函数f;每隔100毫秒调用一次;true表示立即启动定时器,否则要通过 菜单->设置->计时器设置 来启动。
init(x)= cwSetTimer[@f, 100, true];
ChartWnd[@init];
!!!using("win","math");
init(x,k) =
{
x=linspace[-8.0, 8.0, 0.2],
k=len(x),
cwAddCurve{x, sin(x), k},
cwAddCurve{x, x-sin(x), k},
cwAddCurve{x, x.*sin(x), k},
cwSetExactXRange[true], //设置X坐标轴范围与数据范围相同,不向两端扩展。
cwSetExactYRange[true] //设置Y坐标轴范围与数据范围相同,不向两端扩展。
};
ChartWnd[@init];
比较一下下面的图与前面的图有什么不同:
!!!using("win","math");
init(x,k,k1,k2) =
{
x=linspace[-8.0, 8.0, 0.5],
k=len(x),
k1=cwAddCurve{x, sin(x), k},
cwSetScatter[cwGetIndex(k1)], //绘制k1曲线为散点图
k2=cwAddCurve{x, x-sin(x), k},
cwSetMarkerShow[true,cwGetIndex(k2)], //显示k2曲线的标记
cwSetMarkerFreq[1,cwGetIndex(k2)], //设置k2曲线的标记频率为1,即对每个点都进行标记
cwAddCurve{x, x.*sin(x), k}
};
ChartWnd[@init];
版权所有© Lu程序设计
2002-2013,保留所有权利
E-mail: forcal@sina.com
QQ:630715621
最近更新:
2014年02月15日