Документация Engee

Проверка данных

Страница в процессе перевода.

Makie предоставляет инструмент проверки данных DataInspector(x), где x может быть рисунком, осью или сценой. С его помощью при наведении указателя мыши на один из элементов графика вы получаете всплывающую подсказку с важной информацией о графике.

По умолчанию инспектор может проверять любые графики, кроме графиков на основе text и volume. График можно игнорировать, задав его атрибут plot.inspectable[] = false. В этом случае будет выбираться следующий ближайший график (в пределах диапазона).

DataInspector(figure_axis_or_scene = current_figure(); kwargs...)

Создает инспектор данных, который будет отображать соответствующую информацию в виде подсказки при наведении указателя мыши на график.

Эту функцию можно отключить для отдельного графика, установив plot.inspectable[] = false. Отображаемый текст можно настроить, задав в plot.inspector_label функцию (plot, index, position) -> "my_label", возвращающую метку. Дополнительные сведения см. в документации Makie.

Именованные аргументы:

  • range = 10: определяет диапазон привязки для выбора элемента графика.

  • priority = 100: приоритет создания подсказки по событию перемещения мыши или прокрутки.

  • enabled = true: при значении false проверка графиков отключается. Можно также настроить с помощью enable!(inspector) и disable!(inspector).

  • indicator_color = :red: цвет индикатора выбора.

  • indicator_linewidth = 2: толщина линии индикатора выбора.

  • indicator_linestyle = nothing: стиль линии индикатора выбора.

  • enable_indicators = true): включает или отключает индикаторы.

  • depth = 9e3: значение глубины подсказки. Чтобы подсказка всегда была на переднем плане, значение должно быть высоким.

  • apply_tooltip_offset = true: включает или отключает смещение подсказок на основе, например, размера маркера.

  • Все атрибуты Tooltip

Пользовательский текст

Текст, отображаемый DataInspector, можно настроить для каждого графика отдельно с помощью атрибута inspector_label. Он должен содержать функцию (plot, index, position) -> "my_string", где plot — это график, метка которого настраивается, index — индекс, возвращаемый функцией pick (см. документацию по событиям), а position — положение проверяемого объекта.

lbls = ["Type A", "Type B"]
fig, ax, p = scatter(
    rand(10), color = rand(1:2, 10), colormap = [:red, :blue],
    inspector_label = (self, i, p) -> lbls[self.color[][i]]
)
DataInspector(fig)
fig

Расширение DataInspector

В инспекторе реализованы подсказки для примитивных графиков и нескольких непримитивных графиков (шаблонов). Для остальные графиков по умолчанию используются подсказки одного из дочерних графиков.

Например, poly состоит из mesh и графика wireframe, где график wireframe реализован как lines. Так как ни у poly, ни у wireframe нет специализированного метода show_data, DataInspector использует либо mesh, либо lines для создания подсказки.

Это означает, что у большинства графиков есть подсказка, однако у многих из них может не быть подходящей подсказки. Реализовать более подходящую подсказку для нового типа графика можно путем расширения.

function show_data(inspector::DataInspector, my_plot::MyPlot, idx, primitive_child::SomePrimitive)
    ...
end

Здесь my_plot — это график, для которого нужно создать пользовательскую подсказку, primitive_child — один из примитивов, из которых состоит график (scatter, text, lines, linesegments, mesh, surface, volume, image или heatmap), а idx — индекс этого примитивного графика. Последние два элемента являются результатом pick_sorted в текущей позиции мыши. Как правило, необходимо настроить индекс idx в соответствии с MyPlot.

Давайте рассмотрим метод BarPlot, который также лежит в основе hist. Он содержит два примитивных графика: Mesh и Lines. Индекс idx в результате выбора Mesh основан на вершинах, которых у каждого прямоугольника четыре. Из Lines мы получаем индекс, основанный на конечной точке линии. Чтобы нарисовать контур прямоугольника, как это делается в barplot, нам понадобится 5 точек и разделитель, то есть всего 6 элементов. Таким образом мы реализуем

import Makie: show_data

function show_data(inspector::DataInspector, plot::BarPlot, idx, ::Lines)
    return show_barplot(inspector, plot, div(idx-1, 6)+1)
end

function show_data(inspector::DataInspector, plot::BarPlot, idx, ::Mesh)
    return show_barplot(inspector, plot, div(idx-1, 4)+1)
end

