png, pdf, tiff margin limitations - r

In order to get some space for a special ylab text, I use mar=c(5,7,4,2). This provides me with 7 lines of space for ylab. On the default device (screen) everything functions as anticipated. However, I cannot get this output to any other device than the screen.
par(mar=c(5,7,4,2))
png(file="a.png", width=500, height=500)
plot(1,1,ylab="A very very long axis title\nthat need special care",xlab="",type="n")
I verified the same behavior with png, tiff, pdf. It seems that the maximum printable size in these devices is 4. Anything that goes beyond this number gets cut off. The same behavior is when plotting xlabs, eg by using mgp=c(5,1,0). mgp=c(4,1,0) (line 4) is the maximum printable line in any other device than the screen.
Even after upgrading to the latest R version does not change this behavior and it is the same on Windows and Ubuntu.
Any advice on the root cause of this behavior is appreciated.

The problem is the order of your statements. The par() call applies to the current device. Since you open the png() device after that, it doesn't have any effect. Just put things in this order and they'll be fine:
png(file="a.png", width=500, height=500)
par(mar=c(5,7,4,2))
plot(1,1,ylab="A very very long axis title\nthat need special care",xlab="",type="n")
dev.off()
This gives this image in the file:

Related

How do I conveniently resize a ggplot2 plot on R+VSC?

