9 JSON R packages

R has 3 packages for working with JSON data

  • "RJSONIO" by Duncan Temple Lang

  • "rjson" by Alex Couture-Beil

  • "jsonlite" by Jeroen Ooms, Duncan Temple Lang, Jonathan Wallace

All packages provide 2 main functions, toJSON() and fromJSON(), that allow conversion to and from data in JSON format, respectively. We’ll focus on the functions from "jsonlite".

For illustration purposes, let us consider the package "jsonlite".

There are 2 primary functions in "jsonlite":

  • toJSON() converts an R object to a string in JSON

  • fromJSON() converts JSON content to R objects

9.1 Function toJSON()

The function jsonlite::toJSON() converts an R object to a string in JSON.

Example: single number to JSON-array

Let’s begin with a super simple example by passing a single data value to the function toJSON():

toJSON(pi, digits = 4)
#> [3.1416]

Example: vectors to JSON-arrays

Consider the following vectors

num <- c(1, 2, 3, 4, 5)
lts <- c('a', 'b', 'c', 'd', 'e')

Applying toJSON() to the vectors num and lts produces JSON arrays:

toJSON(num)
#> [1,2,3,4,5]

toJSON(lts)
#> ["a","b","c","d","e"]

The argument pretty = TRUE allows you to obtain a JSON string with added indentation whitespace:

toJSON(num, pretty = TRUE)
#> [1, 2, 3, 4, 5]

toJSON(lts, pretty = TRUE)
#> ["a", "b", "c", "d", "e"]

What about an R vector with named elements? For example, here’s a vector vec

vec <- num
names(vec) <- lts
vec
#> a b c d e 
#> 1 2 3 4 5

Converting vec to JSON, we get:

toJSON(vec)
#> [1,2,3,4,5]

As you can tell, the names of the elements in vec are lost in translation.

Example: matrix to JSON-array

Here’s another example from an matrix to a JSON array:

mat <- matrix(9:1, nrow = 3, ncol = 3)
mat
#>      [,1] [,2] [,3]
#> [1,]    9    6    3
#> [2,]    8    5    2
#> [3,]    7    4    1

toJSON() converts an R matrix into a JSON-array

toJSON(mat)
#> [[9,6,3],[8,5,2],[7,4,1]]

Notice that the returned output arranges the values of the matrix row-by-row, also referred to as row-major. This means that when the input is an R matrix, toJSON() uses its argument matrix = "rowmajor".

You can change the arrangement to column-major by specifying the argument matrix = "columnmajor":

toJSON(mat, matrix = "columnmajor")
#> [[9,8,7],[6,5,4],[3,2,1]]

Example: data frame to JSON-object

We can also use toJSON() on data frames. Here’s an example of an assembled data frame swdf which will be converted to a JSON-object:

# toy data
sw_data <- rbind(
  c("Anakin", "male", "Tatooine", "41.9BBY",  "yes"),  
  c("Amidala", "female", "Naboo", "46BBY", "no"),
  c("Luke", "male", "Tatooine", "19BBY", "yes"),
  c("Leia", "female", "Alderaan", "19BBY", "no")
)

# convert to data.frame and add column names
swdf <- data.frame(sw_data, stringsAsFactors = FALSE)
names(swdf) <- c("Name", "Gender", "Homeworld", "Born", "Jedi")
swdf
#>      Name Gender Homeworld    Born Jedi
#> 1  Anakin   male  Tatooine 41.9BBY  yes
#> 2 Amidala female     Naboo   46BBY   no
#> 3    Luke   male  Tatooine   19BBY  yes
#> 4    Leia female  Alderaan   19BBY   no

The default output when you pass a data frame to jsonlite::toJSON() is

# convert R data.frame to JSON
sw_json = toJSON(swdf)
sw_json
#> [{"Name":"Anakin","Gender":"male","Homeworld":"Tatooine","Born":"41.9BBY","Jedi":"yes"},{"Name":"Amidala","Gender":"female","Homeworld":"Naboo","Born":"46BBY","Jedi":"no"},{"Name":"Luke","Gender":"male","Homeworld":"Tatooine","Born":"19BBY","Jedi":"yes"},{"Name":"Leia","Gender":"female","Homeworld":"Alderaan","Born":"19BBY","Jedi":"no"}]

The argument dataframe gives you more control on the output. This argument has three options:

  • "rows": each row is converted to a JSON-object with key-value pairs formed by "column_name": "row_value";
toJSON(swdf, dataframe = "rows")
#> [{"Name":"Anakin","Gender":"male","Homeworld":"Tatooine","Born":"41.9BBY","Jedi":"yes"},{"Name":"Amidala","Gender":"female","Homeworld":"Naboo","Born":"46BBY","Jedi":"no"},{"Name":"Luke","Gender":"male","Homeworld":"Tatooine","Born":"19BBY","Jedi":"yes"},{"Name":"Leia","Gender":"female","Homeworld":"Alderaan","Born":"19BBY","Jedi":"no"}]
  • "columns": each column is converted into a JSON-object with a single key for each column, and values stored as arrays;
toJSON(swdf, dataframe = "columns")
#> {"Name":["Anakin","Amidala","Luke","Leia"],"Gender":["male","female","male","female"],"Homeworld":["Tatooine","Naboo","Tatooine","Alderaan"],"Born":["41.9BBY","46BBY","19BBY","19BBY"],"Jedi":["yes","no","yes","no"]}
  • "values": the values in each column are converted to a JSON-array, and the names of the columns are lost.
