1

我是 Julia (v1.7.1) 的新手,我一直在使用 VSCode 作为 IDE。在 VSCode (v1.64) 中,我安装了 Julia Extension (v1.5.10)。在 VSCode 中绘图时,绘图默认显示在绘图窗格中。我正在使用 Plots (v1.25.7) 包和“gr”后端,因为它是“更快”选项之一。

我正在尝试制作一个“实时”时间序列图,其中该系列在循环中更新。这似乎是一个流行的问题,因为有很多问题可以解决这个问题,但我还没有找到“干净”的解决方案。我要强调的是,我并不是要制作动画,它是在循环终止时制作的。我想在循环运行时更新绘图。我看过SmoothLivePlot,但我认为这需要我事先知道系列大小,而我的应用程序并非如此。再说一次,也许我误解了这个包。

我将介绍我到目前为止所做的工作,希望能有所改进。我首先创建了一个绘图功能

function plt_update(p,time_series,var_series)
    plot!(time_series, var_series,
        label = "",
        linecolor = :red)
    display(p)
end

然后我初始化了情节

model_time = 100
p = plot([0.0],[0.0],
    label = "",
    linecolor = :red,
    xlims = (0, model_time),
    ylims = (0, 1),

display(p)

然后调用我的循环(注意:本文中显示的所有代码都包装在一个函数中并在 RPEL 中运行,因此变量不需要在while循环内用“全局”定义。这是由于 Julia 的优化和范围设计...从我读到的内容。有关示例,请参见另一个讨论)。

run_time = 0.0
time_series = [0.0]
var_series = [0.0]
while run_time < model_time

    # Calculate new timestep
    timestep = rand(Float64)  # Be sure to add Random
    run_time += timestep

    # Computations
    sleep(timestep/10)

    # Build vector
    push!(time_series,run_time)
    push!(var_series,timestep)

    # Live plots
    plt_update(p,time_series,var_series)
    
end

我遇到了一些问题。首先,我不知道这是否只是 VSCode 的问题,或者指向谁,但是将函数放入display(p)函数内部以更新 VSCode 绘图窗格中的绘图最终会为循环中的每次迭代创建一个新绘图。显然这不是本意。我发现如果我关闭“在窗格中绘图”选项(文件 > 首选项 > 设置 > 扩展 > Julia),则会创建一个绘图窗口。我不确定“在窗格中创建新绘图”是预期的还是问题(再次,我是新手)。然而,当在 VSCode 之外绘图时,上面的代码按我的预期工作。

对于下一个问题,我认为这里最重要的是,在绘图函数内部,调用plot!将新向量添加到p,同时保存前一个向量。换句话说,p并没有随着新系列更新,而是通过附加一个全新的向量来增长。这一点很明显,因为经过多次迭代后绘图就停止了。此外,如果您删除“颜色”属性,您会看到线在每次迭代时都会改变颜色。实际上,正在绘制的是许多线,全部重叠。

然后我深入p研究正在发生的事情并对绘图功能进行了一些更改

function plt_update(p,time_series,var_series)
    push!(p.series_list[1].plotattributes[:x],time_series[:][end])
    push!(p.series_list[1].plotattributes[:y],var_series[:][end])
    display(p)
end

上面,而不是创建一个新的series_list(如 w/ 之前的情况plot!),我现在正在更新带有新数据的系列。这比以前工作得更好,并且表现如预期。虽然只是轻微的改进,但我通过传递标量而不是 vecotr 进一步修改了函数和函数调用

function plt_update(p,run_time,variable)
    push!(p.series_list[1].plotattributes[:x],run_time)
    push!(p.series_list[1].plotattributes[:y],variable)
    display(p)
end

函数调用现在在其中plt_update(p,run_time,timestep)。正如你所看到的,我随机睡了一段时间,然后将其除以 10,我发现在它失去“近乎实时”的吸引力之前,我可以承受尽可能多的延迟。例如,除以 100 会导致相当明显的滞后。

所以我的问题是......有没有办法改善这一点,减少滞后?作为 Julia 的新手,我不知道所有绘图选项或如何访问“胆量”以自行改进。

编辑:

我刚刚开始了解“Makie”和“Observables”。我将对那些做更多的研究,看看这是否能改善延迟。

编辑2:

在我的研究中,我发现了一种更简洁的方式来表达最后一个功能(另请参见此处以进一步确认该方法

function plt_update(p,run_time,variable)
    push!(p,1,run_time,variable)
    display(p)
end
4

1 回答 1

1

我找到的带有Makieobservables的解决方案无疑是最好的!在YouTube 视频代码之间,我能够将它应用到我上面的示例中。当然,我的循环只有大约 150 次迭代,滞后可以忽略不计(这与之前的情况相去甚远)。取出睡眠功能,剧情瞬间完成。我会鼓励其他人为“近乎实时”的绘图尝试这种方法。

需要的包是

using GLMakie
using GeometryTypes

我不确定是否GeometryTypes明确需要(我认为 GLMakie 会引入必要的库),但我收到一条错误消息,指出Point2f0未找到。

首先,创建 observable(注意它是一个类型的向量Point2f0

pt_series = Observable([Point2f0(0, 0)])

然后初始化情节

fig = Figure(); display(fig)
ax = Axis(fig[1,1])

lines!(ax, pt_series; linewidth = 4, color = :purple)

# Static elements
ax.title = "Time Series"
ax.xlabel = "Time (s)"
ax.ylabel = "Data"
xlims!(ax, 0, 100)
ylims!(ax, 0, 1)

然后运行循环

model_time = 100
run_time = 0.0 
while run_time < model_time

    # Calculate new timestep
    timestep = rand(Float64)
    run_time += timestep

    # Computations
    #sleep(timestep/1000)

    # Live plots
    push!(pt_series[], Point2f0(run_time, timestep))
    pt_series[] = pt_series[]

end

正如我在问题中所说,上面的所有代码都应该包装在一个函数中以防止范围错误。

于 2022-02-07T04:49:49.550 回答