Home > front end >  Conditional Number Formatting in R
Conditional Number Formatting in R

Time:06-23

Can anyone tell me how I can conditionally format my data.table so that numbers >= 1000 do not have decimal places and those below 1000 only have one decimal place?

Here's an image of my data.table

enter image description here

CodePudding user response:

You could use tibbles which allows to print vectors as you like, see vignette("pillar", package = "vctrs").

As shown in this answer on a similar need :

You can get basic control over how a vector is printed in a tibble by providing a format() method

To answer your question, you could create a custom_numeric class extending numeric, see vignette("s3-vector", package = "vctrs"):

library(vctrs)
library(data.table)
library(tibble)

data <- data.table(a=1.11,b=100.11,c=1000.11)

custom_numeric<- function(x = numeric()) {
  vec_assert(x, numeric())
  new_vctr(x, class = "vctrs_custom_numeric")
}

# Create custom format
format.vctrs_custom_numeric<- function(x,...) {
  sapply(vec_data(x),function(x) {if (x>1000) round(x) else x})
}

# Rename custom type name in column header
vec_ptype_abbr.vctrs_custom_numeric <- function(x) {
  "numeric"
}

# Apply custom type to all numeric columns
data[,(names(data)):= lapply(.SD,function(col) if (is.numeric(col)) custom_numeric(col) else col )]

# Convert to tibble
tibble::tibble(data)

#> # A tibble: 1 × 3
#>           a         b         c
#>   <numeric> <numeric> <numeric>
#> 1      1.11    100.11      1000

CodePudding user response:

Using the dev version of data.table (1.14.3), you could implement a numeric method for format_col generic. More information about customized printing of data.table is available at HERE

Here is an example:

library(data.table)
update.dev.pkg()          # to use the dev version

# sample data
set.seed(123)
dt = data.table(a=rnorm(10, 1000, 100), b=rnorm(10, 1000, 100))

# run dt before creating a numeric method for format_col generic
dt
#             a         b
#         <num>     <num>
#  1:  943.9524 1122.4082
#  2:  976.9823 1035.9814
#  3: 1155.8708 1040.0771
#  4: 1007.0508 1011.0683
#  5: 1012.9288  944.4159
#  6: 1171.5065 1178.6913
#  7: 1046.0916 1049.7850
#  8:  873.4939  803.3383
#  9:  931.3147 1070.1356
# 10:  955.4338  952.7209

# create a numeric method for format_col
format_col.numeric = function(x, ...) {
  ifelse(abs(x)<=1000, round(x), round(x, 1))
}

# printing after
dt
#          a      b
#      <num>  <num>
#  1:    944 1122.4
#  2:    977   1036
#  3: 1155.9 1040.1
#  4: 1007.1 1011.1
#  5: 1012.9    944
#  6: 1171.5 1178.7
#  7: 1046.1 1049.8
#  8:    873    803
#  9:    931 1070.1
# 10:    955    953
  • Related