-
Notifications
You must be signed in to change notification settings - Fork 1
/
RequiredFormat.R
834 lines (635 loc) · 31 KB
/
RequiredFormat.R
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
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
#'RequiredFormat
#'
#'@param Data Forest inventory data set (data.frame or data.table) - already stacked, merged and tidyed
#'
#'@param input A named list, typically the output of function
#' RequiredFormat_interactive, also called site profile. It has information on
#' column names correspondence, size units etc...
#'
#'@param x For internal use when function used by Shiny app
#'
#'@param MeasLevel your deepest level of measurements(When function is run outside of Shiny app). Options are one of c("Plot", "Species", "Tree", "Stem")
#'
#'
#'@details This function takes the forest inventory data.frame or data.table as
#' it is, and converts the column names to the standardized names used in this
#' package. It also generates missing information, when possible (e.g. Diameter when
#' only circumference is givent, Genus and Species when only scientifique name
#' is given etc...). All the decisions are made based on what is provided in
#' the input argument, which is a named list, as returned by function
#' RequiredFormat_interactive or Profile.rds file downloaded from shiny app
#'
#'@return Input inventory (data.frame) in the required package format.
#'
#'@export
#'
#'@importFrom data.table copy setDT setDF melt tstrsplit :=
#'@importFrom utils read.csv
#'@importFrom units install_unit remove_unit
#'
#' @examples
#'\dontrun{
#' data(ParacouSubset)
#' data(ParacouProfile)
#' ParacouSubsetFormated <- RequiredFormat(
#' ParacouSubset,
#' input = ParacouProfile,
#' MeasLevel = "Tree")
#' }
#'
RequiredFormat <- function(
Data,
input,
x = NULL,
MeasLevel = NULL
){
# data(ParacouSubset)
# data(ParacouProfile)
# Data <- ParacouSubset
# input <- ParacouProfile
ThisIsShinyApp = shiny::isRunning() # this is for internal use when function used by Shiny app
# prepare a place to hold all warnings so we get only one pop up window
AllWarnings <- NULL
# Arguments check
if (!inherits(Data, c("data.table", "data.frame")))
stop("Data must be a data.frame or data.table")
if(!ThisIsShinyApp & !inherits(input, "list")) {
stop("input must be a list (typically, the output of funcion RequireFormat_interactive.R,
or a profile saved viw the Shiny App")
}
# Load interactive items to see what we are missing ####
if(!ThisIsShinyApp) {
x <- try(expr = read.csv(system.file("/app/data/", "interactive_items.csv", package = "DataHarmonization", mustWork = TRUE)), silent = T)
if (class(x) %in% "try-error"){
AllWarnings <- c(AllWarnings, "DataHarmonization package not loaded. Assuming you are in the root of the package instead.")
x <- read.csv("inst/app/data/interactive_items.csv")
}
# keep only what is "active" (the rest is not in used)
x <- x[x$Activate,]
# add MeasLevel
if(!MeasLevel %in% c("Plot", "Species", "Tree", "Stem")) stop("MeasLevel needs to be one of 'Plot, 'Species', 'Tree' or 'Stem'")
input$MeasLevel <- MeasLevel
}
CharacVar <- x$ItemID[x$DataType %in% "character"]
NumVar <- x$ItemID[x$DataType %in% "numeric"]
LogicVar <- x$ItemID[x$DataType %in% "logical"]
FactorVar <- x$ItemID[x$DataType %in% "factor"]
# standardize column names ####
setDF(Data) # just for this step then we can put back in data.table
idx <- match(gsub("[[:punct:]]| ", "", colnames(Data)), gsub("[[:punct:]]| ", "", input[x$ItemID]))
NewColNames <- names(input[x$ItemID])[idx]
## deal with TreeCodes separately
## repeat cases where multiple columns match one item (only checked for TreeCodes, need to check what happens for other columns)
multiplecolumns <- names(which(sapply(input[x$ItemID[!x$Group %in% "second column"]], length)>1))
if(any(!multiplecolumns %in% "TreeCodes")) stop ("You've selected multiple columns for something other than 'TreeCodes', please contact us at herrmannv@si.edu")
if(length(multiplecolumns) > 0 & all(multiplecolumns %in% "TreeCodes")) {
TreeCodes <- input[multiplecolumns][[1]]
names(TreeCodes) <- rep(multiplecolumns, length(TreeCodes))
input[multiplecolumns] <- NULL
Data[, paste0("Original_", colnames(Data)[colnames(Data) %in% TreeCodes])] <- Data[, colnames(Data) %in% TreeCodes]
NewColNames <- c(NewColNames, paste0("Original_", colnames(Data)[colnames(Data) %in% TreeCodes]))
} else {
if(!is.null(input$TreeCodes) && !input$TreeCodes %in% "none" & all(input$TreeCodes %in% names(Data)) ) {
Data[, paste0("Original_", colnames(Data)[colnames(Data) %in% input$TreeCodes])] <- Data[, colnames(Data) %in% input$TreeCodes]
NewColNames <- c(NewColNames, paste0("Original_", colnames(Data)[colnames(Data) %in% input$TreeCodes]))
}
}
# change columns
colnames(Data) <- NewColNames
## delete columns we don't want (except the ones related to TreeCodes)
Data[which(is.na(colnames(Data)))] <- NULL
# save some Original columns
Data[, paste0(intersect(names(Data),x$ItemID[x$SaveCopy]), "Original")] <- Data[, intersect(names(Data),x$ItemID[x$SaveCopy])]
## add columns missing
Data[, setdiff(gsub("[[:punct:]]| ", "", x$ItemID[x$RequiredColumn]), gsub("[[:punct:]]| ", "", colnames(Data)))] <- NA
## deal with case where one column represents more than one thing
DoubleFctColumn <- input[names(input) %in% x$ItemID[x$RequiredColumn] & !input %in% "none" & input %in% input[duplicated(input) & names(input) %in% x$ItemID[x$RequiredColumn]]]
for(j in names(DoubleFctColumn)) {
if(all(is.na(Data[, j]))) Data[, j] <- Data[, names(DoubleFctColumn[DoubleFctColumn %in% DoubleFctColumn[[j]] & !names(DoubleFctColumn) %in% j])]
if( !paste0(j, "Original") %in% names(Data)) Data[, paste0(j, "Original")] <- Data[, j]
}
setDT(Data)
Data <- copy(Data) # <~~~~~ KEY LINE so things don't happen on the global environment
# coerce to data types ####
### as.character
CharacVar <- CharacVar[CharacVar %in% colnames(Data)]
Data[, (CharacVar) := lapply(.SD, as.character), .SDcols = CharacVar] # (CharacVar) to say that these are existing columns and not new ones to create
### as.numeric
NumVar <- NumVar[NumVar %in% colnames(Data)]
Data[, (NumVar) := lapply(.SD, as.character), .SDcols = NumVar] # first as character when the variable is in factor, to preserve information
suppressWarnings(Data[, (NumVar) := lapply(.SD, as.numeric), .SDcols = NumVar]) # () to say that these are existing columns and not new ones to create
#### as.factor
FactorVar <- FactorVar[FactorVar %in% colnames(Data)]
Data[, (FactorVar) := lapply(.SD, as.factor), .SDcols = FactorVar] # (FactorVar) to say that these are existing columns and not new ones to create
### as.logical
## Here we have to use user input to know what is TRUE and what is not
### Life/Dead status
if( !is.null(input$LifeStatus)) {
if(is.null(input$DeadStatus)) {
stop("Your profile is missing 'DeadStatus'")
} else {
if(!input$LifeStatus %in% "none" & !input$DeadStatus %in% "none") {
# Data[, LifeStatusOriginal := LifeStatus]
Data[LifeStatusOriginal %in% input$IsLiveMan, LifeStatus := TRUE]
Data[DeadStatusOriginal %in% input$IsDeadMan, LifeStatus := FALSE]
Data[, LifeStatus := as.logical(LifeStatus)] # any other thing that "TRUE" and "FALSE" will be converted to NA.
Data[, DeadStatus := NULL] # delete that as we don't need it.
}
}
}
### commercial species
if( !is.null(input$CommercialSp)) {
if( !input$CommercialSp %in% "none") {
# Data[, CommercialSpOriginal := CommercialSp]
Data[, CommercialSp := ifelse(CommercialSp %in% input$IsCommercial, TRUE, FALSE)]
}
}
# LogicVar <- LogicVar[LogicVar %in% colnames(Data)]
# Data[, (LogicVar) := lapply(.SD, as.logical), .SDcols = LogicVar] # () to say that these are existing columns and not new ones to create
# Deal with Date of measurement before anything else ####
# add Year if given manually
if(input$Year %in% "none" & !input$YearMan %in% -999) {
Data[, Year := as.numeric(as.character(input$YearMan))]
# overwrite input
input$Year = "Year"
}
# concatenate if in 3 different columns
if(!input$Month %in% "none" & !input$Day %in% "none" & input$Date %in% "none") {
if(!input$Year %in% "none") {
Data[, Date := paste(trimws(Year), trimws(Month), trimws(Day), sep = "-")]
# overwrite input
input$Date = "Date"
input$DateFormatMan = "yyyy-mm-dd"
} else {
AllWarnings <- c(AllWarnings, "You did not provide a Year so we can't recreate a date using your Month and Day columns.")
}
}
# consider date as June 15th if not Date is given
if(input$Date %in% "none") {
if(!input$Year %in% "none") {
Data[, Date := paste0(Year, "-06-15")]
AllWarnings <- c(AllWarnings, "You did not provided a Date of measurement but provided a Year. We consider the date as 15th June of the year so as to prevent NA.")
# overwrite input
input$Date = "Date"
input$DateFormatMan = "yyyy-mm-dd"
} else {
AllWarnings <- c(AllWarnings, "You did not provide a Year so we can't recreate a date.")
}
}
# put in date format
if(!input$Date %in% "none"){
# save the orginal dates
# Data[, DateOriginal := Date]
# transform to standard format
DateFormat <- trimws(input$DateFormatMan)
if(grepl("num|dec", DateFormat, ignore.case = T)) {
if(grepl("num", DateFormat, ignore.case = T)) suppressWarnings(Data[, Date := as.Date(as.numeric(trimws(Date)), origin = "1970-01-01")])
if(grepl("dec", DateFormat, ignore.case = T)) suppressWarnings(Data[, Date := as.Date(lubridate::date_decimal(as.numeric(trimws(Date))))])
} else {
DateFormat <- gsub("(?<=^)\\w|(?<=[[:punct:]])\\w", "%", DateFormat, perl = T, ignore.case = T) # replace first letter of each word by '%'
DateFormat <- gsub("yyy", "Y", DateFormat, ignore.case = T)# if remains 3 `y`, change to upper case Y
Data[, Date := as.Date(trimws(as.character(Date)), format = DateFormat)]
}
# send warning if some dates translated as NA
if(any(!is.na(Data$DateOriginal) & is.na(Data$Date))) AllWarnings <- c(AllWarnings, "Some dates were translated as NA... Either your data format does not correspond to the format of your date column, or you do not have a consistent format across all your dates.")
}
# make input complete ####
## enter all itemID in input as "none" so we can refer to them - make sure this happens after standardizing column names otherwise that won't work...
input[setdiff(x$ItemID, names(input))] <- x$Default[match(setdiff(x$ItemID, names(input)), x$ItemID)]
# Fill in info in column missing ####
## Year
if(input$Year %in% "none") {
if(!input$Date %in% "none") Data[, Year := format(Date, "%Y")] else AllWarnings <- c(AllWarnings, "You did not provide Date nor Year.")
Data$Year <- as.numeric(as.character(Data$Year))
}
## Month
if(input$Month %in% "none") {
if(!input$Date %in% "none") Data[, Month := format(Date, "%m")]
Data$Month <- as.numeric(as.character(Data$Month))
}
## Day
if(input$Day %in% "none") {
if(!input$Date %in% "none") Data[, Day := format(Date, "%d")]
Data$Day <- as.numeric(as.character(Data$Day))
}
## IdCensus
### if Date, use that to order the IdCensus
if(!input$IdCensus %in% "none") {
if(!input$Date %in% "none") Data[, IdCensus := factor(IdCensus, levels = unique(IdCensus[order(Date)]), ordered = T)]
}
### if not IdCensus, use Year instead
if(input$IdCensus %in% "none") {
AllWarnings <- c(AllWarnings, "You did not provide a Census ID column. We will use year as census ID.")
Data$IdCensus <- factor(Data$Year, ordered = TRUE)
}
## Site, Plot, subplot
if (input$Site %in% "none") {
if(input$SiteMan %in% "") AllWarnings <- c(AllWarnings, "You did not specify a Site column or name, we will consider you have only one site called 'SiteA'.")
SiteMan <- ifelse(input$SiteMan %in% "", "SiteA", input$SiteMan)
Data[, Site := SiteMan]
}
if (input$Plot %in% "none") {
if(input$PlotMan %in% "") AllWarnings <- c(AllWarnings, "You did not specify a Plot column or name, we will consider you have only one plot called 'PlotA'.")
PlotMan <- ifelse(input$PlotMan %in% "", "PlotA", input$PlotMan)
Data[, Plot := PlotMan]
}
if (input$Subplot %in% "none"){
if(input$SubplotMan %in% "") AllWarnings <- c(AllWarnings, "You did not specify a subplot column or name, we will consider you have only one subplot called 'SubplotA'.")
SubplotMan <- ifelse(input$SubplotMan %in% "", "SubplotA", input$SubplotMan)
Data[, Subplot := SubplotMan]
}
## IdTree (unique along IdCensus) ####
if ((input$IdTree %in% "none" | any(is.na(Data$IdTree))) & input$MeasLevel %in% c("Tree", "Stem")) {
# if we also don't have TreeFieldNum, we are just considering that each row within a plot and subplot is one tree
if(input$IdTree %in% "none") Data$IdTree <- NA
# if we have TreeFieldNum, we use it
if (!input$TreeFieldNum %in% "none") {
AllWarnings <- c(AllWarnings, paste("You are missing treeIDs (either you are missing some tree IDs or you did not specify a column for tree IDs). But you did specified a column for tree tag, so we are considering that each tree tag within a Site, plot, subplot and census ID", ifelse(input$IdCensus %in% "none", "(taken as your Year, since you did not specify a census ID column)", ""), "refers to one tree, and we are using your tree field tag to construct the tree ID.", ifelse(any(is.na(Data$TreeFieldNum)), "And since some of your tree field tag are NAs, we will automatically generating those assuming each NA represents one single-stem tree and that the order of those trees is consistent accross censuses.", "")))
if(any(is.na(Data$TreeFieldNum))) {
Data[is.na(TreeFieldNum), TreeFieldNum := paste0(seq(1, .N), "_auto") , by = .(Site, Plot, Subplot, IdCensus)]
}
Data[is.na(IdTree), IdTree := paste(Site, Plot, Subplot, TreeFieldNum, "auto", sep = "_") , by = .(IdCensus)]
Data[is.na(IdTree), IdTree := paste(Site, Plot, Subplot, TreeFieldNum, "auto", sep = "_") , by = .(IdCensus)]
}
# if we also don't have TreeFieldNum, we are just considering that each row within a plot and subplot is one tree (or we use stemID, which will take care of ForestPlot data where theyonly have idTree for multistem tree)
if (input$TreeFieldNum %in% "none") {
if (input$IdStem %in% "none") {
AllWarnings <- c(AllWarnings, paste("You are missing treeIDs (either you are missing some tree IDs or you did not specify a column for tree IDs). You also did not specify a column for Tree Tags, so we are considering that each row within a Site, plot, subplot and census ID", ifelse(input$IdCensus %in% "none", "(taken as your Year, since you did not specify a census ID column)", ""), "refers to one unique (single-stem) tree. This is assuming the order of your trees is consistent accross censuses."))
Data[is.na(IdTree), IdTree := paste0(seq(1, .N), "_auto") , by = .(IdCensus)]
}
if (!input$IdStem %in% "none") {
AllWarnings <- c(AllWarnings, paste("You are missing treeIDs (either you are missing some tree IDs or you did not specify a column for tree IDs). You also did not specify a column for Tree Tags, BUT you did specify a column for Stem tags, so we are using IdStem to replace missing IdTree. WARNING: This was created to deal with ForestPlots data, where only only multiple stems have an IdTree, so, in that particular case, it is safe to use IdStem as IdTree."))
Data[is.na(IdTree), IdTree := paste0(IdStem, "_auto")]
}
}
}
## IdStem (unique along IdCensus) ####
if ((input$IdStem %in% "none" | any(is.na(Data$IdStem))) & input$MeasLevel %in% c("Tree", "Stem")) {
# if we also don't have StemFieldNum, we are just considering that each row within a plot and subplot and tree is one stem
if(input$IdStem %in% "none") Data$IdStem <- NA
if (input$StemFieldNum %in% "none") {
if (input$MeasLevel %in% "Stem") AllWarnings <- c(AllWarnings, "You are missing stemIDs (either you are missing some stem IDs or you did not specify a column for stem IDs). You also did not specify a column for stem Tags, so we are considering that each row without a stem ID refers to one unique stem within its tree ID. This is assuming that the order of each stem within a tree is consistent across censuses.")
Data[is.na(IdStem), IdStem := paste0(.(IdTree), "_", seq(1, .N), "_auto"), by = .(IdCensus, IdTree)]
}
# if we have TreeFieldNum, we use it
if (!input$StemFieldNum %in% "none") {
if (input$MeasLevel %in% "Stem") AllWarnings <- c(AllWarnings, "You are missing stemIDs (either you are missing some tree IDs or you did not specify a column for stem IDs). But you did specify a column for stem tags, so we are considering that each stem field number within a tree refers to a unique stem and are using your stem field number to construct the stem ID.", ifelse(any(is.na(Data$StemFieldNum)), "And since some of your stem field tags are NAs, we will automatically generating those assuming assuming that the order of each stem within a tree is consistent across censuse.", ""))
if(any(is.na(Data$StemFieldNum))) {
Data[is.na(StemFieldNum), StemFieldNum := paste0(seq(1, .N), "_auto") , by = .(IdCensus, IdTree)]
}
Data[is.na(IdStem), IdStem := paste(IdTree, StemFieldNum, "auto", sep = "_"), by = .(IdCensus)]
}
}
## Genus, Species, ScientificNameSepMan ####
if(!input$MeasLevel %in% c("Plot")) {
### Genus and species if we have ScientificName and ScientificNameSepMan
if(!input$ScientificName %in% "none" & !input$ScientificNameSepMan %in% "none") {
if(input$Genus %in% "none") Data[, Genus := tstrsplit(ScientificName, input$ScientificNameSepMan, fixed = TRUE, keep = c(1))]
if(input$Species %in% "none") Data[, Species := tstrsplit(ScientificName, input$ScientificNameSepMan, fixed = TRUE, keep = c(2))]
if(input$Subspecies %in% "none" & any(grepl(
"(.* .*){2,}", Data$ScientificName))) Data[, Subspecies := tstrsplit(ScientificName, input$ScientificNameSepMan , fixed = TRUE, keep = c(3))]
}
### ScientificName if we have Genus and species
if(!input$Genus %in% "none" & !input$Species %in% "none" & input$ScientificName %in% "none" ) Data[, ScientificName := paste(Genus, Species)]
}
## Diameter if we have circumference ####
if(input$MeasLevel %in% c("Tree", "Stem")) {
if(input$Diameter %in% "none" & input$Circ %in% "none" & input$BD %in% "none" & input$BCirc %in% "none") AllWarnings <- c(AllWarnings, "You did not specify what column represents tree size (Diameter, Circonference, BD or basal circonference) in your data.")
if(input$Diameter %in% "none" & !input$Circ %in% "none") {
Data[, Diameter := round(Circ/pi, 2)]
input$DiameterUnitMan <- input$CircUnitMan
}
if(input$BD %in% "none" & !input$BCirc %in% "none") {
Data[, BD := round(BCirc/pi, 2)]
input$BDUnitMan <- input$BCircUnitMan
}
}
## LifeForm if provided manuall
if(input$LifeForm %in% "none" & length(input$LifeFormMan) > 0) {
Data[, LifeForm := paste(input$LifeFormMan, collapse = ";")]
input$LifeForm = "LifeForm"
}
## MinDBH if we don't have it
if(input$MinDBH %in% "none") {
if(!input$MinDBHMan %in% -999) {
Data[, MinDBH := input$MinDBHMan]
input$MinDBHUnitMan <- "cm" # if MinDBH given by hand, it should be in cm
}
if(input$MinDBHMan %in% -999) {
if(input$MeasLevel %in% c("Tree", "Stem")) {
Data[, MinDBH := min(Diameter, na.rm = T)]
input$MinDBHUnitMan <- grep("[^none]", c(input$DiameterUnitMan, input$CircUnitMan), value = T)[1] # take Diameter in priority, otherwise CircUnit
AllWarnings <- c(AllWarnings, "MinDBH was calculated.")
} else {
AllWarnings <- c(AllWarnings, "You did not specify a MinDBH.")
}
}
}
## HOM if we don't have it
if(input$HOM %in% "none") {
if(!input$HOMMan %in% -999) {
Data[, HOM := input$HOMMan]
input$MinDBHUnitMan <- "m" # if HOM given by hand, it should be in m
}
if(input$HOMMan %in% -999) {
if(input$MeasLevel %in% c("Tree", "Stem")) {
AllWarnings <- c(AllWarnings, "You did not specify a height of measurement (HOM)")
}
}
}
# PlotArea (if area is entered manually, it is supposed to be in ha already)
if(input$PlotArea %in% "none") {
if(!input$PlotAreaMan %in% -999) {
Data[, PlotArea := input$PlotAreaMan]
input$PlotAreaUnitMan <- "ha"
}
if(input$PlotAreaMan %in% -999) AllWarnings <- c(AllWarnings, "You did not specify a plot area.")
}
# SubplotArea (if area is entered manually, it is supposed to be in ha already)
if(input$SubplotArea %in% "none") {
if(!input$SubplotAreaMan %in% -999) {
Data[, SubplotArea := input$SubplotAreaMan]
input$SubplotAreaUnitMan <- "ha"
}
if(input$SubplotAreaMan %in% -999) AllWarnings <- c(AllWarnings, "You did not specify a subplot area.")
}
# convert units to standards ####
units::remove_unit(c("ha", "ind", "gC"), c("hectare", "individual", "carbon"))
units::install_unit("ha", "10000 m2", "hectare")
units::install_unit("ind", name = "individual")
units::install_unit("gC", "0.47 g", "carbon")
StandardUnitTable <- do.call(rbind, lapply(grep("UnitMan", x$ItemID, value = T), function(i) {
ItemID <- sub("UnitMan", "", i)
if(is.na(x$Unit[match(ItemID, x$ItemID)])) ItemID <- paste0(c("X", "Y"), ItemID)
data.frame(ItemID = ItemID,
UnitMan = i,
StandardUnit = x$Unit[match(ItemID, x$ItemID)]
)
}))
StandardUnitTable <- StandardUnitTable[!input[StandardUnitTable$ItemID] %in% "none", ] # keep only the ones we need
if(any(is.na(StandardUnitTable$StandardUnit))) stop("Some Stanadrd unit have not been defined, contact HerrmannV@si.edu")
setDF(Data)
idx <- which(StandardUnitTable$ItemID %in% NewColNames)
# if(any(input[StandardUnitTable$UnitMan[idx]] %in% "none")) stop(paste0("You did not specify units for ", gsub("UnitMan", "", StandardUnitTable$UnitMan[idx][input[StandardUnitTable$UnitMan[idx]]%in%"none"]), "."))
#
# idx <- idx[!input[StandardUnitTable$UnitMan[idx]] %in% "none"]
for(i in idx) {
# setting units
units(Data[, StandardUnitTable$ItemID[i]]) <- input[[StandardUnitTable$UnitMan[i]]]
# converting units
units(Data[, StandardUnitTable$ItemID[i]]) <- StandardUnitTable$StandardUnit[i]
# remove units class
units(Data[, StandardUnitTable$ItemID[i]]) <- NULL
}
setDT(Data)
Data <- copy(Data)
# # Units changing ####
#
# unitOptions <- c("mm", "cm", "dm", "m") # c("mm", "millimetre", "millimeter", "milimetro", "milimetrica", "cm", "centimetre", "centimeter", "centimetro", "dm", "decimetre", "decimeter", "decimetro", "m", "metre", "meter", "metro")
#
# AreaUnitOptions <- c("m2", "ha", "km2")
# ### Diameter, MinDBH and BD in cm ####
# # if((!input$Diameter %in% "none" & !input$DiameterUnit %in% "none") | (!input$Circ %in% "none" & !input$CircUnit %in% "none")) stop("We have not coded the case where size units are not constant across your data yet - Please contact us or unify your units first.")
#
# if(!input$Diameter %in% "none" | !input$Circ %in% "none") {
#
# SizeUnit <- grep("[^none]", c(input$DiameterUnitMan, input$CircUnitMan), value = T)[1] # take Diameter in priority, otherwise CircUnit (not a big deal since we only care about Diameter and we already converted it from Circ if that was the only size we had)
#
# if(!SizeUnit %in% unitOptions) stop(paste("Your tree size units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if(SizeUnit %in% unitOptions) {
#
# if (SizeUnit == "mm") Data[, Diameter := Diameter/10] # mm -> cm
#
# if (SizeUnit == "dm") Data[, Diameter := Diameter*10] # dm -> cm
#
# if (SizeUnit == "m") Data[, Diameter := Diameter*100] # m -> cm
# }
#
# # (re)calculate Circ
# Data[, Circ := round(Diameter*pi, 2)]
# }
#
# if(!input$BD %in% "none" | !input$BCirc %in% "none") {
#
# BSizeUnit <- grep("[^none]", c(input$BDUnitMan, input$BCircUnitMan), value = T)[1] # take Diameter in priority, otherwise CircUnit (not a big deal since we only care about Diameter and we already converted it from Circ if that was the only size we had)
#
# if(!BSizeUnit %in% unitOptions) stop(paste("Your basal size units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if(BSizeUnit %in% unitOptions) {
# if (BSizeUnit == "mm") Data[, BD := BD/10] # mm -> cm
#
# if (BSizeUnit == "dm") Data[, BD := BD*10] # dm -> cm
#
# if (BSizeUnit == "m") Data[, BD := BD*100] # m -> cm
# }
#
# Data[, BCirc := round(BD*pi, 2)]
# }
#
# if(!input$MinDBH %in% "none") {
#
# SizeUnit <- input$MinDBHUnitMan
#
# if(!SizeUnit %in% unitOptions) stop(paste("Your minimum DBH size units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if(SizeUnit %in% unitOptions) {
#
# if (SizeUnit == "mm") Data[, MinDBH := MinDBH/10] # mm -> cm
#
# if (SizeUnit == "dm") Data[, MinDBH := MinDBH*10] # dm -> cm
#
# if (SizeUnit == "m") Data[, MinDBH := MinDBH*100] # m -> cm
# }
#
# }
#
# ### HOM and BHOM in m ####
# # if(!input$HOM %in% "none" & !input$HOMUnit %in% "none") stop("We have not coded the case where HOM units are not constant across your data yet - Please contact us or unify your units first.")
#
# if(!input$HOM %in% "none") {
#
# # if(input$HOMUnitMan %in% "none") stop("we need HOM units")
#
# HOMUnit <- input$HOMUnitMan
#
# if(!HOMUnit %in% unitOptions) stop(paste("Your HOM units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if (HOMUnit %in% unitOptions) {
#
# if (HOMUnit == "mm") Data[, HOM := HOM/1000] # mm -> m
#
# if (HOMUnit == "cm") Data[, HOM := HOM/100] # cm -> m
#
#
# if (HOMUnit == "dm") Data[, HOM := HOM/10] # dm -> m
# }
# }
#
# if(!input$BHOM %in% "none") {
#
# # if(input$BHOMUnitMan %in% "none") stop("we need basal HOm units")
#
#
# BHOMUnit <- input$BHOMUnitMan
#
# if(!BHOMUnit %in% unitOptions) stop(paste("Your basal HOM units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if (BHOMUnit %in% unitOptions) {
#
# if (BHOMUnit == "mm") Data[, BHOM := BHOM/1000] # mm -> m
#
# if (BHOMUnit == "cm") Data[, BHOM := BHOM/100] # cm -> m
#
# if (BHOMUnit == "dm") Data[, BHOM := BHOM/10] # dm -> m
# }
# }
#
#
# ### TreeHeight in m ####
# # if(!input$TreeHeight %in% "none" & !input$TreeHeightUnit %in% "none") stop("We have not coded the case where height units are not constant across your data yet - Please contact us or unify your units first.")
#
#
# if(!input$TreeHeight %in% "none") {
#
# # if(input$TreeHeightUnitMan %in% "none") stop("we need tree height units")
#
# TreeHeightUnit <- input$TreeHeightUnitMan
#
# if(!TreeHeightUnit %in% unitOptions) stop(paste("Your height units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if (TreeHeightUnit %in% unitOptions) {
#
# if (TreeHeightUnit == "mm") Data[, TreeHeight := TreeHeight/1000] # mm -> m
#
# if (TreeHeightUnit == "cm") Data[, TreeHeight := TreeHeight/100] # cm -> m
#
# if (TreeHeightUnit == "dm") Data[, TreeHeight := TreeHeight/10] # dm -> m
# }
# }
#
#
#
#
### PlotArea in ha ####
# if(!input$PlotArea %in% "none") {
#
# # if(input$PlotAreaUnitMan %in% "none") stop("we need Plot Area units")
#
# PlotAreaUnit <- input$PlotAreaUnitMan
#
# if(!PlotAreaUnit %in% AreaUnitOptions) stop(paste("Your plot area units are not one of:", paste(AreaUnitOptions, collapse = ", ")))
#
# if (PlotAreaUnit %in% AreaUnitOptions) {
#
# if (PlotAreaUnit == "m2") Data[, PlotArea := PlotArea/10000] # m2 -> ha
#
# if (PlotAreaUnit == "km2") Data[, PlotArea := PlotArea*100] # km2 -> ha
# }
# }
# ### SubplotArea in ha ####
#
# if(!input$SubplotArea %in% "none") {
#
# SubplotAreaUnitMan <- input$SubplotAreaUnitMan
#
# if(!SubplotAreaUnitMan %in% AreaUnitOptions) stop(paste("Your subplot area units are not one of:", paste(AreaUnitOptions, collapse = ", ")))
#
# if (SubplotAreaUnitMan %in% AreaUnitOptions){
#
# if (SubplotAreaUnitMan == "m2") Data[, SubplotArea := SubplotArea/10000] # m2 -> ha
# if (SubplotAreaUnitMan == "km2") Data[, SubplotArea := SubplotArea*100] # km2 -> ha
# }
# }
#
#
# ### XY coordinates in m ####
#
#
# if(!input$XTreeUTM %in% "none") {
#
# TreeUTMUnitMan <- input$TreeUTMUnitMan
#
# if(!TreeUTMUnitMan %in% unitOptions) stop(paste("Your utm units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if (TreeUTMUnitMan %in% unitOptions) {
#
# if (TreeUTMUnitMan == "mm") {
# Data[, XTreeUTM := XTreeUTM/1000] # mm -> m
# Data[, YTreeUTM := YTreeUTM/1000] # mm -> m
# }
#
# if (TreeUTMUnitMan == "cm") {
# Data[, XTreeUTM := XTreeUTM/100] # cm -> m
# Data[, YTreeUTM := YTreeUTM/100] # cm -> m
#
# }
#
# if (TreeUTMUnitMan == "dm") {
# Data[, XTreeUTM := XTreeUTM/10] # dm -> m
# Data[, YTreeUTM := YTreeUTM/10] # dm -> m
# }
#
# }
# }
#
# if(!input$XTreePlot %in% "none") {
#
# TreePlotUnitMan <- input$TreePlotUnitMan
#
# if(!TreePlotUnitMan %in% unitOptions) stop(paste("Your plot coordinates units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if (TreePlotUnitMan %in% unitOptions) {
#
# if (TreePlotUnitMan == "mm") {
# Data[, XTreePlot := XTreePlot/1000] # mm -> m
# Data[, YTreePlot := YTreePlot/1000] # mm -> m
# }
#
# if (TreePlotUnitMan == "cm") {
# Data[, XTreePlot := XTreePlot/100] # cm -> m
# Data[, YTreePlot := YTreePlot/100] # cm -> m
#
# }
#
# if (TreePlotUnitMan == "dm") {
# Data[, XTreePlot := XTreePlot/10] # dm -> m
# Data[, YTreePlot := YTreePlot/10] # dm -> m
# }
#
# }
# }
#
# if(!input$XTreeSubplot %in% "none") {
#
# TreeSubplotUnitMan <- input$TreeSubplotUnitMan
#
# if(!TreeSubplotUnitMan %in% unitOptions) stop(paste("Your subplot coordinates units are not one of:", paste(unitOptions, collapse = ", ")))
#
# if (TreeSubplotUnitMan %in% unitOptions) {
#
# if (TreeSubplotUnitMan == "mm") {
# Data[, XTreeSubplot := XTreeSubplot/1000] # mm -> m
# Data[, YTreeSubplot := YTreeSubplot/1000] # mm -> m
# }
#
# if (TreeSubplotUnitMan == "cm") {
# Data[, XTreeSubplot := XTreeSubplot/100] # cm -> m
# Data[, YTreeSubplot := YTreeSubplot/100] # cm -> m
#
# }
#
# if (TreeSubplotUnitMan == "dm") {
# Data[, XTreeSubplot := XTreeSubplott/10] # dm -> m
# Data[, YTreeSubplot := YTreeSubplot/10] # dm -> m
# }
#
# }
# }
# show warnings
if(!is.null(AllWarnings)) warning(paste(AllWarnings, collapse = "\n"))
# return output ####
ColumnsToReturn <- intersect(c(x$ItemID, grep("Original", colnames(Data), value = T)), colnames(Data))
# ColumnsToReturn <- ColumnsToReturn[unlist(Data[, lapply(.SD, function(x) !all(is.na(x))), .SDcols = ColumnsToReturn] )]
return(Data[, ..ColumnsToReturn])
}