朱莉娅·普洛特莉(Julia Plotly)不展示有子图

时间:2019-10-11 13:00:52

标签: julia plotly metaprogramming subplot

我曾做过一些变通办法,以在Julia Plotly中实现出色的子图,但目前正遇到一个更复杂的问题。下面有三种方法可以完成这项工作。 draw1可以很好地完成它,但不适用于我的情况,draw2不能,draw3在REPL中可以,但是否则不能。

这是图形又称为子图的预期矩阵。 expected matrix of graphs

draw1完成工作->出现期望的图形矩阵

function draw1()
    [plot([1,1,1]) plot([2,2,2]); plot([3,3,3]) plot([4,4,4])]
end

draw2a和draw2b不会,无论是作为模块的函数调用还是复制到REPL

function draw2a()
    local mx = [1 2; 3 4]
    local p(i) = plot([i,i,i])
    p.(mx)
end
function draw2b()
    local mx = [1 2; 3 4]
    local p = map(i-> plot([i,i,i]), collect(1:4))
    p[mx]
end

REPL对draw2a和draw2b相同:

julia> subplots.draw2()
2×2 Array{PlotlyJS.SyncPlot,2}:
 SyncPlot(data: [
  "scatter with fields type, x, and y"
]
...
followed by the content of the graphs
如果将

draw3复制到REPL中,它会完美地完成工作,但是如果被调用,则不会

function draw3()
    local p(i) = plot([i,i,i])
    eval(Meta.parse("[p(1) p(2); p(3) p(4)]"))
end

如果叫:

julia> subplots.draw3()
ERROR: UndefVarError: p not defined

必须是范围问题

1 个答案:

答案 0 :(得分:0)

修复

以下是对draw2a的修改,该修改有效(即,它显示了预期的图形):

function draw4()
    local mx = [1 2; 3 4]
    local p(i) = plot([i,i,i])
    matrix_with_plots = p.(mx)
    hvcat((2, 2), matrix_with_plots...)
end

要了解为什么hvcat显示期望的图形,我们必须退后一步,了解SyncPlot的工作原理。

SyncPlot如何工作?

让我们以draw1代码为例:

[plot([1,1,1]) plot([2,2,2]); plot([3,3,3]) plot([4,4,4])]

shell通过以下步骤处理此代码块:

  1. plot([1,1,1])调用PlotlyJS.plot,这将创建一个SyncPlot object,其中包含绘图信息和一些元数据。 PlotlyJS.plot函数的其他调用会产生类似的对象。

  2. [a b; c d]只是Base.hvcat((2, 2), a, b, c, d)的语法糖。 (2, 2)元组表示应创建2x2矩阵。因此,下一步是Julia外壳程序以(2, 2)元组和我们的图作为参数:Base.hvcat((2, 2), sync_plot1, sync_plot2, sync_plot3, sync_plot4)调用Base.hvcat function

  3. 但是(扭转!)Base.hvcat函数具有一种专门用于SyncPlot对象的方法,该方法在PlotlyJS/utils.jl中定义:

    # subplot methods on syncplot
    Base.hcat(sps::SyncPlot...) = SyncPlot(hcat([sp.plot for sp in sps]...))
    Base.vcat(sps::SyncPlot...) = SyncPlot(vcat([sp.plot for sp in sps]...))
    Base.vect(sps::SyncPlot...) = vcat(sps...)
    Base.hvcat(rows::Tuple{Vararg{Int}}, sps::SyncPlot...) =
        SyncPlot(hvcat(rows, [sp.plot for sp in sps]...))
    

    这意味着Julia不会执行Base.hvcat函数的常规内置版本并创建常规的Array,而是调用PlotlyJS自己的Base.hvcat函数,该函数会产生一个新的{ {1}}对象。这个新的SyncPlot对象将前四个图封装为子图。

  4. 当Julia Shell完成对代码块的评估时,它将尝试显示结果。通过在代码块的返回值上调用Base.display function来实现。

    在我们的例子中,代码块的返回值为SyncPlot,因此调用了SyncPlot

  5. 但是(又一曲!)Base.display(<our SyncPlot>)函数具有一种专门用于PlotlyJS/display.jl中的Base.display对象的方法:

    SyncPlot

    这意味着Julia不会执行Base.display(::PlotlyJSDisplay, p::SyncPlot) = display_blink(p::SyncPlot) 函数的常规内置版本并将数据结构打印到控制台,而是调用PlotlyJS自己的Base.display函数,这将打开AtomShell窗口并显示那里的图。

最后一点还意味着您可以显式调用Base.display。以下调用将打开四个包含四个图的窗口:

display

为什么for i in 1:4 display(plot([i, i, i])) end 调用会修复代码?

hvcat中的matrix_with_plots变量是一个包含图的普通Julia矩阵。由draw4返回。因此,在调用draw2a函数时,display只需在控制台上打印数据结构。

通过调用display,我们称为PlotlyJS的自定义hvcat,它创建了一个带有四个子图的hvcat(与包含四个SyncPlot对象的普通Julia矩阵相反)。