I have several data and I need to plot them compactly in a picture like this:
I already tried par() layout() and ggplot() but plots are displayed so far each other.
I need them to be very close, as if they were in the same plot with a different y (e.g. plot1 y=0, plot2 y=1, plot3 y=3 and so on..)
Can someone help me?
That can be acquired using the layout, also, but maybe an easier approach is to set the graphical parameters in a suitable way.
Function par() let's you specify the number of panels in a single figure using the argument mfrow. It takes a vector of two numbers, that specify the number sub-figure rows and columns. For example, c(2,1) would create two rows of figure,s but only a single column. That's what is in your example figure. You can change the number of figure rows to the number of sub-figures you would like to plot vertically.
In addition, the margins around each sub-figure can be set using the argument mar. The margins are specified in the order of 1. bottom, 2. left, 3. top., and 4. right. Making the bottom and top margins smaller would draw your sub-figures closer together.
In R this could look something like the following:
# Simulate some random data
a<-runif(10000)
b<-runif(10000)
# Open a new plot windows
# width: 7 inches, height: 2 inches
x11(width=7, height=1)
# Specify the number of sub-figures
# Specify the margins (top and bottom are 0.1, left and right are 2)
# Needs some experimenting with to get these right
par(mfrow=c(2,1), mar=c(0.1,2,0.1,2))
# Plot the figures
barplot(a)
barplot(b)
The resulting figure should roughly resemble this:
Here is ggplot version using facet_grid:
df <- data.frame(a=runif(3e3), b=rep(letters[1:3], 1e3), c=rep(1:1e3, 3))
ggplot(df, aes(y=a, x=c)) + geom_bar(stat="identity") + facet_grid(b ~ .)
Related
I'm trying plots a graph lines using ggplot library in R, but I get a good plots but I need reduce the gradual space or height between rows grid lines because I get big separation between lines.
This is my R script:
library(ggplot2)
library(reshape2)
data <- read.csv('/Users/keepo/Desktop/G.Con/Int18/input-int18.csv')
chart_data <- melt(data, id='NRO')
names(chart_data) <- c('NRO', 'leyenda', 'DTF')
ggplot() +
geom_line(data = chart_data, aes(x = NRO, y = DTF, color = leyenda), size = 1)+
xlab("iteraciones") +
ylab("valores")
and this is my actual graphs:
..the first line is very distant from the second. How I can reduce heigth?
regards.
The lines are far apart because the values of the variable plotted on the y-axis are far apart. If you need them closer together, you fundamentally have 3 options:
change the scale (e.g. convert the plot to a log scale), although this can make it harder for people to interpret the numbers. This can also change the behavior of each line, not just change the space between the lines. I'm guessing this isn't what you will want, ultimately.
normalize the data. If the actual value of the variable on the y-axis isn't important, just standardize the data (separately for each value of leyenda).
As stated above, you can graph each line separately. The main drawback here is that you need 3 graphs where 1 might do.
Not recommended:
I know that some graphs will have the a "squiggle" to change scales or skip space. Generally, this is considered poor practice (and I doubt it's an option in ggplot2 because it masks the true separation between the data points. If you really do want a gap, I would look at this post: axis.break and ggplot2 or gap.plot? plot may be too complexe
In a nutshell, the answer here depends on what your numbers mean. What is the story you are trying to tell? Is the important feature of your plots the change between them (in which case, normalizing might be your best option), or the actual numbers themselves (in which case, the space is relevant).
you could use an axis transformation that maps your data to the screen in a non-linear fashion,
fun_trans <- function(x){
d <- data.frame(x=c(800, 2500, 3100), y=c(800,1950, 3100))
model1 <- lm(y~poly(x,2), data=d)
model2 <- lm(x~poly(y,2), data=d)
scales::trans_new("fun",
function(x) as.vector(predict(model1,data.frame(x=x))),
function(x) as.vector(predict(model2,data.frame(y=x))))
}
last_plot() + scale_y_continuous(trans = "fun")
enter image description here
I am trying to arrange 3 plots together. All 3 plots have the same y axis scale, but the third plot has a longer x axis than the other two. I would like to arrange the first two plots side by side in the first row and then place the third plot on the second row aligned to the right. Ideally I would like the third plot's x values to align with plot 2 for the full extent of plot 2 and then continue on below plot one. I have seen some other postings about using the layout function to reach this general configuration (Arrange plots in a layout which cannot be achieved by 'par(mfrow ='), but I haven't found anything on fine tuning the plots so that the scales match. Below is a crappy picture that should be able to get the general idea across.
I thought you could do this by using par("plt"), which returns the coordinates of the plot region as a fraction of the total figure region, to programmatically calculate how much horizontal space to allocate to the bottom plot. But even when using this method, manual adjustments are necessary. Here's what I've got for now.
First, set the plot margins to be a bit thinner than the default. Also, las=1 rotates the y-axis labels to be horizontal, and xaxs="i" (default is "r") sets automatic x-axis padding to zero. Instead, we'll set the amount of padding we want when we create the plots.
par(mar=c(3,3,0.5,0.5), las=1, xaxs="i")
Some fake data:
dat1=data.frame(x=seq(-5000,-2500,length=100), y=seq(-0.2,0.6,length=100))
dat2=data.frame(x=seq(-6000,-2500,length=100), y=seq(-0.2,0.6,length=100))
Create a layout matrix:
# Coordinates of plot region as a fraction of the total figure region
# Order c(x1, x2, y1, y2)
pdim = par("plt")
# Constant padding value for left and right ends of x-axis
pad = 0.04*diff(range(dat1$x))
# If total width of the two top plots is 2 units, then the width of the
# bottom right plot is:
p3w = diff(pdim[1:2]) * (diff(range(dat2$x)) + 2*pad)/(diff(range(dat1$x)) + 2*pad) +
2*(1-pdim[2]) + pdim[1]
# Create a layout matrix with 200 "slots"
n=200
# Adjustable parameter for fine tuning to get top and bottom plot lined up
nudge=2
# Number of slots needed for the bottom right plot
l = round(p3w/2 * n) - nudge
# Create layout matrix
layout(matrix(c(rep(1:2, each=0.5*n), rep(4:3,c(n - l, l))), nrow=2, byrow=TRUE))
Now create the graphs: The two calls to abline are just to show us whether the graphs' x-axes line up. If not, we'll change the nudge parameter and run the code again. Once we've got the layout we want, we can run all the code one final time without the calls to abline.
# Plot first two graphs
with(dat1, plot(x,y, xlim=range(dat1$x) + c(-pad,pad)))
with(dat1, plot(x,y, xlim=range(dat1$x) + c(-pad,pad)))
abline(v=-5000, xpd=TRUE, col="red")
# Lower right plot
plot(dat2, xaxt="n", xlim=range(dat2$x) + c(-pad,pad))
abline(v=-5000, xpd=TRUE, col="blue")
axis(1, at=seq(-6000,-2500,500))
Here's what we get with nudge=2. Note the plots are lined up, but this is also affected by the pixel size of the saved plot (for png files), and I adjusted the size to get the upper and lower plots exactly lined up.
I would have thought that casting all the quantities in ratios that are relative to the plot area (by using par("plt")) would have both ensured that the upper and lower plots lined up and that they would stay lined up regardless of the number of pixels in the final image. But I must be missing something about how base graphics work or perhaps I've messed up a calculation (or both). In any case, I hope this helps you get the plot layout you wanted.
I am trying to plot a variable over time using ggplot2.
My current plot looks like this:
However, I want the scaled values with significant numbers shown on the axis. The scale needs to be shown at the top left corner. Something like:-
I don't want to scale the plot. The axis needs to show the significant numbers and the exponential scale needs to be shown at the top left.
Is this what you had in mind (my own MWE):
library(ggplot2)
df <- data.frame( x=rnorm(10), y=seq(1e8,10e8,by=1e8))
p <- ggplot(df)+
geom_point(aes(x=x,y=y/1e8))+
geom_text(aes(x=-Inf,y=Inf,label=as.character(paste("10^8"))), parse=T, hjust=1, vjust=0.8, size=5/14*10)+
scale_y_continuous(name="y")
gt <- ggplot_gtable(ggplot_build(p))
gt$layout$clip[gt$layout$name == "panel"] <- "off"
grid.draw(gt)
Basically divide by the exponent, and then write it manually at the top left. The parse=T renders the power as an actual power. That factor of 5/14 was mentioned on another post as being the rough factor by which geom_text size relates to the size you set text to be elsewhere on the graph (no idea why but I've found doing 5/14*text-size-you-want gives a decent looking geom_text). Finally the last three lines prevent the off-plot-panel text being cropped out (you wouldn't see the geom_text otherwise). Hope this gives you something to work with.
Hi there: I'm playing around with the ``tips'' data set for a course that I'm teaching. I'd like to produce one .png file that has the plot of tip as a function of size on the top row of the plotting device (ideally in the center-top, of the window) and the bottom row being the conditioning plot of tip as a function of size grouped by a categorical variable recoded from the total_bill variable contained in the data set. I'm much more familiar with the ggplot2 environment, although I can't quite figure out how to do this there, either.
Thanks!
library(reshape2)
library(grid)
library(lattice)
data(tips)
tips$bill2<-cut(tips$total_bill, breaks=3, labels=c('low', 'medium', 'high'))
#Create one plot window with this plot on the top row, ideally in the center
xyplot(tip~size, data=tips,type=c('r', 'p'))
#With this plot in the second row
xyplot(tip~size|bill2, data=tips, type=c('r', 'p'))
You can use the split argument to print
p1 <- xyplot(tip~size, data=tips,type=c('r', 'p'))
p2 <- xyplot(tip~size|bill2, data=tips, type=c('r', 'p'))
print(p1,split=c(1,1,1,2),more=TRUE)
print(p2,split=c(1,2,1,2),more=FALSE)
see ?print.trellis
Update: to adjust size
That also is in ?print.trellis.
print(p1,split=c(1,1,1,2),more=TRUE,position=c(.3,0,.7,1))
print(p2,split=c(1,2,1,2),more=FALSE)
Tweak the position if you like.
By the way, lattice might not always arrange your second plot as 3 panels in one row, depending on the shape of your graphics window. You can force this by
p2 <- xyplot(tip~size|bill2, data=tips, type=c('r', 'p'),layout=c(3,1))
Is it possible to extract specific sections of a ggplot figure/map and place them side by side in a secondary figure but still add points to the three frames as if they were still one plot i.e. for the following map
create a map split into 3 sections which can then be manipulated as one graph (i.e. adding points to all three sections of the graph simultaneously?
UPDATE: Reproducible example
set.seed(1)
dfx<-c(sample(1:1000,100),sample(2000:3000,100),sample(4000:3000,100))
dfy<-c(sample(1:1000,100),sample(2000:3000,100),sample(4000:3000,100))
p<-ggplot()+
coord_fixed()+
geom_point(aes(x=dfx,y=dfy))
p
I can get partway there but can't retain the effects of coord_equal or coord_fixed while allowing free scales ... hopefully someone else can step in and get the rest of the way. (This has come up before -- scatterplot with equal axes -- but I haven't seen a solution.)
dd <- data.frame(dfx,dfy)
dd2 <- transform(dd,panel=cut(dfx,seq(0,4000,by=1000),labels=1:4))
p <- ggplot(dd2)+geom_point(aes(dfx,dfy)) + coord_equal()
p + facet_wrap(~panel,nrow=1,scale="free")