使用ggplot创建色盲测试

时间:2017-04-18 15:56:26

标签: r ggplot2

我想使用ggplot创建一个类似于下面的色盲测试。

enter image description here

基本思想是使用java.nio.file.NoSuchFileException: **the directory** at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) at sun.nio.fs.WindowsDirectoryStream.<init>(WindowsDirectoryStream.java:86) at sun.nio.fs.WindowsFileSystemProvider.newDirectoryStream(WindowsFileSystemProvider.java:518) at java.nio.file.Files.newDirectoryStream(Files.java:457) at java.nio.file.Files.list(Files.java:3451) (或者可能是voronoi图,或者甚至可能是上图中的圆圈)作为起点,并定义一个数据帧,当在ggplot中绘制时,会产生图像。

我们首先要创建一个数据集,例如:

geom_hex

然后绘制这个:

df <- data.frame(x = rnorm(10000), y = rnorm(10000))

给出了下图:

enter image description here

主要的缺失步骤是创建一个实际绘制有意义符号(字母或数字)的数据集,并且我不确定如何最好地进行此操作而不需要精心绘制坐标。理想情况下,人们可以从图像文件中读取坐标。

最后,稍微整理可以通过移除边远点来围绕绘图边缘。

非常欢迎所有建议!

修改

更接近我所追求的目标,我们可以使用下面字母'e'的图像:

enter image description here

使用ggplot(df, aes(x, y)) + geom_hex() + coord_equal() + scale_fill_gradient(low = "red", high = "green", guide = FALSE) + theme_void() 包,我们可以阅读此内容并将其转换为数据帧:

imager

然后使用img <- imager::load.image("e.png") df <- as.data.frame(img) 绘制该数据框:

geom_raster

enter image description here

如果我们使用ggplot(df, aes(x, y)) + geom_raster(aes(fill = value)) + coord_equal() + scale_y_continuous(trans = scales::reverse_trans()) + scale_fill_gradient(low = "red", high = "green", guide = FALSE) + theme_void() 代替geom_hex,我们可以得到以下情节:

geom_raster

enter image description here

所以,到达那里但显然还有很长的路要走......

1 个答案:

答案 0 :(得分:5)

这是创建此图的方法:

enter image description here

您需要的套餐:

library(tidyverse)
library(packcircles)

将图像输入值的二维矩阵(x和y坐标)。为此,我将e的.png文件下载为“e.png”并保存在我的工作目录中。然后进行一些处理:

img <- png::readPNG("e.png")

# From http://stackoverflow.com/questions/16496210/rotate-a-matrix-in-r
rotate <- function(x) t(apply(x, 2, rev))

# Convert to one colour layer and rotate it to be in right direction
img <- rotate(img[,,1])

# Check that matrix makes sense:
image(img)

enter image description here

接下来,创建一大堆圈子!我是根据this post做到的。

# Create random "circles"
# *** THESE VALUES WAY NEED ADJUSTING
ncircles <- 1200
offset   <- 100
rmax     <- 80
x_limits <- c(-offset, ncol(img) + offset)
y_limits <- c(-offset, nrow(img) + offset)

xyr <- data.frame(
  x = runif(ncircles, min(x_limits), max(x_limits)),
  y = runif(ncircles, min(y_limits), max(y_limits)),
  r = rbeta(ncircles, 1, 10) * rmax)

# Find non-overlapping arrangement
res <- circleLayout(xyr, x_limits, y_limits, maxiter = 1000)
cat(res$niter, "iterations performed")
#> 1000 iterations performed

# Convert to data for plotting (just circles for now)
plot_d <- circlePlotData(res$layout)

# Check circle arrangement
ggplot(plot_d) + 
  geom_polygon(aes(x, y, group=id), colour = "white", fill = "skyblue") +
  coord_fixed() +
  theme_minimal()

enter image description here

最后,插入每个圆的中心的图像像素值。这将指示圆是否在形状上居中。添加一些噪音以获得颜色和绘图的差异。

# Get x,y positions of centre of each circle
circle_positions <- plot_d %>%
  group_by(id) %>% 
  summarise(x = min(x) + (diff(range(x)) / 2),
            y = min(y) + (diff(range(y)) / 2))

# Interpolate on original image to get z value for each circle
circle_positions <- circle_positions %>% 
  mutate(
    z = fields::interp.surface(
      list(x = seq(nrow(img)), y = seq(ncol(img)), z = img),
      as.matrix(.[, c("x", "y")])),
    z = ifelse(is.na(z), 1, round(z))  # 1 is the "empty" area shown earlier
  )

# Add a little noise to the z values
set.seed(070516)
circle_positions <- circle_positions %>%
  mutate(z = z + rnorm(n(), sd = .1))

# Bind z value to data for plotting and use as fill
plot_d %>% 
  left_join(select(circle_positions, id, z)) %>% 
  ggplot(aes(x, y, group = id, fill = z)) + 
  geom_polygon(colour = "white", show.legend = FALSE) +
  scale_fill_gradient(low = "#008000", high = "#ff4040") +
  coord_fixed() +
  theme_void()
#> Joining, by = "id"

enter image description here

要获得正确的颜色,请在scale_fill_gradient

中进行调整