This lesson introduces hypothesis-driven data analysis in R, and introduces the concept of circular data while providing some tools for importing it and analyzing it in R. After exploring a sample dataset to learn these tools, we will apply what we have learned to two examples of circular datasets: one testing for magnetoreception in salmon (simulated based on Putman et al. 2014), and the other testing for visual orientation in deep-sea squids (Thomas et al. 2017). The lesson is designed to be a code after me, step-by-step journey through data analysis.
Circular data is data that indicates an angular orientation (for example, which way an animal is facing or moving, which can be measured in degrees or radians) or a periodic event (for example, circadian rhythms). Today, we will focus on orientation data measured in degrees. Ciruclar data requires special consideration and statitstics for analysis, as we will see in the following exercise.
The image above shows an example of how one might measure the orientation of a lobster in a circular arena. This will produce a circular dataset
We’re going to create our own ‘dummy’ dataset to practice the basics of analyzing a circular datset before we move on to looking at real examples of circular data. Doing a sample analysis on a small dataset is good practice, to make sure everything works and flows logically. Also, at each step, we want to think about what we expect the outcome of our code and calculations to be. It’s a good way to check that we’re probably doing the right thing.
You will need to install the circular
and knitr
packages if you haven’t already.
# Packages - install if you haven't
#install.packages("circular")
#install.packages("knitr")
#Load libraries for packages
library(circular)
library(knitr)
# Directory
knitr::opts_chunk$set(root.dir = "~/repos/dataexpedition", results="hide", echo=TRUE, warning=FALSE, message=FALSE) #set directory for your files and options for your rmarkdown document. Set root.dir = [file path to your folder for this project]
getwd() #check our working directory
Let’s imagine two tests of orientation with six animals each, which are plotted below. What would we estimate as the mean orientation of the animals in the control treatment? Of the experimental treatment?
Let’s enter these data so we can analyze them and plot them ourselves.
control <- c(0, 45, 90, 135, 180, 225, 270, 315) #assign control data
experimental <- c(0, 5, 10, 15, 350, 355) #assign experimental data
control.mean <- mean(control) #calculate and assign control mean
print(control.mean)
## [1] 157.5
experimental.mean <- mean(experimental) #calculate and assign experimental mean
print(experimental.mean)
## [1] 122.5
We got numbers! Math works! But…
We can’t calculate an arithmetic mean for circular data. So we have to calculate a circular mean.
circular()
The first step for dealing with circular data in R is to convert it to a specific type called ‘circular’. We can use the circular()
function, from the circular
package, which we have already loaded. We want to specify the units (“degrees”) and template (“geographics”, aka North, South, East, West with North = 0 degrees) for our data here.
?circular #check out the help file
#Convert control data to circular
control.circ <- circular(control, units = "degrees", template = "geographics")
#Convert experimental data to circular
experimental.circ <- circular(experimental, units = "degrees", template = "geographics")
Plotting is a good way to inspect our data. We will plot the experimental
data together for the next several steps, but you can do the same steps with control
on your own for practice.
plot.circular(experimental.circ) #plots experimental data
Now that our data is in a circular format, we can calculate the circular mean using mean()
. Let’s do this for our ‘experimental’ dataset (the panel on the left).
#Calculate and assign experimental circular mean
experimental.circ.mean <- mean(experimental.circ)
print(experimental.circ.mean)
## Circular Data:
## Type = angles
## Units = degrees
## Template = geographics
## Modulo = asis
## Zero = 1.570796
## Rotation = clock
## [1] 2.5
R gives us an output that reminds us we’re working with circular data (thanks, R!), and the answer to our calculation on the line that says [1] 2.5
.
Plot the experimental data, the arithmetic mean, and the circular mean. We can use arrows.circular()
to represent the means with arrows. Remember that R will execute your commands in the order they are written, so you must tell it to make a plot (plot.circular()) before you can tell it to add anything to that plot (like arrows.circular()).
plot.circular(experimental.circ) #plot experimental data
arrows.circular(experimental.mean) # plot arithmetic mean, default color is black
arrows.circular(experimental.circ.mean, col = "red") # plot circular mean in red (col = "red")
Let’s now use these skills to explore a real dataset: Testing for magnetoreception in salmon using circular data.
Juvenile salmon are born in a river, swim down to the sea, and then must find their adult feeding grounds. They do this reliably! But how do they make a trip they’ve never made before? Ocean currents and chemical cues are too variable to be reliable. It may be that they have an internal map of the earth’s magnetic field and can sense their position by sensing magnetic forces (magnetoreception). If this is true, we would expect salmon to orient differently, depending on where they are in their range (e.g. north vs. south, or “ambient” a.k.a. middle of the range/out of range?). The dataset we use below is pulled from a published study of salmon orientation in different magnetic field conditions (Putnam et al. 2004).
Think about the things you need to do to get from this raw data file to answering your biological question. Writing pseudocode is a way to outline and break down the steps you want to take in data analysis. You can use comments to write out exactly what you want to do. Using verbs is helpful! Break it down as much as possible.
## set up R -- DONE
## import dataset
## inspect dataset
## subset data
## transform to circular data
## plot data
## do data analysis
Import the Putman-data.txt
data file.
?read.table #check help file
data <- read.table("supplemental/Putman-data.txt", sep="\t", header=T) #read in our data
Take a look at your dataset. What do the columns represent? What about the rows?
data #this prints out data in the console/rmd file
head(data) #shows first 5 rows, or customizable
tail(data) #shows last 5 rows, or customizable
Let’s open Putman-data.txt
as a file from our regular file folders to check it imported correctly. Does it look the same?
We can transform and subset at the same time, for efficiency. Since “North”, “South”, and “Ambient” represent different experimental treatments, we want to subset each of these for further analysis.
## Subset each column (each treatment), and assign as circular data
north <- circular(data$North, units="degrees", template="geographics") #assign north subset to "north" variable
south <- circular(data$South, units="degrees", template="geographics") #south
ambient <- circular(data$Ambient, units="degrees", template="geographics") #ambient
#check that the data was subsetted correctly (south & ambient, too if did already)
print(north)
print(south)
print(ambient)
Let’s look at just the North treatment first. Plot the north treatment data.
plot.circular(north) #plot circular plot
How exciting! But what’s wrong with this plot? Does this have the right number of data points considering your dataset? No, should be ~245! This is because you must control the attributes of your plot – currently all datapoints are plotted directly on top of each other so you can only see one of each value. Let’s play around with plotting arguments to make this look a little nicer.
#Tell plot to stack the points instead of putting them all directly on the edge of the circle (on top of each other)
plot.circular(north, stack = TRUE) #stack points
Above we told R to stack the points, essentially creating a frequency histogram around the edge of the circle representing the number of salmon that oriented at each direction around the plot. But it’s still a bit scrunched up, so let’s play with attributes further to make it look better.
#Make the plot look nicer (you can play with these attributes yourself to make it look how you like it)
plot.circular(north, stack = TRUE, pch = 20, sep = 0.08, shrink = 1.6)
#stack = stack overplotted points
#pch = point type
#sep = space between stacked points
#shrink = make graph a little smaller
?plot.circular # help file let's you know what knobs you have to twiddle
Much nicer! Let’s move on to data analysis now that the plot is looking good.
After this, you can calculate the mean orientation of the north
data.
mean(north) #does this work? why not? look at the structure of your data, notice all of the NA values in the data. Those need to be eliminated before analysis.
?mean #check help file
#na.rm is very useful! Different functions handle NAs (empty spots) in the dataset differently. na.rm is a common argument to use to ignore/use them.
#side note: be aware of where the gaps in your data are. they're a good indicator to use if you're getting weird calculations, or blanks are appearing in the wrong spots.
mean(north, na.rm = TRUE) #remove NAs from dataset, then find mean
north.mean <- mean(north, na.rm = TRUE) #assigns to the 'north.mean' object
Does this mean make sense? Where would it go on a our plot?
plot.circular(north, stack = T, pch = 20, sep = 0.08, shrink = 1.6)
arrows.circular(north.mean) #add mean to plot
Good! Now let’s add a title to our plot so we can keep it organized from the other plots we will make.
plot.circular(north, stack = T, pch = 20, sep = 0.08, shrink = 1.6, main = "North")
arrows.circular(north.mean) #add mean to plot
## Repeat plots of data and means for ‘south’ and ‘ambient’ treatments as well
#Calculate south circular mean
south.mean <- mean(south, na.rm = TRUE)
#Plot south data & circ. mean
plot.circular(south, stack = T, pch = 20, sep = 0.08, shrink = 1.6, main = "South")
arrows.circular(south.mean)
#Calculate ambient circular mean
amb.mean <- mean(ambient, na.rm = TRUE)
#Plot ambient data & circ. mean
plot.circular(ambient, stack = T, pch = 20, sep = 0.08, shrink = 1.6, main = "Ambient")
arrows.circular(amb.mean)
Compare the three groups. Are they different? Do they show evidence for different orientations in salmon under different magnetic field conditions? It’s a bit hard to tell by just looking at noisy behavioral data, so let’s apply some quantitative statistical tests to address our questions.
A Rayleigh Test is a test for significant unimodal orientation (e.g. Is everyone in the treatment going the same direction?). There are other statistical tests for bimodal and other models, but we’re not going to worry about that here, as our question is about a unimodeal response: Do animals given a given magnetic field (north, south, ambient) significantly orient in a particular direction?
?rayleigh.test # check help file
rayleigh.test(north)
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.135
## P-value: 0.0143
rayleigh.test(south)
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.1631
## P-value: 0.002
rayleigh.test(ambient)
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.0402
## P-value: 0.6788
What groups show significant orientations (significance is generally accepted if p < 0.05)? Does this test compare the groups to each other? No; this test only tells us whether each treatment individually shows significant evidence of non-uniform orientation (here, the North and South treatments do and the Ambient treatment does not). We must apply another statistical test to determine whether each treatment (different magnetic fields) yields different directions of orientation among the salmon.
A Watson Test determines if two groups’ orientations are significantly different from each other. Here, it will allow us to test whether the ‘north’ and ‘south’ groups orient in different directions (we already know that the ‘ambient’ group is uniform and doesn’t orient in a particualr direction).
?watson.two.test #help file on this statistical test
# Test whether North and South orient differently
watson.two.test(north, south)
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 0.5046
## P-value < 0.001
##
# You can also test whether south/ambient and north/ambient orient differently, but we already know that ambient doesn't orient in a particular direction at all.
watson.two.test(south, ambient)
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 0.1709
## 0.05 < P-value < 0.10
##
watson.two.test(north, ambient)
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 0.1474
## P-value > 0.10
##
Which treatment groups significantly differ from each other? What does this mean for our original biological question? Do juvenile salmon differ in their orientation when exposed to different magnetic fields (e.g. north, south, or ambient)? Does this support the hypothesis that they may have an internal magnetic map? What evidence do we have (from our analysis)?
You can look at the published paper using a very similar dataset (ours is simulated but shows the same trends). Putman, et al. 2014. An Inherited Magnetic Map Guides Ocean Navigation in Juvenile Pacific Salmon. Current Biology, 24, 4:446-450. doi: http://dx.doi.org/10.1016/j.cub.2014.01.017
Above: Salmon exposed to the ‘north’ magnetic stimulus (Figure 1A, Putman et al., 2014).
Above: Salmon exposed to the ‘south’ magnetic stimulus (Figure 1B, Putman et al., 2014).
Above: Salmon exposed to the ‘ambient’ magnetic stimulus (Figure 1C, Putman et al., 2014).
Table 1 from Putman et al. (2014). Do your p-values match the published ones for the Rayleigh Test?
Now, we will use the same techniques we just learned to answer a completely different biological question with a new dataset. In the twilight zone of the deep-sea, there is a family of squids (the Histioteuthidae) that have two differently sized and shaped eyes. This strange trait gave them the nickname “cockeyed squids,” and one hypothesis for the difference between their eyes is that they use them to look in different directions. The large eye may look upward toward dim downwelling sunlight to look for the sillhouettes of potential prey, while the smaller eye may look downward into the dark depths to scan for bioluminescent flashes from other deep-sea animals. The dataset we will use below measured the orientations of cockeyed squid eyes in their natural habiat from video observations to test this hypothesis, and comes from (Thomas et al. 2017).
A semi-transparent juvenile Histioteuthis heteropsis showing the differently sized and shaped eyes; the left eye is semitubular and huge, while the right eye is hemispherical and normally proportioned.
(Click here for video of a cockeyed squid)
Try to work through answering this question based on the Thomas-data.txt dataset. These data were recorded as eye orientation in degrees, with eye orientation upward toward the ocean surface set at 0 degrees (0 is directly up, 180 is directly down). Note that there are data for two different species of squids: Histioteuthis heteropsis and Stigmatoteuthis dofleini. Like before, start by making a commented outline of the steps you will need to take to get from this dataset through analysis and answer your questions: Do cockeyed squids use their left eye to look up toward the ocean surface and their right eye to look down? Does this vary across species?
squid.data <- read.table("supplemental/Thomas-data.txt", sep="\t", header=T) #read in our data
squid.data #prints data in console. You can also see it by clicking on "squid.data" in the Environment (this will open a new window with the data table)
What is the structure of these datasets? How many species are included? What do the columns represent? How does this dataset differ from the salmon orientation dataset? What will that mean for subsetting and analysis?
One new aspect of this dataset is that it includes two different species that are distinguished by the column “Genus_species”. To start, we will need to break the dataframe apart by species so that we can easily analyze them separately.
#Make one dataframe that only contains observations of the squid Histioteuthis heteropsis
hh<-squid.data[squid.data$Genus_species=="Histioteuthis_heteropsis", ] #takes rows where the species is Histioteuthis heteropsis and all columns of that row
#Make another with only observations of the squid Stigmatoteuthis dofleini
sd<-squid.data[squid.data$Genus_species=="Stigmatoteuthis_dofleini", ] #takes rows where the species is Stigmatoteuthis dofleini and all columns of that row
Take a look at your subset dataframes. Did your subsetting work how you wanted it to? What is the new structure of your data? Is it ready for analysis?
Now we will subset and transform to circular data, just like we did in the previous salmon example.
?circular() #take a look at the circular function information again. Last time we told R to use a "geographics" data template. Is that appropriate for our new dataset? No, we are not looking at geographic data here, so we will specify that 'template = none'
hh_left<-circular(hh$Leye, units = "degrees", template = "none") #left eye of Histioteuthis
hh_right<-circular(hh$Reye, units = "degrees", template = "none") #right eye of Histioteuthis
sd_left<-circular(sd$Leye, units = "degrees", template = "none") #left eye of Stigmatoteuthis
sd_right<-circular(sd$Reye, units = "degrees", template = "none") #right eye of Stigmatoteuthis
We’ll go through the Histioteuthis data first, as that’s where most of our data is.
We can plot data the same way we did previously with the salmon to start out.
plot.circular(hh_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1.8, main = "Histioteuthis heteropsis left eye") #plots the orientations of the left eye (0 = up toward surface)
plot.circular(hh_right, stack = TRUE, pch = 20, sep = 0.08, shrink = 1.8, main = "Histioteuthis heteropsis right eye") #use 'points()' if you want to add additional points to the same plot (in this case we have colored them red to distinguish them from the first dataset)
This is a good start, but since these data occur on the same animal (every squid has a right and a left eye), it would make more sense to plot them both on the same plot. We can do this by replacing the second plot.circular() command with points(), which adds new points to the existing plot.
plot.circular(hh_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1.8, main = "Histioteuthis heteropsis", sub = "black = left eye, red = right eye") #plots the orientations of the left eye (0 = up toward surface)
points(hh_right, stack = TRUE, pch = 20, sep = 0.08, col= "red") #use 'points()' if you want to add additional points to the same plot (in this case we have colored them red to distinguish them from the first dataset)
That looks better! Notice that we added a subheading to say what each color represents on the chart.
Now let’s find the circular mean for the orientation of each eye (still just in Histioteuthis) and assign each to a variable.
#Find the means for the left eye and the right eye orientations
hh_left.mean<-mean(hh_left, na.rm=TRUE)
hh_right.mean<-mean(hh_right, na.rm=TRUE)
Now we can add arrows to the plot where the means fall.
#Plot the means as arrows on the plot
plot.circular(hh_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1.8, main = "Histioteuthis heteropsis") #plots the orientations of the left eye (0 = up toward surface)
points(hh_right, stack = TRUE, pch = 20, sep = 0.08, col= "red") #
arrows.circular(hh_left.mean) #adds a black arrow where the mean for the left eye falls
arrows.circular(hh_right.mean) #adds a red arrow where the mean for the right eye falls
Great! But as one last step, let’s make the mean for the right eye (red points) be red to match.
#Plot the means as arrows on the plot with colors corresponding to data points
plot.circular(hh_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1.8, main = "Histioteuthis heteropsis") #plots the orientations of the left eye (0 = up toward surface)
points(hh_right, stack = TRUE, pch = 20, sep = 0.08, col= "red")
arrows.circular(hh_left.mean) #
arrows.circular(hh_right.mean, col="red") #adds a red arrow where the mean for the right eye falls
That looks good! Compare your data by eye. Do you see evidence for orientation in the two different eyes? Does it look different? Next use statistical tests to quantitatively test this.
Let’s apply the Rayleigh test to determine whether each eye shows evidence for a non-uniform distribution.
rayleigh.test(hh_left) # test for orientation of left eye
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.9778
## P-value: 0
rayleigh.test(hh_right) #test for orientation of right eye
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.9836
## P-value: 0
Do the eyes show evidence of orientation? (They certainly do! P-values are so low that they are rounding to 0, which is highly significant evidence for non-uniform distribution.)
Now let’s apply the Watson test to determine whether the orientations of each eye are significantly different.
watson.two.test(hh_left, hh_right)
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 1.1725
## P-value < 0.001
##
Do the left and right eye orient in significantly different directions? (Yes, they do!) What can we say about our hypothesis given this evidence? Remember that 0 degrees is defined as an orientation directly up toward the surface of the ocean. So given our data distributions and statistical results, we can say that we have significant evidence that the large, left eye of Histioteuthis orients upward (mean of 44 degrees away from surface), while the smaller, right eye orients downward (mean of 123 degrees away from surface).
Now let’s take a look at the other species in our original dataset, Stigmatoteuthis doflieni. We don’t have very much data for this species, but the little data we do have could allow us to ask some preliminary questions. Do other species show the same trends in eye orientation as Histioteuthis? Are the orientations of eyes different among different species?
We already subset these data and converted it to circular format so we can move straight on to plotting.
First plot your data for the left and right eye together.
plot.circular(sd_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1, main = "Stigmatoteuthis dofleini", sub = "black = left eye, red = right eye") #plots the orientations of the left eye (0 = up toward surface)
points(sd_right, stack = TRUE, pch = 20, sep = 0.08, col= "red") #adds red points for the right eye
That worked! Or did it.. Take a look at your dataset.
sd_right #shows dataset in console
sd_left #shows dataset in console
Look at the values for each dataset. Are they the same as what’s plotting on your graph. No! What is going on?
When using computing tools, it’s always important to check that things are working along the way, or you can end up with wonky results due to assumptions your tool is making that you may not even realize are happening. Why might these data be plotting this way?
In this case, it’s because we have used plot.circular() to create a frequency histogram but not specified the size of the bins for data. When we had a larger dataset, the program selected a small bin size because that’s what made the most sense for our data, but now that we have only 6 data points for each eye, the program selected very large bins that are making our data appear misleading on the chart. To fix this, we will specify the number of bins (in this case 360– one for each degree on our plot) for our frequency histogram.
plot.circular(sd_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1, bins=360, main = "Stigmatoteuthis dofleini") #plots the orientations of the left eye (0 = up toward surface)
points(sd_right, stack = TRUE, pch = 20, sep = 0.08, col= "red", bins = 360) #adds orientations of right eye in red points
#note that with less data on the plot, it was crucial to specify how many bins to use for data plotting ('bins=360'), or R assumed bins should be large to accomodate a small sample size, and plot looked very inaccurate.
Much better! Our tiny dataset is now plotting where we expect given the distribution of values in our dataset.
Now let’s add circular means to this plot just like we did with the last one.
#Find the means for the left eye and the right eye orientations
sd_left.mean<-mean(sd_left, na.rm=TRUE)
sd_right.mean<-mean(sd_right, na.rm=TRUE)
#Plot the means as arrows on the plot with colors corresponding to data points
plot.circular(sd_left, stack = TRUE, pch = 20, sep = 0.08, shrink = 1, bins=360, main = "Stigmatoteuthis dofleini") #plots the orientations of the left eye (0 = up toward surface)
points(sd_right, stack = TRUE, pch = 20, sep = 0.08, col= "red", bins = 360) #use 'points()' if you want to add additional points to the same plot (in this case we have colored them red to distinguish them from the first dataset)
arrows.circular(sd_left.mean, col="black") #adds a black arrow where the mean for the left eye falls
arrows.circular(sd_right.mean, col="red") #adds a red arrow where the mean for the right eye falls
Now let’s apply the same statistical tests that we did for the other species.
rayleigh.test(sd_left) # test for orientation of left eye
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.9818
## P-value: 0.0018
rayleigh.test(sd_right) #test for orientation of right eye
##
## Rayleigh Test of Uniformity
## General Unimodal Alternative
##
## Test Statistic: 0.9976
## P-value: 0.0011
Did we find evidence of orientation in the eyes of the other speices, Stigmatoteuthis dofleini? Yes, we do see evidence of non-uniform orientation, even in this tiny dataset.
Now let’s again test whether we see significantly different orientations in the left and right eye of Stigmatoteuthis.
#test whether Stigmatoteuthis right and left eyes show significantly different orientations
watson.two.test(sd_right, sd_left)
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 0.225
## 0.01 < P-value < 0.05
##
We do! There is evidence that they are orienting in different directions, with the left eye again orienting slightly toward the surface and the right eye slightly downward.
But what about the two species. Can we test whether the orientations of each species eyes differ from each other?
#test whether Histioteuthis and Stigmatoteuthis eye show significantly different orientations
watson.two.test(hh_left, sd_left) #for left eyes
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 0.073
## P-value > 0.10
##
watson.two.test(hh_right, sd_right) #for right eyes
##
## Watson's Two-Sample Test of Homogeneity
##
## Test Statistic: 0.2184
## 0.01 < P-value < 0.05
##
We can try, but our dataset is so small that it isn’t completely clear. The data for the right eye isn’t significantly different between species, but the data for the left eye just makes our standard for significance. The mean viewing direction for the larger, left eye in Histioteuthis was 44 degrees off from an upward direction, while the mean viewing direction in Stigmatoteuthis was only 35 degrees off from upward. The Watson test indicates that this is a significant difference in orientation, though the magnitude of the difference is small. However, the dataset for Stigmatoteuthis has a very small sample size and we would benefit greatly from more data.
Given our starting dataset, what can we say about the hypothesis that the large, left eye of cockeyed squids is used for looking upward toward the surface, while the smaller, right eye is used for looking downward into the ocean depths? What can we say about how this varies within and among different speices?
Data from: Thomas KN, Robison BH, Johnsen S. 2017 Two eyes for two purposes: in situ evidence for asymmetric vision in the cockeyed squids Histioteuthis heteropsis and Stigmatoteuthis dofleini. Phil. Trans. R. Soc. B 372: 20160069. http://dx.doi.org/10.1098/rstb.2016.0069
Above: Histioteuthid eye and body axis orientations (left, solid white lines) relative to a vertical axis (left, dotted white lines). (a) Absolute eye orientations, with 0° indicating an eye oriented directly upward and 180° directly downward. Orientations of the larger, left eye are plotted on the right (grey) and the smaller, right eye on the left (black) to show where the eyes are directed relative to one another. (Figure 3A, Thomas et al., 2017).
Above: A cross section through both eyes of a histioteuthid showing the approximate field of view for each eye (shaded) given an orientation of 45° for the large left eye and 120° for the small right eye. (Figure 3C, Thomas et al., 2017).