Archive by Author | docconcoct

EggHatch – a function for easy pattern addition in ggplot2 bar plots.

So, when I had a little time a few months ago I started coding a wrapper function for ggplot2 in R, with the aim of making it a straight forward process when adding 3 basic patterns (hatching) to ggplot2 bar graphs.

Here’s the original answer I provided to the question posed on StackOverflow.

As you can see it’s a little cumbersome.

Anyway, below is the function ‘EggHatch’ (Easy ggplot2 Hatch) that I wrote to make the process a lot easier.

NOTE 1: All patterns work with a regular single plot of bar/s, however, I haven’t found the time to make the diagonal patterns work with facet_grid in ggplot2. The horizontal and vertical patterns do work with facet_grid.

NOTE 2: The following libraries should be installed in order to use this function:


install.packages('Epi')
install.packages('stringi')
install.packages('plyr')
install.packages('gtools')
install.packages('stringr')

NOTE 3: I’ve added example data and some instructions on how to use EggHatch further down the page.

 

EggHatch <- function(ggplot2_plot, cond.list, width_Man = NULL){

    # use this for Relevel
    library(Epi)
    # default relevel to avoid index issue
    ggplot2_plot$data$Variable = Relevel(ggplot2_plot$data$Variable, ref = c(ggplot2_plot$data$Variable))

    print("When choosing patterns ensure that scaling does not obscure horizontal lines. Should horizontal lines be obscured consider a different pattern (A, C, D, or any combination of them.)")
    # if statement for when no value input in 'fill'
      library(stringi)
      library(plyr)
      library(gtools)
      library(stringr)

      input_position_dodge<-ggplot2_plot$layers[[1]]$position$width
      input_colour<-ggplot2_plot$layers[[1]]$aes_params$colour
      fill_value<-ggplot2_plot$layers[[1]]$aes_params$fill
      input_size<-ggplot2_plot$theme$rect$size
      input_width<-ggplot2_plot$layers[[1]]$geom_params$width

      # remove any spaces, tabs etc. from input string
      cond.list<-stri_replace_all_charclass(cond.list, "\\p{WHITE_SPACE}", "")

      # list of conditions input by users
      string_split1<-strsplit(cond.list, ",")[[1]]

      # Dataframe shaped to match number of patterns and conditions entries
      df <- data.frame(matrix(ncol = 2, nrow = length(string_split1)))
      colnames(df) <- c("Pattern", "Condition")

      pattern_options <- c("A", "B", "C", "D") 

      BAR_OUTPUT1<-ggplot2_plot
      BAR_OUTPUT<-BAR_OUTPUT1

      for (pos in 1:length(string_split1)){

        # seperate pattern from input condition into list, dropping '='
        cond_patterns <- as.list(strsplit(string_split1[pos], "=")[[1]])

        # write values to relevant colomns on current row
        df$Pattern[pos]<-cond_patterns[1]
        df$Condition[pos]<-cond_patterns[2]

      }

      # find largest mean value and pass 2% of it
      two_percent_of_largest_mean<-((max(unlist(lapply(ggplot2_plot$data$Value,FUN=max)))/100)*2)

      # loop around for number of conditions
      for (pos in 1:length(df$Condition)){

          Condition_Pos=0

        # split pattern into individual characters
        pattern_split_loop_var<-as.character(df$Pattern[pos])
        pattern_split_loop_var<- strsplit(pattern_split_loop_var, "")[[1]]

        if(grep("A|B|C|D", df$Pattern[pos], ignore.case=TRUE)){

          if ((grepl('A', df$Pattern[pos], ignore.case=TRUE))){

            # get 25% of original width
            vert_bar_count = (((ggplot2_plot$layers[[1]]$geom_params$width)/100)*10)
            Condition_Pos<-as.numeric(df$Condition[pos])

            for (i in 1){

              if (is.null(fill_value)){

                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width=(ggplot2_plot$layers[[1]]$geom_params$width))

              }

              if (!is.null(fill_value)){

              BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width=(ggplot2_plot$layers[[1]]$geom_params$width),fill=fill_value)

              }

              # loop 4 times
              for (i in 1:((ggplot2_plot$layers[[1]]$geom_params$width)/vert_bar_count)){

                # when calculating the number of times to loop and draw consider making value = bar width
                # additionally consider add a verticle line '0' by default. Should get around any
                # stepping outside range
                # alternative just draw a line on each unit on the x-axis inside bounds of bar: number at given
                # point (x-axis label) then either side of number, for example:
                # geom_vline(xintercept=c(1.5,2.5, 10.5), linetype="dotted", size=.8)
                #
                # ensure the Condition_Position value is correct here
                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width=(ggplot2_plot$layers[[1]]$geom_params$width)-vert_bar_count, fill='transparent')
                vert_bar_count = vert_bar_count + (((ggplot2_plot$layers[[1]]$geom_params$width)/100)*10)#((ggplot2_plot$layers[[1]]$geom_params$width)/4)

              }
            }

            if ((grepl('B', df$Pattern[pos], ignore.case=TRUE))){  

              point_1_percent_of_current_mean <- ((BAR_OUTPUT$data$Value[Condition_Pos]/100)*.1)                              while((BAR_OUTPUT$data$Value[Condition_Pos])>=two_percent_of_largest_mean){ 

                # this breaks while loop to prevent going below x-axis 0
                if(((as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-(ggplot2_plot$data$Value[Condition_Pos]/100))<0){

                  break

                }

                BAR_OUTPUT$data$Value[Condition_Pos]<-(as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-two_percent_of_largest_mean

                # This stops line very close to 0 on y-axis
                if(((BAR_OUTPUT$data$Value[Condition_Pos])<((two_percent_of_largest_mean/100)*15))){

                  break

                }

                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width, fill='transparent')

              }

            } # end of sub grepl 'B'

            if ((grepl('C', df$Pattern[pos], ignore.case=TRUE))){

              # Code for diagonal C
              position_input_x<-as.numeric(df$Condition[pos])
              position_input_y<-as.numeric(df$Condition[pos])
              # half of input width
              # when minused from centre of bar point on x-axis
              # it gives value at start of bar on x-axis
              # inverse true for end of bar width
              half_input_width<-input_width/2
              ten_perc_input_width<-((input_width/100)*10)

              x_axis_min <- position_input_x-half_input_width
              x_axis_start_top<-x_axis_min
              x_axis_start_bottom<-x_axis_min
              x_axis_max <- position_input_x+half_input_width

              y_axis_max<- ggplot2_plot$data$Value[position_input_y]
              # need to pull the max value from the example_plot the max boundries...
              # or caluclate the
              z_percent_of_current_mean<-(y_axis_max/100)*10

              df_diag <- data.frame(

                # start on x-axis-end on x-axis
                x = c(x_axis_start_bottom,x_axis_start_top),

                # start on y-axis-end on y-axis
                y = c(y_axis_max,y_axis_max), Fill='Hope you\'re having a nice day.')

              for(i in 1:19){

                # run if 2nd x-position is less or equal to rightmost edge of bar
                # minus 10% of total input width
                if (df_diag$x[2]<(as.character(x_axis_max))){

                  # 1/10 of unit value in width field
                  df_diag$x[2]<-df_diag$x[2]+(ten_perc_input_width)

                  # subtract z percent from 1st y height
                  df_diag$y[1]<-df_diag$y[1]-(z_percent_of_current_mean)

                  # draw using current df_diag values
                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when less than x_axis_max

                # run this code to limit 2nd x-point from moving past rightmost edge of bar
                if (df_diag$x[2]==as.character(x_axis_max)){

                  # drop height of 2nd y-position by z percentage
                  df_diag$y[2]<-df_diag$y[2]-(z_percent_of_current_mean)

                  if(df_diag$y[1]<=z_percent_of_current_mean){

                    df_diag$x[1]<-df_diag$x[1]+ten_perc_input_width
                  }

                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when x_axis_max reached

              } # end of for loop 1:19

            } # end of sub grepl 'C'

            if ((grepl('D', df$Pattern[pos], ignore.case=TRUE))){

              # Code for left leaning diagonal 'D'
              position_input_x<-as.numeric(df$Condition[pos])
              position_input_y<-as.numeric(df$Condition[pos])
              # half of input width
              # when minused from centre of bar point on x-axis
              # it gives value at start of bar on x-axis
              # inverse true for end of bar width
              half_input_width<-input_width/2
              ten_perc_input_width<-((input_width/100)*10)

              x_axis_min <- position_input_x-half_input_width
              x_axis_max <- position_input_x+half_input_width
              y_axis_max<- ggplot2_plot$data$Value[position_input_y]
              # need to pull the max value from the example_plot the max boundries...
              # or caluclate the
              z_percent_of_current_mean<-(y_axis_max/100)*10

              df_diag <- data.frame(                                  # start on x-axis-end on x-axis                 x = c(x_axis_max,x_axis_max),                                                   # start on y-axis-end on y-axis                 y = c(y_axis_max,y_axis_max), Fill='Hope you\'re having a nice day.')                                            for(i in 1:19){                                  # run if 1st x-position is less or equal to leftmost edge of bar                 # minus 10% of total input width                 if (df_diag$x[2]>(as.character(x_axis_min))){

                  # 1/10 of unit value in width field
                  df_diag$x[2]<-df_diag$x[2]-(ten_perc_input_width)

                  # subtract z percent from 1st y height
                  df_diag$y[1]<-df_diag$y[1]-(z_percent_of_current_mean)

                  # draw using current df_diag values
                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when less than x_axis_max

                # run this code to limit 2nd x-point from moving past rightmost edge of bar
                if (df_diag$x[2]==as.character(x_axis_min)){

                  # drop height of 2nd y-position by z percentage
                  df_diag$y[2]<-df_diag$y[2]-(z_percent_of_current_mean)

                  if(df_diag$y[1]<=z_percent_of_current_mean){

                    df_diag$x[1]<-df_diag$x[1]-ten_perc_input_width
                  }

                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when x_axis_max reached

              } # end of for loop 1:19

            }

          } # end of if grepl 'A'

          # This runs code when *only* 'B' in string
          if ((!grepl("[^B]", df$Pattern[pos], ignore.case=TRUE))==TRUE){

            Condition_Pos<-as.numeric(df$Condition[pos])
            one_percent_horiz<-(BAR_OUTPUT$data$Value[Condition_Pos])/100
            Twenty_percent_horiz<-(one_percent_horiz*20)

            point_1_percent_of_current_mean <- ((BAR_OUTPUT$data$Value[Condition_Pos]/100)*.1)                          # draw original bar -> avoids any issue with 'fill' and drawing incorrect height
            BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width)                          # drawing lines (via minusing mean) above 0 on y-axis             while((BAR_OUTPUT$data$Value[Condition_Pos])>=two_percent_of_largest_mean){ 

              # this breaks while loop to prevent going below x-axis 0
              if(((as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-(ggplot2_plot$data$Value[Condition_Pos]/100))<0){

                break

              }

              # check null value
              if (is.null(fill_value)){

                BAR_OUTPUT$data$Value[Condition_Pos]<-(as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-two_percent_of_largest_mean

                if(((BAR_OUTPUT$data$Value[Condition_Pos])<((two_percent_of_largest_mean/100)*15))){

                  break

                }

                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width)

              }

              if (!is.null(fill_value)){

                BAR_OUTPUT$data$Value[Condition_Pos]<-(as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-two_percent_of_largest_mean

                if(((BAR_OUTPUT$data$Value[Condition_Pos])<((two_percent_of_largest_mean/100)*15))){

                  break

                }

                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width, fill=fill_value)

              }

            }

          } # end of if grepl 'B'

          if ((!grepl('A', df$Pattern[pos], ignore.case=TRUE))==TRUE){
          # Only run this code if 'A' is NOT in string - issue lies in BAR_OUTPUT value
            if ((grepl('C', df$Pattern[pos], ignore.case=TRUE))){

              Condition_Pos<-as.numeric(df$Condition[pos])                              if ((grepl('B', df$Pattern[pos], ignore.case=TRUE))){                 # draw original bar -> avoids any issue with 'fill' and drawing incorrect height
                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width)

                point_1_percent_of_current_mean <- ((BAR_OUTPUT$data$Value[Condition_Pos]/100)*.1)                                  while((BAR_OUTPUT$data$Value[Condition_Pos])>=two_percent_of_largest_mean){

                  # this breaks while loop to prevent going below x-axis 0
                  if(((as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-(ggplot2_plot$data$Value[Condition_Pos]/100))<0){

                    break

                  }

                  BAR_OUTPUT$data$Value[Condition_Pos]<-(as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-two_percent_of_largest_mean

                  # This stops line very close to 0 on y-axis
                  if(((BAR_OUTPUT$data$Value[Condition_Pos])<((two_percent_of_largest_mean/100)*15))){

                    break

                  }

                  BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width, fill='transparent')

                }

              } # end of sub grepl 'B'

              # Code for right leaning diagonal 'C'
              position_input_x<-as.numeric(df$Condition[pos])
              position_input_y<-as.numeric(df$Condition[pos])
              # half of input width
              # when minused from centre of bar point on x-axis
              # it gives value at start of bar on x-axis
              # inverse true for end of bar width
              half_input_width<-input_width/2
              ten_perc_input_width<-((input_width/100)*10)

              x_axis_min <- position_input_x-half_input_width
              x_axis_max <- position_input_x+half_input_width

              y_axis_max<- ggplot2_plot$data$Value[position_input_y]
              # need to pull the max value from the example_plot the max boundries...
              # or caluclate the
              z_percent_of_current_mean<-(y_axis_max/100)*10

              df_diag <- data.frame(

                                  # start on x-axis-end on x-axis
                                  x = c(x_axis_min,x_axis_min),

                                  # start on y-axis-end on y-axis
                                  y = c(y_axis_max,y_axis_max), Fill='Hope you\'re having a nice day.')

             for(i in 1:19){

                # run if 2nd x-position is less or equal to rightmost edge of bar
                # minus 10% of total input width
                if (df_diag$x[2]<(as.character(x_axis_max))){

                  # 1/10 of unit value in width field
                  df_diag$x[2]<-df_diag$x[2]+(ten_perc_input_width)

                  # subtract z percent from 1st y height
                  df_diag$y[1]<-df_diag$y[1]-(z_percent_of_current_mean)

                  # draw using current df_diag values
                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when less than x_axis_max

                # run this code to limit 2nd x-point from moving past rightmost edge of bar
                if (df_diag$x[2]==as.character(x_axis_max)){

                  # drop height of 2nd y-position by z percentage
                  df_diag$y[2]<-df_diag$y[2]-(z_percent_of_current_mean)

                  if(df_diag$y[1]<=z_percent_of_current_mean){

                    df_diag$x[1]<-df_diag$x[1]+ten_perc_input_width
                  }

                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when x_axis_max reached

              } # end of for loop 1:19

            } # end of grepl 'C'

            if ((grepl('D', df$Pattern[pos], ignore.case=TRUE))){

              Condition_Pos<-as.numeric(df$Condition[pos])                              if ((grepl('B', df$Pattern[pos], ignore.case=TRUE))){                                  # draw original bar -> avoids any issue with 'fill' and drawing incorrect height
                BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width)

                point_1_percent_of_current_mean <- ((BAR_OUTPUT$data$Value[Condition_Pos]/100)*.1)                                  while((BAR_OUTPUT$data$Value[Condition_Pos])>=two_percent_of_largest_mean){

                  # this breaks while loop to prevent going below x-axis 0
                  if(((as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-(ggplot2_plot$data$Value[Condition_Pos]/100))<0){

                    break

                  }

                  BAR_OUTPUT$data$Value[Condition_Pos]<-(as.numeric(BAR_OUTPUT$data$Value[Condition_Pos]))-two_percent_of_largest_mean

                  # This stops line very close to 0 on y-axis
                  if(((BAR_OUTPUT$data$Value[Condition_Pos])<((two_percent_of_largest_mean/100)*15))){

                    break

                  }

                  BAR_OUTPUT<-BAR_OUTPUT+geom_bar(data=BAR_OUTPUT$data[Condition_Pos,], position=position_dodge(input_position_dodge), stat="identity", colour=input_colour, size=input_size, width = ggplot2_plot$layers[[1]]$geom_params$width, fill='transparent')

                }

              } # end of sub grepl 'B'

              # Code for left leaning diagonal 'D'
              position_input_x<-as.numeric(df$Condition[pos])
              position_input_y<-as.numeric(df$Condition[pos])
              # half of input width
              # when minused from centre of bar point on x-axis
              # it gives value at start of bar on x-axis
              # inverse true for end of bar width
              half_input_width<-input_width/2
              ten_perc_input_width<-((input_width/100)*10)

              x_axis_min <- position_input_x-half_input_width
              x_axis_max <- position_input_x+half_input_width

              y_axis_max<- ggplot2_plot$data$Value[position_input_y]
              # need to pull the max value from the example_plot the max boundries...
              # or caluclate the
              z_percent_of_current_mean<-(y_axis_max/100)*10

              df_diag <- data.frame(                                  # start on x-axis-end on x-axis                 x = c(x_axis_max,x_axis_max),                                                   # start on y-axis-end on y-axis                 y = c(y_axis_max,y_axis_max), Fill='Hope you\'re having a nice day.')                                             for(i in 1:19){                                  # run if 1st x-position is less or equal to leftmost edge of bar                 # minus 10% of total input width                 if (df_diag$x[2]>(as.character(x_axis_min))){

                  # 1/10 of unit value in width field
                  df_diag$x[2]<-df_diag$x[2]-(ten_perc_input_width)

                  # subtract z percent from 1st y height
                  df_diag$y[1]<-df_diag$y[1]-(z_percent_of_current_mean)

                  # draw using current df_diag values
                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when less than x_axis_max

                # run this code to limit 2nd x-point from moving past rightmost edge of bar
                if (df_diag$x[2]==as.character(x_axis_min)){

                  # drop height of 2nd y-position by z percentage
                  df_diag$y[2]<-df_diag$y[2]-(z_percent_of_current_mean)

                  if(df_diag$y[1]<=z_percent_of_current_mean){

                    df_diag$x[1]<-df_diag$x[1]-ten_perc_input_width
                  }

                  BAR_OUTPUT<-BAR_OUTPUT+geom_path(data=df_diag, aes(x=x, y=y),colour = "black")

                } # end of if statement when x_axis_max reached

              } # end of for loop 1:19

            } # end of grepl 'D'

        } # end of no 'A' if statment

        }  

        } # second loop

      BAR_OUTPUT

  }

Below is some example data and a brief explanation of how to use the function.


library(ggplot2)

Example.Data<- data.frame(matrix(vector(), 0, 3, dimnames=list(c(), c("Value", "Variable", "Fill"))), stringsAsFactors=F)

Example.Data[1, ] <- c(80.9, 'Horizontal Pattern','Horizontal Pattern' )
Example.Data[2, ] <- c(67.677777, 'Vertical Pattern','Vertical Pattern' )
Example.Data[3, ] <- c(10.678, 'Mesh HorizVert Pattern','Mesh HorizVert Pattern' )
Example.Data[4,] <- c(95.8, 'Diagonal Pattern 1','Diagonal Pattern 1' )
Example.Data[5,] <- c(67.67, 'Diagonal Pattern 2','Diagonal Pattern 2' )
Example.Data[6,] <- c(58.9, 'Mesh Diagonal Pattern','Mesh Diagonal Pattern' )
Example.Data[7,] <- c(75, 'Mesh HorizVertDiag Pattern','Mesh HorizVertDiag Pattern' )

HighlightDataVert<-Example.Data[2, ]
HighlightHorizontal<-Example.Data[1, ]
HighlightMesh<-Example.Data[3, ]
HighlightHorizontal$Value<-as.numeric(HighlightHorizontal$Value)
Example.Data$Value<-as.numeric(Example.Data$Value)

example_plot<-ggplot(Example.Data, aes(x=Variable, y=Value, fill=factor(Fill))) +
  theme_bw() +
  theme(legend.position = "none")+
  scale_fill_grey(start=.4)+
  geom_bar(position='identity', stat="identity", colour="black", width=.86565656)

example_plot

# Understanding the EggHatch function:

# Patterns are represented by letters and assigned by row numbers.
# You can combine patterns by combining letters, for example: AB, ABC etc.
#
# Letters for each pattern:
# A=vertical lines
# B=horizontal lines
# C=diagonal lines bottom-top
# D=diagonal lines top-bottom

# Simply drop the already created ggplot2 bar plot into the function, as shown
# below, and make the desired pattern/s = the desired row number
# NOTE: the numbers correspond to the row in the dataframe NOT the default plot output order of bars
# You can simplify by using the Relevel function in library(Epi) if you want to reorder
# the rows in the dataframe to match the desired order of bars in the plot.
EggHatch_output<-EggHatch(example_plot, ('b=1, A=2, Ba=3, C=4, d=5, Dc=6, ABcD=7'))

EggHatch_output

And here’s the output:

EggHatch

There is plenty of repetition of code in this function that can be elimated relatively easily by dropping some of the separate patterns code into functions. However, I’ll leave it as it is for now so that it is (in my opinion) clear what the inner workings of each pattern is.

When/if I find time I’ll adapt the code here to allow for diagonal patterns in facet_grid. Until then I hope someone finds this useful. If you have found this function useful feel free to add a vote to the answer I gave to the original question posed on StackOverflow.

FINAL NOTE: you are free to use this code but I’d appreciate credit (even if you adapt my original code) where possible, and please don’t try to pass this work off as your own.

Advertisements

The Price of Knowledge.

There is a debate raging at the moment surrounding the practice of hiding research behind paywalls. The controversy lies not least in that many argue scientific research should be free and accessible to all, and that monetising it is counterproductive/unethical. But the fact that the scientists that conduct the research are not paid once their work has been accepted and published, highlights a strange model that favours the journals alone. I’m not going to get into debates about impact factors and that journals also have running costs. There are plenty of points on both sides of these arguments and the debate is easily found on the web. Instead I’m going to point you, the reader, to approaches used in accessing paywalled papers. This is simply an academic collection/cataloguing of approaches that people are currently using to bypass paywalls.

Disclaimer: The sci-hub site is currently being challenged in courts in America and I don’t necessarily advocate using this approach. I’m merely demonstrating how people get around paywalls when their university cannot afford the licence fees etc. Here is a piece on the origins of the sci-hub site etc. : http://bigthink.com/neurobonkers/a-pirate-bay-for-science

The following is a list of approaches I’ve discovered online that people use to bypass scientific journal paywalls:

1) Search on Google using this format: “paper name” filetype:pdf site:edu

2) Check out r/scholar

