我曾做过一些变通办法,以在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
必须是范围问题
答案 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通过以下步骤处理此代码块:
plot([1,1,1])
调用PlotlyJS.plot
,这将创建一个SyncPlot
object,其中包含绘图信息和一些元数据。 PlotlyJS.plot
函数的其他调用会产生类似的对象。
[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。
但是(扭转!)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
对象将前四个图封装为子图。
当Julia Shell完成对代码块的评估时,它将尝试显示结果。通过在代码块的返回值上调用Base.display
function来实现。
在我们的例子中,代码块的返回值为SyncPlot
,因此调用了SyncPlot
。
但是(又一曲!)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矩阵相反)。