Using image files as plot patterns in R - r

I am producing a stratigraphy plot which should look something like the following
I've got to the point where I can plot the layout of the plot using some dummy data and the following code
Strat <- c(657,657,657,657,657,657,657,657,657,657,601,601,601,601,601,601,601,601,601,601,610,610,610,610,610,610,610,610,610,610)
Distance <- c(7.87,17.89,22.09,42.84,50.65,55.00,65.74,69.38,72.36,75.31,7.87,17.89,22.09,42.84,50.65,55.00,65.74,69.38,72.36,75.31,7.87,17.89,22.09,42.84,50.65,55.00,65.74,69.38,72.36,75.31)
Altitude <- c(565.05,191.98,808.12,609.19,579.10,657.08,708.00,671.44,312.10,356.14,565.05,191.98,808.12,609.19,579.10,657.08,708.00,671.44,312.10,356.14,565.05,191.98,808.12,609.19,579.10,657.08,708.00,671.44,312.10,356.14)
strat_max <- c(565.05,191.98,808.12,609.19,579.10,657.08,708.00,671.44,312.10,356.14,565.04,176.23,795.52,608.06,567.89,641.83,698.69,664.50,310.21,350.11,526.47,147.30,762.49,601.99,544.22,632.54,689.33,636.40,282.71,313.56)
strat_min <- c(565.04,176.23,795.52,608.06,567.89,641.83,698.69,664.50,310.21,350.11,526.47,147.30,762.49,601.99,544.22,632.54,689.33,636.40,282.71,313.56,463.31,81.01,718.11,594.38,539.53,616.18,670.79,602.96,249.59,289.63)
strat <- cbind(Strat, Distance, Altitude, strat_max, strat_min)
strat <- as.data.frame(strat)
attach(strat)
ggplot(strat, aes(x=Distance, y=Altitude, colour=factor(Strat))) +
geom_linerange(aes(x=Distance, ymax=strat_max, ymin=strat_min, colour=factor(Strat)), lwd=10) +
geom_line(lty=1, lwd=1.5, colour="black") +
xlab("Distance") + ylab("Altitude") +
theme_bw() + scale_colour_discrete(name="Stratigraphy Type")
However, I have been unable to add the relevant patterns. Each rock/ sediment type has a standard plotting pattern for use in stratigraphic plots from the USGS and I would like to relate the code in strat$Strat to the relevant pattern and use that as the pattern
Does anyone know how to import these (e.g. as PNG files) and then use them as patterns? I had thought to try and call them as colours but I don't know if that would work and there's probably no framework for telling R how to repeat them. Currently I am writing the plot as shown and then adding in the patterns in adobe illustrator
Any insight appreciated!

Related

how to mimic histogram plot from flowjo in R using flowCore?

I'm new to flowCore + R. I would like to mimic a histogram plot after gating that can be manually done in FlowJo software. I got something similar but it doesn't look quite right because it is a "density" plot and is shifted. How can I get the x axis to shift over and look similar to how FlowJo outputs the plot? I tried reading this document but couldn't find a plot similar to the one in FlowJo: howtoflowcore Appreciate any guidance. Thanks.
code snippet:
library(flowCore)
parentpath <- "/parent/path"
subfolder <- "Sample 1"
fcs_files <- list.files(paste0(parentpath, subfolder), pattern = ".fcs")
fs <- read.flowSet(fcs_files)
rect.g <- rectangleGate(filterId = "main",list("FSC-A" = c(1e5, 2e5), "SSC-A" = c(3e4,1e5)))
fs_sub <- Subset(fs, rect.g)
p <- ggcyto(fs_sub[[15]], aes(x= `UV-379-A`)) +
geom_density(fill='black', alpha = 0.4) +
ggcyto_par_set(limits = list(x = c(-1e3, 5e4), y = c(0, 6e-5)))
p
FlowJo output:
R FlowCore output:
The reason that for the "shift" is that the x axis is logarithmic (base 10) in the flowJo graph. To achieve the same result in R, add
+ scale_x_log10()
after the existing code. This might interact weirdly with the axis limits you've set, so bare that in mind.
To make the y-axis "count" rather than density, you can change the first line of your ggcyto() call to:
aes(x= `UV-379-A`, y = after_stat(count))
Let me know if that works - I don't have your data to hand so that's all from memory!
For any purely aesthetic changes, they are relatively easy to look up.

Trying to plot in tmap shapefile with attribute

