FOCUS | numeric

TENS Banner

An example Markdown Report

One of the best things about R is how much it has been extended with libraries to perform different tasks. One of my favorite packages is Markdown. With Markdown, R can be used to produce beautiful PDFs, HTML, Microslop Word Docs and more. Even better, LaTeX code can be embedded in these documents so mathematics can be notated correctly. Truly excellent!

I produced code to produce PDF reports for UPS, STS, and PDU data at work. I'd love to post that code because it's 25+ pages of R code that does serious data manipulation, analysis, and plotting. However, I don't own that code - and I certainly do not own the data! Fortunately I have some other data I can use to create a good Markdown example.

I am assuming a few things if you are going to follow along.

I skipped some steps. If you need clarification, send me an email and I'll do my best to answer any questions you have! You can just download the *.Rmd files and OscOut7.csv file and run it yourself if you just want to see a Markdown example.

There are a few things you have to do to run Markdown. Run the following in the R GUI (or R Studio):


then load the libraries:


You don't have to reinstall the packages every time you run Markdown. But you do have to load the libraries.

To run LaTeX you also have to install MikTek or equivalent. You also must have TeX installed to render PDF documents with Markdown. Installing on Linux can be accomplished via
sudo apt-get install texlive-full

You also need to install "Pandoc." It is very easy to install. Just follow the directions at

Markdown documents are a little different from standard R files. The file extension is *.Rmd rather than *.R, which contains R code, LaTeX (possibly), and formatting information that is interpreted by the Markdown package. A markdown document is 'rendered' rather than executed. Enter something like this in the command line to produce a PDF document:

render("MyMarkdownFile.Rmd", output_format="pdf_document",output_file=paste("MyMarkdownOutputFile", Sys.Date(), ".pdf"))

Of course you can put these in an R function to generate several of these in a batch. For example, "RenderReports.R" which renders four separate PDFs from MyMarkdownFile1.Rmd, MyMarkdownFile2.Rmd, etc.

RenderReports <- function(){
 library(markdown)  # load the required libraries if you haven't done so already.  Doing it twice won't hurt anything.
 render("MyMarkdownFile1.Rmd", output_format="pdf_document",output_file=paste("MyMarkdownOutputFile1", Sys.Date(), ".pdf"))
 render("MyMarkdownFile2.Rmd", output_format="pdf_document",output_file=paste("MyMarkdownOutputFile2", Sys.Date(), ".pdf"))
 render("MyMarkdownFile3.Rmd", output_format="pdf_document",output_file=paste("MyMarkdownOutputFile3", Sys.Date(), ".pdf"))
 render("MyMarkdownFile4.Rmd", output_format="pdf_document",output_file=paste("MyMarkdownOutputFile4", Sys.Date(), ".pdf"))
To run this file, type:

I have a nice dataset produced by connecting my oscilloscope to my TENS unit. The data itself is very simple: just one column containing AC voltage. Here is an image of what the data looks like (plotted in Mathematica):

TENS plotted with Mathematica

A TENS unit is a medical device that delivers a little pulse of AC voltage to exercise muscles. (I have one because someone ran over me with a car in the parking lot of IBM last year.) It's a nice medication-free way of relieving pain.

There are a few issues with the actual data as I collected it. First, I accidentally set my oscilloscope probes to something other than "1x." A dumb mistake on my part - but to be fair the setting was buried in the oscilloscope settings menu. That means that I have to transform the data so that the voltage output is closer to what my Fluke 87V read. Also, there's no actual "time" data since the oscilloscope didn't produce a time column. We can operate on the data without this... But the TENS unit produces pulses at a measurable frequency and subtle differences in that frequency are noticeable for a user. I'll produce both a meaningful "time" vector for plotting and transform the voltage data here. There are a few things I'd like R to do with the data.

Everything is included in the comments!

# TENS data with R, Markdown and LaTeX... [Focus Numeric](
Note: You call LaTeX by using '\( stuff \)' (inline) and double dollar signs for equation blocks.

```{r echo=TRUE, results='asis'}
# Pull OscData from the dataset
    OscData <- read.csv("OscOutput7.csv")
# Create a plotting vector -- find the length first, then create a plotting sequence 
# "plotVec".  I want to start the vector at 0 so we have to adjust the length appropriately.
    dataLength <- length(OscData$VAC.Out)
    plotVec <- 0:(dataLength-1)
# and plot with:
# plot(plotVec,OscData$VAC.Out, type="l", col="blue", main="Raw (unscaled) OscData 
# from TENS unit", xlab="Time", ylab="Volts AC")  
```{r echo=FALSE, results='asis'}

	plot(plotVec,OscData$VAC.Out, type="l", col="blue", main="Raw (unscaled) OscData from TENS unit", xlab="Time", ylab="Volts AC")


We scale the output.  The maximum output read from the TENS was 3.457 VAC (using my Fluke DMM).  However, the maximum value of the 
data is 284.  We can scale the output by $k = \frac{3.457}{284}$, and setup a new set in R:

```{r echo=TRUE, results='asis'}
    k <- 3.457 / 284
	scaledData <- k*OscData$VAC.Out

We can also scale the plotting vector so that it accurately represents time.  The TENS unit puts out pulses at about 50 Hertz so we 
want the pulses to happen about 50 times per second.  But where does it happen?  A useful built-in R function is 'which()'.  Use it 
to find the first index where the data is original data is over 275.
```{r echo=TRUE, results='asis'}


From this we can see that 1/50th of a second happens in about 400 units of our plotting vector plotVec.  Thus we can scale the 
plotting vector using a little stoichiometry:

$$ 400 \ \text{units} \ = \ \frac{1}{50} \ \text{second} $$
$$ 20,000 \ \text{units} \ = \ 1 \ \text{second} $$
$$ \frac{1}{20,000} \ \text{second} \ = 1 \ \text{unit} $$

```{r echo=TRUE, results='asis'}
    timeVec <- 1/20000 * plotVec
which gives us fully scaled data.  Here's an updated plot:

```{r echo=FALSE, results='asis'}
	plot(timeVec,scaledData, type="l", col="blue", main="Fully scaled TENS data", xlab="Time", ylab="Volts AC")

Cool.  Looks good.  

We will use 'approx()' to find a function that approximates the data.  Remember: I'm just trying to provide an interesting 
Markdown example!

```{r echo=TRUE, results='hide'}

The output from that command is hidden since it returns many numbers.  Based on the results I am going to pick the interval 
'scaledData[171:350]'.  Here is a plot of the data with 'approx(pulseSubset)':

```{r echo=FALSE, results='asis'}
    pulseSubset <- scaledData[171:350] 
    plotPulse <- timeVec[171:350]
    plot(approx(pulseSubset), type="l", col="blue", main="Fully scaled TENS data - Pulse Subset", xlab="Time", ylab="Volts AC")
    points(pulseSubset, col="red")

That should provide a simple Markdown example that has a little LaTeX mixed in.

Scaled TENS plot from R

Links to TENS data and the actual Markdown file.
Raw oscilloscope output data
TENS.Report.Rmd file
TENS.Report rendered as PDF
Depending on your browser you may have to 'save as.'

Some places to find out more:

  1. LaTeX installation: Obtaining LaTeX at
  2. The main Markdown site: R Markdown. The assumption is generally that you will be using R Studio. You can run Markdown in the regular R GUI without any complication. I can't use R Studio at work because of security restrictions but can use Markdown anyway.
  3. Pandoc is required for running Markdown. See
  4. A great R resource! See: "R In Action" from It is worth a little extra to get the second edition. (Markdown isn't even covered in the first edition.) I highly recommend this book.

Contact me: