anrepr-package: Analysis Reporting in R

Description Details Author(s) Examples

Description

Anrepr provides a report generator that acts as a graphical logger turning the output of your analysis pipeline into a static Web site

Details

The main entry point is the constructor of the anrep class.

INSTALLATION NOTE: This package needs the Pandoc Markdown converter executable installed on your system. You can refer to the documentation of the pander package for the alternative ways of installing Pandoc.

Author(s)

Maintainer: Andrey Tovchigrechko andreyto@gmail.com

Examples

  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
# ---- example_sections_report_functions ----

make_example_sections_report <- function(report_dir=NULL,export=TRUE) {

  # grDevices code to prevent stops when this example is checked by CRAN because
  # apparently some code inside (pander?) closes all open devices, including one
  # device that a checking wrapper opens and then tries to close after running the
  # example.
  any.open.devs = !is.null(grDevices::dev.list())

  # First, we define several functions which will be called one from another,
  # in order to mimic a flow of some typical analysis pipeline. Each
  # function uses our `report` object to add data to the report as well as
  # to create new sections and subreports. We create the `report` object
  # below the definitions of the "analysis" functions.

  ## Top-level function of the analysis pipeline
  my.func.1<-function() {
    print("my.func.1")

    # Add new header. Section numbering will be auto-incremented at the current level
    # (e.g. 1.1 to 1.2)
    report$add.header("H1")

    # Add Markdown-formatted text
    report$add.descr("*H1 text*")

    # Add new header and shift the section numbering into a sub-section
    # with `%anrep>>%` operator (e.g. 1.2 >> 1.2.1)
    report$add.header("H2 with subsections") %anrep>>% {

      # Add a plot with base graphics. Caption will be auto-numbered and
      # contain HTML anchor to reference it later inside the report if your need,
      # for example, to send a link to that plot to a collaborator.
      report$add(plot(x <- sort(rnorm(47))),caption="Figure one in H2",
                 hi.res = TRUE,
                 graph.unify=TRUE)

      # Call deeper into the analysis pipeline
      my.func.2()
    }
    # The closing } above has returned us to the section level that was current
    # before the `%anrep>>% {` call, e.g. 1.2.1 >> 1.2

    # Add new header. Section numbering will be auto-incremented at the current level
    # (e.g. 1.2 to 1.3)
    report$add.header("H3")

    # Add a plot with base graphics
    report$add(plot(x <- sort(rnorm(10))),caption="Figure one in H3",
               hi.res = TRUE,
               graph.unify=TRUE)
  }

  ## This function is called from the top-level function
  my.func.2<-function() {
    print("my.func.2")

    # Add new header and shift the section numbering into a sub-section
    # with `%anrep>>%` operator (e.g. 1.1 >> 1.1.1)
    report$add.header("H2.1") %anrep>>% {
      # Call another function a loop with different parameters, which will
      # result in three subreports, each with two sub-subreports itself. In
      # the HTML output, the subreports will become separate Web pages,
      # accessible through a Subreport link in the parent report.
      for(i in 1:3) {
        my.func.3(sprintf("H2.1 two subreports here %s",i))
      }
    }
    # The closing } above has returned us to the section level that was current
    # before the `%anrep>>% {` call
  }

  # This function will be called in a loop with different parameters for the
  # "analysis" (in this mock case - just different header strings). This
  # will result in several subreports being generated, one for each iteration.
  my.func.3<-function(subreports.header) {
    print("my.func.3")

    # Add new header and drop into a subreport (notice the `%anrep//%` operator)
    report$add.header(subreports.header) %anrep//% {

      # Add new header and drop one more level into another subreport
      report$add.header("H2.1.subreport 1") %anrep//% {

        report$add.descr("**Some text**")

        # Add a sample ggplot2 plot if the package is available
        if(requireNamespace("ggplot2", quietly = TRUE)) {
          report$add(ggplot2::qplot(mpg, wt, data = mtcars,
                                    facets = vs ~ am,geom = "violin"),
                     caption = "Ggplot2 example",
                     hi.res = TRUE)
        }

        if(requireNamespace("DT", quietly = TRUE)) {
          dt = DT::datatable(mtcars, options = list(pageLength = 15))
          report$add.widget(dt,
                            caption = "Dynamic DataTable viewer from DT package")
        }

        if(requireNamespace("plotly", quietly = TRUE)) {
          report$add.widget(plotly::plot_ly(cbind(Model=rownames(mtcars),mtcars),
            x = ~mpg, y = ~qsec, color = ~hp, mode="markers",
            marker = list(size = ~wt),
            text =~paste("Model:", Model, "<br>Weight:", wt)),
            caption = "Dynamic Plotly plot: hover, zoom and brush with your mouse")
        }

        # This simply adds a header and increments the section numbering
        report$add.header("H2.1.subreport 1 incremented section")

        # Add a table
        report$add.table(data.frame(A=c("a","b"),B=c(1,2)),caption="Table")

        # Generate a unique file name into we could save some data
        # inside the report directory
        report$add.descr(
          paste("Generated a unique file name to save some extra output:",
                report$make.file.name("data.csv")))
      }
      # The closing } above has returned us to the reporting level that was
      # current before the `%anrep//% {` call

      # Add new header and drop one more level into another subreport
      report$add.header("H2.1.subreport 2") %anrep//% {
        report$add.descr("Some text")
        report$add.header("H2.1.subreport 2 incremented section")
        report$add.table(data.frame(A=c("a","b"),B=c(1,2)),caption="Table")
        report$add.descr(paste("File name with extra output is ",
                               report$make.file.name("data.csv")))
      }
    }
  }

  ## And now, setting up the report object and running the pipeline

  message(sprintf("Working dir is %s",getwd()))

  # If requested, run in a separate output directory, and make sure we
  # restore the current working directory at the end
  if(!is.null(report_dir)) {
    curdir = getwd()
    dir.create(report_dir,showWarnings = FALSE,recursive = TRUE)
    on.exit(setwd(curdir))
    setwd(report_dir)
  }

  # Create a report object visible from all functions that will need it.
  # Here it will be visible because it is bound to the frame in which the
  # functions were defined, but you can also pass it as a parameter (it is
  # the instance of a reference class, and will not be copied), assign it
  # to the global environment using `<<-` operator, or create a helper
  # function to extract it from some other environment.
  # Note that we set out.format to 'html' to make sure that we get the results in
  # HTML output files on disk even if this is executed from a knitr session
  # (otherwise under knitr we would get repot as a string return value)

  report <- anrep(out.formats="html")

  # Call my complicated analysis pipeline
  my.func.1()

  # Finally, save the report and, optionally (True by default), export it
  # to the final HTML format. The report is organized as a number of files
  # and directories under the current working directory.
  report$save(export=export)

  if(any.open.devs) {
    if(is.null(grDevices::dev.list())) {
      grDevices::pdf("dummy.pdf")
    }
  }
}

# ---- example_sections_report_run ----

make_example_sections_report("example_sections_report")

andreyto/anrepr documentation built on Feb. 24, 2020, 5:31 a.m.