Джулия Плотли не показывает сюжет с подзаговорами - PullRequest
2 голосов
/ 11 октября 2019

Я уже делал некоторые обходные пути, чтобы добиться замечательных сюжетов в Джулии Плотли, но в настоящее время борюсь с более сложной проблемой. Ниже приведены три способа, которые должны сделать эту работу. 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

это должна быть проблема с областью действия

1 Ответ

0 голосов
/ 13 ноября 2019

Исправление

Ниже приводится модификация 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])]

Оболочка обрабатывает этот блок кода с помощью следующих шагов:

  1. plot([1,1,1]) вызывает PlotlyJS.plot, что создает SyncPlot объект , который содержит информацию о графикеи некоторые метаданные. Другие вызовы функции PlotlyJS.plot производят похожие объекты.

  2. [a b; c d] - просто синтаксический сахар для Base.hvcat((2, 2), a, b, c, d). Кортеж (2, 2) означает, что должна быть создана матрица 2x2. Поэтому следующим шагом является то, что оболочка Julia вызывает функцию Base.hvcat с кортежем (2, 2) и нашими графиками в качестве параметров: Base.hvcat((2, 2), sync_plot1, sync_plot2, sync_plot3, sync_plot4).

  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]...))
    

    Это означает, что вместо выполнения общей встроенной версии функции Base.hvcat и создания обычной Array Джулия вызывает собственную функцию Base.hvcat PlotlyJS, которая создает новый объект SyncPlot. Этот новый объект SyncPlot инкапсулирует четыре предыдущих графика в виде вспомогательных участков.

  4. Когда оболочка Julia завершит оценку блока кода, она попытается отобразить результат. Это делается путем вызова функции Base.display для возвращаемого значения кодового блока.

    В нашем случае возвращаемое значение кодового блока - SyncPlot, поэтому Base.display(<our SyncPlot>) вызывается.

  5. Но (еще один поворот!) Функция Base.display имеет метод специально для SyncPlot объектов, который определен в PlotlyJS / display.jl :

    Base.display(::PlotlyJSDisplay, p::SyncPlot) = display_blink(p::SyncPlot)
    

    Это означает, что вместо выполнения общей встроенной версии функции Base.display и вывода структуры данных на консоль Джулия вызывает PlotlyJS. собственная функция Base.display, которая открывает окно AtomShell и показывает там графики.

Последняя точка также означает, что вы можете явно вызывать display. Следующий вызов открывает четыре окна с четырьмя графиками:

for i in 1:4 display(plot([i, i, i])) end

Почему вызов hvcat исправляет код?

Переменная matrix_with_plots в draw4 представляет собой простую матрицу Джулиисодержащие участки. Это возвращается draw2a. Поэтому, когда вызывается функция display, display просто печатает структуру данных на консоли.

Вызывая hvcat, мы вызываем пользовательский PlotlyJS hvcat, который создает SyncPlotс четырьмя подзаговорами (в отличие от простой матрицы Джулии, содержащей четыре SyncPlot объекта).

...