Skip to content

Commit

Permalink
correct create_viewer(); close #10
Browse files Browse the repository at this point in the history
  • Loading branch information
agricolamz committed Jun 20, 2020
1 parent 89c7210 commit 0803464
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 114 deletions.
3 changes: 2 additions & 1 deletion NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ phonfieldwork 0.0.6 (20.06.2020)
- add text_size argument to the "draw_sound()" function
- add zoom argument to the "draw_sound()" function
- add the "get_sound_duration()" function
- fix ploting of multiple sounds with multiple .TextGrid
- fix ploting of multiple sounds with multiple .TextGrids
- add an argument "title_as_filename" to the "draw_sound()" function
- change textgrid asociated arguments of the "create_viewer()" function to "table" argument; as a result users now need to provide a table for the annotation viewer and not a TextGrid

phonfieldwork 0.0.5 (07.06.2020)
- add "textgrid_to_df()" function for reading Praat files
Expand Down
8 changes: 7 additions & 1 deletion R/create_image_look_up.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,20 @@
#'

create_image_look_up <- function(img_src,
img_caption = "",
img_caption = NULL,
text = "&#x1f441;"){
if(is.null(img_caption)){
img_caption <- rep("", length(img_src))
}


if(length(img_src) != length(img_caption)){
stop(paste0("It looks like the img_src variable contains ",
length(img_src),
" objects and the img_caption variable contains ",
length(img_caption)))
}

paste0("<a ",
"onmouseover=\"resize(this, '200%')\" ",
"onmouseout=\"resize(this, '100%')\" ",
Expand Down
47 changes: 15 additions & 32 deletions R/create_viewer.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,9 @@
#'
#' @param audio_dir path to the directory with sounds
#' @param picture_dir path to the directory with pictures
#' @param textgrid string with a filename or path to the TextGrid
#' @param tiers vecors of numbers or names of TextGrid tiers. They merged into a table and used in the created viewer.
#' @param merge_column string with a column name that will be used for merging stimuli and video and audio viewer.
#' @param caption_column string with a column name that will be used for captions for a picture (by default is the same as merge_column).
#' @param table data frame with data ordered according to files in the audio folder
#' @param captions vector of strings that will be used for captions for a picture.
#' @param sorting_columns vector of strings for sorting the result column
#' @param output_file the name of the result .html file (by default stimuli_viewer)
#' @param output_dir the output directory for the rendered file
#' @param render the logical argument, if \code{TRUE} renders the created R Markdown viewer to the \code{output_dir} folder, otherwise returns the path to the temporary file with a .csv file.
Expand All @@ -22,18 +21,15 @@
#' @importFrom utils installed.packages
#' @importFrom utils write.csv


create_viewer <- function(audio_dir,
picture_dir,
textgrid,
tiers = 1,
merge_column,
caption_column = NULL,
table,
captions = NULL,
sorting_columns = NULL,
about = "Created with the `phonfieldworks` package (Moroz 2020).",
output_dir,
output_file = "stimuli_viewer",
render = TRUE){
if(is.null(caption_column)){caption_column = merge_column}
if(!("DT" %in% utils::installed.packages()[,"Package"])){
stop('For this function you need to install DT package with a command install.packages("DT").')
}
Expand All @@ -46,37 +42,25 @@ create_viewer <- function(audio_dir,
stop("The number of audio files is less then number of pictures.")
}

result_df <- lapply(seq_along(tiers), function(i){
df <- tier_to_df(textgrid = textgrid, tier = tiers[i])
return(df$annotation[df$annotation != ""])
})
result_df <- as.data.frame(result_df)


# check whether there is an empty names -----------------------------------
tier_names <- get_textgrid_names(textgrid)[tiers]
tier_names <- lapply(seq_along(tier_names), function(i){
ifelse(tier_names[i] == "", paste0("X", i), tier_names[i])
})
tier_names <- unlist(tier_names)

# make a column names ------------------------------------------------------
colnames(result_df) <- tier_names

# create correct relative paths -------------------------------------------
audio_dir <- strsplit(normalizePath(audio_dir),
normalizePath(output_dir))[[1]][2]
audio_dir <- substr(audio_dir, 2, nchar(audio_dir))
result_df$audio <- paste0(audio_dir, "/", audio)
table$audio <- paste0(audio_dir, "/", audio)

picture_dir <- strsplit(normalizePath(picture_dir),
normalizePath(output_dir))[[1]][2]
picture_dir <- substr(picture_dir, 2, nchar(picture_dir))
result_df$pictures <- paste0(picture_dir, "/", pictures)
table$pictures <- paste0(picture_dir, "/", pictures)

# sort rows according to sorting_columns
if(!is.null(sorting_columns)){
table <- table[do.call(order, table[sorting_columns]), ]
}

# create a .csv file ------------------------------------------------------
tmp1 <- tempfile(fileext = ".csv")
utils::write.csv(result_df, tmp1, row.names = FALSE)
utils::write.csv(table, tmp1, row.names = FALSE)

# create about file -------------------------------------------------------
if(substr(about, nchar(about)-3, nchar(about)) == ".Rmd"){
Expand All @@ -92,8 +76,7 @@ create_viewer <- function(audio_dir,
"/phonfieldwork/rmarkdown/templates/annotation_viewer/skeleton/skeleton.Rmd"),
params = list(data = tmp1,
about = tmp2,
merge_column = merge_column,
caption_column = caption_column),
captions = captions),
output_dir = output_dir,
quiet = TRUE,
output_file = output_file)
Expand Down
6 changes: 5 additions & 1 deletion R/draw_sound.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#'
#' @return Oscilogram and spectrogram plot (and possibly TextGrid annotation).
#'
#' @examples
#' draw_sound(system.file("extdata", "test.wav", package = "phonfieldwork"))
#'
#' @export
#'
#' @importFrom tuneR readWave
Expand Down Expand Up @@ -74,7 +77,8 @@ draw_sound <- function(file_name,
if(class(file_name) == "Wave"){
s <- file_name
} else{
ext <- tolower(substring(file_name, regexpr("\\..*$", file_name) + 1))
ext <- unlist(strsplit(file_name, "\\."))
ext <- ext[length(ext)]

if(ext == "wave"|ext == "wav"){
s <- tuneR::readWave(file_name)
Expand Down
7 changes: 6 additions & 1 deletion R/get_sound_durations.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#' @param file_name a sound file
#' @param sounds_from_folder path to a folder with multiple sound files. If this argument is not \code{NULL}, then the function goes through all files and calculates duration for all of them.
#'
#' @examples
#' get_sound_duration(
#' sounds_from_folder = system.file("extdata", package = "phonfieldwork"))
#'
#' @export
#'
#' @importFrom tuneR readWave
Expand All @@ -18,7 +22,8 @@ get_sound_duration <- function(file_name,
if(class(file_name) == "Wave"){
s <- file_name
} else{
ext <- tolower(substring(file_name, regexpr("\\..*$", file_name) + 1))
ext <- unlist(strsplit(file_name, "\\."))
ext <- ext[length(ext)]

if(ext == "wave"|ext == "wav"){
s <- tuneR::readWave(file_name)
Expand Down
Binary file modified docs/glossed_document.docx
Binary file not shown.
111 changes: 89 additions & 22 deletions docs/index.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -364,28 +364,6 @@ tree | tail -n 25 | head -n 23

It is also possible to use the argument `textgrid_from_folder` in order to specify the folder where .TextGrids for annotation are (could be the same folder as the sound one). By default the `draw_sound()` function with the `sounds_from_folder` argument adds a title with the file name to each pictures' title, but it is possible to turn it off using the argument `title_as_filename = FALSE`.

## Create a viewer

It is possible to create an annotation viewer.

```{r, message= FALSE, warning=FALSE}
create_viewer(audio_dir = "s1/s1_sounds/",
picture_dir = "s1/s1_pics/",
textgrid = "s1/s1_all.TextGrid",
tiers = c(1, 3),
merge_column = "labels",
output_dir = "s1/",
output_file = "stimuli_viewer")
```

As a result, a `stimuli_viewer.html` was created in the `s1` folder.

```{bash, echo = FALSE}
tree | tail -n 26 | head -n 24
```

You can find the created example [here](https://agricolamz.github.io/phonfieldwork/s1/stimuli_viewer.html).

# Read linguistic files into R

The `phonfieldwork` package provides also several methods for reading different file types into R. This makes it possible to analyze them and convert into `.csv` files (e. g. using the `write.csv()` function):
Expand Down Expand Up @@ -423,4 +401,93 @@ create_glossed_document(flextext = "files/zilo_test.flextext",
file.copy("files/glossed_document.html", to = "glossed_document.html", overwrite = TRUE)
```

# Create a viewer

In oredr to create a sound viewer you need three things:

* folder with sounds
* folder with pictures
* dataframe with some details (e. g. annotation, utterance number etc.)

We will start with the previous folder structure:

```{bash, echo = FALSE}
tree | tail -n 25 | head -n 23
```

We have all folders:

```{r}
list.files("s1/s1_sounds/") # sounds
list.files("s1/s1_pics/") # pictures
```

So what is left is the table. It is possible to create manually (or upload it form .csv or .xlsx files, see section 4.1):

```{r}
df <- data.frame(word = c("tap", "tip", "top"),
sounds = c("æ", "ı", "ɒ"))
df
```

This table could be used in order to create an annotation viewer:

```{r, warning = FALSE}
create_viewer(audio_dir = "s1/s1_sounds/",
picture_dir = "s1/s1_pics/",
table = df,
output_dir = "s1/",
output_file = "stimuli_viewer")
```

As a result, a `stimuli_viewer.html` was created in the `s1` folder.

```{bash, echo = FALSE}
tree | tail -n 26 | head -n 24
```

You can find the created example [here](https://agricolamz.github.io/phonfieldwork/s1/stimuli_viewer.html).

Unfortunately, the way of table creation for the annotation viewer presented in this section is not a good solution for the huge amount of sounds. It is possible to derive such a table from annotation TextGrid, that we have created earlier. Here is a TextGrid:

```{r}
textgrid_to_df("s1/s1_all.TextGrid")
```

So in order to create desired table we can use `tier_to_df()` function:

```{r}
t1 <- tier_to_df("s1/s1_all.TextGrid", tier = 1)
t1
t3 <- tier_to_df("s1/s1_all.TextGrid", tier = 3)
t3
```

As we see the first tier is ready, but the third tier contains empty annotations. Let's remove them:

```{r}
t3 <- t3[t3$annotation != "",]
t3
```

So from this point it is possible to create the table that we wanted:

```{r}
new_df <- data.frame(words = t1$annotation,
sounds = t3$annotation)
new_df
```

So now we are ready to run our code for creating an annotation viewer:

```{r, warning = FALSE}
create_viewer(audio_dir = "s1/s1_sounds/",
picture_dir = "s1/s1_pics/",
table = new_df,
output_dir = "s1/",
output_file = "stimuli_viewer")
```

By default sorting in the result annotation viewer will be according file names in the system, so if you want to have another default sorting you can specify column names that the result table should be sorted by using the `sorting_columns` argument.

# References
158 changes: 124 additions & 34 deletions docs/index.html

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions docs/s1/stimuli_viewer.html
Original file line number Diff line number Diff line change
Expand Up @@ -3252,8 +3252,8 @@ <h1 class="title toc-ignore">Sound Viewer</h1>
<h1></h1>
<div id="data" class="section level2">
<h2>data</h2>
<div id="htmlwidget-6f1c50ef636fa007e550" style="width:100%;height:auto;" class="datatables html-widget"></div>
<script type="application/json" data-for="htmlwidget-6f1c50ef636fa007e550">{"x":{"filter":"top","filterHTML":"<tr>\n <td data-type=\"character\" style=\"vertical-align: top;\">\n <div class=\"form-group has-feedback\" style=\"margin-bottom: auto;\">\n <input type=\"search\" placeholder=\"All\" class=\"form-control\" style=\"width: 100%;\"/>\n <span class=\"glyphicon glyphicon-remove-circle form-control-feedback\"><\/span>\n <\/div>\n <\/td>\n <td data-type=\"character\" style=\"vertical-align: top;\">\n <div class=\"form-group has-feedback\" style=\"margin-bottom: auto;\">\n <input type=\"search\" placeholder=\"All\" class=\"form-control\" style=\"width: 100%;\"/>\n <span class=\"glyphicon glyphicon-remove-circle form-control-feedback\"><\/span>\n <\/div>\n <\/td>\n<\/tr>","data":[["tap <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'pic_appear(\"s1_pics/1_s1_æ.png\", \"tap\")'> &#x1f441;<a> <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'sound_play(\"s1_sounds/1_s1_æ.wav\")'> &#x1f442;<a>","tip <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'pic_appear(\"s1_pics/2_s1_ı.png\", \"tip\")'> &#x1f441;<a> <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'sound_play(\"s1_sounds/2_s1_ı.wav\")'> &#x1f442;<a>","top <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'pic_appear(\"s1_pics/3_s1_ɒ.png\", \"top\")'> &#x1f441;<a> <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'sound_play(\"s1_sounds/3_s1_ɒ.wav\")'> &#x1f442;<a>"],["æ","ı","ɒ"]],"container":"<table class=\"display\">\n <thead>\n <tr>\n <th>labels<\/th>\n <th>X2<\/th>\n <\/tr>\n <\/thead>\n<\/table>","options":{"pageLength":50,"dom":"tip","order":[],"autoWidth":false,"orderClasses":false,"orderCellsTop":true}},"evals":[],"jsHooks":[]}</script>
<div id="htmlwidget-7c19380a1ffc7b1a7a15" style="width:100%;height:auto;" class="datatables html-widget"></div>
<script type="application/json" data-for="htmlwidget-7c19380a1ffc7b1a7a15">{"x":{"filter":"top","filterHTML":"<tr>\n <td data-type=\"character\" style=\"vertical-align: top;\">\n <div class=\"form-group has-feedback\" style=\"margin-bottom: auto;\">\n <input type=\"search\" placeholder=\"All\" class=\"form-control\" style=\"width: 100%;\"/>\n <span class=\"glyphicon glyphicon-remove-circle form-control-feedback\"><\/span>\n <\/div>\n <\/td>\n <td data-type=\"character\" style=\"vertical-align: top;\">\n <div class=\"form-group has-feedback\" style=\"margin-bottom: auto;\">\n <input type=\"search\" placeholder=\"All\" class=\"form-control\" style=\"width: 100%;\"/>\n <span class=\"glyphicon glyphicon-remove-circle form-control-feedback\"><\/span>\n <\/div>\n <\/td>\n <td data-type=\"character\" style=\"vertical-align: top;\">\n <div class=\"form-group has-feedback\" style=\"margin-bottom: auto;\">\n <input type=\"search\" placeholder=\"All\" class=\"form-control\" style=\"width: 100%;\"/>\n <span class=\"glyphicon glyphicon-remove-circle form-control-feedback\"><\/span>\n <\/div>\n <\/td>\n<\/tr>","data":[["tap","tip","top"],["æ","ı","ɒ"],["<a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'pic_appear(\"s1_pics/1_s1_æ.png\", \"\")'> &#x1f441;<a> <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'sound_play(\"s1_sounds/1_s1_æ.wav\")'> &#x1f442;<a>","<a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'pic_appear(\"s1_pics/2_s1_ı.png\", \"\")'> &#x1f441;<a> <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'sound_play(\"s1_sounds/2_s1_ı.wav\")'> &#x1f442;<a>","<a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'pic_appear(\"s1_pics/3_s1_ɒ.png\", \"\")'> &#x1f441;<a> <a onmouseover=\"resize(this, '200%')\" onmouseout=\"resize(this, '100%')\" onclick = 'sound_play(\"s1_sounds/3_s1_ɒ.wav\")'> &#x1f442;<a>"]],"container":"<table class=\"display\">\n <thead>\n <tr>\n <th>words<\/th>\n <th>sounds<\/th>\n <th>viewer<\/th>\n <\/tr>\n <\/thead>\n<\/table>","options":{"pageLength":50,"dom":"tip","order":[],"autoWidth":false,"orderClasses":false,"orderCellsTop":true}},"evals":[],"jsHooks":[]}</script>
<div id="my_block" class="my_block" onclick="pic_disappear()">
<span class="close">×</span> <img class="my_img" id="my_img">
<div id="caption" class="caption">
Expand Down
16 changes: 6 additions & 10 deletions inst/rmarkdown/templates/annotation_viewer/skeleton/skeleton.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@ title: "Sound Viewer"
output: html_document
params:
data: your_file.csv
merge_column: "merge_column"
caption_column: "caption_column"
captions: "caption_for_pictures"
about: about.Rmd
editor_options:
chunk_output_type: console
Expand Down Expand Up @@ -44,15 +43,12 @@ editor_options:
## data

```{r make_viewer, echo=FALSE, message=FALSE, warning=FALSE}
df <- read.csv(params$data, stringsAsFactors = FALSE)
merge <- which(colnames(df) %in% params$merge_column)
captions <- which(colnames(df) %in% params$caption_column)
df <- read.csv(tmp1, stringsAsFactors = FALSE)
df[,merge] <-
paste(df[,merge],
phonfieldwork::create_image_look_up(img_src = df$pictures,
img_caption = df[,captions]),
phonfieldwork::create_sound_play(snd_src = df$audio))
df$viewer <-
paste(phonfieldwork::create_image_look_up(img_src = df$pictures,
img_caption = captions),
phonfieldwork::create_sound_play(snd_src = df$audio))
df <- df[, -which(colnames(df) %in% c("audio", "pictures"))]
Expand Down
2 changes: 1 addition & 1 deletion man/create_image_look_up.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 6 additions & 9 deletions man/create_viewer.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions man/draw_sound.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions man/get_sound_duration.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 0803464

Please sign in to comment.