Surface plotting with ggplot2 - ggplot2

Is it possible to plot with ggplot2 3D surface which is presented as (x, y, z)-vector with labeled countour lines?
Desired result is presented below
Surface map with countour lines

This is exactly what the geomtextpath package was built for.
Example copied from ?geomtextpath::geom_textcontour
library(geomtextpath)
#> Loading required package: ggplot2
df <- expand.grid(x = seq(nrow(volcano)), y = seq(ncol(volcano)))
df$z <- as.vector(volcano)
ggplot(df, aes(x, y, z = z)) +
geom_contour_filled(bins = 6, alpha = 0.6) +
geom_textcontour(bins = 6, size = 2.5, padding = unit(0.05, "in")) +
scale_fill_manual(values = terrain.colors(11)) +
theme_classic() +
theme(legend.position = "none")
Created on 2023-01-26 with reprex v2.0.2

Related

Plotly does not properly show axis numbers with math_format

The code below indicates that, while using math_format command in ggplot 'labels', the plot displays well if ggplot is used, but it fails if it is displayed through plotly. I need to use plotly in my code. Does somebody have some suggestion?
library(tidyverse)
library(scales)
library(plotly)
p <- mtcars %>% ggplot(aes(x=mpg, y=disp))+
geom_point() +
scale_x_continuous(trans = log_trans(),
breaks = trans_breaks("log", function(x) exp(x), n.breaks = 5),
labels = trans_format("log", math_format(e^.x, format = function(x) number(x, accuracy = 0.01, decimal.mark = ','))))
p
ggplotly(p)

ggplot2 geom_text position in pie chart

I am plotting pie charts with ggplot2 and succeeded in having the percentage-labels centered in each slice
library(dplyr)
library(ggplot2)
library(ggpubr)
library("readxl")
df <- read_excel("Radiocomp.xlsx")
df$Pattern <- factor(cc$Pattern)
str(cc)
GGO <- ggplot(data=df, aes(x = "", y = GGO, fill = Pattern)) +
geom_bar(stat="identity", color = "white") +
geom_text(aes(label = paste0(GGO, "%")), position = position_stack(vjust = 0.5)) +
coord_polar("y") +
theme_void()
GGO
Pie chart
I try to place the percent-label outside the pie for better readability
Any recommendation?
Thank you
This can be achieved by setting the x aesthetic inside geom_text, e.g. x = 1.6 will put the label just outside of the pie.
library(ggplot2)
library(dplyr)
# example data
mpg1 <- mpg %>%
count(class) %>%
mutate(pct = n / sum(n))
ggplot(mpg1, aes(x = "", y = pct, fill = class)) +
geom_bar(stat = "identity", color = "white") +
geom_text(aes(x = 1.6, label = scales::percent(pct, accuracy = .1)), position = position_stack(vjust = .5)) +
coord_polar("y") +
theme_void()
Created on 2020-06-03 by the reprex package (v0.3.0)

ggplot multiple densities with common density

I would like to plot something that is "between" a histogram and a density plot. Here is an example:
library(ggplot2)
set.seed(1)
f1 <- rep(1, 100)
v1 <- rnorm(100)
df1 <- data.frame(f1, v1)
f1 <- rep(2, 10)
v1 <- (rnorm(10)+1*2)
df2 <- data.frame(f1, v1)
df <- rbind(df1, df2)
df$f1 <- as.factor(df$f1)
ggplot(df, aes(x = v1, colour = f1)) +
geom_density(position="identity", alpha = 0.6, fill = NA, size = 1)
You will see that the area under each curve is 1.0, which is OK for a density. BUT notice that the second distribution is made up of just 10 observations rather than the 100 of the first. What I would like is that the area under curve 2 reflects this, e.g. is a tenth of that of curve 1. Thanks.
There is a computed variable for stat_density that you can use, called count.
ggplot(df, aes(x = v1, colour = f1)) +
geom_density(position="identity", alpha = 0.6, fill = NA, size = 1,
aes(y = after_stat(count)))
Note for ggplot2 <3.3.0 use stat(count) instead of after_stat(count).
You can find these tricks in the documentation of ?geom_density() under the section "Computed Variables".

geom_area renders differently between ggplot and ggplotly

I'm a little confused as to why ggplot can render geom_area correctly in the first plot, but when wrapped with ggplotly it produces something a little different. Any insights?
library(tidyverse)
library(plotly)
my_dates <- Sys.Date() + c(1,2,3,4,4,5,6)
my_data <- tibble(a = my_dates,
b = c(1,3,7,10,14,16,22))
my_plot <- ggplot(my_data, aes(a, b)) +
geom_line() +
geom_area(position = "identity", alpha = 0.6)
my_plot
ggplotly(my_plot)
Created on 2020-04-03 by the reprex package (v0.3.0)

contour lines from the edge of a map don't show up on basemap

