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

datashader

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

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
57f7f4a

Агрегирование среднего значения

Для типа агрегирования 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
c0081b8

Странные аттракторы

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
f9dae30

Более крупные примеры

Временные показатели в комментариях приведены для ноутбука 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
c32dd62

Также можно повторно использовать предыдущий пример с такси Нью-Йорка для построения категориального графика.

@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
nyc per vendor

Расширенный 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).

highclip

Значение по умолчанию: automatic
цвет для любого значения выше цветового диапазона.

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

lowclip

Значение по умолчанию: automatic
цвет для любого значения ниже цветового диапазона.

method

Значение по умолчанию: AggThreads()
возможные значения: AggThreads() (потоковое агрегирование) или AggSerial() (последовательное агрегирование).

model

Значение по умолчанию: automatic
задает модельную матрицу для графика. Переопределяет настройки, выполненные с помощью translate!, rotate! и scale!.

nan_color

Значение по умолчанию: :transparent
цвет для значений NaN.

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.

transformation

Значение по умолчанию: automatic
документация недоступна.

transparency

Значение по умолчанию: false
определяет то, как реализуется прозрачность графика. В GLMakie transparency = true приводит к использованию прозрачности, независимой от порядка.

visible

Значение по умолчанию: true
определяет то, будет ли отрисовываться график.