-
Notifications
You must be signed in to change notification settings - Fork 10
/
README.Rmd
242 lines (173 loc) · 5.7 KB
/
README.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
---
output: github_document
editor_options:
chunk_output_type: console
---
[![R build status](https://github.com/SymbolixAU/jsonify/workflows/R-CMD-check/badge.svg)](https://github.com/SymbolixAU/jsonify/actions)
[![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/jsonify)](https://CRAN.R-project.org/package=jsonify)
![downloads](http://cranlogs.r-pkg.org/badges/grand-total/jsonify)
[![CRAN RStudio mirror downloads](http://cranlogs.r-pkg.org/badges/jsonify)](https://CRAN.R-project.org/package=jsonify)
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "# ",
fig.path = "man/figures/README-",
out.width = "100%"
)
library(jsonify)
```
# jsonify
Converts between R objects and JSON.
```{r}
js <- '[{"x":1,"y":"a"},{"x":2,"y":"b"}]'
( df <- from_json( js ) )
( to_json( df ) )
```
### There are already JSON converters, why did you build this one?
Because I wanted it available at the source ( C++ ) level for integrating into other packages.
### What do you mean by "available at the source" ?
I want to be able to call the C++ code from another package, without going to & from R. Therefore, the C++ code is implemented in headers, so you can "link to" it in your own package.
For example, the `LinkingTo` section in **DESCRIPTION** will look something like
```yaml
LinkingTo:
Rcpp,
rapidjsonr (>= 1.2.0),
jsonify
```
And in a c++ source file you can `#include` the header and use the available functions
```c++
#include "jsonify/jsonify.hpp"
Rcpp::StringVector my_json( Rcpp::DataFrame df ) {
return jsonify::api::to_json( df );
}
```
You can see an example of this in my `{geojsonsf}` package
- [Description](https://github.com/SymbolixAU/geojsonsf/blob/master/DESCRIPTION#L17)
- [#include](https://github.com/SymbolixAU/geojsonsf/blob/master/inst/include/geojsonsf/geojson/api/sf_api.hpp#L4)
### Can I call it from R if I want to?
Yes. Just like the examples in this readme use `to_json()`
```{r}
df <- data.frame(
id = 1:3
, val = letters[1:3]
)
jsonify::to_json( df )
```
### Is it fast?
yeah it's pretty good.
```{r, eval = FALSE}
library(microbenchmark)
library(jsonlite)
n <- 1e6
df <- data.frame(
id = 1:n
, value = sample(letters, size = n, replace = T)
, val2 = rnorm(n = n)
, log = sample(c(T,F), size = n, replace = T)
, stringsAsFactors = FALSE
)
microbenchmark(
jsonlite = {
jlt <- jsonlite::toJSON( df )
},
jsonify = {
jfy <- jsonify::to_json( df )
},
times = 3
)
# Unit: seconds
# expr min lq mean median uq max neval
# jsonlite 2.017081 2.063732 2.540350 2.110383 2.801984 3.493585 3
# jsonify 1.186239 1.202719 1.514067 1.219198 1.677981 2.136763 3
microbenchmark(
jsonlite = {
df_jlt <- jsonlite::fromJSON( jlt )
},
jsonify = {
df_jfy <- jsonify::from_json( jfy )
},
times = 3
)
# Unit: seconds
# expr min lq mean median uq max neval
# jsonlite 5.034888 5.149688 5.229363 5.264489 5.326601 5.388713 3
# jsonify 4.551434 4.629683 4.678198 4.707932 4.741579 4.775227 3
n <- 1e4
x <- list(
x = rnorm(n = n)
, y = list(x = rnorm(n = n))
, z = list( list( x = rnorm(n = n)))
, xx = rnorm(n = n)
, yy = data.frame(
id = 1:n
, value = sample(letters, size = n, replace = T)
, val2 = rnorm(n = n)
, log = sample(c(T,F), size = n, replace = T)
)
)
microbenchmark(
jsonlite = {
jlt <- jsonlite::toJSON( x )
},
jsonify = {
jfy <- jsonify::to_json( x )
},
times = 5
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# jsonlite 18.52028 18.82241 19.32112 18.99683 19.18103 21.08508 5
# jsonify 17.72060 18.19092 19.58308 19.52457 21.14687 21.33241 5
microbenchmark(
jsonlite = {
df_jlt <- jsonlite::fromJSON( jlt )
},
jsonify = {
df_jfy <- jsonify::from_json( jfy )
},
times = 3
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# jsonlite 62.53554 62.96435 63.12574 63.39316 63.42084 63.44853 3
# jsonify 42.47449 42.53826 43.38475 42.60204 43.83988 45.07773 3
```
### There's no `Date` type in JSON, how have you handled this?
At its core `Dates` in R are numeric, so they are treated as numbers when converted to JSON. However, the user can coerce to character through the `numeric_dates` argument.
```{r}
df <- data.frame(dte = as.Date("2018-01-01"))
jsonify::to_json( df )
df <- data.frame(dte = as.Date("2018-01-01"))
jsonify::to_json( df, numeric_dates = FALSE )
```
### And `POSIXct` and `POSIXlt`?
The same
```{r}
jsonify::to_json( as.POSIXct("2018-01-01 10:00:00") )
jsonify::to_json( as.POSIXct("2018-01-01 10:00:00"), numeric_dates = FALSE)
```
However, here the **POSIXct** values are returned in UTC timezone. This is by design.
**POSIXlt** will return each component of the date-time
```{r}
x <- as.POSIXlt("2018-01-01 01:00:00", tz = "GMT")
jsonify::to_json( x )
jsonify::to_json( x, numeric_dates = FALSE)
```
### I see factors are converted to strings
Yep. Even though I constructed a `data.frame()` without setting `stringsAsFactros = FALSE`, jsonify automatically treats factors as strings.
### Has this changed from v0.1?
Yes. And it's to keep the data more inline with modern concepts and design patterns.
If you want factors, use `factors_as_string = FALSE` in the `to_json()` call
```{r}
jsonify::to_json( df, factors_as_string = FALSE )
```
### How do I install it?
Get the latest release version from CRAN
```{r, eval = FALSE}
install.packages("jsonify")
```
Or the development version from [GitHub](https://github.com/) with:
```{r, eval = FALSE}
# install.packages("devtools")
devtools::install_github("SymbolixAU/jsonify")
```