I'm drawing several contour lines over a basemap projection as shown in the following figure:.
There are 3 contours that are not drawn completely (in Oregon, Washington and California) and seems like there is this line that has cut all 3 of them in the same latitude. I'm not sure how to solve this problem.
I added the number of interpolation points, didn't help. changed the ll and ur points to include more area didn't help.
The code is below (not reproducible but might help):
def visualise_bigaus(mus, sigmas, corxys , output_type='pdf', **kwargs):
lllat = 24.396308
lllon = -124.848974
urlat = 49.384358
urlon = -66.885444
fig = plt.figure(figsize=(4, 2.5))
ax = fig.add_subplot(111, axisbg='w', frame_on=False)
m = Basemap(llcrnrlat=lllat,
urcrnrlat=urlat,
llcrnrlon=lllon,
urcrnrlon=urlon,
resolution='i', projection='cyl')
m.drawmapboundary(fill_color = 'white')
#m.drawcoastlines(linewidth=0.2)
m.drawcountries(linewidth=0.2)
m.drawstates(linewidth=0.2, color='lightgray')
#m.fillcontinents(color='white', lake_color='#0000ff', zorder=2)
#m.drawrivers(color='#0000ff')
m.drawlsmask(land_color='gray',ocean_color="#b0c4de", lakes=True)
lllon, lllat = m(lllon, lllat)
urlon, urlat = m(urlon, urlat)
mlon, mlat = m(*(mus[:,1], mus[:,0]))
numcols, numrows = 1000, 1000
X = np.linspace(mlon.min(), urlon, numcols)
Y = np.linspace(lllat, urlat, numrows)
X, Y = np.meshgrid(X, Y)
m.scatter(mlon, mlat, s=0.2, c='red')
shp_info = m.readshapefile('./data/us_states_st99/st99_d00','states',drawbounds=True, zorder=0)
printed_names = []
ax = plt.gca()
ax.xaxis.set_visible(False)
ax.yaxis.set_visible(False)
for spine in ax.spines.itervalues():
spine.set_visible(False)
for k in xrange(mus.shape[0]):
#here x is longitude and y is latitude
#apply softplus to sigmas (to make them positive)
sigmax=np.log(1 + np.exp(sigmas[k][1]))
sigmay=np.log(1 + np.exp(sigmas[k][0]))
mux=mlon[k]
muy=mlat[k]
corxy = corxys[k]
#apply the soft sign
corxy = corxy / (1 + np.abs(corxy))
#now given corxy find sigmaxy
sigmaxy = corxy * sigmax * sigmay
#corxy = 1.0 / (1 + np.abs(sigmaxy))
Z = mlab.bivariate_normal(X, Y, sigmax=sigmax, sigmay=sigmay, mux=mux, muy=muy, sigmaxy=sigmaxy)
#Z = maskoceans(X, Y, Z)
con = m.contour(X, Y, Z, levels=[0.02], linewidths=0.5, colors='darkorange', antialiased=True)
'''
num_levels = len(con.collections)
if num_levels > 1:
for i in range(0, num_levels):
if i != (num_levels-1):
con.collections[i].set_visible(False)
'''
contour_labels = False
if contour_labels:
plt.clabel(con, [con.levels[-1]], inline=True, fontsize=10)
'''
world_shp_info = m.readshapefile('./data/CNTR_2014_10M_SH/Data/CNTR_RG_10M_2014','world',drawbounds=False, zorder=100)
for shapedict,state in zip(m.world_info, m.world):
if shapedict['CNTR_ID'] not in ['CA', 'MX']: continue
poly = MplPolygon(state,facecolor='gray',edgecolor='gray')
ax.add_patch(poly)
'''
if iter:
iter = str(iter).zfill(3)
else:
iter = ''
plt.tight_layout()
plt.savefig('./maps/video/gaus_' + iter + '.' + output_type, frameon=False, dpi=200)
The problem is the meshgrid not covering the complete map. The meshgrid simply doesn't have any points at the positions where you want to draw the gaussian contour line.
An example to reproduce this behaviour is the following, where the meshgrid in x directio starts at -1, such that points lower than that are not drawn.
import matplotlib.pyplot as plt
import matplotlib.mlab as mlab
import numpy as np
fig, ax=plt.subplots()
ax.plot([-2,2],[-2,-2], alpha=0)
X,Y = np.meshgrid(np.linspace(-1,2),np.linspace(-2,2))
Z = mlab.bivariate_normal(X, Y, sigmax=1., sigmay=1., mux=0.1, muy=0.1, sigmaxy=0)
con = ax.contour(X, Y, Z, levels=[Z.max()/3, Z.max()/2., Z.max()*0.8],colors='darkorange')
plt.show()
A similar problem occurs in the code from the question.
While in Y direction, you use the complete map, Y = np.linspace(lllat, urlat, numrows), in X direction you restrict the mesh to start at mlon.min(),
X = np.linspace(mlon.min(), urlon, numcols)
The solution would of course be not to start the mesh in Portland, but somewhere in the ocean, i.e. at the edge of the shown map.