для сопоставления индекса idx примитива с индексом, идентифицирующим столбцы в BarPlot. Теперь мы можем получить позицию столбца, на который наведен указатель мыши, с помощью plot[1][][idx]. Чтобы выровнять подсказку по выбранному элементу, необходимо вычислить соответствующую позицию в экранном пространстве и обновить позицию подсказки.

using Makie: parent_scene, shift_project, update_tooltip_alignment!, position2string

function show_barplot(inspector::DataInspector, plot::BarPlot, idx)
    # Получаем график, с которым связана подсказка
    tt = inspector.plot

    # Получаем сцену, к которой относится BarPlot
    scene = parent_scene(plot)

    # Получаем позицию наведения в пространстве данных
    pos = plot[1][][idx]
    # проецируем в экранное пространство и смещаем для корректного размещения в корневой сцене
    proj_pos = shift_project(scene, to_ndim(Point3f, pos, 0))
    # закрепляем подсказку в спроецированной позиции
    update_tooltip_alignment!(inspector, proj_pos)

    # Обновляем итоговый текст подсказки.
    if haskey(plot, :inspector_label)
        tt.text[] = plot[:inspector_label][](plot, idx, pos)
    else
        tt.text[] = position2string(pos)
    end
    # Отображаем подсказку
    tt.visible[] = true

    # возвращаем true, чтобы указать, что подсказка обновлена
    return true
end

Далее нам нужно отметить прямоугольник, на который наведен указатель мыши. В этом случае можно использовать прямоугольники, которые BarPlot передает в Poly, то есть plot.plots[1][1][][idx]. DataInspector содержит ряд функций для отслеживания временных графиков, поэтому индикатор можно построить в том же объекте scene, который используется BarPlot. Результат будет следующим:

using Makie:
    parent_scene, shift_project, update_tooltip_alignment!, position2string,
    clear_temporary_plots!

function show_data(inspector::DataInspector, plot::BarPlot, idx)
    # inspector.attributes содержит ряд атрибутов, относящихся к индикаторам, и
    # используется в качестве кэша для наблюдаемых объектов индикаторов
    a = inspector.attributes
    tt = inspector.plot
    scene = parent_scene(plot)

    pos = plot[1][][idx]
    proj_pos = shift_project(scene, plot, to_ndim(Point3f, pos, 0))
    update_tooltip_alignment!(inspector, proj_pos)

    # Отмечать прямоугольник нужно только в том случае, если эта настройка включена
    if a.enable_indicators[]
        # Получаем соответствующий прямоугольник
        bbox = plot.plots[1][1][][idx]

        # Создаем индикатор, если он еще не создан
        if inspector.selection != plot
            # очищаем старые индикаторы
            clear_temporary_plots!(inspector, plot)

            # Создаем новый индикатор, используя настройки из `DataInspector`.
            p = wireframe!(
                scene, bbox, model = plot.model[], color = a.indicator_color,
                strokewidth = a.indicator_linewidth, linestyle = a.indicator_linestyle,
                visible = a.indicator_visible, inspectable = false
            )

            # Подсказки выдвигаются вперед на некоторую величину, чтобы они
            # отрисовывались поверх других элементов. Этот индикатор также следует выдвинуть
            # вперед на ту же величину
            translate!(p, Vec3f(0, 0, a.depth[]))

            # Отслеживаем график индикатора
            push!(inspector.temp_plots, p)

        # Если график индикатора уже был создан, достаточно обновить
        # его. В этом случае нужно обновить только прямоугольник.
        elseif !isempty(inspector.temp_plots)
            p = inspector.temp_plots[1]
            p[1][] = bbox
        end

        # При удалении от графика это значение автоматически изменится на false, поэтому
        # его всегда нужно задавать равным true.
        a.indicator_visible[] = true
    end

    if haskey(plot, :inspector_label)
        tt.text[] = plot[:inspector_label][](plot, idx, pos)
    else
        tt.text[] = position2string(pos)
    end
    tt.visible[] = true

    return true
end

На этом реализация пользовательской подсказки для BarPlot завершена.

show_data для отдельных графиков

Вызов show_data также можно заменять для каждого отдельного графика с помощью атрибута inspector_hover. DataInspector предполагает, что это функция (inspector, this_plot, index, hovered_child) -> Bool. Вы также можете настроить пользовательскую очистку посредством plot.inspector_clear = (inspector, plot) -> ..., которая вызывается каждый раз, когда отменяется выбор графика.