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.

# Written as part of an answer for a question posed here:
# https://stackoverflow.com/questions/2895319/how-to-add-texture-to-fill-colors-in-ggplot2/20426482#20426482
# Please add a vote to the original answer linked above if you find this
# function useful.
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/ https://sci-hub.tw/ 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

.sci-hub.tw

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

http://www.nature.com.sci-hub.tw/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 stopped 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.

1225 Challenge: ‘The Struggle’

W.P. Boyce recently posted about the 1225 Story Challenge here and I decided to give it a go.

Simon P. Clark challenges us to:
Write a story either (a) in 1225 words or less or (b) featuring ‘1225’ as its theme

Publish / share it before December 25th, 2014.

The Struggle

The smell of the cold drifted in through the gap in the narrow window, piercing its way through the staleness inside. It was dark, but the sun was beginning to stir and only the whistle of a gentle wind could be heard.

“A new day,” said the man quietly to himself as he surveyed the scene.

He took a deep breath, allowing the cool morning air to cleanse his being, and returned to the sunken mattress in the corner of the room, ritually lighting a clumsily rolled cigarette. A half-eaten takeaway sat on the floor beside the bed, flanked by two empty bottles of beer.

There was a pile of old newspapers and magazines stacked high against the wall opposite him, discoloured and torn. Nestled among them was a blue bible, a gift given to him after he began attending local prayer group. He had become somewhat of a hoarder and his cramped box room was slowly closing in around him.

The man picked up a picture from the bed-side table and examined it deliberately as he smoked. The frame was cheap but decorative. After staring at the image for nearly a minute, a tragic, fleeting smile flashed across his face and he replaced it, carefully. In contrast to the surrounding squalor, the bed-side table stood empty and neat; the picture frame its only tenant. The man would look searchingly at the photo each morning upon waking and sometimes in the evenings too.

There was no room for a closet in the hovel and his few clothes formed a desperate mound on top of the chair next to the front door. He had one good suit, however, which he kept for special occasions, but he rarely had cause to wear it. Not anymore. It hung hopefully in the tiny toilet adjoining the flat gathering dust.

When he was finished his cigarette, the man rummaged through the heap on the chair and got dressed. His clothes were damp and dirty and clung horribly to his swollen physique. He walked gingerly over to the counter and filled the kettle with water. Slivers of the morning light quietly crept in through the window, lighting up his face as he turned it on.

“A new day, with new possibilities,” the man thought, repeating what his guide had told him at the prayer group.

As the kettle boiled he cast his mind back to the last meeting. The group met each week at a youth club in a council estate nearby. They were a diverse group and would have refreshments before engaging in discussion, prayer and meditation. The man’s sponsor, a guy named Joe, had reassuringly told him that every day brought with it a plethora of opportunities.

“We have a shot at redemption every single day,” Joe would beam. “That’s a beautiful thing.”

Even if he didn’t fully believe Joe, such platitudes comforted him and he genuinely enjoyed the social aspect of the group, for he had grown increasingly isolated in recent years. It was by no means glamorous, but it was warm and welcoming there.

A loud click of the kettle snapped him back into the icy filth of his own home. He poured the tea and sat back down on the bed, cautiously slurping from his mug. His eyes were drawn once more to the photo on the bed-side table and a trembling fear suddenly gripped his throat. He started to sob silently but stopped himself and stood up. He gazed out the window.

“A new day,” repeated the man as tears welled up in his eyes. He picked up the photo again, clutching it tightly. It showed the man delightfully hugging a young child.

“Happy Christmas, son.”

By Ryan Kelly

Constitutional Convention Fallout