I am trying to work with municipality data in Norway, and I'm totally new to QGIS, shapefiles and plotting this in R. I download the municipalities from here:
Administrative enheter kommuner / Administrative units municipalities
Reproducible files are here:
Joanna's github
I have downloaded QGIS, so I can open the GEOJson file there and convert it to a shapefile. I am able to do this, and read the data into R:
library(sf)
test=st_read("C:/municipality_shape.shp")
head(test)
I have on my own given the different municipalities different values/ranks that I call faktor, and I have stored this classification in a dataframe that I call df_new. I wish to merge this "classification" on to my "test" object above, and wish to plot the map with the classification attribute onto the map:
test33=merge(test, df_new[,c("Kommunekode_str","faktor")],
by=c("Kommunekode_str"), all.x=TRUE)
This works, but when I am to plot this with tmap,
library(tmap)
tmap_mode("view")
tm_shape(test33) +
tm_fill(col="faktor", alpha=0.6, n=20, palette=c("wheat3","red3")) +
tm_borders(col="#000000", lwd=0.2)
it throws this error:
Error in object[-omit, , drop = FALSE] : incorrect number of
dimensions
If I just use base plot,
plot(test33)
I get the picture:
You see I get three plots. Does this has something to do with my error above?
I think the main issue here is that the shapes you are trying to plot are too complex so tmap is struggling to load all of this data. ggplot also fails to load the polygons.
You probably don't need so much accuracy in your polygons if you are making a choropleth map so I would suggest first simplifying your polygons. In my experience the best way to do this is using the package rmapshaper:
# keep = 0.02 will keep just 2% of the points in your polygons.
test_33_simple <- rmapshaper::ms_simplify(test33, keep = 0.02)
I can now use your code to produce the following:
tmap_mode("view")
tm_shape(test_33_simple) +
tm_fill(col="faktor", alpha=0.6, n=20, palette=c("wheat3","red3")) +
tm_borders(col="#000000", lwd=0.2)
This produces an interactive map and the colour scheme is not ideal to tell differences between municipalities.
static version
Since you say in the comments that you are not sure if you want an interactive map or a static one, I will give an example with a static map and some example colour schemes.
The below uses the classInt package to set up breaks for your map. A popular break scheme is 'fisher' which uses the fisher-jenks algorithm. Make sure you research the various different options to pick one that suits your scenario:
library(ggplot2)
library(dplyr)
library(sf)
library(classInt)
breaks <- classIntervals(test_33_simple$faktor, n = 6, style = 'fisher')
#label breaks
lab_vec <- vector(length = length(breaks$brks)-1)
rounded_breaks <- round(breaks$brks,2)
lab_vec[1] <- paste0('[', rounded_breaks[1],' - ', rounded_breaks[2],']')
for(i in 2:(length(breaks$brks) - 1)){
lab_vec[i] <- paste0('(',rounded_breaks[i], ' - ', rounded_breaks[i+1], ']')
}
test_33_simple <- test_33_simple %>%
mutate(faktor_class = factor(cut(faktor, breaks$brks, include.lowest = T), labels = lab_vec))
# map
ggplot(test_33_simple) +
geom_sf(aes(fill = faktor_class), size= 0.2) +
scale_fill_viridis_d() +
theme_minimal()

Merging Legends for both geom Line and Point

I was very new to R Script. If you are able to help my problem that would be really great... Here is my problem...
I am able to create custom visual using R Script and make hover over work in that visual by using this below link Link I think It is displaying legend for both line and point as well. This is how it’s showing me in the graph Both Legends
But I would like to show up something like this…. Which represents both the line and point in the same legend name Same legend.
Please find the R Script below, Please go through that and can you tell me where I was going wrong….
source('./r_files/flatten_HTML.r')
Library Declarations
library(htmlwidgets);library(XML);library(ggplot2);library(plotly);
Values$Storiesgrouping <- as.character(Values$Storiesgrouping)
Cols <- as.character(Values$Color)
names(Cols) <- as.character(Values$Builder_CommunityName)
Sizs <- as.numeric(Values$Size)
names(Sizs) <- as.character(Values$Builder_CommunityName)
Actual code
g <- ggplot(Values, aes(x=BaseSquareFeet, y=BasePriceM,
group=Builder_CommunityName, color=Builder_CommunityName))+
geom_line()+
geom_point(aes(shape=Storiesgrouping), show.legend=FALSE,size=3)+
scale_colour_manual(values = Cols)+
scale_size_manual(values = Sizs)+
scale_shape_manual(values=c("1"=19, "2"=15, "3+"=17))
plot(g)
Create and save widget
p = ggplotly(g); internalSaveWidget(p, 'out.html');

How to plot 3D scatter diagram using ggplot?