3) Use the hastag: #canihazpdf on twitter along with a link to the paper (or its title) and your email address.

4) Here’s another approach to try and gain access to articles behind pay-walls: https://t.co/ZigAgimxW7

5a) You can also go straight here: http://sci-hub.io/  http://sci-hub.cc/ and search for your paper of choice.

5b) This is an extension of the above and allows access from the url that hosts the paper of interest:

I’ll use an example. Say you want to access this article that is pay-walled:

http://www.nature.com/neuro/journal/v18/n10/full/nn.4105.html

By adding this:

.sci-hub.io .sci-hub.cc

straight after the .com you will be able to access the article for free via the sci-hub website.

Here’s the amended URL:

http://www.nature.com.sci-hub.io/neuro/journal/v18/n10/full/nn.4105.html

http://www.nature.com.sci-hub.cc/neuro/journal/v18/n10/full/nn.4105.html

6) Of course many academics also contact one of the authors of a paper via email who often are more than happy to forward a copy of their research for free. Professional and polite is the order of the day in this approach.

Again, sci-hub is currently being challenged in American courts so I am not advocating or recommending the use of the sci-hub website. The above paper is used merely as an example of how people use this approach and this blog is purely an academic exercise in cataloguing approaches currently being used by people to bypass paywalls in scientific journals.

