Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw a stem and leaf plot which shows the real leaf without rounding up

Tags:

plot

r

For example, I have numbers: 43.2, 45.3, 48.1, 54.2. When I use stem() function to draw a plot, I get this: stem() function shows like this

x <- c(43.2, 45.3, 48.1, 54.2)

stem(x)
# 
# The decimal point is 1 digit(s) to the right of the |
#   
#   4 | 3
#   4 | 58
#   5 | 4

But from the plot I can only know the numbers are: 43,45,48,54. So I want a function to draw a stem and leaf plot with which I can still know the exact number without rounded up.

Moreover, I want it to use only one digit to represent stem, while showing the else in the leaf. For example, 43.2 should be a stem 4 and a leaf 3.2, 43.22 should be a stem 4 and a leaf 3.22. For numbers: 43.2, 45.3, 48.1, 54.2. I want the plot like this:

enter image description here

like image 300
王昊天 Avatar asked Sep 03 '16 16:09

王昊天


2 Answers

x <- c(43.2, 45.3, 48.1, 54.2)

stem(x)
# 
# The decimal point is 1 digit(s) to the right of the |
#   
#   4 | 3
#   4 | 58
#   5 | 4

stem2(x)
# 
# The decimal point is 1 digit(s) to the right of the |
#   
#   4 | 3.2
#   4 | 5.3, 8.1
#   5 | 4.2

stem2 <- function(x) {
  cx <- gsub('^.', ', ', as.character(sort(x)))
  co <- capture.output(stem(x))
  m <- gregexpr('\\d(?!.*\\|)', co, perl = TRUE)
  l <- regmatches(co, m)
  l <- t(do.call('rbind', lapply(l, `length<-`, max(lengths(l)))))
  l[!is.na(l)] <- cx
  regmatches(co, m) <- data.frame(l)
  cat(gsub(' , ', ' ', co), sep = '\n')
}
like image 195
rawr Avatar answered Oct 19 '22 22:10

rawr


Here's one way. I have used the data.table package below, so if you do not have it, please install it first. If you really prefer that the plot be created using the regular data frame, let me know and I will adjust it accordingly.

library(data.table) # Install via install.packages(data.table)

# x is the vector of numbers for which you want to create the stem and leaf plot
# leftDigits gives the position of the '|' relative to the decimal point, 
# e.g. leftDigits = 0 will result in 43.2 being represented as 43 | 0.2
# e.g. leftDigits = 1 will result in 43.2 being represented as 4 | 3.2
# I have included a rounding parameter, due to floating point problems seen when taking the difference of two numbers
# rounding = 2 means that your numbers will show to 2 decimal places. Change as desired.
myStem <- function(x, leftDigits, rounding = 2){
  data = data.table("x" = x) # Create a data.table
  data[, left := floor(x/10^leftDigits)] # Get the number that will be to the left of '|'
  data[, right := round(x - left*10^leftDigits, rounding)] # The remainder will be on the right
  data = data[, paste(sort(right), collapse = ", "), by = left] # For each 'left', Place all the 'right' values in a comma separated string.
  data[, out := paste(left, " | ", V1), by = left] # Add the "|"
  cat(data$out, sep = "\n") # Output
}

# Example
myStem(x = c(43.2, 45.3, 48.1, 54.2), 1)
# 4  |  3.2, 5.3, 8.1
# 5  |  4.2

Edit: If you would like a back to back plot, then the following code should work. It works in a similar manner as the previous code

myStem <- function(leftVals, rightVals, mainDigits, rounding = 10){
  data = data.table("x" = leftVals, "ind" = "x") 
  data = rbind(data, data.table("x" = rightVals, "ind" = "y")) 
  data[, main := floor(x/10^mainDigits)] 
  data[, right := round(x - main*10^mainDigits, rounding)] 
  data = data[, ifelse(ind == "x", paste0(-sort(-right), collapse = ", "), paste0(sort(right), collapse = ", ")), by = c("ind", "main")] # For each 'main', Place all the 'right' values in a comma separated string.
  data = dcast(data, main ~ ind, value.var = "V1")
  data[, "left|" := ifelse(is.na(x), "", "|")]
  data[, "right|" := ifelse(is.na(y), "", "|")]
  data[, x := ifelse(is.na(x), "", x)]
  data[, y := ifelse(is.na(y), "", y)]
  data = data[, c("x", "left|", "main", "right|", "y"), with = F]
  maxLengthY = max(nchar(data$y))
  data[, y := unlist(lapply(y, function(z) paste0(z, paste0(replicate(maxLengthY - nchar(z), " "), collapse = ""))))]
  colnames(data) = rep(" ", ncol(data))
  data
}

# Example
myStem(leftVals = c(43.2, 45.3, 48.1, 54.2), rightVals = c(30.2, 34.5, 44.3), 1)

1:                 3 | 0.2, 4.5
2: 8.1, 5.3, 3.2 | 4 | 4.3     
3:           4.2 | 5           
like image 32
jav Avatar answered Oct 19 '22 22:10

jav