Проверка данных
|
Страница в процессе перевода. |
Makie предоставляет инструмент проверки данных DataInspector(x), где x может быть рисунком, осью или сценой. С его помощью при наведении указателя мыши на один из элементов графика вы получаете всплывающую подсказку с важной информацией о графике.
По умолчанию инспектор может проверять любые графики, кроме графиков на основе text и volume. График можно игнорировать, задав его атрибут plot.inspectable[] = false. В этом случае будет выбираться следующий ближайший график (в пределах диапазона).
#
Makie.DataInspector — Type
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) -> ..., которая вызывается каждый раз, когда отменяется выбор графика.