I tried to use the plotly package, but it is not working in my case at all. The ggplot package is working for 2D plots but it is giving an error when adding one more axis. How to solve this issue?
ggplot(data,aes(x=D1,y=D2,z=D3,color=Sample)) +
geom_point()
How to add one more axis and get the 3D plot in this?
Since you tagged your question with plotly and said that you've tried to use it with plotly, I think it would be helpful to give you a working code solution in plotly:
Creating some data to plot with:
set.seed(417)
library(plotly)
temp <- rnorm(100, mean=30, sd=5)
pressure <- rnorm(100)
dtime <- 1:100
Graphing your 3d scatterplot using plotly's scatter3d type:
plot_ly(x=temp, y=pressure, z=dtime, type="scatter3d", mode="markers", color=temp)
Renders the following:
ggplot as others have note, by itself does not support 3d graphics rendering.
A possible solutions is gg3D.
gg3D is a package created to extend ggplot2 to produce 3D plots. It does exactly what you are asking for: it adds a third axis to a ggplot. I find it quite good and easy to use and that is what I use for my limited needs.
An example taken from the vignette to produce a basic plot
devtools::install_github("AckerDWM/gg3D")
library("gg3D")
## An empty plot with 3 axes
qplot(x=0, y=0, z=0, geom="blank") +
theme_void() +
axes_3D()
## Axes can be populated with points using the function stat_3D.
data(iris)
ggplot(iris, aes(x=Petal.Width, y=Sepal.Width, z=Petal.Length, color=Species)) +
theme_void() +
axes_3D() +
stat_3D()
There are other options not involving ggplot. For example the excellent plot3D package with its extension plot3Drgl to plot in openGL.
In your question, you refer to the plotly package and to the ggplot2 package. Both plotly and ggplot2 are great packages: plotly is good at creating dynamic plots that users can interact with, while ggplot2 is good at creating static plots for extreme customization and scientific publication. It is also possible to send ggplot2 output to plotly. Unfortunately, at the time of writing (April 2021), ggplot2 does not natively support 3d plots. However, there are other packages that can be used to produce 3d plots and some ways to get pretty close to ggplot2 quality. Below I review several options. These suggestions are by no means exhaustive.
plotly
See onlyphantom's answer in this thread.
gg3D
See Marco Stamazza's answer in this thread. See also my effort below.
scatterplot3d
See Seth's answer in a related thread.
lattice
See Backlin's answer in a related thread.
rgl
See this overview in the wiki guide.
rayshader
See this overview of this package's wonderful capabilities.
trans3d
See data-imaginist use trans3d to get a cube into ggplot2.
ggrgl
See this cool and useful coolbutuseless introduction.
Now let me review some of my efforts with the Lorenz attractor trajectories. While customization remains limited, I've had best results for PDF output with gg3D. I also include a ggrgl example.
gg3D
# Packages
library(deSolve)
library(ggplot2)
library(gg3D) # remotes::install_github("AckerDWM/gg3D")
# Directory
setwd("~/R/workspace/")
# Parameters
parms <- c(a=10, b=8/3, c=28)
# Initial state
state <- c(x=0.01, y=0.0, z=0.0)
# Time span
times <- seq(0, 50, by=1/200)
# Lorenz system
lorenz <- function(times, state, parms) {
with(as.list(c(state, parms)), {
dxdt <- a*(y-x)
dydt <- x*(c-z)-y
dzdt <- x*y-b*z
return(list(c(dxdt, dydt, dzdt)))
})
}
# Make dataframe
df <- as.data.frame(ode(func=lorenz, y=state, parms=parms, times=times))
# Make plot
make_plot <- function(theta=0, phi=0){
ggplot(df, aes(x=x, y=y, z=z, colour=time)) +
axes_3D(theta=theta, phi=phi) +
stat_3D(theta=theta, phi=phi, geom="path") +
labs_3D(theta=theta, phi=phi,
labs=c("x", "y", "z"),
angle=c(0,0,0),
hjust=c(0,2,2),
vjust=c(2,2,-2)) +
ggtitle("Lorenz butterfly") +
theme_void() +
theme(legend.position = "none")
}
make_plot()
make_plot(theta=180,phi=0)
# Save plot as PDF
ggsave(last_plot(), filename="lorenz-gg3d.pdf")
Pros: Outputs high-quality PDF:
Cons: Still limited customization. But for my specific needs, currently the best option.
ggrgl
# Packages
library(deSolve)
library(ggplot2)
library(rgl)
#remotes::install_github("dmurdoch/rgl")
library(ggrgl)
# remotes::install_github('coolbutuseless/ggrgl', ref='main')
library(devout)
library(devoutrgl)
# remotes::install_github('coolbutuseless/devoutrgl', ref='main')
library(webshot2)
# remotes::install_github("rstudio/webshot2")
library(ggthemes)
# Directory
setwd("~/R/workspace/")
# Parameters
parms <- c(a=10, b=8/3, c=26.48)
# Initial state
state <- c(x=0.01, y=0.0, z=0.0)
# Time span
times <- seq(0, 100, by=1/500)
# Lorenz system
lorenz <- function(times, state, parms) {
with(as.list(c(state, parms)), {
dxdt <- a*(y-x)
dydt <- x*(c-z)-y
dzdt <- x*y-b*z
return(list(c(dxdt, dydt, dzdt)))
})
}
# Make dataframe
df <- as.data.frame(ode(func=lorenz, y=state, parms=parms, times=times))
# Make plot
ggplot(df, aes(x=x, y=y, z=z)) +
geom_path_3d() +
ggtitle("Lorenz butterfly") -> p
# Render Plot in window
rgldev(fov=30, view_angle=-10, zoom=0.7)
p + theme_ggrgl(16)
# Save plot as PNG
rgldev(fov=30, view_angle=-10, zoom=0.7,
file = "~/R/Work/plots/lorenz-attractor/ggrgl/lorenz-ggrgl.png",
close_window = TRUE, dpi = 300)
p + theme_ggrgl(16)
dev.off()
Pros: The plot can be rotated in a way similar to plotly. It is possible to 'theme' a basic plot:
Cons: The figure is missing a third axis with labels. Cannot output high-quality plots. While I've been able to view and save a low-quality black trajectory in PNG, I could view a colored trajectory like the above, but could not save it, except with a low-quality screenshot:
Related threads: plot-3d-data-in-r, ploting-3d-graphics-with-r.

