Variable Size of geom_tile plot

2019-07-22 06:47发布

I have a code that takes in positional data as well as values at that positional data and then plots it with geom_tile. The matrix size of the plot is not constant from data item to data item and each "cell" in the geom tile has a possibility of containing an additional matrix, again of inconsistent size. The code that I have currently works as long as the additional detail cell is a 2x2, but is failing with an attempt at adaptation to any other size, say a 5x5. The code requires the user to input the major x and y distances (x=c(0,2,4,6,8) has a major distance of 2 for example) as well as the size of the additional detail cell. An image below is the successful geom_tile for a 2x2 additional detail cell.
geom_tile with 2x2 additional detail

The code that produced it is below.

  x <- c(0,0,4,3,3,5,5)
  y <- c(0,4,0,3,5,3,5)


  #USER INPUT
  major_x_dist <- 4 #x distance between the major data points 
  major_y_dist <- 4 #x distance between the major data points 
  division_cells <- as.character("2x2") #size of the cell containing additional detail



  #######################################
  if (division_cells == "2x2") {
    div_cells <- 2
  } else if (division_cells == "3x3") 
  { div_cells <- 3
  } else if (division_cells == "4x4")
  { div_cells <- 4
  } else if (division_cells == "5x5")
  { div_cells <- 5
  } else 
  { div_cells <-1
  }
  data_width <- ifelse(x%% major_x_dist==0, major_x_dist, major_x_dist/div_cells)
  data_height <- ifelse(y%% major_y_dist==0, major_y_dist, major_y_dist/div_cells)


  data_val <- sample(0:100, 7)
  alldata <-data.frame(x, y, data_width, data_height, data_val)




  ggplot(data= alldata, aes(x=x, y=y, width=data_width, height=data_height)) +
    geom_tile(fill = "white", color="black") + 
    geom_text(aes(label = data_val), colour="black") +
    coord_fixed()

The attempted adaptation for a 5x5 additional cell is below.

  x <- c(0,0,0,2,2,2,4,4,4,-0.8,-0.8,-0.8,-0.8,-0.8,-0.4,-0.4,-0.4,-0.4,-0.4,0,0,0,0,0.4,0.4,0.4,0.4,0.4,0.8,0.8,0.8,0.8,0.8)
  y <- c(0,2,4,0,2,4,0,2,4,3.2,3.6,4,4.4,4.8,3.2,3.6,4,4.4,4.8,3.2,3.6,4.4,4.8,3.2,3.6,4,4.4,4.8,3.2,3.6,4,4.4,4.8)


  #USER INPUT
  major_x_dist <- 2 #x distance between the major data points 
  major_y_dist <- 2 #x distance between the major data points 
  division_cells <- as.character("5x5") #size of the cell containing additional detail 



  #######################################
  if (division_cells == "2x2") {
    div_cells <- 2
  } else if (division_cells == "3x3") 
  { div_cells <- 3
  } else if (division_cells == "4x4")
  { div_cells <- 4
  } else if (division_cells == "5x5")
  { div_cells <- 5
  } else 
  { div_cells <-1
  }
  data_width <- ifelse(x%% major_x_dist==0, major_x_dist, major_x_dist/div_cells)
  data_height <- ifelse(y%% major_y_dist==0, major_y_dist, major_y_dist/div_cells)


  data_val <- sample(0:100, 33)
  alldata <-data.frame(x, y, data_width, data_height, data_val)




  ggplot(data= alldata, aes(x=x, y=y, width=data_width, height=data_height)) +
    geom_tile(fill = "white", color="black") + 
    geom_text(aes(label = data_val), colour="black") +
    coord_fixed()

Note that the size of the overall matrix, major distances between data points, location of the additional detail cell, and size of the additional detail cell are all different from the solution that works with a 2x2 additional detail cell. It appears that the text is in the correct location, but the cells are not. I think the issue might have to do with the fact that the center data point of the additional detail cell lies on a major point (0,4). The plot that this code produces is below.

enter image description here Any troubleshooting advice that can be provided is much appreciated!

标签: r ggplot2
1条回答
Root(大扎)
2楼-- · 2019-07-22 07:27

I don't think the method you have of identifying the small squares works. Not quite sure why, but I thought it might be easier to go back to scratch on this. Here is a generalised solution. First I will set up some data - with the dimensions, number of squares and location of the sub-grid all picked at random...

large_x <- sample(2:5,1) #large grid no of x squares
large_y <- sample(2:5,1) #large grid no of y squares
small_x <- sample(2:5,1) #small grid no of x squares
small_y <- sample(2:5,1) #small grid no of y squares
large_w <- round(runif(1,0.5,1.5),2) #width of large squares
large_h <- round(runif(1,0.5,1.5),2) #height of large squares
df <- expand.grid(x=large_w*(1:large_x),y=large_h*(1:large_y)) #large grid
divsq <- sample(nrow(df),1) #random row of df to determine square to divide
sm_x <- df$x[divsq] #coordinates of divided square
sm_y <- df$y[divsq]
df <- rbind(df[-divsq,], #large grid without subdivided square
            expand.grid(x=sm_x-large_w*((1+1/small_x)/2-(1:small_x)/small_x), #x coordinates of small grid
                        y=sm_y-large_h*((1+1/small_y)/2-(1:small_y)/small_y))) #y coordinates of small grid
df$val <- sample(0:100,nrow(df))
df <- df[sample(nrow(df)),] #shuffle df for good measure!

Now I am going to ignore all the random parameters and just work with df, which only contains x, y and val columns. The approach is to look at the intervals between x values for constant y (and vice versa) and use this to work out the small square characteristics. This information can then be used to mark whether each data point belongs to a small square, after which the rest is straightforward.

xdists <- tapply(df$x,df$y,function(z) diff(sort(z))) #list of differences between x values for constant y
ydists <- tapply(df$y,df$x,function(z) diff(sort(z))) #list of differences between y values for constant x
smallw <- min(unique(unlist(xdists))) #identify small width
smallh <- min(unique(unlist(ydists))) #identify small height

#the next lines check for rows that contain diffs equal to the small values, and return the appropriate values of x or y 
smally <- as.numeric(names(xdists)[sapply(xdists,function(z) min(abs(z-smallw))<0.0000001)]) #values of y corresponding to small grid
smallx <- as.numeric(names(ydists)[sapply(ydists,function(z) min(abs(z-smallh))<0.0000001)]) #values of x corresponding to small grid

nx <- length(smallx) #x-size of small grid
ny <- length(smally) #y-size of small grid

#this checks which data points are in small squares (allowing some tolerance for rounding)
df$small <- mapply(function(x,y) (min(abs(x-smallx))<0.0000001 & 
                                  min(abs(y-smally))<0.0000001),df$x,df$y)

df$w <- ifelse(df$small,smallw,smallw*nx)
df$h <- ifelse(df$small,smallh,smallh*ny)

ggplot(data=df, aes(x=x, y=y, width=w, height=h)) +
  geom_tile(fill = "white", color="black") + 
  geom_text(aes(label = val), colour="black") +
  coord_fixed()

enter image description here

查看更多
登录 后发表回答