The Scheming Clown

The London Mayor had funny hair,
And pretended to be the fool.

He helped his friends build corporate dens,
At the expense of objective rule.

With rising rent he didn’t repent,
Over growing numbers on the streets.

Instead he schemed against the PM esteemed,
“Exit the EU!”, is what he bleats.

#Octobophobia

Chris Brosnahan (over here: http://chrisbrosnahan.blogspot.co.uk/ ) is running a daily challenge for the month of October called #Octobophobia where he presents a new phobia each day and challenges himself, and anyone else who fancies a pop, to write a short story about the relevant phobia. Do follow him to see what he creates (). Some of the early entries are disturbing and I’m sure the trend will continue.

Below is my contribution for Cynophobia (a fear of dogs). I can be found here @BoyceWP on Twitter.

Wolves Clothing

I often wonder, do people know the aetiology of their fears? The things that can keep them awake at night, or those niggles that are never quite at the back of their mind? Chances are most have no idea. I know where and when mine was birthed into my world, snarling and convulsing. I was eight and visiting family. Outside I played with the older children and watched them pet their dog, which was tethered with fraying, blue plastic, rope. It was a collie and passive at their touch. When they stop petting the dog it turned its attention to me. It lowered its head and bared its teeth. Growls found their way from deep in its throat as a prelude to the explosive bark that followed each one. Saliva was pulping at one corner of its mouth and shook with each threat of violence it sent my way. I was safe though. The rope, although fraying was holding true. I was advancing towards the dog. I had a hand on my back.

`No, I don’t want to.’ I said.

`It’s friendly really’ they insisted as I was pushed forward.

One of them reached out and petted the dog immediately subduing its savagery. It kept its eyes on me.

`Pet it.’ I was told.

My protests were unheeded. I reached out and tentatively petted the dog’s head at arms length and withdrew my hand in one piece. I smiled with relief at the taller children and turned to get back to a safe distance. There was no growl, no bark, just searing pain in my exposed thigh. The dog withdrew its teeth from my flesh with speed and I was dragged away from its snarling, rabid mouth. Tears spilled down my face as the blood spilled down my leg. The ensuing chaos saw me whisked off to the local GP with a long stay in the waiting area dripping blood onto the floor, before being bandaged and receiving shots. I wasn’t seriously injured, apart from being gifted six scars that could be used as a dental record for the dog. The bastard wasn’t even put down. It would have another victim, the face that time, before the owners decided that their pet was indeed a danger to children. The experience taught me a couple of things. Dogs were dangerous, and people’s stupidity equally so.

***

As an adult I wouldn’t say I had a phobia of dogs as such. I wasn’t transformed to a quivering wreck in their presence but I sure as hell didn’t trust them. I would sometimes cross the street to avoid them if I saw a person walking more than one at a time, but that was just good sense from my perspective. I’d risk passing a single dog and its owner if said owner had it on a short leash. The small yapping dogs didn’t really bother me at all. I barely even saw them as dogs. They were almost a distinct species. Parks though, I never went to parks. People have a habit of letting their pets gallop freely. No thank you.

Sometimes I did have dreams. Nightmares really. Never about the day I was bitten specifically. They would be about white teeth bared in shadow that concealed the size of their owner. I knew though, I knew they were wolves. Circling me. Hunting me. I’d awaken with my heart racing and chest tight. But, again, I wouldn’t say I had a phobia exactly. Those were nightmares and I could function just fine around dogs. I simply preferred not to be in their company.

***

I’d started a new job two weeks prior to getting my first invite to a work social. I wasn’t ever a fan of unofficial compulsory team building. Maybe that was the cynic in me speaking. It was a Friday evening and the quick pint quickly turned into pints. I was having a good time despite my best efforts. Jay-Jay, who I’d not had a chance to talk to properly prior to that was a fun guy. He had a smart answer to everything and a back-catalogue of funny stories that I wasn’t quite convinced were all of his own. But who cares? I was having fun and bullshitters are a harmless breed. I sent a text to my partner to let her know I would be running later than expected. Jay-jay had convinced me to join him for a `few more cheeky pints’ at a betting venue he knew.

`A casino?’ I asked.

`Something like that, but better.’

I was intrigued and followed his lead. We took a cab thirty minutes from the city centre. I was sobering up, tiring, and was significantly less interested in a “few more cheeky pints” than I had been. The cab fare home alone was going to render the extra couple of drinks a waste of time and money. But I didn’t complain. Jay-jay was fidgety with what I assumed was excitement and I wasn’t going to be “that guy”.

We rolled up to a warehouse in what looked like an industrial estate. Jay-Jay paid the fare and I watched the cab disappear back the way it came. I wasn’t at my most comfortable but I had just enough alcohol in my system to decide everything was alright. Jay-Jay knocked hard on the metal door and like something out of a gangster film a slot scraped open and a shadowed figure asked for a password.

`Red Baron’ Jay-Jay said.

The figure slid open the door and we stepped inside. I was led down a few steps towards a basement. Halfway down, that’s when I first heard it. It wasn’t the cheers and shouts from the amassed crowd somewhere below. It was barks.

`Jay-Jay?’ I said.

`It’s cool man. It’s cool.’

I didn’t feel I could turn around and leave. I hadn’t heard what destination Jay-Jay had told the driver. `Shit.’ I thought as Jay-Jay opened another door and led us into the arena. People surrounded a pit dug into the ground and two men stood inside it with their dogs on a leash that were squaring up to each other and straining their leashes to attack. Money was exchanging hands and the smell in the air was musty and of metal. Jay-Jay told me to wait and watch the `fight’. I only saw glimpses. I couldn’t bring myself to watch it all. The dogs ripped and tore at each others flesh adding to the blood already caked into the dirt. It didn’t last long. It was long enough for the losing dog to suffer as it whined in the jaws of the victor. The life escaped its broken body to cheers, braying, and boos from the crowd.

I felt nauseous. Not least by the savage display but also because I’d never before seen a pitbull. The victor, now back on its leash was so pumped full of adrenaline that the owner — and I say owner, not master, as this monster was its own master — could barely keep control of it. The animal, the dog I mean, was enormous and its mouth was wide, like a comic book grin from ear-to-ear.

`Just what the hell am I doing here?’ I thought as I felt sweat trickle down my left temple.

I turned away from the monsters and the bloodbath looking for Jay-Jay. I saw him talking to a large man in a leather jacket. Jay-Jay spotted me. I must have been pasty white at that point. He waved me to approach them and I did. I was unsteady on my feet but managed to navigate the boisterous, blood-thirsty punters. I stood wobbling by Jay-Jay’s side keen to ask him to take me away from this place. I was going to give him a piece of my mind. Didn’t he know how much trouble we could get into? Jay-Jay looked at me and then back to the stranger in leather.

`Our debt is settled?’ Jay-Jay asked.

The man simply nodded in reply. Jay-Jay turned to me with an almost apologetic look on his face and took a step back. I was confused. That was until I felt a sharp push into my back and no longer felt the ground beneath me. I slammed into the pit floor hard. The wind was knocked out of my lungs. There were cheers from the crowd that now surrounded me. Like something you’d hear from assholes in a pub after a member of staff smashed a glass. I looked up and saw the victor of the last fight. Snarling. Growling. Barking. There was saliva congealing in both corners of its mouth and it only had eyes for me.

Swansea City’s Triumphant Return and Other Less Publicised Happenings.

Six of us left the university campus, running predictably late, and made our way over to the Guildhall. This was the final destination of the victory parade of Swansea City after claiming the League Cup on Sunday in a 0-5 defeat over Bradford. It was a momentous occasion in the club’s 100 year history being their first major trophy, and, as a speaker later went to great pains to highlight, the first time a Welsh team had won it.

We walked down Mumbles Road and due to one of the group having hours previous passed his PhD defence our spirits were high. However, we couldn’t say the same for the gentleman we came upon who was having car troubles.

Some people were having a better day than others.

Naughty car.

There was some concern amongst the group that we’d left it too late and probably missed the arrival of the team bus. The eldest of us – taking a well earned break from extinguishing the light in the eyes of students by building a convincing case against free will – tapped into his infinite, aged, wisdom and proclaimed that “These things always run late.” followed by a less assured “Don’t they?” He wasn’t wrong.

As we turned the corner onto the Guildhall the team bus was just at that moment moving at a crawl through the assembled fans. Perfect timing.

This was the scene that awaited us at the Guildhall.

The scene that awaited us at the Guildhall.

Swansea City players overlooking the throng of fans.

Swansea City players overlooking the throng of fans.

The Swans mascots also made an appearance with the players atop the double decker bus. Apparently there are two. One male, and presumably one female. You know, because it’s got pink feathers and looks ‘girly’… The male on the other hand looked like a very moody breadstick. By the looks of it he didn’t appreciate me taking a photo of him either. I can almost hear him hissing. I’m sure there’s some joke and pop reference to Angry Birds in there somewhere but I’ll spare you.

I wonder do they have any cygnets?

I wonder do they have any cygnets?

Some of the jubilant Swansea fans took to the rooftops in a Beatles-esque moment.

Well, granted there are 5 of them and they don't have any instruments.

Well, granted there are 5 of them and they don’t have any instruments.

Other people took advantage of the very specific demographic that turned out for the event by offering flags and various items of clothing emblazoned with the black and white colours of Swansea.

Look at the size of those pegs! Where does someone go to buy them?

Look at the size of those pegs! Where does someone go to buy them?

After the initial excitement of the team’s arrival the cheers of the crowd were drowned out by, at least to me, an unknown figure with a microphone. He boomed over our heads trying to whip us into an even greater state of frenzy before the team, and all associated with them, made their way through from the back of the Guildhall.

The master of the microphone.

The master of the microphone.

The excitable and affable speaker invited Swansea City manger Michael Laudrup forward and made a remark to the effect of Laudrup being elected president of Denmark only for Laudrup to retort “…we don’t have a president” to the amusement of the crowd. Laudrup went on to state that “The first time you win something like that (League Cup) it’s tremendous.” and while expressing his pride and also that the players are always the most important element in any success, he thanked the crowd for turning out on a cold February evening.

Michael Laudrup making his way forward to address the fans.

Michael Laudrup making his way forward to address the fans.

Clearly I struggled to get a good vantage point for my camera but others had no such problem. Granted they may not have been too excited by what they were seeing.

I can't remember now if he was standing on something or was abnormally tall. Either way, he looks bored of looking down on the halfings.

I can’t remember now if he was standing on something or was abnormally tall. Either way, he looks bored of looking down on the halfings.

The microphone maestro invited various players forward to speak and thank the fans. There was some banter about the fans being warm to welcome the team back in this fashion with a player quipping that “I think they’re cold!” – in reference to the conditions – but the most amusement was had with the appearance of Chico Flores. “Hello my friends. My English is not very good but it’s important.” he began, presumably referring to their victory. The keeper of the microphone joked “I’ll translate. He said, ‘My English is not very good but I’m important’ ” which was met with laugher from the crowd. After having other things he said mistranslated from poor English into poor humour Chico rounded his speech off with a cry of “I love you!

Chico trying his hand at English and possibly not understanding the ridicule from the speaker.

Chico trying his hand at English and possibly not understanding the ridicule from the speaker.

At this point I realised I was in the situation where nature was calling at the most inopportune time. I made a quick escape in search of facilities. It was only then that I noticed the television broadcast vans.

Nice bit of kit.

Nice bit of kit.

On my return to the celebration I popped over and was kindly allowed to take a snap of the interior of the van in the foreground above. The tech nerd in me couldn’t resist.

That all looks very expensive.

That all looks very expensive. Apart from the whiteboard. That just looks like it’s in deep cover, infiltrating the advanced enemy.

From there the event began to wind down. Not that this was a cue for our group to return home. Far from it. We embarked on a dual celebration of Swansea City’s success and that of my aforementioned colleague. We popped into the pub next door and admittedly had a few pints. While there I noticed one of the punters had apparently decided that the pub was the best place to watch The Ricky Gervais Show. If he was having a beer I’d imagine a lot of Pilkington’s streams of consciousness would become even more difficult to follow.

Punter listening to the wisdom of Karl Pilkington.

Punter listening to the wisdom of Karl Pilkington.

As the evening progressed, at one point, apparently my hand had swollen to gargantuan proportions dwarfing my pint.

I felt like Alice in Wonderland. Except Alice was a 31 year old man and Wonderland was a pub.

I felt like Alice in Wonderland. Except Alice was a 31 year old man and Wonderland was a pub.

From there the evening’s festivities continued, resulting – inevitably perhaps – in some members of the group being a little worse for wear by nights end than others, but that’s a tale for another time. To their credit they all made it into work the following day. Myself included. Well done to Swansea City for a truly admirable journey of success and may the future bring more of the same. The parade was a great family event, on a par with the Olympic torch passing through Swansea, and also the perfect launching pad for our night of celebrations.

These Fucking Politicians.

Pasty prats. (Image created by Brian Adcock)

The following angry poem is meant as a release of my frustrations regarding the blatant corruption and insincerity, and worse, of our elected officials, specifically in this case the UK but I think the sentiment could be transposed to most nations.

These fucking Politicians.

These fucking politicians and their fucking lies,
A photo-op eating their subjects’ pies.

These fucking politicians and their harebrained schemes,
The big society’s not what it seems.

These fucking politicians and their media friends,
Cosy lunches and texts, to what end?

These fucking politicians protecting the banks,
Take the public’s money without even a thanks.

These fucking politicians, they have no shame,
Coerce their wife to take the blame.

These fucking politicians, don’t justify their expense,
Known henceforth for their embezzlement.

These fucking politicians, whoring their reach,
Yet values they hypocritically preach.

These fucking politicians taking from the vulnerable,
Spin some bullshit that they’re the real criminals.

These fucking politicians and their strategic distractions,
To keep us apart and in warring factions.

These fucking politicians the career hungry dogs,
Climbed to the top of the heap, self proclaimed demigods.

These fucking politicians, the many headed beast,
Cut one off, it’s quickly replaced.

Lest we forget these fucking politicians and their illegal wars,
Death toll rises, lack accountability at all.

These fucking politicians.
We’re all to blame.
These fucking politicians.
We need to change.

Image Source.

Handling Images in the Digital Age.

Legal representatives of the British Royal family have pursued action in French courts due to the publishing of naked images of one of the most recent people brought into their fold. The first steps of this legal move resulted in (as reported by the BBC News website):

  • A court in Paris ruled the publishers of Closer must hand over the original photographs within 24 hours or face a daily fine of 10,000 euros (£8,000).

Before actually taking on board the above statement I think a necessary digression is in order.

Since the horrific chain of events which ultimately led to the death of Diana Spencer there is, understandably,  an obvious sensitivity surrounding paparazzi and her surviving children. However, gradually the media have gone to great lengths to attempt to recapture the public obsession surrounding Diana with her son William and more importantly his wife Kate Middleton. The media frenzy surrounding their wedding is evidence enough. The machine grinds on.

True to form, the peddlers of celebrity snap shots (and what a service they provide the world) have yet again crossed the line – thankfully nothing like the aforementioned tragedy – which separates mutually beneficial publicity from what is deemed inappropriate and boy is that a fine line. The recent ‘topless’ images of Kate Middleton have caused all sorts of outcry from Royalists and the like. I won’t delve into why the backlash is so much more severe when it comes to images of a princess – I even shudder at typing the word –  when compared to a ‘regular’ celebrity. That’s a whole other topic of discussion which ultimately revolves around class in society. However, I’ll go on the record and suggest that no one deserves the unwanted attention of paparazzi, and it is indeed distasteful for them to be harassing the family of a woman who died indirectly due to their pursuit, but I also think that this reaction to a topless image of someone who benefits from media attention in the same way as other celebrities who are victims of this extreme voyeurism is certainly disproportionate. Either condemn all voyeuristic, opportunistic pictures of celebrities equally or keep schtum. Kate Middleton is not deserving of special treatment in this regard. It should be one rule for all. She should have no more or less rights than the average Joe.

Getting back on topic. The quote above clearly states that the publishers of the image have to hand over the ‘original photographs’ . Consider that instruction. Assuming the images were digital – which I think is a fair assumption to make in 2012 – you have to wonder what exactly qualifies as the ‘original photographs’? Was it the first digital files saved on the camera? The transferred files from the camera to the computer? The first email with the images attached to it that was sent to Closer? The one of doubtless many emails circulated within the confines of Closer headquarters? Also, how does one go about handing over these originals? Forward an email to the legal team? I think I’ve made my point. This seems like an exercise in futility. If they were printed images with negatives attached this order would make sense but in the digital age it’s almost laughable.

I’m sure all of this will rumble on with continued cries of outrage at the nerve of a French magazine to publish such images of a royal for the foreseeable few days – maybe weeks – but I don’t think this court ruling can be considered a victory since it makes little sense and will have virtually no impact. After all, the images are only a Google click away now and I doubt they fall under the definition of being the originals.