home   >   tutorials   >   3d visualization   >   plotting 3d arrows (svg)

Plotting 3D arrows

This tutorial will show you how to plot static and animated 3D arrows using the R package svgViewR. The uninterrupted block of code can be found at the end of this tutorial.

Preliminary steps

Make sure that you have R installed on your system (you can find R installation instructions here).You will also need to install the latest version of the R package svgViewR on CRAN.

# Install the svgViewR package (if not already installed)
install.packages('svgViewR', dependencies=TRUE)

Creating an arrow

Start by loading the svgViewR package into the current R workspace.

# Load the svgViewR package
library(svgViewR)

Create a single arrow. This is specified as a matrix with the first and second row of the matrix corresponding to the base and tip of the arrow, respectively.

## Create arrow of length 1
arrow <- rbind(rep(0,3), rep(1,3))
arrow
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    1    1    1

Then open a connection to a new svgViewR .html file. All of the shapes that you draw will be written to this .html file. At the end you'll be able to open this file in a web browser and view the shapes as an interactive visualization. All of the needed code is contained within this html file which will allow you to share this file so others can view the visualization (they do not even need to have R installed to view it).

# Open a connection to .html file
svg.new(file='plot_static_arrow.html')

Add the arrow to the plot.

# Add arrow
svg.arrows(arrow)

Optionally, add a frame around the arrow. This function outputs the limits of the drawn frame. To surpress this output from being written to the console send the function's output to svg_frame.

# Add coordinate axis planes around the arrow
svg_frame <- svg.frame(arrow)

Close the connection to the .html file. This adds some closing tags that are needed for the visualization to work properly.

# Close the file connection
svg.close()

You can open the resulting .html file.

Plot of static 3D arrow and bounding coordinate planes.

Note that unlike the base R plotting functions you are not required to specify limits for the plot region prior to plotting shapes. When you open the .html file the javascript code inside the .html file will automatically determine the necessary viewing window dimensions so that all the shapes are visible.

To rotate the graphic click and drag the cursor while holding down the 'r' key or click on the circle arrow icon in the top right corner and then click and drag the cursor. To move the graphic click and drag the cursor or click on the intersecting arrows icon in the top right and click and drag the cursor. To zoom scroll in and out. To return to the initial orientation of the graphic (or to see changes if you re-write the file) refresh the browser.

Creating an animated arrow

To animate this arrow you just need to convert the matrix into an array, similar to animating 3D points. However, one difference between the svg.points function and the svg.arrows function is that and the svg.points can plot multiple static or animated points while svg.arrows can only plot a single static or animated arrow.

Set the number of iterations you'd like.

## Set number of iterations
n_iter <- 100

Create an array of the arrow at each iteration.

# Animate arrows, save into array
arrow_anim <- array(arrow, dim=c(dim(arrow), n_iter))
for(iter in 0:(n_iter-1)){

	# Translate along vector direction
	tm <- matrix(0.1*iter*(arrow[2,]-arrow[1,]), 2, 3, byrow=TRUE)
	
	# Apply translation
	arrow_anim[, , iter] <- arrow + tm
}

This array is a series of 2-row matrices specifying the start and end of the arrow at each interval.

arrow_anim[,,1]
     [,1] [,2] [,3]
[1,]  0.1  0.1  0.1
[2,]  1.1  1.1  1.1

Start a new plot file and add the animated arrow to the plot. Optionally, add a frame around the animated arrow. Use the len parameter to set the arrowhead length since the default is not the right size.

# Open a connection to .html file
svg.new(file='plot_animated_arrow.html')

# Plot arrows, set arrowhead length
svg.arrows(arrow_anim, len=0.5)

# Add coordinate axis planes around the points
svg_frame <- svg.frame(arrow_anim)

# Close the file connection
svg.close()

You can open the resulting .html file.

Plot of animated 3D arrow and bounding coordinate planes.

Creating multiple arrows

To create multiple arrows you'll have to call svg.arrows for each arrow. Set the number of arrows you'd like to draw.

## Set number of arrows
n_arrows <- 100

Use a normal distribution to set randomly oriented arrows radiating from the origin.

# Create randomly oriented arrows
arrowm <- list()
for(i in 1:n_arrows) arrowm[[i]] <- rbind(rep(0,3), uvector_svg(rnorm(3)))

Optionally, if you'd like to draw a coordinate frame around the arrows, get the xyz-coordinate ranges.

# Get range
arrow_range <- apply(matrix(unlist(arrowm), ncol=3, byrow=TRUE), 2, 'range', na.rm=TRUE)

Start a new plot file and add each arrow to the plot, optionally adding a frame around the arrows.

# Open a connection to .html file
svg.new(file='plot_static_arrows.html')

# Plot arrows
for(i in 1:n_arrows) svg.arrows(arrowm[[i]])

# Add coordinate axis planes around the points
svg_frame <- svg.frame(arrow_range)

# Close the file connection
svg.close()

You can open the resulting .html file.

Plot of static 3D arrows and bounding coordinate planes.

Creating multiple animated arrows

