datashader
|
Страница в процессе перевода. |
#
Makie.datashader — Function
datashader(points::AbstractVector{<: Point})
|
Warning Эта возможность может меняться вне критических выпусков, так как API еще не доработан. Если наблюдаются необычные проявления в работе, это может быть следствием ошибок в реализации. Также можно ознакомиться с открытыми проблемами. |
Аргументом points может быть массив любого типа, поддерживающий итерацию и функцию getindex, включая размещенные в памяти массивы. Если у вас отдельные массивы для координат x и y и вы хотите избежать конвертации и копирования, можно поступить так:
using Makie.StructArrays
points = StructArray{Point2f}((x, y))
datashader(points)
Однако обратите внимание, что если для x и y не реализована быстрая итерация и getindex, такой подход может оказаться медленнее, чем простое копирование данных в новый массив.
Для повышения производительности используйте method=Makie.AggThreads() и обязательно запускайте Julia с параметром julia -tauto либо присвойте переменной среды JULIA_NUM_THREADS имеющееся количество ядер.
Тип графика
Псевдоним типа графика для функции datashader — DataShader.
Примеры
Аэропорты
using GLMakie
using DelimitedFiles
airports = Point2f.(eachrow(readdlm(assetpath("airportlocations.csv"))))
fig, ax, ds = datashader(airports,
colormap=[:white, :black],
# для вывода документации мы не должны вычислять изображение асинхронно,
# так как не сможем дождаться окончания отрисовки и встроить пустое изображение
async = false,
figure = (; figure_padding=0, size=(360*2, 160*2))
)
Colorbar(fig[1, 2], ds, label="Number of airports")
hidedecorations!(ax); hidespines!(ax)
fig
Агрегирование среднего значения
Для типа агрегирования AggMean требуется Point3, где среднее значение берется по значениям z всех точек, которые попадают в один и тот же столбец x/y.
using GLMakie
with_z(p2) = Point3f(p2..., cos(p2[1]) * sin(p2[2]))
points = randn(Point2f, 100_000)
points_with_z = map(with_z, points)
f = Figure()
ax = Axis(f[1, 1], title = "AggMean")
datashader!(ax, points_with_z, agg = Makie.AggMean(), operation = identity)
ax2 = Axis(f[1, 2], title = "AggMean binsize = 3")
datashader!(ax2, points_with_z, agg = Makie.AggMean(), operation = identity, binsize = 3)
f
Странные аттракторы
using GLMakie
# Взято из статьи Beautiful Maki Лазаро Алонсо (Lazaro Alonso):
# https://beautiful.makie.org/dev/examples/generated/2d/datavis/strange_attractors/?h=cliffo#trajectory
Clifford((x, y), a, b, c, d) = Point2f(sin(a * y) + c * cos(a * x), sin(b * x) + d * cos(b * y))
function trajectory(fn, x0, y0, kargs...; n=1000) # kargs = a, b, c, d
xy = zeros(Point2f, n + 1)
xy[1] = Point2f(x0, y0)
@inbounds for i in 1:n
xy[i+1] = fn(xy[i], kargs...)
end
return xy
end
cargs = [[0, 0, -1.3, -1.3, -1.8, -1.9],
[0, 0, -1.4, 1.6, 1.0, 0.7],
[0, 0, 1.7, 1.7, 0.6, 1.2],
[0, 0, 1.7, 0.7, 1.4, 2.0],
[0, 0, -1.7, 1.8, -1.9, -0.4],
[0, 0, 1.1, -1.32, -1.03, 1.54],
[0, 0, 0.77, 1.99, -1.31, -1.45],
[0, 0, -1.9, -1.9, -1.9, -1.0],
[0, 0, 0.75, 1.34, -1.93, 1.0],
[0, 0, -1.32, -1.65, 0.74, 1.81],
[0, 0, -1.6, 1.6, 0.7, -1.0],
[0, 0, -1.7, 1.5, -0.5, 0.7]
]
fig = Figure(size=(1000, 1000))
fig_grid = CartesianIndices((3, 4))
cmap = to_colormap(:BuPu_9)
cmap[1] = RGBAf(1, 1, 1, 1) # Убедитесь, что фон локально белый,
let
# можно получить неплохие результаты с n_points.
# Например, 4*(10^7), но нам не нужно слишком сильное замедление docbuild.
n_points = 10^6
for (i, arg) in enumerate(cargs)
points = trajectory(Clifford, arg...; n=n_points)
r, c = Tuple(fig_grid[i])
ax, plot = datashader(fig[r, c], points;
colormap=cmap,
async=false,
axis=(; title=join(string.(arg), ", ")))
hidedecorations!(ax)
hidespines!(ax)
end
end
rowgap!(fig.layout,5)
colgap!(fig.layout,1)
fig
Более крупные примеры
Временные показатели в комментариях приведены для ноутбука Ryzen 5800H с 32 ГБ памяти. Оба примера еще не полностью оптимизированы и используют только необработанные, неотсортированные, размещенные в памяти массивы Point2f. В будущем мы сможем добавить структуры ускорения, чтобы оптимизировать доступ к подобластям.
Набор данных о такси Нью-Йорка с 14 миллионами точек
using GLMakie, Downloads, Parquet2
bucket = "https://ursa-labs-taxi-data.s3.us-east-2.amazonaws.com"
year = 2009
month = "01"
filename = join([year, month, "data.parquet"], "/")
out = joinpath("$year-$month-data.parquet")
url = bucket * "/" * filename
Downloads.download(url, out)
# Загрузка ~1,5 с
@time begin
ds = Parquet2.Dataset(out)
dlat = Parquet2.load(ds, "dropoff_latitude")
dlon = Parquet2.load(ds, "dropoff_longitude")
# Здесь можно было бы использовать массив структуры, но dlon/dlat являются
# пользовательским типом массива из Parquet2, поддерживающего отсутствующие и некоторые другие функции, которые замедляют работу.
# points = StructArray{Point2f}((dlon, dlat))
points = Point2f.(dlon, dlat)
groups = Parquet2.load(ds, "vendor_id")
end
# ~0,06 с
@time begin
f, ax, dsplot = datashader(points;
colormap=:fire,
axis=(; type=Axis, autolimitaspect = 1),
figure=(;figure_padding=0, size=(1200, 600))
)
# Увеличим масштаб фрагмента изображения
limits!(ax, Rect2f(-74.175, 40.619, 0.5, 0.25))
# сделаем так, чтобы изображение заполняло весь экран
hidedecorations!(ax)
hidespines!(ax)
display(f)
end
2,7 миллиарда GPS-точек OSM
Скачаем данные из GPS-точек OSM и используем обновленный скрипт отсюда, чтобы преобразовать CSV в двоичный BLOB-объект, который можно разместить в памяти.
using GLMakie, Mmap
path = "gpspoints.bin"
points = Mmap.mmap(open(path, "r"), Vector{Point2f});
# ~ 26 с
@time begin
f, ax, pl = datashader(
points;
# Интересно посмотреть, сколько времени занимает каждое агрегирование в большом наборе данных.
show_timings = true,
# Используем локальную операцию, которая быстрее вычисляется и неплохо выглядит.
local_operation=x-> log10(x + 1),
#=
in the code we used to save the binary, we had the points in the wrong order.
A good chance to demonstrate the `point_transform` argument,
Which gets applied to every point before aggregating it
=#
point_transform=reverse,
axis=(; type=Axis, autolimitaspect = 1),
figure=(;figure_padding=0, size=(1200, 600))
)
hidedecorations!(ax)
hidespines!(ax)
display(f)
end
aggregation took 1.395s aggregation took 1.176s aggregation took 0.81s aggregation took 0.791s aggregation took 0.729s aggregation took 1.272s aggregation took 1.117s aggregation took 0.866s aggregation took 0.724s
Категориальные данные
В настоящее время существует два способа построения графика на основе категориальных данных.
datashader(one_category_per_point, points)
datashader(Dict(:category_a => all_points_a, :category_b => all_points_b))
Тип категории не имеет значения, но внутренне она будет преобразована в строку, чтобы корректно отображаться в условных обозначениях. Сейчас категории объединяются в один холст для каждой категории, а затем накладываются друг на друга с помощью альфа-смешивания.
using GLMakie
normaldist = randn(Point2f, 1_000_000)
ds1 = normaldist .+ (Point2f(-1, 0),)
ds2 = normaldist .+ (Point2f(1, 0),)
fig, ax, pl = datashader(Dict("a" => ds1, "b" => ds2); async = false)
hidedecorations!(ax)
fig
Также можно повторно использовать предыдущий пример с такси Нью-Йорка для построения категориального графика.
@time begin
f = Figure(figure_padding=0, size=(1200, 600))
ax = Axis(
f[1, 1],
autolimitaspect=1,
limits=(-74.022, -73.827, 40.696, 40.793),
backgroundcolor=:black
)
datashader!(ax, groups, points)
hidedecorations!(ax)
hidespines!(ax)
# Создадим стилизованные условные обозначения
axislegend("Vendor ID"; titlecolor=:white, framecolor=:grey, polystrokewidth=2, polystrokecolor=(:white, 0.5), rowgap=10, backgroundcolor=:black, labelcolor=:white)
display(f)
end
Расширенный API
Шаблон datashader позволяет легко начать работу, он также имеет оптимальную реализацию, поэтому при большинстве изменений, таких как f, ax, pl = datashader(...); pl.colorrange=new_range; pl.operation=log10, не нужно повторно выполнять агрегирование. Но если вам все еще требуется большой объем управления вручную, можно также использовать базовый API Canvas напрямую.
Атрибуты
agg
Значение по умолчанию: AggCount{Float32}()
возможные значения: AggCount(), AggAny() или AggMean(). Обязательно используйте правильный тип элементов, например AggCount{Float32}(). Он должен соответствовать выходным данным local_operation. Может расширяться пользователем путем перегрузки:
struct MyAgg{T} <: Makie.AggOp end
MyAgg() = MyAgg{Float64}()
Makie.Aggregation.null(::MyAgg{T}) where {T} = zero(T)
Makie.Aggregation.embed(::MyAgg{T}, x) where {T} = convert(T, x)
Makie.Aggregation.merge(::MyAgg{T}, x::T, y::T) where {T} = x + y
Makie.Aggregation.value(::MyAgg{T}, x::T) where {T} = x
alpha
Значение по умолчанию: 1.0
альфа-значение цветовой карты или атрибута цвета. Несколько альфа-значений, как в plot(alpha=0.2, color=(:red, 0.5), перемножаются.
async
Значение по умолчанию: true
вычисляет get_aggregation в задаче и пропускает все обновления масштаба и панорамирования во время выполнения. Отлично подходит для взаимодействия, но необходимо отключать при сохранении, например в формате PNG или при встраивании в Documenter.
binsize
Значение по умолчанию: 1
коэффициент, определяющий количество ячеек на пиксель экрана. Чтобы получить более грубое изображение, задайте n > 1.
clip_planes
Значение по умолчанию: automatic
плоскости отсечения позволяют выполнять отсечение в трехмерном пространстве. Здесь можно указать вектор из 8 плоскостей Plane3f, за которыми графики будут отсечены (т. е. станут невидимыми). По умолчанию плоскости отсечения наследуются от родительского графика или сцены. Чтобы удалить родительский объект clip_planes, передайте Plane3f[].
colormap
Значение по умолчанию: @inherit colormap :viridis
задает цветовую карту, из которой производится выборка для числовых значений color. Также можно использовать PlotUtils.cgrad(...), Makie.Reverse(any_colormap) или любой символ из ColorBrewer или PlotUtils. Чтобы увидеть все доступные цветовые градиенты, можно вызвать Makie.available_gradients().
colorrange
Значение по умолчанию: automatic
значения, представляющие начальную и конечную точки colormap.
colorscale
Значение по умолчанию: identity
функция преобразования цвета. Может быть любой функцией, но с Colorbar хорошо работают только identity, log, log2, log10, sqrt, logit, Makie.pseudolog10 и Makie.Symlog10.
depth_shift
Значение по умолчанию: 0.0
корректирует значение глубины графика после всех остальных преобразований, т. е. в пространстве отсечения, где 0 <= depth <= 1. Применимо только к GLMakie и WGLMakie и может использоваться для настройки порядка отрисовки (настраиваемая перерисовка).
fxaa
Значение по умолчанию: true
определяет то, будет ли график отрисовываться с помощью fxaa (сглаживание, только GLMakie).
inspectable
Значение по умолчанию: true
определяет, должен ли график проверяться с помощью DataInspector.
inspector_clear
Значение по умолчанию: automatic
задает функцию обратного вызова (inspector, plot) -> ... для очистки пользовательских индикаторов в DataInspector.
inspector_hover
Значение по умолчанию: automatic
задает функцию обратного вызова (inspector, plot, index) -> ..., которая заменяет методы show_data по умолчанию.
inspector_label
Значение по умолчанию: automatic
задает функцию обратного вызова (plot, index, position) -> string, которая заменяет метку по умолчанию, сгенерированную DataInspector.
interpolate
Значение по умолчанию: false
должно ли итоговое изображение отображаться как интерполированное. Обратите внимание, что в некоторых бэкендах из-за интерполяции соседние с NaN ячейки также могут становиться NaN, например вследствие схем интерполяции, применяемых в GPU. Из-за этого может казаться, что ячеек NaN больше, чем есть на самом деле.
local_operation
Значение по умолчанию: identity
функция, которая вызывается для каждого элемента после агрегирования (map!(x-> local_operation(x), final_aggregation_result)).
method
Значение по умолчанию: AggThreads()
возможные значения: AggThreads() (потоковое агрегирование) или AggSerial() (последовательное агрегирование).
model
Значение по умолчанию: automatic
задает модельную матрицу для графика. Переопределяет настройки, выполненные с помощью translate!, rotate! и scale!.
operation
Значение по умолчанию: automatic
по умолчанию функция Makie.equalize_histogram, которая вызывается для всего массива get_aggregation перед отображением (operation(final_aggregation_result)).
overdraw
Значение по умолчанию: false
определяет то, будет ли график отрисовываться поверх других графиков. В частности, это означает игнорирование проверок глубины в бэкендах GL.
point_transform
Значение по умолчанию: identity
функция, которая применяется к каждой точке перед ее агрегированием.
show_timings
Значение по умолчанию: false
задайте значение true, чтобы отображалось время агрегирования каждого кадра.
space
Значение по умолчанию: :data
задает пространство преобразования для прямоугольника, охватывающего график. Возможные входные данные см. в описании Makie.spaces().
ssao
Значение по умолчанию: false
определяет то, будет ли график отрисовываться с использованием ssao (преграждение окружающего света в экранном пространстве). Обратите внимание, что это имеет смысл только для трехмерных графиков и применимо только с fxaa = true.