Constitutional change in Ireland is imminent (Image: http://www.constitution.ie)

On April 14th, 2013, the Irish Constitutional Convention concluded their deliberations on the issue of changing the Irish Constitution so as to recognise the rights of all citizens to have their relationships enshrined in marriage with all the rights and benefits that go with it. This, of course, is only the first step of the process and the constitutional change will now be put to the people in a referendum, so this is where the real fight starts. The convention is made up of 100 delegates, 66 randomly chosen citizens and 33 parliamentarians with an independent chairperson. Possible changes to the Irish constitution were discussed and recommendations were made to the Government (more information is available at www.constitution.ie).  As a firm believer in the democratic process, yesterday was a real shot in the arm, although where you have winners you have losers and yesterday we had some real sore losers. This post is not about gloating, rather it is to serve as a warning as to the tactics of the ‘No’ camp in the coming months.

It is pretty clear how the No campaign will frame their argument in the coming months and they were quick out of the blocks yesterday. The No campaign will try to present Catholics as a bullied and persecuted section of society who are having their religious freedoms stomped all over by insidious creeping secularism, while comparisons with Soviet Russia will be made with a straight face. Let’s have  a quick look at some of the objections that emerged in the aftermath of the constitutional convention.

One of the leading lights for the No campaign will be David Quinn. Mr Quinn is the founder and head of the Iona Institute, a conservative Catholic lobby group, and a regular columnist on religious affairs for the Irish Independent.

David Quinn@DavQuinn 20h

BTW, if the delegates were randomly chosen, how did a husband and wife end up on it? #ccven

Now if David Quinn had a problem with the make-up of delegates perhaps the beginning of the process would have been the time to raise his objection, not when his motion has been defeated. Perhaps he smells a conspiracy?

David Quinn@DavQuinn 14h

In social debates the dice are always loaded in favour of the ‘liberal’ point of view. They were even more heavily loaded at #ccven

So the convention favoured ‘liberal’ points of view; surely Quinn’s participation in the process can be construed as tacit approval of said process. Here we see the No campaign laying the ground-work for the portrayal of those who are against equality of marriage for all as being a persecuted body in Ireland, fighting against an unjust conspiracy which is systemically enshrined. One reason why the process may have appeared loaded in favour of the Yes campaign is because people of a ‘Liberal’ persuasion have been traditionally more open to progress and development of society. Those who are arguing from a Catholic (I am not suggesting that the No side is 100 per cent Catholic, merely that this is David Quinn and Iona Institute’s default position) position are arguing from a comprehensive doctrine, that is to say that they have a version of the truth and of how things should be done that is enshrined in doctrine and not open to debate.

David Quinn@DavQuinn 14h

One delegate at the #ccven spoke to me about the bullying attitude displayed towards her for not favouring marriage redefinition.

Now, I cannot speak as to this delegate’s experience but the time to bring this issue to light is during the process itself. These conventions serve to enrich our democratic process and nobody should feel bullied expressing a view in this forum. People are chosen randomly to best represent the country we live in at this moment. This is not an exercise in propaganda; rather it is an attempt to create a more inclusive and participatory democracy. Any attempt at bullying is the very antithesis of the convention’s intention:

‘The Convention operates in an inclusive and open manner with its documents and deliberations available on-line and formal plenary sessions streamed live on the web.’ (www.constitution.ie)

The previous sentence was taken directly from the convention’s website. Any accusations of bullying or intimidation should be easily cleared up by the very structures of the convention. Offence can be very easily taken with such an emotive issue but that is not necessarily to say offence was intended to be given. The failure to raise this issue during the process once again smacks of the No campaign setting up a narrative to paint themselves as victims in this process.

David Quinn@DavQuinn 20h

Press release from The Iona Institute: Refusal of Convention to protect religious freedom of deep concern http://bit.ly/130ko82  #ccven

Here we have it folks: the failure to protect religious freedoms. How anybody can claim religious freedom, in particular Catholic religious freedom, is not protected by the Irish state with a straight face is beyond me. The Irish constitution goes out of its way to protect religious freedom, especially those of the Catholic faith. I would be interested to know where David Quinn and Iona draw the line with religious freedoms. Would he be in favour of say, a Muslim who adheres to Sharia Law and wishes to perform female genital mutilation (FGM) on his daughter therefore exercising his religious freedom within the boundaries of this state? I would hate to put words in his mouth but I can imagine Mr Quinn would not be in favour of that. People should be and are free to practice their religion in Ireland so long as it does not impinge on the rights of Irish citizens regardless of their race, colour, sexual orientation or creed. FGM is horrific as it impinges on the physical integrity of our most helpless of citizens: children. Equality of marriage for homosexuals may be an affront to Catholic sensibilities but it does not stop Catholics from living a full life and despite some of the lies Iona are happy too spread it has no detrimental affect on children of these unions either.

This is sure to be an emotive campaign and what the Yes camp needs to concentrate on is the mobilisation of those sympathetic to their cause. If you are not registered to vote, get registered and encourage as many people as possible to do the same. This is merely the first blow in the fight for equality for marriage.


Who is paying the penalty?

Ireland: where the public and officials only reap short term rewards and ignore long term consequences.

Ireland: where the public and officials only reap short term rewards and ignore long term consequences.

Humility is not a quality that Irish political culture seems to be over burdened with. It could well be argued that humility is one of the first qualities to be jettisoned in the pursuit of a successful political career. One would hope that those pursuing a career in politics do so with their heart full of an altruistic sense of public duty and a desire to fight for the greatest good for the greatest number of people; you would hope that people look beyond the local and the immediate to think nationally and in the long term. Many may well launch themselves steeled by this zeal only to have it stripped away by the reality of our political culture. The truth of the political arena in Ireland is that it has been overpopulated by an incestuous ruling-class and quasi-hereditary seats in the Dail. So as this bloated edifice became beyond parody in the final throes of the Celtic Tiger, we hoped, given Ireland’s fall from grace and the punishment doled out to Fianna Fáil at the ballot box, that the surviving politicians of Ireland would notice the sea change and act accordingly.

This of course has not happened, due mainly to the reason that Ireland had its sovereignty signed away by the last shower, who gave the new Government ready made excuses for their policies. The harshness of our government’s policies is not the focus of my ire on this occasion, rather it is the continued absence of any humility on behalf of our politicians and complacency among the Irish electorate in expecting more from their representatives. There are plenty of bogey men to point the finger at in Government, not least ‘Big’ Phil Hogan, a man blessed with an ego and sense of righteousness which would not seem out of place amongst the cartoonish villains of the WWE. Rather it is the political culture and the lack of its evolution which has brought me to the keyboard today.

On the front page of the Irish Examiner 8/04/2013, former Ceann Comhairle and current Fianna Fáil TD Seamus Kirk said it was as easy as picking up the phone to get rid of penalty points. There is a constitutional clause which exempts TD’s from road offences if they are on their way to take part in a Dáil vote. This was a clause left over from the Civil War and by right should be exorcised from the constitution. However, more telling about the political culture in Ireland is the revelation of the willingness of constituents to ask their TDs to get penalty points squashed for them, this kind of localism and clientalism is one of the objectionable practices we would have hoped would have been left behind after the last election. The Gardaí have since had an internal investigation, where it was found that, while penalty points have been squashed, nothing corrupt has occurred. This is a staggering example of a worrying culture within the Gardaí, our politicians and ourselves. An offence has been committed and there is nothing corrupt about asking the Gardaí to get rid of the punishment. What has set alarm bells ringing is how this seems to have infected some of the newest members of the Dáil.

The last election, lest we forget, is when the Irish people put down the ‘Bolly’, stepped away from artichoke canapé and voted to punish the political culture which we had allowed to flourish by allowing them to dope us up to the gills with cheap money. “Down with that sort of thing!” was what we bellowed from the ballot box. Fine Gael stomped away with a record number of seats but what was more interesting was the emergence of independents who represented, they claimed, the ordinary person on the street and promised to ask the difficult questions.

Archaic parliamentary processes make it difficult for a lone voice to have any affect and so this motley crew banded together despite having ideologies that ranged from Claire Daly on the left and Shane Ross on the right. Included in this group we have Luke ‘Ming’ Flanagan, a man who has undergone an interesting evolution; from outsider-agitator sending joints to TDs in an effort to legalise marijuana, to the Mayor of Roscommon and now an independent TD promising to protect turf-cutters in his locality. He is one individual who has recently found himself in trouble for having penalty points squashed. This is an issue that he campaigned against – Gardaí corruption – so I hope the irony hasn’t been lost on him (although judging by the beard he has been sporting, perhaps Ming and irony are not familiar bedfellows).

The issue of the penalty point squashing may appear to be a small fish compared to the problems facing Ireland on a day-to-day basis. The public service is on the verge of a mass walk out over pay and conditions so why do I concern myself with issues that pale in significance in comparison? The reason is that this is a systemic problem, one which permeates through every level of decision making. It is the culture which will force homeowners in unfinished estates across the country to pay the property tax despite the fact they are living in estates that are continuing to degenerate. It is a culture that has, two years on from the general election and five years on from the beginning of the economic collapse, endorsed a government which seems to be incapable of standing up to the banking system in Ireland. We are still no closer to sorting out a deal which takes the proposition of evictions off the table for families across the country. I’m not talking about debt forgiveness here but there are many other options such as equity for debt which are viable.

It seems that the cosy relationship between our political class and the banking sector continues despite the pain and suffering which it has caused in the last five years. Perhaps the margin of their election win has meant that Fine Gael have become complacent in their position as Ireland’s biggest party but it is the very lack of political cultural evolution which they should be wary of. They may well suffer a double whammy of being in charge when there is no money with difficult and unpopular policies to be made (see Cameron’s Conservatives in Britain who are on their way out after one term but are determined to dismantle as much of the state as possible before they leave) and the willingness of the Irish electorate to forgive and forget about Fianna Fail’s ineptitude when they last had their hands on the wheel. One should always be suspicious of mid-term popularity polls but there is the very real prospect of Fianna Fáil making a significant recovery before the next election.

So, are we, in fact, responsible for the lack of development in our political culture? Have politicians, bankers and developers driven us into this quagmire because we have allowed them to? A former History professor of mine, who is of some note, told us that we were ‘face down in the trough for too long’ and that we are all culpable for letting this culture to develop. We were bought off with tax cuts, cheap credit and second homes and we allowed this attitude of arrogance and ‘cuteness’ to fester.

There is an intriguing email exchange between two heavyweights in the theory of Power, Stephen Lukes and Clarrisa Hayward, debating the role of responsibility and agency in power. To try and sum it up would be a fool’s errand but here we go anyway. Lukes’ case is that full responsibility must lie with the actors, whereas Hayward puts forward the case that the social constructs of society influence greatly the actions of actors – essentially that society creates the parameters under which abuses of power are exercised.

What have we done to change this? We elect on local issues and we tolerate abuses of position and power and we solicit abuses to have our own penalty points squashed. Look across the water, to Britain where Chris Hune MP is facing prison time for asking his wife to take his penalty points. I’m not being unrealistic here, I’m not asking for whiter than white politicians who never put a foot out of step and I am aware by continuing to use words such as ‘evolution’ that time is required.

What we should, at a bare minimum, be asking for is transparency and accountability from our politicians, those at least would be steps in the right direction in arresting the decline in the relationships between the people and the officials we put into power. Then when faced with honest and open assessment of their work perhaps we can reassess our own actions and motivations at the ballot box beyond our own selfish desires.