Skip to content

Commit 97ab851

Browse files
Merge pull request #496 from StoXProject/develop
Develop
2 parents fe3fff1 + e2c1de7 commit 97ab851

10 files changed

Lines changed: 162 additions & 15 deletions

File tree

DESCRIPTION

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Package: RstoxData
2-
Version: 2.2.1-9001
3-
Date: 2026-03-13
2+
Version: 2.2.1-9002
3+
Date: 2026-03-20
44
Title: Tools to Read and Manipulate Fisheries Data
55
Authors@R: c(
66
person(given = "Arne Johannes",

NAMESPACE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export(convertBioticFile)
6161
export(convertToLandingData)
6262
export(convertToLssData)
6363
export(createOrderKey)
64+
export(cropAcoustic)
6465
export(do.call_robust)
6566
export(filterData)
6667
export(filterTables)

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Added a check for existence of the resource file in DefineTranslation().
33
* Improved warning when bottomdepthstart or bottomdepthstop used to calcualte BottomDepth in StoxBiotic() contains missing values.
44
* Added error message in StoxAcoustic when the Time is not unique in AcousticData in the ICESAcsoutic format, since StoX uses Time as the LogKey in StoxAcousticData.
5+
* Added the funciton cropAcoustic() to extract only a subset of the logs of an acoustic file.
56

67

78
# RstoxData v2.2.0-9011 (2026-01-23)

R/Definitions.R

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,7 @@ initiateRstoxData <- function(){
317317
reportingUnit = c("mm", "mm", "cm"),
318318
numericResolution = c(1, 5, 1)
319319
)
320+
320321
lengthCode_unit_table[, rank := seq_len(.N)]
321322

322323

R/Read.R

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -471,3 +471,76 @@ scaleUsingUnit <- function(x, inputUnit, outputUnit) {
471471

472472

473473

474+
475+
##################################################
476+
##################################################
477+
#' Write a cropped copy of an acoustic file
478+
#'
479+
#' This function writes a copy of an acoustic file in either the NMDEchosounder og ICESAcoustic format, keeping only the logs specified by the user.
480+
#'
481+
#' @param filePath Character: The path to the acoustic file.
482+
#' @param logsToKeep Numeric: The indiced of the logs to keep. NULL implies to keep all logs.
483+
#' @param newFilePath Optional, character: The path to the new file, defaulted to \code{filePath} with the suffix before file extension
484+
#' @param ow Logical: If TRUE overwrite the \code{newFilePath}.
485+
#' @param suffix Character: The suffix to append to the \code{filePath} before the file extension, in the case that \code{newFilePath} is not specified
486+
#'
487+
#' @return
488+
#' The path to the cropped file.
489+
#'
490+
#' @examples
491+
#' exampleFile <- system.file("testresources","ICES_Acoustic_2.xml", package="RstoxData")
492+
#' acousticData <- ReadAcoustic(exampleFile)
493+
#' newFilePath <- tempfile(fileext = ".xml")
494+
#' cropAcoustic(exampleFile, logsToKeep = 2, newFilePath = newFilePath)
495+
#' croppedAcousticData <- ReadAcoustic(newFilePath)
496+
#'
497+
#' @export
498+
#'
499+
cropAcoustic <- function(filePath, logsToKeep = NULL, newFilePath = NULL, ow = FALSE, suffix = "_croppedLogs.") {
500+
501+
# Get the file type and the start and end tags for logs:
502+
fileType <- autodetectXml(filePath)
503+
if(fileType$xsd == "nmdechosounderv1") {
504+
startLogTag = "<distance log_start"
505+
endLogTag = "</distance>"
506+
}
507+
else if(fileType$xsd == "icesAcoustic") {
508+
startLogTag = "<Log>"
509+
endLogTag = "</Log>"
510+
}
511+
512+
# Read the lines:
513+
l <- readLines(filePath)
514+
if(length(l) == 1) {
515+
stop("The XML must be prettified to be cropped.")
516+
}
517+
518+
# Find the end log tags:
519+
atStartLog <- which(grepl(startLogTag, l))
520+
atEndLog <- which(grepl(endLogTag, l))
521+
522+
# Subset the logs:
523+
if(length(logsToKeep)) {
524+
logsToDelete <- setdiff(seq_along(atStartLog), logsToKeep)
525+
linesToDelete <- unlist(mapply(seq, atStartLog[logsToDelete], atEndLog[logsToDelete]))
526+
l <- l[- linesToDelete]
527+
}
528+
529+
# Create the file path of the copy:
530+
if(!length(newFilePath)) {
531+
newFilePath <- paste0(tools::file_path_sans_ext(filePath), suffix, tools::file_ext(filePath))
532+
}
533+
# And check existence of the copy:
534+
if(file.exists(newFilePath) && !ow) {
535+
stop("The file ", newFilePath, " exists. Choose a different file path using newFilePath or set ow to TRUE to overwrite.")
536+
}
537+
538+
# Write the copy:
539+
writeLines(l, newFilePath)
540+
541+
return(newFilePath)
542+
}
543+
544+
545+
546+

R/StoxAcoustic.R

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,9 @@ StoxAcousticOne <- function(data_list) {
105105
#data_list$ChannelReference[, LogKey:= paste0(gsub(' ','T',start_time),'.000Z')]
106106
#data_list$NASC[, LogKey:= paste0(gsub(' ','T',start_time),'.000Z')]
107107
data_list$Log[, LogKey := formatLogKey(as.POSIXct_NMDEchosounder(start_time))]
108+
# Duplicated LogKey is an error:
109+
duplicatedLogKeyError(data_list$Log, format = "NMDEchosounder")
110+
108111
data_list$Beam[, LogKey := formatLogKey(as.POSIXct_NMDEchosounder(start_time))]
109112
data_list$AcousticCategory[, LogKey := formatLogKey(as.POSIXct_NMDEchosounder(start_time))]
110113
data_list$ChannelReference[, LogKey := formatLogKey(as.POSIXct_NMDEchosounder(start_time))]
@@ -323,12 +326,10 @@ StoxAcousticOne <- function(data_list) {
323326

324327
data_list$Log[, LogKey := getLogKey_ICESAcoustic(Time)]
325328

326-
# Throw an error if the LogKey is not unique:
327-
atDuplicatedLogKey <- data_list$Log[, which(duplicated(LogKey) | duplicated(LogKey, fromLast = TRUE))]
328-
if(length(atDuplicatedLogKey)) {
329-
duplicatedTimes <- data_list$Log$Time[atDuplicatedLogKey]
330-
stop("The AcousticData has duplicated Time, which results in duplicated LogKey in StoxAcoustic, which is not allowed. The data are from an acoustic file in the ICESAcoustic format, and contains the following duplicated Time (first 30):\n", paste(head(duplicatedTimes, 30), collapse = ", "))
331-
}
329+
# Duplicated LogKey is an error:
330+
duplicatedLogKeyError(data_list$Log, format = "ICESAcoustic")
331+
332+
332333

333334
data_list$Log[, EDSU:= paste(LocalID,LogKey,sep='/')]
334335

@@ -427,9 +428,6 @@ StoxAcousticOne <- function(data_list) {
427428

428429
#add integration distance
429430
PingAxisInterval <- data_list$Beam[, c('PingAxisInterval', 'LogKey')]
430-
#if(any(duplicated(PingAxisInterval))) {
431-
# stop("Time in the Beam table is not unique. StoX requires Time to be unique across the rows of the Log table as Time in order to use Time as the LogKey. This problem typically occurs when the resolution of the Time is too low, e.g. hours. Please change the input data so that Time is unique.")
432-
#}
433431
data_list$Log <- merge(data_list$Log, PingAxisInterval, all.x = TRUE)
434432
names(data_list$Log)[names(data_list$Log) == 'PingAxisInterval'] <- 'LogDistance'
435433

@@ -549,6 +547,7 @@ StoxAcousticOne <- function(data_list) {
549547
}
550548

551549

550+
552551
hasMinuteResoslution_ICESAcoustic <- function(Time) {
553552
# Count the number of colons, where 2 indicates seconds and 1 indicates minutes:
554553
max(stringi::stri_count(Time, fixed = ':'), na.rm = TRUE) == 1
@@ -567,6 +566,26 @@ getLogKey_ICESAcoustic <- function(Time) {
567566
}
568567

569568

569+
duplicatedLogKeyError <- function(Log, format = c("NMDEchosounder", "ICESAcoustic")) {
570+
571+
format <- match.arg(format)
572+
573+
atDuplicatedLogKey <- Log[, which(duplicated(LogKey) | duplicated(LogKey, fromLast = TRUE))]
574+
if(length(atDuplicatedLogKey)) {
575+
if(format == "NMDEchosounder") {
576+
duplicatedTimes <- sort(Log$start_time[atDuplicatedLogKey])
577+
}
578+
else if(format == "ICESAcoustic") {
579+
duplicatedTimes <- sort(Log$Time[atDuplicatedLogKey])
580+
}
581+
582+
badTimes <- head(unique(duplicatedTimes), 30)
583+
stop("The AcousticData (from an ", format, " file) has duplicated Time, which results in duplicated LogKey in StoxAcoustic, which is not allowed. Please add sufficient time resolution in your input data (preferrable in the data source). The following Time are duplicated (first ", length(badTimes), "):\n", paste(badTimes, collapse = "\n"))
584+
}
585+
586+
}
587+
588+
570589

571590
getBeamTiltAngle <- function(x) {
572591
# Check code words:
@@ -614,16 +633,19 @@ as.POSIXct_ICESAcoustic <- function(x) {
614633
"%Y-%m-%d %H:%M"
615634
)
616635
allowedTimeFormatsICESAcoustic <- c(
636+
# The order here is important, since the allowedTimeFormatsICESAcousticSansSeconds accepts also times WITH seconds. So first convert with seconds, then the remaining sans seconds!!!:
617637
paste0(allowedTimeFormatsICESAcousticSansSeconds, ":%OS"),
618638
allowedTimeFormatsICESAcousticSansSeconds
619639
)
620640

621641
areNotNAs <- !is.na(x)
622642

623-
DateTime <- NULL
643+
DateTime <- rep(as.POSIXct(NA), length(x))
644+
# Fill inn the missing times. This supports different resolutions in the same object, as we check the highest resolution first (with seconds then minutes, as specified in the allowedTimeFormatsICESAcoustic):
624645
for(format in allowedTimeFormatsICESAcoustic) {
625-
if(!length(DateTime) || !all(!is.na(DateTime[areNotNAs]))) {
626-
DateTime <- as.POSIXct(x, tz = StoxTimeZone, format = format)
646+
isNaDateTime <- is.na(DateTime)
647+
if(any(isNaDateTime)) {
648+
DateTime[isNaDateTime] <- as.POSIXct(x[isNaDateTime], tz = StoxTimeZone, format = format)
627649
}
628650
}
629651

R/StoxExport.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -743,9 +743,14 @@ BioticData_NMDToICESBioticOne <- function(
743743
WeightUnit = "kg", # Always kg in NMDBiotic (see http://www.imr.no/formats/nmdbiotic/)
744744
SpeciesCategoryWeight = catchweight,
745745
SpeciesSex = NA_character_,
746+
747+
#SubsampledNumber = lengthsamplecount,
746748
SubsampledNumber = lengthsamplecount,
747749
SubsamplingFactor = catchcount / lengthsamplecount,
750+
#SubsamplingFactor = ifelse(is.na(lengthsampleweight), 1, catchcount / lengthsamplecount),
748751
SubsampleWeight = lengthsampleweight,
752+
#SubsampleWeight = ifelse(is.na(lengthsampleweight), catchweight, lengthsampleweight),
753+
749754
LengthCode = NA_character_, # NMDBiotic has no way of storing a length distribution.
750755
LengthClass = NA_integer_, # NMDBiotic has no way of storing a length distribution.
751756
#LengthType = "1", # Should not this be interpreted from the catchsample$lengthmeasurement ???

R/xsdUtils.R

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,8 +285,13 @@ createXsdObject <- function(xsdFile) {
285285

286286

287287
#' @importFrom xml2 xml_child read_html xml_find_all
288-
autodetectXml <- function(xmlFile, xsdObjects, verbose) {
288+
autodetectXml <- function(xmlFile, xsdObjects, verbose = FALSE) {
289289

290+
# Get the xsdObjects:
291+
if(missing("xsdObjects")) {
292+
data(xsdObjects, package="RstoxData", envir = environment())
293+
}
294+
290295
# Read first 500 characters
291296
tmpText <- tryCatch(
292297
{

inst/extdata/functionArguments.rds

514 Bytes
Binary file not shown.

man/cropAcoustic.Rd

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)