【问题标题】:Creating plots with disconnected/discrete lines创建具有断开/离散线的图
【发布时间】:2016-09-28 12:18:05
【问题描述】:

这是我的代码:

for p = 1:length(id_unique)
    h=figure;
    hold on
    j = 1;
    for i = 1:1:length(id)
        if id_unique(p)==id(i)
            h=plot([startdate(i),enddate(i)],[j,j],'ok-');
            hold on
            j = j + 1;        
        end
    end
    grid on
    hold off
    savefig([plotname,'.fig'])
    print(plotname,'-djpeg','-r300')
    close
end

% id:           integer vector containing 50000 values
% id_unique:    sorted unique values from vector 'id'
% startdate:    datetime vector containing 50000 dates
% enddate:      datetime vector containing 50000 dates

id”向量中的每个元素/值都表示一个事件,其中该事件的开始日期和结束日期在“startdate”和“ enddate' 向量。 因此,事件 id(1)startdate(i) 中具有开始日期,在 enddate(i) 中具有结束日期。

程序从 'id_unique' 向量中获取一个值,对于在 'id' 中找到的每个匹配值,它会在图中画一条线,表示开始以及活动的结束时间。

例如,假设 55 是向量“id_unique”中的一个 id 值,我们在 id 中有 1000 次这个值。因此,对于 55,创建了一个图,描绘了 1000 条单独的线,事件开始时带有标记“o”,事件结束时有标记“o”,以及连接两个标记的线。

请查看从该代码块生成的附加图。如果 id_unique 有 70 个值,则将从该代码创建 70 个这样的图。在图像中,由于开始日期和结束日期之间的差异很小,许多线条太小,所以标记相互重叠,看起来像一个点。

现在问题来了,对于 'id_unique' 中的 id 值,我们在 'id' 向量中有很多它的实例。当程序将单条线绘制到 100 条时,它的工作速度非常快,但是在同一图中绘制 300 条线后,程序变得很慢。当程序在同一图中绘制 1000 条线时,每条线大约需要 5-7 秒。所以生成一个多行的图需要很多小时。

有没有办法改进我的代码以使这些绘图生成更快。