Plot ggplot polygons with holes with geom_polygon

There are questions out there about the fact that ggplot2 can't plot polygon shapes that have holes.
That is because, if the order of points is not OK, the end graph looks bad, usually with clipping/trimming lines inside the donut shape.
I have read a lot about how order matters, but I am not able to step forward.
I have a SpatialPolygonsDataFrame with 26 features (comes from raster::rasterToPolygons(dissolve=T)) and I want to plot it with ggplot.
Here's what happens -
r3.pol <- rasterToPolygons(r3, dissolve=T)
r3.df <- fortify(r3.pol)
names(r3.df) <- c('x','y','order','hole','piece','ID','group')
p <- ggplot(r3.df)
p <- p + geom_polygon(mapping=aes(x=x,y=y,group=ID), fill='red')
p <- p + coord_equal()
I see this output:
While it should be like so, with plot(r3.pol):
How can I make this work?
I tried for hours but I am not able to reorder r3.df.
Also, can the information in r3.df$hole be helpful? It is returned by the function fortify for points that are holes (I think).
Side question: how can I give you my r3.pol SpatialPolygonsDataFrame, so that you can try yourself? I remember seeing long, reproducible "dumps" of objects here, but I don't know how to do it.
I saved the polygons data frame here. Was not able to save it using dput, sorry. You can fetch it using load.
I suggest to install the package "ggpolypath" and use geom_polypath instead of geom_polygon. Works for me.
My temporary solution is: ##$% polygons, and use the raster package.
Namely:
r <- raster(x=extent(r3.pol), crs=crs(r3.pol)) # empty raster from r3.pol
res(r) <- 250 # set a decent resolution (depends on your extent)
r <- setValues(r, 1) # fill r with ones
r <- mask(r, r3.pol) # clip r with the shape polygons
And now plot it as you would do with any raster with ggplot. The rasterVis package might come helpful here, but I'm not using it, so:
rdf <- data.frame(rasterToPoints(r))
p <- ggplot(rdf) + geom_raster(mapping=aes(x=x, y=y), fill='red')
p <- p + coord_equal()
And here it goes.
Alternatively, you can create the raster with rasterize, so the raster will hold the polygons values (in my case, just an integer):
r <- raster(x=extent(r3.pol), crs=crs(r3.pol))
res(r) <- 250
r <- rasterize(r3.pol, r)
rdf <- data.frame(rasterToPoints(r))
p <- ggplot(rdf) + geom_raster(mapping=aes(x=x, y=y, fill=factor(layer)))
p <- p + coord_equal()
If someone comes up with a decent solution for geom_polygon, probably involving re-ordering of the polygons data frame, I'll be glad to consider it.

Resources