I'm in the process of learning R (I'm still a newcomer on SO as well). Being very used to using Visual Studio Code, I decided to choose that over RStudio or RStudio Cloud.
One of the best parts of RStudio was that plots automatically resized/reshaped themselves if we resized the right pane. Moreover, in the tutorials I watched, plots involving map data automatically rendered in the correct aspect ratio (as seen on physical maps).
I replicated the code to make my own plot of the world map. Unfortunately it rendered as a square shape, and resizing the right pane does not affect its shape:
enter image description here
Am I missing any commonly used VSC extensions which can make plots resizeable like in RStudio? (I've installed only the most downloaded extension for R, by Yuki Ueda)
If not, can I modify my code to specify the exact dimensions I need the plot to have?
Thanks in advance!
You can add robust plot viewing options for R in VSCode by installing the httpgd package and then amending your JSON settings.
First, install httpgd via the R console:
install.packages("httpgd")
Then, open your JSON settings in VSCode by opening the Command Palette (either via Ctrl+Shift+P or via View > Command Palette) and then searching for "Preferences: Open Settings (JSON)", where you'll insert the following:
"r.plot.useHttpgd": true
You can add a comma after 'true' if needed (i.e. if there are other lines below that in your JSON settings).
Following that, restart VSCode and launch the R terminal inside it, and plot something using either ggplot2 or base R graphics:
plot(mtcars$mgp, mtcars$wt)
A plot viewer should then pop up in VSCode. You can either manually resize the window there, zoom in or out, or, my preference (particularly if I'm cycling through a series of already-plotted graphs), open it in an external browser where it'll automatically adjust to however you resize the window. After that, you can save or copy the image as needed.
You can specify the dimensions when you save the file. I usually use (approximately) the golden ratio:
ggsave("./earth.png", width = 16, height = 10)
The ggsave function reference explains how you can change units - options are c("in", "cm", "mm", "px").

How do I rotate the orientation in the ghostscript plot for ps file?

I am plotting the (postscript) ps file using the ghostscript in the terminal.
When I use the command"gs file.ps", it always gives the portrait orientation like following
enter image description here
do you know how could I rotate the plot with 90 degree with landscape orientation?
Without seeing the input file its not really possible to tell. However, the simple answer is that you need to produce your PostScript program so that it prints on landscape media.
Most likely you created the program by printing to a device which was described as using portrait media. So the application generated PostScript which would fit on that media.
You could edit the PostScript program, or you could try getting Ghostscript to do this for you. It may not work, it depends on how the program is written.
If you set the Ghostscript media to the size and orientation you want, tell Ghostscript the media is 'fixed' so that programs can't change it, and then tell Ghostscript to 'fit' the content, then it will choose the orientation which fits best.
Example command line:
gs -sDEVICE=<insert here> -sOutputFile=<your path> -dDEVICEWIDTHPOINTS=612 -dDEVICEHEIGHTPOINTS=792 -dFIXEDMEDIA -dFitPage <input.ps>
That sets up US Letter media (612x792 points), makes it fixed and requests the content fit the page.
If that doesn't work for you then I'd need to see the inptu PostScript program before offering further suggestions.

iPython Notebook svg Figures by Default

I just started using ipython, and I'm creating figures such as:
fig, axes = plt.subplots()
xs = range(0,100)
axes.plot(xs, [x*x for x in xs], 'r')
I know that the figures can be rendered as svgs, see here. Unfortunately, the figures are always rendered as a rasterized image. The rasterized images become very ugly when I'm using the notebook's zoom feature. Is there a way to change this behavior, such that figures are displayed as svg by default?
The magic I was looking for:
%matplotlib inline
%config InlineBackend.figure_format = 'svg'
import matplotlib.pyplot as plt
Alternatively you might still want to show png but save a figure into a file:
plt.savefig(fig_filename, format='svg')
You can change the default figure format in the ipython profile configuration files. What I did was create a configuration profile especially for the notebook server, using:
ipython profile create nbserver
At the command line. This creates a whole bunch of files under ~/.ipython/profile_nbserver which have example lines for almost every setting you could want to change (it might be somewhere such as ~/.config/ipython instead depending on your OS, not sure about where it would be under windows). You need to look in the file ipython_notebook_config.py. You should then add the the line:
c.InlineBackend.figure_formats = ['svg']
Note that this only applied to IPython 3.x, and that you can also specify additional formats as per #HarrySchreiner's comment. For IPython 2.x, you should set c.InlineBackEnd.figure_format='svg'. To use this profile you should start the notebook with
ipython notebook --profile=nbserver
If this is too much trouble then don't give a profile name when running create, and modify the default profile instead.
Also, you may want to have the line
c.IPKernelApp.matplotlib = 'inline'
so that each notebook will automatically start with the matplotlib inline backend used.
Originally I also wanted to use the svg backend instead of png to enable zooming etc. However, I found that certain plots, such as pcolor with a large number of points can just kill my browser when using the svg backend. So I find it easier to use png, and just use the xlim and ylim commands to zoom in manually if I need to.
Also, you should definitely tweak the line c.InlineBackend.rc to set more reasonable defaults for the figure size and the fonts used.
edit
Current recommended best practice is not to use pylab, but to explicitly import matplotlib and numpy instead, so I modified my answer to stop encouraging this. See this post for the reasons why:
http://carreau.github.io/posts/10-No-PyLab-Thanks.html
Also, if svg rendering is too slow for particular plot elements (such as pcolor or plot_surface), you can pass the option rasterized=True to these plot commands. This means that those particular parts of the plot will have fast pixel based rendering, but all the other plot elements will be nicely vectorized.

Fail to display any image via X11

Recently, when I wanted to display any image via X11, I just see a big white window and nothing else. For example:
#Running X11() or not doesn't matter
#X11()
#plot anything
plot(1:10)
And then, I get nothing but a white windows just like I purely run X11(). When I use other device (pdf(), png()), I can get image after dev.off().
Problem solved. It's a problem about cairo. AddgrDevices::X11.options(type="ncairo") to ~/.Rprofile
Having a blank window is the correct behaviour for calling X11(). Usually, you won't need to call that function, but it means that you can specify how tall/wide the plot window is before you create a plot.
If you still have a blank window after you try and plot something, then you are probably writing to a different device.
Have you opened another device (maybe with png, etc.) and forgotten to close it?
What does dev.cur() return?
A reproducible example of this:
png("foo.png")
x11()
dev.set(dev.list()[names(dev.list()) == "png:foo.png"])
plot(1:10)
#Make sure you call this afterwards
graphics.off()

Using jpeg(file= ) creates an empty jpeg even though there's not a call to create a plot

This is observed running in batch. Given the following code snippet, I don't understand why R creates an empty jpeg file in Windows even though I am not calling a plot or graph. When I run similar code under Linux or OS X, the jpeg file is not created. I don't know ahead of time if the user is going to want a plot so I setup the filename(s) ahead of time and give them a name and location.
##
sink("c:\\temp\\test.lst")
jpeg(file="c:\\temp\\test%d.jpeg")
norm <- rnorm(100)
print(norm)
Any suggestions would be appreciated.
The ?jpeg help file (which also applies to bmp(), png() and tiff() devices) indicates that:
The ‘type = "windows"’ versions of these devices effectively plot
on a hidden screen and then copy the image to the required format.
This Windows-specific implementation detail most likely explains the difference in the behavior of Windows and *NIX systems.
On Windows, calling any of the functions above (and pdf() and postscript() as well) creates a file --- whether or not you then plot anything to that hidden screen. Except for pdf() (which produces files that I can't open with a viewer), the image that's registered on the plotting device is that of a white rectangle of height and width specified in the call to the specific device.
I wouldn't worry about it. if the prospect of zero-length files cluttering up the folder bothers you, you can clean up afterwards with something like
jpgs <- file.path("c:/temp", dir(pattern="c:/temp/test[0-9]*\\.jpeg"))
s <- file.info(jpgs)[["size"]]
for(i in seq_along(s))
if(s[i] == 0) file.remove(jpgs[i])

Resources