Julia 茱莉亚·普洛特利没有';不显示带有子图的绘图

Julia 茱莉亚·普洛特利没有';不显示带有子图的绘图,julia,plotly,metaprogramming,subplot,Julia,Plotly,Metaprogramming,Subplot,我以前做过一些变通,在Julia Plotly中实现了精彩的子情节,但目前正在努力解决一个更复杂的问题。下面有三种方法可以完成这项工作。draw1做得很完美,但不适用于我的情况,draw2不适用,draw3在REPL中适用,但在其他情况下不适用 这里是图的期望矩阵,也称为子图。 draw1完成任务->出现预期的图形矩阵 function draw1() [plot([1,1,1]) plot([2,2,2]); plot([3,3,3]) plot([4,4,4])] end dra

我以前做过一些变通,在Julia Plotly中实现了精彩的子情节,但目前正在努力解决一个更复杂的问题。下面有三种方法可以完成这项工作。draw1做得很完美,但不适用于我的情况,draw2不适用,draw3在REPL中适用,但在其他情况下不适用

这里是图的期望矩阵,也称为子图。

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
它必须是范围问题

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

要理解为什么
hvcat
显示预期的图形,我们必须后退一步,了解
SyncPlot
是如何工作的

SyncPlot
是如何工作的? 让我们看一下
draw1
code:

[plot([1,1,1]) plot([2,2,2]); plot([3,3,3]) plot([4,4,4])]
shell通过以下步骤处理此代码块:

  • plot([1,1,1])
    调用
    PlotlyJS.plot
    ,它创建一个包含绘图信息和一些元数据的。另一个是调用
    PlotlyJS.plot
    函数生成类似的对象

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

  • 但是(twist!)
    Base.hvcat
    函数有一个专门用于
    SyncPlot
    对象的方法,定义如下:

    这意味着Julia没有执行常规的内置版本的
    Base.hvcat
    函数并创建一个常用的
    数组
    ,而是调用PlotlyJS自己的
    Base.hvcat
    函数,该函数生成一个新的
    SyncPlot
    对象。这个新的
    SyncPlot
    对象将之前的四个绘图封装为子绘图

  • 当Julia shell完成对代码块的求值时,它将尝试显示结果。它通过在代码块的返回值上调用

    在我们的例子中,代码块的返回值是
    SyncPlot
    ,因此调用
    Base.display()

  • 但是(另一个扭曲!)
    Base.display
    函数有一个专门用于
    SyncPlot
    对象的方法,该方法定义在:

    这意味着Julia没有执行常规的内置版本的
    Base.display
    函数并将数据结构打印到控制台,而是调用PlotlyJS自己的
    Base.display
    函数,打开AtomShell窗口并在那里显示图形

  • 最后一点还意味着您可以显式调用
    display
    。以下调用将打开四个窗口,其中包含四个绘图:

    for i in 1:4 display(plot([i, i, i])) end
    
    为什么
    hvcat
    调用会修复代码?
    draw4
    中带有_plots变量的
    matrix_是一个包含plots的纯Julia矩阵。这是通过
    draw2a
    返回的。因此,当对其调用
    display
    功能时,
    display
    只是在控制台上打印数据结构

    通过调用
    hvcat
    ,我们调用PlotlyJS的定制
    hvcat
    ,它创建了一个带有四个子地块的
    SyncPlot
    (与包含四个
    SyncPlot
    对象的普通Julia矩阵相反)

    # 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]...))
    
    Base.display(::PlotlyJSDisplay, p::SyncPlot) = display_blink(p::SyncPlot)
    
    for i in 1:4 display(plot([i, i, i])) end