第五章图形显示技巧本章概要在上一章节了学习了一些图形显示技术。在这一章节将学习几个新的图形显示技巧,以便让图形显示具有专业的感观效果。具体来说,将学会:1.怎样让鼠标交互作用于图形显示2.怎样从图形显示中删除注释3.怎样在图形显示上画“橡皮条”4.怎样在图形显示技巧中使用Z图形缓冲区将光标用于图形显示数据可视化显示的原因之一是用户可用不同的方式对数据进行交互式的操作。用户喜欢的一种对数据交互式操作的方式是使用光标去选择或者标注部分数据。这种交互作用在IDL中用Cursor命令很容易完成。用LoadData命令装入TimeSeries数据集,可看到Cursor命令是如何工作的。IDLcurve=LoadData(1)输入下述命令,显示曲线:IDLWindow,Xsize=400,Ysize=400IDLLoadCT,0IDLTvLCT,255,255,0,1IDLPlot,curveCursor命令接受两个参数。这些参数必须是记录鼠标键按下时光标位置的变量。Cursor命令要求光标位于当前图形窗口中。(即被!D.Window系统变量指向的窗口。)例如,如果输入这个命令,IDL将会等待光标被移动到当前图形窗口(如果输入的是上述命令,就是0号索引窗口)并单击鼠标键。当执行上述动作后,IDL将光标位置返回到变量xLocation和yLocation中。输入:IDLCursor,xLocation,yLocation如果打印出这些变量的值,将发现这些值被赋予的是数据坐标空间。xLocation的数值从0到100,yLocation的数值从0到30。(如果是在图形边界内点击的鼠标,它们至少是这么多。如果不是在图形边界内点击的鼠标会怎么样?)缺省时,Cursor命令返回数据坐标位置。IDLPrint,xLocation,yLocation什么时候返回的光标位置?从上面的命令看,似乎鼠标键被按下时返回光标位置,但并非总是这样。事实上,Cursor命令什么时候报告光标的位置是由Cursor命令的关键字所决定的。这些关键字是:Change当光标位置发生改变或用户移动光标时,返回光标位置。Down当鼠标键被按下时,返回光标位置。NoWait当Cursor命令执行时,光标位置被立即返回。没有任何延迟或等待鼠标的按键。这个关键字有时用于当对象正在显示窗口中被移动时的循环中。UP不是在鼠标键被按下时,而是放开或释放后返回光标位置。WaitCursor命令等待鼠标键被按下后返回光标的位置。只要鼠标键被按下,此关键字对Cursor命令的作用就类似于用NoWait关键字调用Cursor命令。此关键字是Cursor命令的缺省状态。在Cursor命令中,小心使用合适的关键字,特别是在循环过程中使用Cursor命令。用户有时习惯地认为Cursor命令的缺省属性是只有鼠标键被按下时才返回光标的位置。其实不然,缺省属性只是等待一个单击动作,以后的行为就和NoWait关键字一样。在循环中这个区别是至关重要的。哪一个鼠标键和光标共同作用呢?除了设置光标属性外,有时还想知道哪个鼠标键用于对Cursor命令作出反应。例如,想要用鼠标左键做某件事,而做另外不同的事情要用鼠标右键Cursor命令作出的反应。可以检查系统变量!Mouse中的Button字段,来判断哪一个鼠标键在和Cursor命令共同作用。(老版本的IDL是用系统变量!Err的值来判断的。)这个字段是一个整型位映象。Button这个字段的有效值及其意义如下:!Mouse.Button=0当前没有按键被使用!Mouse.Button=1左键用于Cursor命令!Mouse.Button=2中间键用于Cursor命令!Mouse.Button=4右键用于Cursor命令用光标标注图形输出使用Cursor命令的一种方法是允许用户交互地在线画图上放置符号标记。例如,正确无误地输入下列命令。当输完最后一个回车键后,在当前的图形窗口上单击鼠标五次。五个符号将放置在窗口中。(如果在输入下列代码时出现打字错误,必须从头开始重新输入。)输入:IDLForj=0,4DOBEGIN$IDLCursor,xloc,yloc,/DOWN&$IDLPlots,xloc,yloc,Psym=4,SymSize=2,Color=1&ENDFOR画方框有时可能为了选取图形显示中的某部分,而在它的周围画上方框。这里有些命令可用来选择由Cursor命令产生的方框的对角,画出该方框,并将图形缩放到该方框坐标范围。首先画图:IDLPlot,curve接着,使用光标选择想画的方框的一角。要确保在当前图形窗口上点击光标。为确定哪个是当前窗口,并让它不被隐藏,可输入:IDLWShow现在键入第一个Cursor命令。在图形轴的范围内某处点击:IDLCursor,x1,y1,/DOWN;Selectonecornerofbox.接着输入第二个Cursor命令。在图形轴的范围内某处点击:IDLCursor,x2,y2,/DOWN;Selectdiagonalcornerofbox.上述Cursor命令返回的坐标是数据空间坐标。按如下画方框:IDLPlots,[x1,x1,x2,x2,x1],[y1,y2,y2,y1,y1],color=1输出结果应类似于图58中所示,尽管实际的图形上方框取决于在窗口中点击的位置。为了放大这部分图形,必须保证方框坐标的正确顺序。这是非常必要的,因为可能先选择的是方框的右下角,然后是左上角,这样x1将大于x2。还可以想象其它的假设。为了适应所有的情况,键入:图58:在部分数据周围画上方框的线画图。用Cursor命令选择方框的坐标,用PlotS命令画方框。IDLXmin=Min([x1,x2],Max=xmax)IDLYmin=Min([y1,y2],Max=ymax)最后,已经为放大对方框内的数据做好了准备。除了正确地设置数据范围外,还必须设置XYStyle关键字。知道为什么吗?如果不知道,可在不使用这两个关键字的情况下试试下面的命令。将会发生什么呢?IDLPlot,curve,XRange=[xmin,xmax],Yrange=[ymin,ymax],$Xstyle=1,Ystyle=1在图像上使用Cursor命令通常当在处理图像数据时使用Cursor命令,希望用设备坐标而不是数据坐标返回光标位置。这是因为设备坐标和图像中对应的位置之间通常存在一种简单的关系(大多数是一对一的关系)。为了解如何工作的,可用LoadData命令打开360*360的WorldElevation数据集,键入:IDLimage=LoadData(7)显示图像,并装入某些颜色。如下:IDLtopColor=!D.Table_Size-1IDLLoadCT,3,Ncolors=!D.Table_Size-1IDLTvLCT,255,255,0,TopColorIDLWindow,XSize=360,YSize=360IDLTV,BytScl(image,Top=!D.Table_Size-2)利用光标在图像中选择某一特定行和列。注意Cursor和PlotS命令中的Device关键字。这是确保返回的坐标是设备坐标而不是数据坐标。在该位置上画一个十字线。(确保在输入Cursor命令后,在图像窗口中点击一下。)键入:IDLS=Size(image)IDLCursor,col,row,/Device;Clickinthewindow!IDLPlots,[col,col],[0,s(2)],/Device,Color=topColorIDLPlots,[0,s(1)],[row,row],/Device,Color=topColor注意,在图像中某一特定的行和列上获得图像数据是多么的容易。例如,可以轻易地绘制出图像中行和列的数据剖面,键入:IDLWindow,1,Xsize=500,Ysize=300IDL!P.Multi=[0,2,1]IDLPlot,image[*,row],Title=’RowProfile’IDLPlot,image[col,*],Title=’ColumnProfile’IDL!P.Multi=0IDLWset,0输出结果类似于图59所示。在循环中使用Cursor命令有时想在循环中使用Cursor命令。例如,当用光标选择图像上的单个像素时,可能想知道它的像素值。下面是个简单的循环程序,它将一直执行下去,直到单击右键或中键退出。打开文本编辑器,准确无误地输入如下代码。TopColor=!D.Table_Size-1LoadCT,3,Ncolors=!D.Table_Size-1TvLCT,255,255,0,topColorTV,BytScl(image,Top=!D.Table_Size-2)!Mouse.Button=1REPEATBEGINCursor,col,row,/Down,/DevicePrint,‘PixelValue:’,image[col,row]ENDREPUNTIL!Mouse.ButtonNE1END图59:用Cursor命令在图像中选择的行和列的剖面。保存到loop1.pro文件中(此文件已经存在于下载的本书配套程序之中)。编译,并运行这个小主程序,输入:IDL.RUNloop1移动光标进入图像窗口,开始单击左键。图像像素值就会出现在日志窗口中,直到点击其它键,而不是左键。如果在Cursor命令中使用除了Down之外的其它关键字会发生什么呢?实验一下,找出答案。从显示中删除注释当使用光标在图形显示上按照刚才使用的方法来添加注释时,也许会问:“怎样才能删除刚放置在那儿的注释呢?”有两种较好的方法删除注释。称之为异或法和设备拷贝法。笔者认为在两者之中设备拷贝法更能给出专业的感观效果。两种方法都列举出来,但重点将集中在设备拷贝法上。删除注释的异或法异或法是在图形函数的基础上起作用的。图形函数是两个数的位操作。这两个数分别与已经显示出来的像素(称作所谓的目标像素)以及希望放置在同一位置的像素(称作所谓的源像素)相关联。通常,IDL使用的图形函数称作源。在这种图形函数里,IDL忽略了目标像素的值,仅仅在该像素位置上放置源像素的值。但如果这种图形函数变成XOR(异或法),IDL将目标像素和源像素进行逐位比较。这会产生反向目标像素的效果。换句话说,如果像素的二进制表示为01100101,那么执行XOR命令后,像素的二进制表示为10011010。(实际的XOR过程远比这复杂,因为只有IDL在颜色索引表中的邻近位置上有256种颜色时,它才按这种方式运行,而这是一种少见的情形。大多数人只是认为XOR法是用“相反的”颜色画,并保留原来的。在实际的XOR法中,可能预测将会使用哪种颜色来画,但在大多数情形下并不是这样。这就是为什么绝大多数IDL专业程序员宁愿采用设备拷贝法。)在任何时侯,图形函数的作用效果都是由Device命令和Set_Graphics_Function关键字设置的。源模式下图形函数为3。XOR模式下图形函数为6。此时IDL处于系统缺省的源模式下。当处于这种模式时,重新显示图像窗口中的图像。输入:IDLTV,BytScl(image,Top=!D.Table_Size-2)现在,选择XOR模式:IDLDevice,Set_Graphics_Function=6在图像中画一个方框:IDLPlots,[0.2,0.2,0.8,0.8,0.2],Color=topColor,$[0.2,0.8,0.8,0.2,0.2],/Normal注意,方框线的颜色不是预测的黄色。取而代之是多彩的,尽管它显得也很合理。在这个模式下线下的像素已经被翻转了。要删除方框,只须将底下的像素值翻转回它们的原值。再次用PlotS命令很容易完成。IDLPlots,[0.2,0.2,0.8,0.8,0.2],Color=topColor,$[0.2,0.8,0.8,0.2,0