如何绘制 "moving" 沿 x 轴的实时值图(使用 psychtoolbox)?

How to plot a "moving" graph for real time values along the x-axis (using psychtoolbox)?

我正在为使用 psychtoolbox 呈现刺激的实时实验编写代码。在我的实验中,我需要向受试者展示一张表明他表现的图表。我用这个简单的代码绘制了图表:

        % Draw the graph
        figure('visible','off','color',[0 0 0]);
        pcolor([0 Num_timepoint+2],[-10 0],ones(2,2));
        hold on;
        pcolor([0 Num_timepoint+2],[0 10],2*ones(2,2));
        colormap([79 167 255;255 187 221]/256);      
        plot(1:subloop,value0,'*-',...
        'color',[0,0,0],...
        'LineWidth',1,...
        'MarkerSize',5,...
        'MarkerEdgeColor','k',...
        'MarkerFaceColor',[0.5,0.5,0.5]);
        axis([0,Num_timepoint+2,-10,10]);
        saveas(gcf,'line_chart.png');   %save it
        close(figure);
        line_chart=imread('line_chart.png');   %read it
        resized_plot=imresize(line_chart,0.5);
        imageSize = size(resized_plot);
        [imageHeight,imageWidth,colorChannels]=size(resized_plot);
        bottomRect = [xCenter-imageWidth/1.5, yCenter+gapdown, xCenter+imageWidth/1.5, yCenter+gapdown+imageHeight];
        imageDisplay=Screen('MakeTexture', win0, resized_plot);
        Screen('DrawTexture', win0, imageDisplay, [], bottomRect);

不幸的是,这个简单的代码非常慢。此外,一旦新值出现,我无法让图形沿 x 轴移动。

任何帮助都会很棒。预先感谢您的努力。

为什么要保存图形并重新显示为图像?也许我遗漏了一些东西,但你应该能够通过使用绘图的句柄属性用新数据更新现有绘图来完成你需要的东西:

 .... First time through we need the initial plot ....
 % Set up figure with colormaps and such but leave as 'visible','on'
 hPlot = plot(plot(1:subloop,value0,'*-',...
    'color',[0,0,0],...
    'LineWidth',1,...
    'MarkerSize',5,...
    'MarkerEdgeColor','k',...
    'MarkerFaceColor',[0.5,0.5,0.5]);
 hAxes = gca;


 .... Loop over your real time updates ....
 % Assuming value0 has subject's results from t=0 to t=now 
 hPlot.XData = value0; hPlot.YData = [1:subloop];   
 hAxes.XLim = [0 numTimePoints+2];
 hAxes.YLim = [-10 10]

 .... Continue test and update value0 ....

我认为这应该使您的绘图保持最新状态,而不必将图形另存为图像到文件然后重新打开图像以显示给主题。

如果要将数据移动一个样本,可以使用 circshift 函数。例如,如果您希望新值显示在左侧,您可以将所有值向右移动 1 个样本,然后将新值添加到第一个位置。

对于将 MATLAB 图转换为 Psychtoolbox 纹理,您无需保存,然后加载临时图像。您可以改为使用 getframe 函数来捕获 MATLAB 图形数据,然后将其提供给 MakeTexture 以将其转换为 Psychtoolbox 纹理。

我不确定您实际为子循环、value0 等使用的值是什么,但我认为有一个示例可能接近您想要的值。在此示例中,绘制了 30 帧图形,每个图形在屏幕上显示 1 秒。新的数据点是随机生成的,并出现在图的左侧。

根据您的实验细节,您可能会发现这种方法仍然太慢。您也可以通过 DrawLines 等 Psychtoolbox 绘图方法直接创建图形,但这需要更多的努力。

try

    win0 = Screen('OpenWindow', 0, 0);

    Num_timepoint = 100;
    subloop = 100;
    value0 = zeros(1,100);

    num_demo_frames = 30;

    % Draw the graph
    fig_h = figure('visible','off','color',[0 0 0]);
    pcolor([0 Num_timepoint+2],[-10 0],ones(2,2));
    hold on;
    pcolor([0 Num_timepoint+2],[0 10],2*ones(2,2));
    colormap([79 167 255;255 187 221]/256);
    plot_h = plot(1:subloop,value0,'*-',...
        'color',[0,0,0],...
        'LineWidth',1,...
        'MarkerSize',5,...
        'MarkerEdgeColor','k',...
        'MarkerFaceColor',[0.5,0.5,0.5]);
    axis([0,Num_timepoint+2,-10,10]);

    for f = 1:num_demo_frames
        new_value = randn(1,1);
        data_values = plot_h.YData;
        data_values = circshift(data_values, 1);
        data_values(1) = new_value;
        plot_h.YData = data_values;

        plot_values = getframe(fig_h);
        imageDisplay=Screen('MakeTexture', win0, plot_values.cdata);
        Screen('DrawTexture', win0, imageDisplay);
        Screen('Flip', win0);
        WaitSecs(1);
    end

    sca;

catch e
    sca;
    rethrow(e);
end