【问题讨论】:

    标签: matlab plot matlab-figure


    【解决方案1】:

    你不需要循环:

    你可以使用类似的东西:

    a = 1:0.1:4*pi;
    b = sin(a); %vector that represent the start of each line
    c = sin(a)+1; %vector that represent the end of each line
    plot([b;c],[a;a],'-ko','markersize',2)
    

    结果:

    函数plot 需要两个参数:x 和y,但是,这就是世界如此美丽的原因,函数plot 可以管理多行。如果 x 和 y 是矩阵,matlab 将每一列解释为一个新行。

    【讨论】:

    • 哇!这让我大吃一惊。我只需要用分号替换逗号。您能否简要解释一下为什么会这样?
    • @Narnia_Optimus, plot 将矩阵中的不同列视为不同的数据系列。
    • 你让我的一天变得很糟糕 :) 你知道我如何在每行的两端放置两种类型的标记吗?现在它只是两端的一个标记。再次感谢。
    • 只是最后的想法 - 如果采用这种方法来处理多个段,则不可能绘制多个数据系列,使用图例来区分集合,因为每个段被视为单独的行。
    【解决方案2】:

    考虑到这一点,我现在建议执行以下操作 - 与其在绘图中创建多条线,这会在背景中生成大量对象,不如生成 一个 线每个情节,被分成多个部分。如果 startdate 和 enddate 是 1xlength(id) 的向量,那么下面的代码会更快,因为它将所有行连接在一起,中间有 NaN 值。这使得情节在这一点上打破了界限。一切都很快,无需像我之前建议的那样搞乱 xlim 和 ylim...

    这是我的代码:

    for p = 1:length(id_unique)
        h=figure;
        block=[startdate(id==id_unique(p));enddate(id==id_unique(p))];
        x_vals=reshape([block;nan(1,size(block,2))],1,[]);
        y_vals=reshape([(1:size(block,2));(1:size(block,2));nan(1,size(block,2))],1,[]);
        plot(x_vals,y_vals,'ok-');
        grid on
        savefig([plotname,'.fig'])
        print(plotname,'-djpeg','-r300')
        close
    end
    

    我希望这对你更有效。 (当然,如果您的 startdate 和 enddate 向量的长度(id)为 1,那么您应该使用上面第 3 行中的 .' 对它们进行转置)。

    我不确定单独绘图的目的是什么,但如果有用的话,可以将它们全部绘制在同一个图表上。代码将是:

    h=figure;
    hold on;
    for p = 1:length(id_unique)
        block=[startdate(id==id_unique(p));enddate(id==id_unique(p))];
        x_vals=reshape([block;nan(1,size(block,2))],1,[]);
        y_vals=reshape([(1:size(block,2));(1:size(block,2));nan(1,size(block,2))],1,[]);
        plot(x_vals,y_vals,'Marker','o');
        grid on
    end
    savefig([plotname,'.fig'])
    print(plotname,'-djpeg','-r300')
    close
    

    这让 Matlab 可以使用其标准系列设置线型和颜色。它还允许您使用legend 函数添加标签。当然,如果 id 中的位置很重要,而不是使用 y_vals 的序列,您可以使用从find 获得的位置信息,将第 4 行和第 6 行更改为:

    [~,index]=find(id==id_unique(p));
    block=[startdate(index);enddate(index)];
    
    y_vals=reshape(index;index;nan(1,size(block,2))],1,[]);
    

    然后你会在一个图上看到所有的 id,不同的 id 值通过颜色和线型来区分。然后可以使用 legend 函数生成图例:

    legend(num2str(id_unique.'));
    

    (这里假设id_unique是行向量,如果是列向量,去掉.')。

    【讨论】:

    • 非常感谢戴夫。我会按照你的观点看看它是如何工作的。
    • 我意识到我之前的解决方案不是最优的,并且以不同的方式解决了这个问题,结果更快。我已经编辑了我之前的答案以反映新方法。
    • 这是我使用 Matlab 的第四天,我不知道您可以简单地使用 startdate(id==id_unique(p)) 找到所有匹配的日期。非常感谢。我会查一下。非常感谢。
    • 是的 - id==id_unique(p) 产生一个由 0 和 1 组成的逻辑向量,然后使用它作为数组查找的索引,只得到逻辑测试为 1 的条目。它是一个Matlab 真正强大的操作符让编写代码变得很有趣(当然,理解别人的代码也很痛苦 ;-))。
    • 谢谢戴夫!花时间解释。
    【解决方案3】:

    这里也是绘制 2 个不同标记的方法:

    % some random data:
    N = 50;
    id = randi(5,N,1);
    startdate = sort(randi(100,N,1));
    enddate = startdate+randi(10,N,1);
    
    % plotting:
    ax = plot([startdate(:).'; enddate(:).'],[1:N; 1:N],'-k',...
        startdate,1:N,'k<',enddate,1:N,'k>')
    

    向量之后的(:).' 并不是真正需要的,只是为了确保将它们以正确的方向提供给plot - 2 行,startdate 以上enddate

    给出(随机):


    如果您想将数据按id 分组,并以这种方式着色,您可以执行以下操作:

    N = 30;
    id = randi(5,N,1);
    startdate = datetime(sort(736000+randi(100,N,1)),'ConvertFrom','datenum');
    enddate = startdate+randi(20,N,1);
    
    % plotting:
    ax = plot([startdate(:).'; enddate(:).'],[1:N; 1:N],'-',...
        startdate,1:N,'k<',enddate,1:N,'k>');
    
    % coloring:
    cmap = colormap('jet');
    col = cmap(floor(linspace(1,64,numel(unique(id)))),:);
    for k = 1:N
        ax(k).Color = col(id(k),:);
        ax(k).LineWidth = 2;
    end
    
    % set the legend:
    c = 1;
    leg_ent = zeros(numel(unique(id)),1);
    for k = unique(id).'
        leg_ent(c) = find(id==k,1,'first');
        c = c+1;
    end
    legend(ax(leg_ent),num2str(unique(id)),'Location','SouthEast')
    

    你会得到:

    【讨论】:

    • @Narnia_Optimus,看看我的编辑,以另一种方式呈现您的数据。
    • 简直太美了!!!我将来会回到这里使用这些知识。非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2022-01-02
    • 2014-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多