To demonstrate how to plot multiple moving arrows we'll animate the randomly oriented arrows so that they "shoot" outward from the origin.

Create a list of arrows, with each list element as an array of arrow start and end coordinates at each iteration. In the previous example (multiple static arrows) each list element was a matrix so we're effectively converting each "arrow matrix" into an "arrow array".

## Animate arrows
arrowm_anim <- list()
for(i in 1:length(arrowm)){

	# Create array
	arrowm_anim[[i]] <- array(NA, dim=c(dim(arrowm[[i]]), n_iter))

	# Apply transformation at each iteration
	for(iter in 0:(n_iter-1)){
		
		# Translate along vector direction (outward from the origin)
		tm <- matrix(0.05*iter*(arrowm[[i]][2,]-arrowm[[i]][1,]), 2, 3, byrow=TRUE)

		# Apply translation
		arrowm_anim[[i]][, , iter] <- arrowm[[i]] + tm
	}
}

At each iteration, each arrow is translated outward from the origin along its orientation. The translation distance is based on the current iteration number.

To draw a coordinate frame around the arrows get the xyz-coordinate ranges.

# Get range
arrow_range <- apply(matrix(unlist(arrowm_anim), ncol=3, byrow=TRUE), 2, 'range', na.rm=TRUE)

Start a new plot file and add each animated arrow, optionally adding a frame around the arrows. Use the len parameter to set the arrowhead length since the default is not the right size.

# Open a connection to .html file
svg.new(file='plot_animated_arrows.html')

# Plot arrows
for(i in 1:length(arrowm_anim)) svg.arrows(arrowm_anim[[i]], len=0.3)

# Add coordinate axis planes around the points
svg_frame <- svg.frame(arrow_range)

# Close the file connection
svg.close()

You can open the resulting .html file.

Plot of animated 3D arrows and bounding coordinate planes.

Uninterrupted code


# Load the svgViewR package
library(svgViewR)

## Create arrow of length 1
arrow <- rbind(rep(0,3), rep(1,3))
arrow
     [,1] [,2] [,3]
[1,]    0    0    0
[2,]    1    1    1

# Open a connection to .html file
svg.new(file='plot_static_arrow.html')

# Add arrow
svg.arrows(arrow)

# Add coordinate axis planes around the arrow
svg_frame <- svg.frame(arrow)

# Close the file connection
svg.close()

## Set number of iterations
n_iter <- 100

# Animate arrows, save into array
arrow_anim <- array(arrow, dim=c(dim(arrow), n_iter))
for(iter in 0:(n_iter-1)){

	# Translate along vector direction
	tm <- matrix(0.1*iter*(arrow[2,]-arrow[1,]), 2, 3, byrow=TRUE)
	
	# Apply translation
	arrow_anim[, , iter] <- arrow + tm
}

arrow_anim[,,1]
     [,1] [,2] [,3]
[1,]  0.1  0.1  0.1
[2,]  1.1  1.1  1.1

# Open a connection to .html file
svg.new(file='plot_animated_arrow.html')

# Plot arrows, set arrowhead length
svg.arrows(arrow_anim, len=0.5)

# Add coordinate axis planes around the points
svg_frame <- svg.frame(arrow_anim)

# Close the file connection
svg.close()

## Set number of arrows
n_arrows <- 100

# Create randomly oriented arrows
arrowm <- list()
for(i in 1:n_arrows) arrowm[[i]] <- rbind(rep(0,3), uvector_svg(rnorm(3)))

# Get range
arrow_range <- apply(matrix(unlist(arrowm), ncol=3, byrow=TRUE), 2, 'range', na.rm=TRUE)

# Open a connection to .html file
svg.new(file='plot_static_arrows.html')

# Plot arrows
for(i in 1:n_arrows) svg.arrows(arrowm[[i]])

# Add coordinate axis planes around the points
svg_frame <- svg.frame(arrow_range)

# Close the file connection
svg.close()

## Animate arrows
arrowm_anim <- list()
for(i in 1:length(arrowm)){

	# Create array
	arrowm_anim[[i]] <- array(NA, dim=c(dim(arrowm[[i]]), n_iter))

	# Apply transformation at each iteration
	for(iter in 0:(n_iter-1)){
		
		# Translate along vector direction (outward from the origin)
		tm <- matrix(0.05*iter*(arrowm[[i]][2,]-arrowm[[i]][1,]), 2, 3, byrow=TRUE)

		# Apply translation
		arrowm_anim[[i]][, , iter] <- arrowm[[i]] + tm
	}
}

# Get range
arrow_range <- apply(matrix(unlist(arrowm_anim), ncol=3, byrow=TRUE), 2, 'range', na.rm=TRUE)

# Open a connection to .html file
svg.new(file='plot_animated_arrows.html')

# Plot arrows
for(i in 1:length(arrowm_anim)) svg.arrows(arrowm_anim[[i]], len=0.3)

# Add coordinate axis planes around the points
svg_frame <- svg.frame(arrow_range)

# Close the file connection
svg.close()