像素完美渲染
|
该页面正在翻译中。 |
假设您在矩阵中有一些数据,并希望完全按照原样绘制它。 更明确地说,您希望每个绘制的像素从矩阵的一个值中采样,而不发生插值。 本教程将解释如何做到这一点。
热图 和 图像
要绘制一个值矩阵,我们可以使用 图像 或 热图. 使用默认设置 图像 被插值并使用灰度颜色表 热图 是像素化的,并使用了一个彩色的颜色表(viridis). 它们在单元格或"像素"的位置上也有所不同。 在 图像 您可以设置绘图开始和结束的位置,即设置最左边像素的左边缘和最右边像素的右边缘的位置。 (对于底部和顶部像素也是如此。)在 热图 您通常设置单元格中心的位置,但您也可以通过传递来设置边缘 尺寸+1 x和y值。 通过正确的设置,两者都可以看起来相同:
</无翻译>
using CairoMakie
using CairoMakie
data = [1 2; 3 4; 5 6]
f = Figure()
a1, p = image(f[1, 1], data)
a2, p = heatmap(f[1, 2], data)
# 0..3, 0..2 is the default, we could omit it
a3, p = image(f[2, 1], 0..3, 0..2, data, colormap = :viridis, interpolate = false)
a4, p = heatmap(f[2, 2], 0:3, 0:2, data, colormap = :viridis, interpolate = false)
# Note that length(0:3), length(0:2) == size(data) .+ 1
limits!.([a1, a2, a3, a4], -1, 4, -1, 3)
f
全屏剧情
让我们考虑从一些数据创建一个普通图像的情况,没有任何通常的轴装饰。 在这种情况下,使用它是没有用的 图 和 轴心,轴心 因为它们都通过填充和布局来消耗空间。 相反,我们使用 场景 直接。 可以使用以下方法创建特定大小的空场景
</无翻译>
using CairoMakie
using CairoMakie
scene = Scene(size = (200, 100), camera = campixel!)
在这里我们明确地设置 相机=campixel! 使场景采用像素单位。 更具体地说,这将场景的左下角设置为(0,0),右上角设置为 大小. 使用这些限制,我们现在可以绘制一个 图像 (或 热图)完全填充场景的情节:
</无翻译>
using CairoMakie
using CairoMakie
data = [ifelse(x > 180, 0, x/100) * ifelse(y > 80, 0, y/50) for x in 1:200, y in 1:100]
scene = Scene(size = (200, 100), camera = campixel!)
# image will have the correct limits by default (0..200, 0..100)
image!(scene, data, colormap = :viridis, interpolate = false)
# alternatively with heatmap:
# heatmap!(scene, 0:200, 0:100, data)
scene
如果我们想放大图像,我们可以简单地调整场景的大小和情节的限制。 为 热图 我们需要小心一点,因为 0:600 将给我们601个值,而不是我们需要的201个值。 为了解决这个问题,我们需要明确地包含每个单元格的大小作为范围的步骤。
</无翻译>
using CairoMakie
using CairoMakie
data = [ifelse(x > 180, 0, x/100) * ifelse(y > 80, 0, y/50) for x in 1:200, y in 1:100]
scene = Scene(size = (3 * 200, 2 * 100), camera = campixel!)
image!(scene, 0..600, 0..200, data, colormap = :viridis, interpolate = false)
# heatmap!(scene, 0:3:600, 0:2:200, data)
scene
另一种选择是改变 px_per_unit 时保存场景。 使用 麦琪保存(文件名,场景,px_per_unit=2) 场景中的每个"像素"由保存图像中的2个像素表示。 这不会影响情节的限制,即在(200,100)场景中,您应该使用(200,100)作为情节的限制。 (如果你检查这里生成的图像,你会看到它们有两倍的大小给场景,因为文档呈现与 pixel_per_unit=2)
注意事项
照相机
虽然像素相机是直观的使用在这种情况下,它是没有必要的。 如果您创建的场景没有相机,它将默认为剪辑空间相机。 因此,场景坐标的大小总是从-1到1。 这可能会简化绘图,因为在调整场景限制时不必调整图像限制: </无翻译>
using CairoMakie
using CairoMakie
data = [ifelse(x > 180, 0, x/100) * ifelse(y > 80, 0, y/50) for x in 1:200, y in 1:100]
scene = Scene(size = (3 * 200, 2 * 100))
image!(scene, -1..1, -1..1, data, colormap = :viridis, interpolate = false)
scene
同样也可以使用 相机=cam_relative! 以得到0。.1坐标。
GLMakie抗锯齿
using GLMakie
using GLMakie
data = [ifelse(x > 180, 0, x/100) * ifelse(y > 80, 0, y/50) for x in 1:200, y in 1:100]
scene = Scene(size = (3 * 200, 2 * 100))
image!(scene, -1..1, -1..1, data, colormap = :viridis, interpolate = false, fxaa = false)
scene
WGLMakie使用MSAA代替,它在多个子像素处对每个像素进行采样。 通过像素完美映射,这将多次采样相同的颜色,从而产生相同的最终颜色。 所以在WGLMakie我们没有这个问题。
像素完美绘制在一个数字
使用LScene
如果你想绘制多个像素完美矩阵使用 图 对于布局是非常有用的。 我们可以继续依靠 场景 我们上面使用的力学 LScene,LScene. 在这里,我们需要设置 阔度 和 身高 而不是 大小 让layouting知道LScene需要多少空间。 resize_to_layout!() 对于使图形适应场景的大小也非常有用:
</无翻译>
using CairoMakie
using CairoMakie
# length(50:50) = 101
data = [x*y/1000 for x in -50:50, y in -50:50]
fig = Figure()
s1 = LScene(fig[1, 1], width = 101, height = 101, show_axis = false, scenekw = (camera = cam_relative!,))
image!(s1, 0..1, 0..1, data, colormap = :viridis, interpolate = false)
s2 = LScene(fig[1, 2], width = 101, height = 101, show_axis = false, scenekw = (camera = campixel!,))
heatmap!(s2, 0:101, 0:101, data)
resize_to_layout!(fig)
fig
要控制图形生成的空白,您可以调整 图(figure_padding=。..) 用于外填充物和 rowgap!(图,。..) 和 colgap!(图)布局,。..) 为内间隙。
使用轴
using CairoMakie
using CairoMakie
# length(50:50) = 101
data = [x*y/1000 for x in -50:50, y in -50:50]
fig = Figure()
a1 = Axis(fig[1, 1], width = 101, height = 101)
image!(a1, data, colormap = :viridis, interpolate = false)
a2 = Axis(fig[1, 2], width = 101, height = 101)
heatmap!(a2, data)
resize_to_layout!(fig)
fig
为 图像 和 热图 轴将选择与相应绘图紧密对齐的限制。 因此,您不需要将绘图的x和y值与数据和轴的维度进行匹配。 但是,您可能仍然希望将它们设置为 热图 所以蜱不会与细胞中心对齐。 您可能还想关闭棘(leftspinevisible=错误 等),因为它们重叠图像的边缘。