toJSON(swdf, dataframe = "values")
#> [["Anakin","male","Tatooine","41.9BBY","yes"],["Amidala","female","Naboo","46BBY","no"],["Luke","male","Tatooine","19BBY","yes"],["Leia","female","Alderaan","19BBY","no"]]

9.2 Function fromJSON()

In practice, instead of converting R objects to JSON objects, it is more common to have data in JSON format which needs to be converted into an R object.

The function jsonlite::fromJSON() converts a JSON-object to an R object.

Example: JSON-array to R vector

json_array <- '["computing", "with", "data"]'

fromJSON(json_array)
#> [1] "computing" "with"      "data"

Example: JSON-object to R object

Consider a simple JSON-object, and its conversion to R with jsonlite::fromJSON()

json_obj1 <- '{"name": "Jessica"}'

fromJSON(json_obj1)
#> $name
#> [1] "Jessica"

Notice that the obtained object is an R list in which the key becomes the name of the list, and the value becomes the content of the list’s element.

Consider a less simple JSON-object:

json_obj2 <- '{"name1": "Nicole", "name2": "Pleuni", "name3": "Rori"}'

fromJSON(json_obj2)
#> $name1
#> [1] "Nicole"
#> 
#> $name2
#> [1] "Pleuni"
#> 
#> $name3
#> [1] "Rori"

Another example:

fromJSON('{"name": ["X", "Y"], "grams": [30, 20], "qty": [4, null],
"new": [true, false]}')
#> $name
#> [1] "X" "Y"
#> 
#> $grams
#> [1] 30 20
#> 
#> $qty
#> [1]  4 NA
#> 
#> $new
#> [1]  TRUE FALSE

Example: JSON-object to R object

Suppose you have a JSON object with the following data:

{
  "Name": ["Anakin","Amidala","Luke","Leia"],
  "Gender": ["male","female","male","female"],
  "Homeworld": ["Tatooine","Naboo","Tatooine","Alderaan"],
  "Born": ["41.9BBY","46BBY","19BBY","19BBY"],
  "Jedi": ["yes","no","yes","no"]
}

and assume that the above data is stored as a single (continuous) string in an R character vector json_sw; applying fromJSON() to this string gives you the following list:

fromJSON(json_sw)
#> $Name
#> [1] "Anakin"  "Amidala" "Luke"    "Leia"   
#> 
#> $Gender
#> [1] "male"   "female" "male"   "female"
#> 
#> $Homeworld
#> [1] "Tatooine" "Naboo"    "Tatooine" "Alderaan"
#> 
#> $Born
#> [1] "41.9BBY" "46BBY"   "19BBY"   "19BBY"  
#> 
#> $Jedi
#> [1] "yes" "no"  "yes" "no"

Can this be transformed into a data frame? Yes, by passing the obtained list to the function data.frame():

data.frame(fromJSON(json_sw))
#>      Name Gender Homeworld    Born Jedi
#> 1  Anakin   male  Tatooine 41.9BBY  yes
#> 2 Amidala female     Naboo   46BBY   no
#> 3    Luke   male  Tatooine   19BBY  yes
#> 4    Leia female  Alderaan   19BBY   no

9.3 Reading JSON Data

Now that we have discussed the basics of JSON, and the common ways to convert fromJSON() and toJSON(), let’s see how to read JSON data from the Web.

One of the typical ways to import JSON data from the Web to R is by passing the url directly to fromJSON(). Another way is by passing the name of the file with the JSON content as a single string to the function fromJSON().

Here’s an example reading a JSON string from the website Advice Slip. The url https://api.adviceslip.com/advice gives you a random advice (see figure below):

Random advice from Advice Slip

Figure 9.1: Random advice from Advice Slip

As you can tell, the content is a simple JSON string

advice_url <- "https://api.adviceslip.com/advice"

fromJSON(advice_url)
#> $slip
#> $slip$id
#> [1] 9
#> 
#> $slip$advice
#> [1] "True happiness always resides in the quest!"

Example: Colors in Hexadecimal Notation

The following data comes from one of Dave Eddy’s github repositories:

https://raw.githubusercontent.com/bahamas10/css-color-names/master/css-color-names.json

This is a JSON-object in which the keys are color-names, and the values are the hexadecimal digits of the corresponding color:

{
  "aliceblue": "#f0f8ff",
  "antiquewhite": "#faebd7",
  "aqua": "#00ffff",
  "aquamarine": "#7fffd4",
  "azure": "#f0ffff",
  ...
  "wheat": "#f5deb3",
  "white": "#ffffff",
  "whitesmoke": "#f5f5f5",
  "yellow": "#ffff00",
  "yellowgreen": "#9acd32"
}

We pass the url to jsonlite::fromJSON()

colors_json <- "https://raw.githubusercontent.com/bahamas10/css-color-names/master/css-color-names.json"

hex_colors <- fromJSON(colors_json)

The output in hex_colors is a list with 148 elements; the first five elements are displayed below:

hex_colors[1:5]
#> $aliceblue
#> [1] "#f0f8ff"
#> 
#> $antiquewhite
#> [1] "#faebd7"
#> 
#> $aqua
#> [1] "#00ffff"
#> 
#> $aquamarine
#> [1] "#7fffd4"
#> 
#> $azure
#> [1] "#f0ffff"