I’m no expert on this at all, but I’d guess its just some idiosyncracies between the RStudio renderer and the exported image renderer 9if indeed, they are different!)
I’ve noticed a similar thing, particularly with greys, but my hacky solution to date has just been to fiddle with the alpha/opacity till I’m happy with it. You could try the code I’ve moved on to below, which circumvents the limitation on free plotly renders, and uses an RSelenium server instead. The rendering may be a little more faithful.
#!/usr/bin/env Rscript
# Plotting surface plots via ggplot2/plotly
# Usage:
# $ Rscript CDmeltplot.R -i data.csv -o filename
############################################################
# General purpose heatmap plotting script for consistency. #
# This script can be slow as it was designed to be pretty #
# bullet-proof when loading/installing necessary packages. #
# #
# By J. Healey #
# Version 3
############################################################
# Load packages:
list.of.packages <- c("reshape2",
"plotly",
"argparse",
"ggplot2",
"RColorBrewer",
"tools",
"stringr",
"htmltools",
"magrittr",
"RSelenium")
new.packages <- list.of.packages[!(list.of.packages %in% installed.packages()[,"Package"])]
if(length(new.packages)) install.packages(new.packages)
suppressMessages(library("reshape2"))
suppressMessages(library("plotly"))
suppressMessages(library("argparse"))
suppressMessages(library("ggplot2"))
suppressMessages(library("RColorBrewer"))
suppressMessages(library("tools"))
suppressMessages(library("stringr"))
suppressMessages(library("htmltools"))
suppressMessages(library("magrittr"))
suppressMessages(library("RSelenium"))
parser <- ArgumentParser()
parser$add_argument('-i',
'--infile',
action='store',
required=TRUE,
help="Plain csv matrix file for plotting.")
parser$add_argument('-d',
'--device',
action='store',
default='svg',
choices=c('png','svg','jpeg','pdf','webp'),
help='Output image format/device. Default SVG.')
parser$add_argument('-o',
'--outfile',
action='store',
default='None',
help='Filename and path to save the image to. Defaults to the same as the infile with a new extension.')
parser$add_argument('-z',
'--zoom',
action='store',
default=2.5,
help='The zoom value of the camera, larger values move the camera away from the centre. Default 2.5')
parser$add_argument('-v',
'--vangle',
action='store',
default=0.4,
help='The vertical angle of the camera. Increased values will rotate the camera \'overhead\'. Default 0.4')
parser$add_argument('--movie',
action='store',
default='0.5:0.5:1',
help='Render multiple frames to create a video. Specify start:end:increment.')
parser$add_argument('--set_iter',
action='store',
default=0,
help='Set the iteration counter for the output images when rendering in multiple sessions. Keeps images numerically ordered to make video creation easier.')
args <-parser$parse_args()
# Prep variables for use
infile <- args$infile
outfile <- args$outfile
device <- args$device
movie <- args$movie
cam.zoom <- as.numeric(args$zoom)
ver.angle <- as.numeric(args$vangle)
set_iter <- as.numeric(args$set_iter)
browser <- args$browser
port <- as.numeric(args$port)
from <- as.numeric(strsplit(movie,":")[[1]][1])
to <- as.numeric(strsplit(movie,":")[[1]][2])
increment <- as.numeric(strsplit(movie,":")[[1]][3])
if (outfile == 'None'){
outfile <- basename(file_path_sans_ext(infile))
}
cat("Starting RSelenium server", "\n")
RS_server <- rsDriver(verbose = FALSE)
# Read in and prepare data
df <- read.csv(infile, sep=",", check.names=FALSE, row.names = 1, header = TRUE)
matrix <- as.matrix(df)
scan <- as.numeric(rownames(df))
temp <- as.numeric(colnames(df))
matrix.list <- list(z = matrix,
x = temp,
y = scan)
font.pref <- list(size=18, family="Arial, sans-serif", color="black")
x.list <- list(title = "Temperature (˚C)",
titlefont = font.pref,
ticklen = 20,
tickcolor = "white",
zerolinecolor = "black",
zerolinewidth = 2)
y.list <- list(title = "Wavelength (nm)",
titlefont = font.pref,
ticklen = 20,
tickcolor = "white",
zerolinecolor = "black",
zerolinewidth = 2)
z.list <- list(title = "CD Intensity",
titlefont = font.pref,
ticklen = 20,
tickcolor = "white",
zerolinecolor = "black",
zerolinewidth = 2)
iter = set_iter
for(i in seq(from, to, by=increment)){
iter = iter + 1
theta = i/100
graph <- plot_ly(z =~matrix, x=temp, y=scan, type="surface",
colors= c('black','gray','red'),
colorbar = list(title="CD Intensity",
yanchor="middle",
len=1.5)) %>%
layout(scene=list(xaxis = x.list,
yaxis = y.list,
zaxis = z.list,
camera = list(eye = list(x = cos((i/10))*cam.zoom,
y = sin((i/10))*cam.zoom,
z=ver.angle)
)
)
)
outfile_iter <- paste(outfile, ".", str_pad(iter, 4, pad ="0"), sep = "")
outfile_iter_ext <- paste(outfile_iter, device, sep = ".")
# Render images:
export(p = graph, outfile_iter_ext, RS_server)
if (device == "pdf"){
convert.installed <- system("convert --version", ignore.stdout = TRUE) == 0
if (convert.installed == TRUE){
cat("Calling ImageMagick to convert to formats other than PNG/JPEG", "\n")
cat(sprintf('convert %s %s',
paste(outfile_iter, device, sep = "."),
paste(outfile_iter, "pdf", sep = ".")), "\n")
system(sprintf('convert %s %s',
paste(outfile_iter, "png", sep = "."),
paste(outfile_iter, device, sep = ".")))
} else {
cat("Can't convert to that device. Make sure ImageMagick `convert` is in your PATH.", "\n")
}
}
cat("Outfile:", outfile_iter_ext, '\n')
}
# Kill the webserver
RS_server[["server"]]$stop()
cat("Webserver exited. All done.", "\n")