Plot and fill chessboard-like area (and the similars) in R

前端 未结 2 1208
梦毁少年i
梦毁少年i 2021-01-15 02:42

I need some suggestion of how to plot 2D figures and fill them effectively in R. I need to visualize some mathematical \"oddities\", for example the Sierpiński

2条回答
  •  梦毁少年i
    2021-01-15 03:10

    geom_raster() will be the fastest for square tiles of equal shape.

    probably you want geom_polygon() - here is Sierpinski:

    remember to use coord_fixed(ratio=1) or the shape proportions will scale to the shape of your viewer:

    EDIT - sorry realised looking at it I hadn't give you Sierpinski (not sure what I was thinking) fixed

    enter image description here

    require(ggplot2)
    require(reshape2)
    t.h<-sin(2*pi/6)   # eq triangle unit height
    
    sierpinski<-function(iter=3){
      n<-2^iter
      points<-ldply((n-1):0,function(x){
        data.frame(
          y=rep(n-x-1,x)*t.h/n,
          x=seq((from=(0.5/n)+(n-x)*(0.5/n)),by=1/n,length.out=x)
        )  
      })
    
      points$id<-1:nrow(points)
    
      rbind(
        points,
        points+matrix(c((t.h/n),(-0.5/n),0),nrow(points),ncol=3,byrow=T),
        points+matrix(c((t.h/n),(0.5/n),0),nrow(points),3,byrow=T)
      )
    }
    
    axiom<-data.frame(x=c(0,0.5,1),y=c(0,t.h,0))
    
    iterations<-6
    
    ggplot() + theme_bw() + coord_fixed(ratio=1) +
      geom_polygon(data=axiom,aes(x,y), fill="orange") + 
      lapply(1:iterations,function(x){
        geom_polygon(data=sierpinski(x),aes(x,y,group=id), fill="white")
      })
    

    Also, something you should be aware of with these very precise recursive & series models. Sometimes ggplot will not provide an image looking precisely as you expect. e.g. see below for a cantor dust diagram:

    With ggplot (using raster) you can see that even with a high-res output, the 'legs' don't look consistent, whereas you know mathematically that they are. If you download the image and zoom, you'll see the inconsistencies at the bottom.

    enter image description here

    In the code below, I have shown how you can generate your own precise image by creating a raw png file on the fly. Don't be afraid of doing this if you need precision! The output of the raw image generation is below:

    Good luck!

    enter image description here

    # CANTOR
    
    # NUMBER OF ROWS
    n<-9
    
    # MATRIX
    m<-matrix(sapply(n:1,function(x){
        str.zero<-rep(0,3^(x-1))
        str.one<-rep(1,3^(x-1))
        rep(c(str.one,str.zero),length.out=3^(n-1))
    }),nrow=n,byrow=T)
    
    # CLEANUP
    m.cantor<-apply(m,2,cumprod)    
    
    # ggplot
    
    ggplot(melt(m.cantor)) + theme_bw() +
      geom_raster(aes(x=Var2,y=-Var1,alpha=value),color="white")
    
    # MAKE IMAGE FROM RAW DATA
    # LIBRARIES REQUIRED
    require(png)
    
    # AT THE MOMENT WE HAVE A SHORT, WIDE MATRIX
    dim(m.cantor)
    # [1]    9 6561
    # so let's scale it up say * 700 to make an approx square image (9 x 700 = 6300 ~ 6561)
    # basically we're running through each row and replicating x 700
    # then putting the pixels in a matrix with the new height (n=9 * 700) 
    new.m<-matrix(sapply(1:n,function(x)rep(m.cantor[x,],700)),nrow=n*700,byrow=T)
    
    dim(new.m) # check the size
    #[1] 6300 6561       *  OK!
    
    # then let's put it in raw image format
    # png expects an array of 4 matrices, R,G,B and alpha
    
    img.raw<-array(c((1-new.m), # R,G,B pixels oinverted so 1=shading
                     (1-new.m),   # no G
                     (1-new.m),   # no B
                     new.m^0    #note I'm putting this to ^0 to make all alphas 1
                     ),
                   dim=c(dim(new.m),4))
    
    
    writePNG(img.raw,"cantor.png")
    

提交回复
热议问题