使用Makie创建复杂的图形布局
此示例演示Makie库的工具,通过使用嵌套GridLayout、链接轴、自定义图例和色阶,以及高级元素定位和空间管理技术将各种类型的图形(散点图、等值线图、3D模型和时
1. 软件包安装和数据准备
In [ ]:
Pkg.add("Makie")
Pkg.add("CairoMakie")
为第一个图表准备数据:
In [ ]:
seconds = 0:0.1:2
measurements = [8.2, 8.4, 6.3, 9.5, 9.1, 10.5, 8.6, 8.2, 10.5, 8.5, 7.2,
8.8, 9.7, 10.8, 12.5, 11.6, 12.1, 12.1, 15.1, 14.7, 13.1]
using CairoMakie
2. 创建基本图表
让我们从实验数据和指数模型的简单可视化开始。
主要组件:
Figure()为图形创建容器Axis()定义带有标题的坐标系scatter!()增加测量点lines!()绘制模型线axislegend()创建一个传奇
显示带有实验数据和指数模型的图形:
In [ ]:
f = Figure()
ax = Axis(f[1, 1],
title = "Experimental data and exponential fit",
xlabel = "Time (seconds)",
ylabel = "Value",
)
CairoMakie.scatter!(
ax,
seconds,
measurements,
color = :tomato,
label = "Measurements"
)
lines!(
ax,
seconds,
exp.(seconds) .+ 7,
color = :tomato,
linestyle = :dash,
label = "f(x) = exp(x) + 7",
)
# 在右下角添加图例
axislegend(position = :rb)
# 形状显示
f
Out[0]:
3. 形成复杂的布局
创建一个复杂的图形对象(形状),其中包含多个用于绘图的区域:
- 我们使用
GridLayout用于组织嵌套网格 - 我们定义了4个主要区域(A,B,C,D)
- 调整背景和形状大小
- 我们连接轴以同步刻度
In [ ]:
using CairoMakie
using Makie.FileIO # 用于处理文件
# 激活后端并创建形状
CairoMakie.activate!()
f = Figure(
backgroundcolor = RGBf(0.98, 0.98, 0.98),
size = (1000, 700)
)
# 创建嵌套网格
ga = f[1, 1] = GridLayout() # A区
gb = f[2, 1] = GridLayout() # B区
gcd = f[1:2, 2] = GridLayout() # C及D容器
gc = gcd[1, 1] = GridLayout() # C区(3d大脑)
gd = gcd[2, 1] = GridLayout() # D区(脑电信号)
# 为区域A创建相关轴
axtop = Axis(ga[1, 1]) # 上层分布
axmain = Axis(ga[2, 1], # 主要时间表
xlabel = "before",
ylabel = "after")
axright = Axis(ga[2, 2]) # 正确的分配
# 用于同步的链接轴
linkyaxes!(axmain, axright) # 整体Y尺度
linkxaxes!(axmain, axtop) # 整体X尺度
f
Out[0]:
4. 区域A:散射和分布图
A区示范:
-通过颜色编码对数据进行分组
-具有共同刻度的相关轴
-主图边缘的分布
-自动图例放置
-微调元素之间的边距
In [ ]:
# 生成三组的测试数据
labels = ["treatment", "placebo", "control"]
data = randn(3, 100, 2) .+ [1, 3, 5] # 3组×100点×2尺寸
# 每个组的可视化
for (label, col) in zip(labels, eachslice(data, dims = 1))
CairoMakie.scatter!(axmain, col, label = label)
CairoMakie.density!(axtop, col[:, 1]) # 自上而下的分布
CairoMakie.density!(axright, col[:, 2], direction = :y) # 右边的分布
end
# 设置轴边界
CairoMakie.ylims!(axtop, low = 0)
CairoMakie.xlims!(axright, low = 0)
# 在轴上设置标签
axmain.xticks = 0:3:9
axtop.xticks = 0:3:9
# 添加图例并隐藏不必要的元素
leg = Legend(ga[1, 2], axmain)
hidedecorations!(axtop, grid = false)
hidedecorations!(axright, grid = false)
leg.tellheight = true # 固定图例的高度
# 添加区域标题
Label(ga[1, 1:2, Top()], "Stimulus ratings", valign = :bottom,
font = :bold,
padding = (0, 0, 5, 0))
# 设置元素之间的距离
colgap!(ga, 10)
rowgap!(ga, 10)
f
Out[0]:
5. B区:等值线图
B区展示:
-用于2d数据可视化的等值线图
-图层次结构:contourf+contour
-自定义色标与bin标签
-通过 Mixed 对齐模式
-精确控制图形之间的距离
In [ ]:
# 准备等值线图的数据
xs = LinRange(0.5, 6, 50)
ys = LinRange(0.5, 6, 50)
data1 = [sin(x^1.5) * cos(y^0.5) for x in xs, y in ys] .+ 0.1 .* randn.()
data2 = [sin(x^0.8) * cos(y^1.5) for x in xs, y in ys] .+ 0.1 .* randn.()
# 建筑物等高线图
ax1, hm = CairoMakie.contourf(gb[1, 1], xs, ys, data1, levels = 6)
ax1.title = "Histological analysis"
CairoMakie.contour!(ax1, xs, ys, data1, levels = 5, color = :black)
hidexdecorations!(ax1) # 在X轴上隐藏地标
ax2, hm2 = CairoMakie.contourf(gb[2, 1], xs, ys, data2, levels = 6)
CairoMakie.contour!(ax2, xs, ys, data2, levels = 5, color = :black)
# 设置色标
cb = CairoMakie.Colorbar(gb[1:2, 2], hm, label = "cell group")
low, high = CairoMakie.extrema(data1)
edges = range(low, high, length = 7)
centers = (edges[1:6] .+ edges[2:7]) .* 0.5
cb.ticks = (centers, string.(1:6)) # 自定义标签
# 优化对齐方式
cb.alignmode = Mixed(right = 0)
# 设定距离
colgap!(gb, 10)
rowgap!(gb, 10)
f
Out[0]:
6. 区域C:大脑的3d可视化
C区示范:
-3d模型的下载和可视化(STL格式)
-使用 Axis3 对于3D图形
-基于Y坐标的颜色编码
-倒色图更好的感知
-将3D可视化集成到整体布局中
In [ ]:
# 下载和可视化3d大脑模型
brain = load(assetpath("brain.stl"))
ax3d = Axis3(gc[1, 1], title = "Brain activation")
m = mesh!(
ax3d,
brain,
color = [tri[1][2] for tri in brain for i in 1:3],
colormap = Reverse(:magma), # 倒色图
)
Colorbar(gc[1, 2], m, label = "BOLD level") # 色标
f
Out[0]:
7. 区域D:脑电信号
D区展示:
-用于分组图形的轴阵列
-人工脑电信号的产生
-按点数动态缩放轴
-旋转标签以节省空间
-自动对齐列大小
In [ ]:
# 为脑电信号创建轴网格
axs = [Axis(gd[row, col]) for row in 1:3, col in 1:2]
hidedecorations!.(axs, grid = false, label = false) # 简化设计
# 脑电信号的生成和可视化
for row in 1:3, col in 1:2
xrange = col == 1 ? (0:0.1:6pi) : (0:0.1:10pi) # 不同的范围
eeg = [sum(sin(pi * rand() + k * x) / k for k in 1:10)
for x in xrange] .+ 0.1 .* randn.()
lines!(axs[row, col], eeg, color = (:black, 0.5)) # 半透明线条
end
# 轴签名和标题
axs[3, 1].xlabel = "Day 1"
axs[3, 2].xlabel = "Day 2"
Label(gd[1, :, Top()], "EEG traces", valign = :bottom,
font = :bold,
padding = (0, 0, 5, 0))
# 添加旋转的地点标记
for (i, label) in enumerate(["sleep", "awake", "test"])
Box(gd[i, 3], color = :gray90) # Placemark背景
Label(gd[i, 3], label, rotation = pi/2, tellheight = false) # 垂直文本
end
# 按点数自动缩放
n_day_1 = length(0:0.1:6pi)
n_day_2 = length(0:0.1:10pi)
colsize!(gd, 1, Auto(n_day_1))
colsize!(gd, 2, Auto(n_day_2))
# 设定距离
rowgap!(gd, 10)
colgap!(gd, 10)
colgap!(gd, 2, 0) # 从带有标签的列中删除缩进
f
Out[0]:
8. 最终设置和标签
其他设置:
-添加A/B/C/D标签
-微调列比例
-行高平衡
-优化元素的整体排列
In [ ]:
# 添加区域标签
for (label, layout) in zip(["A", "B", "C", "D"], [ga, gb, gc, gd])
Label(layout[1, 1, TopLeft()], label,
fontsize = 26,
font = :bold,
padding = (0, 5, 5, 0),
halign = :right)
end
# 调整比例
colsize!(f.layout, 1, Auto(0.5)) # 减小第一列的宽度
rowsize!(gcd, 1, Auto(1.5)) # 增加3d可视化的高度
# 显示最终结果
f
Out[0]:






