Interfacing XTide and R

Edit: There is now a full-fledged R package, rtide, to accomplish the same basic task of generating time series of tide predictions that is outlined here. See this more recent post for information.

XTide is an open-source program that predicts tide heights and current speeds for hundreds of tide and current stations around the United States. It can be used to produce tide predictions in the past and future for a site at your chosen interval (down to the minute), as well as producing sunrise and sunset times, moon phases, and times when the tide level passes a chosen level mark. It has a user-friendly GUI version (xtide.exe), but also comes in a command line version (tide.exe) that can be interfaced with other programs like R.

Getting R and XTide to talk to each other is a matter of producing a command line query to pass from R to XTide, and then using R to parse the results into a handy format for further manipulation. I have put together an example script that walks through the process, and shows how to parse the results into a data frame with time stamps. The script, xtide_interface.R, is available in this GitHub repository.

# xtide_interface.R
# An example R script to show how to build XTide queries, submit them to the 
# system command line, and then parse the results into a data frame. There are
# several different examples outlined below. 
# Author: Luke Miller May 17, 2013
###############################################################################
# Site names: http://www.flaterco.com/xtide/locations.html 
# List of command line flags: http://www.flaterco.com/xtide/settings.html

# Obviously XTide, or a port like tide.exe (for Windows) must be downloaded from 
# the XTide site and installed. It is a standalone program, separate from R.

# In Windows, the XTide directory that contains the tide.exe program needs to be
# added to the system search PATH. It's easiest if you also put the 
# harmonics.tcd file in the same directory as tide.exe.
###############################################################################

# Sys.setenv(TZ="UTC") 	# Useful if you're getting data for sites in multiple 
						# time zones and need to standardize on one time zone.

# Start and end times, supplied as character strings
startchar = '2013-05-16 16:00'
endchar = '2013-05-20 16:00'
# Site name, taken from http://www.flaterco.com/xtide/locations.html
sitename = 'Bodega Harbor entrance, California'

# Example switches for Xtide command line program
# -l	Give the site name after this switch
# -b	Beginning time, in the format YYYY-MM-DD HH:MM
# -e 	Ending time, in the format YYYY-MM-DD HH:MM
# -f 	output format, c = csv
# -u 	units, i.e. m or ft
# -em	event mask, suppress output of sunrise, sunset, moon phase etc
# -z 	UTC (zulu) time zone
# -ml	mark level, only returns info in plain mode when tide crosses this level
# -m	output information: r = raw, m = medium rare, p = plain
#		raw mode returns the site, unix time code, and height
#		medium rare mode returns site, date, time, and height
#		plain mode returns site, date, time, height, and event
# 			i.e. High Tide, Low Tide, mark level crossing, sunrise, sunset etc

################################################################################
# Example 1
# Create query to return high and low tide times only, with units in feet and
# using the current system time zone. 
tidecommand = paste('tide -l "',sitename,'" -b "',
		startchar, '" -e "', endchar,
		'" -f c -em pSsMm -m p -u ft ', sep = '')

ss = system(tidecommand, intern = TRUE) #invoke tide.exe and return results

# Convert the character strings in 'ss' into a data frame
hilow = read.table(textConnection(ss), sep = ',', colClasses = 'character')
# Add column names to the data frame
names(hilow) = c('Site','Date','Hour','TideHt','Event')
# Combine the Date & Hour columns into a POSIX time stamp
hilow$Time = as.POSIXlt(paste(hilow$Date,hilow$Hour), 
		format = "%Y-%m-%d %I:%M %p")
# Strip off the height units and convert tide height to numeric values
hilow$TideHt = as.numeric(gsub('[ [:alpha:]]',' ',hilow$TideHt))

head(hilow)

################################################################################
# Example 2
# Create query to return high and low tide times, along with any time when 
# the tide crosses the +2.0ft level. (High/low tides are always included).
# Time values will be in the system time zone. Be careful of daylight savings
# transitions.
tidecommand = paste('tide -l "',sitename,'" -b "',
		startchar, '" -e "', endchar,
		'" -f c -em pSsMm -m p -ml 2.0ft -u ft ', sep = '')

ss = system(tidecommand, intern = TRUE) #invoke tide.exe and return results
ss2 = grep('Mark Falling', ss) #find lines with 'Mark Falling' 
# Convert the character strings in 'ss' into a data frame
events = read.table(textConnection(ss[ss2]), sep = ',', 
		colClasses = 'character')
# Add column names to the data frame
names(events) = c('Site','Date','Hour','TideHt','Event')
# Combine the Date & Hour columns into a POSIX time stamp
events$Time = as.POSIXlt(paste(events$Date,events$Hour), 
		format = "%Y-%m-%d %I:%M %p")
# Strip off the height units and convert tide height to numeric values
events$TideHt = as.numeric(gsub('[ [:alpha:]]',' ',events$TideHt))

head(events)
# Calculate time between each event.
diff(events$Time)

################################################################################
# Example 3
# Create query for returning times of high, low tide, plus Sunrise and Sunset,
# all in UTC timezone, for your site. Height units are meters.
tidecommand = paste('tide -l "',sitename,'" -b "',
		startchar, '" -e "', endchar, 
		'" -f c -em pMm -m p -u m -z', sep = '')

ss = system(tidecommand, intern = TRUE) #invoke Xtide and return results

# Convert the character strings in 'ss' into a data frame
hilowSun = read.table(textConnection(ss), sep = ',', colClasses = 'character')
# Add column names to the data frame
names(hilowSun) = c('Site','Date','Hour','TideHt','Event')
# Combine the Date & Hour columns into a POSIX time stamp
hilowSun$Time = as.POSIXlt(paste(hilowSun$Date,hilowSun$Hour), 
		format = "%Y-%m-%d %I:%M %p", tz = "UTC")
# Strip off the height units and convert tide height to numeric values
hilowSun$TideHt = as.numeric(gsub('[ [:alpha:]]',' ',hilowSun$TideHt))

# Convert Time values to current R session time zone, overwriting old timestamps
hilowSun$LocalTime = c(hilowSun$Time)
head(hilowSun)

################################################################################
# Example 4
# Create query to return tide height at fixed time intervals (10 minutes here),
# in UTC time zone, units of meters.
tidecommand = paste('tide -l "',sitename,'" -b "',
		startchar, '" -e "', endchar,
		'" -f c -m m -s 00:10 -u m -z', sep = '')

ss = system(tidecommand, intern = TRUE) #invoke tide.exe and return results
# Convert the character strings in 'ss' into a data frame
tides = read.table(textConnection(ss), sep = ',', colClasses = 'character')
# Add column names to the data frame
names(tides) = c('Site','Date','Hour','TideHt')
# Combine the Date & Hour columns into a POSIX time stamp
tides$Time = as.POSIXlt(paste(tides$Date,tides$Hour), 
		format = "%Y-%m-%d %I:%M %p", tz = "UTC")
# Strip off the height units and convert tide height to numeric values
tides$TideHt = as.numeric(gsub('[ [:alpha:]]',' ',tides$TideHt))
# Create a column of time stamps in the current R session time zone
tides$LocalTime = c(tides$Time)
head(tides)

################################################################################
# Example 5
# Create query to return times of high/low tide, sunrise and sunset, in the 
# local time zone. Extract the time for the Sunsets and place in a data frame
tidecommand = paste('tide -l "',sitename,'" -b "',
		startchar, '" -e "', endchar,
		'" -f c -em pMm -m p -u ft ', sep = '')

ss = system(tidecommand, intern = TRUE) #invoke tide.exe and return results

ss2 = grep('Sunset',ss) #find lines with Sunset
# Convert the character strings in 'ss' into a data frame
sunsets = read.table(textConnection(ss[ss2]), sep = ',', 
		colClasses = 'character')
# Add column names to the data frame
names(sunsets) = c('Site','Date','Hour','TideHt','Event')
# Combine the Date & Hour columns into a POSIX time stamp
sunsets$Time = as.POSIXlt(paste(sunsets$Date,sunsets$Hour), 
		format = "%Y-%m-%d %I:%M %p")
head(sunsets)

The output from the first example would look something like this (I chopped off the last column so it would fit here):

                                Site       Date         Hour TideHt     Event
1 Bodega Harbor entrance| California 2013-05-16  5:30 PM PDT   4.23 High Tide
2 Bodega Harbor entrance| California 2013-05-16 11:16 PM PDT   2.82  Low Tide
3 Bodega Harbor entrance| California 2013-05-17  4:05 AM PDT   4.05 High Tide
4 Bodega Harbor entrance| California 2013-05-17 11:06 AM PDT   0.56  Low Tide
5 Bodega Harbor entrance| California 2013-05-17  6:14 PM PDT   4.41 High Tide
6 Bodega Harbor entrance| California 2013-05-18 12:23 AM PDT   2.47  Low Tide

The output from Example 4 above resembles the following (I’ve cut out some of the columns again to save space):

        Date        Hour   TideHt           LocalTime
1 2013-05-16 4:00 PM UTC 0.180493 2013-05-16 09:00:00
2 2013-05-16 4:10 PM UTC 0.158821 2013-05-16 09:10:00
3 2013-05-16 4:20 PM UTC 0.140198 2013-05-16 09:20:00
4 2013-05-16 4:30 PM UTC 0.124632 2013-05-16 09:30:00
5 2013-05-16 4:40 PM UTC 0.112148 2013-05-16 09:40:00
6 2013-05-16 4:50 PM UTC 0.102741 2013-05-16 09:50:00

 

The interface between R and XTide is the easy part. The hard part is getting XTide properly installed on your computer.

Oddly enough, this is one of those cases where the Windows version (download link)  might actually be easier than the Mac install, since the Mac version only seems to exist as source code that must be built via the command line (found on this page, someone point me to a pre-rolled Mac binary please). To build from source you need both the xtide source and libtcd source. In either case, on Windows, Mac, or Linux, you also need to download a harmonics file (download link) .

On Windows,  after installing the binary XTide file, it’s probably easiest to just put the unzipped harmonics .tcd file in the same directory where you installed XTide (where xtide.exe and tide.exe are found). You also need to edit the Windows environmental variable PATH to include the path to the folder where xtide.exe and tide.exe are installed (see here for an example dealing with Matlab).

On Mac/Linux, it’s easiest to create a xtide.conf file in the /etc directory found inside the system root directory. The screenshot below shows the process of getting to the /etc directory and starting the nano editor to create the xtide.conf file.

Screen Shot 2013-05-17 at 7.20.06 PM

Navigating to the /etc folder on the Mac.

In nano, on the very first line, enter the path to your harmonics .tcd file. Then hit Control+O, Control+X to save and exit nano.

Screen Shot 2013-05-17 at 7.27.37 PM

An example of the path to the harmonics .tcd file that goes on the first line of the xtide.conf file. Change your path to suit wherever your harmonics file ended up.

 

If you got Xtide properly built from source, the xtide.conf file should get it working by helping XTide find the harmonics file. The installation pages for XTide reference the export HFILE_PAGE=…. prior to building the source files, but I didn’t have any success with that method. The xtide.conf method finally got things working for me on the Mac.

When XTide is installed and running, you should be able to open up a system terminal and do something simple like

tide -l "Bodega Harbor entrance, California"

and get a string of tide predictions out. If that works in your system terminal, the R script above should work as well, since R is simply calling the tide program via the system shell.

Finally, if you’re not interested in predictions for Bodega Harbor and instead want data for your local site, you need to find the XTide name for your site here: http://www.flaterco.com/xtide/locations.html. There are tons of sites there, so use Ctrl+F or Command+F to use your browser’s find function to search for the name of your local tide station. If your station has some crazy long name on that page, you’ll need to use that same crazy long name (For example, “Dumbarton Highway Bridge, 0.28 nmi. SE of, San Francisco Bay, California Current (25d)”) for the sitename variable.