J'essaie d'utiliser ggplot2 pour créer un graphique de performances avec une échelle log normale y. Malheureusement, je ne suis pas en mesure de produire de jalons Nice comme pour la fonction de tracé de base.
Voici mon exemple:
library(ggplot2)
library(scales)
# fix RNG
set.seed(seed=1)
# simulate returns
y=rnorm(999,0.02,0.2)
# M$Y are the cummulative returns (like an index)
M=data.frame(X=1:1000,Y=100)
for (i in 2:1000)
M[i,"Y"]=M[i-1,"Y"]*(1+y[i-1])
ggplot(M,aes(x=X,y=Y))+geom_line()+scale_y_continuous(trans=log_trans())
produit des tiques laides:
J'ai aussi essayé:
ggplot(M,aes(x=X,y=Y)) + geom_line() +
scale_y_continuous(trans=log_trans(), breaks=pretty_breaks())
Comment puis-je obtenir les mêmes pauses/ticks que dans la fonction de tracé par défaut:
plot(M,type="l",log="y")
Le résultat devrait ressembler à ceci, mais pas avec une frappe dure, mais dynamique. J'ai essayé des fonctions comme axisTicks()
mais sans succès:
ggplot(M,aes(x=X,y=Y)) + geom_line() +
scale_y_continuous(trans=log_trans(), breaks=c(1,10,100,10000))
Merci!
modifier: images insérées
Le comportement graphique de base peut être reproduit à l'aide d'une fonction de rupture personnalisée:
base_breaks <- function(n = 10){
function(x) {
axisTicks(log10(range(x, na.rm = TRUE)), log = TRUE, n = n)
}
}
Appliquer ceci aux données d'exemple donne le même résultat que d'utiliser trans_breaks('log10', function(x) 10^x)
:
ggplot(M, aes(x = X, y = Y)) + geom_line() +
scale_y_continuous(trans = log_trans(), breaks = base_breaks()) +
theme(panel.grid.minor = element_blank())
Cependant, nous pouvons utiliser la même fonction sur un sous-ensemble de données, avec des valeurs y comprises entre 50 et 600:
M2 <- subset(M, Y > 50 & Y < 600)
ggplot(M2, aes(x = X, y = Y)) + geom_line() +
scale_y_continuous(trans = log_trans(), breaks = base_breaks()) +
theme(panel.grid.minor = element_blank())
Comme les puissances de dix ne conviennent plus ici, base_breaks
produit de jolies coupures alternatives:
Notez que j'ai désactivé les lignes de grille mineures: dans certains cas, il serait judicieux de disposer des lignes de grille à mi-chemin entre les lignes principales de la grille sur l'axe des y, mais pas toujours.
Modifier
Supposons que nous modifions M pour que la valeur minimale soit 0.1:
M <- M - min(M) + 0.1
La fonction base_breaks () sélectionne toujours les jolies coupures, mais les étiquettes sont en notation scientifique, qui peut ne pas être vue comme "jolie":
ggplot(M, aes(x = X, y = Y)) + geom_line() +
scale_y_continuous(trans = log_trans(), breaks = base_breaks()) +
theme(panel.grid.minor = element_blank())
Nous pouvons contrôler la mise en forme du texte en passant une fonction de mise en forme du texte à l'argument labels
de scale_y_continuous
. Dans ce cas, prettyNum
du paquet de base fait le travail correctement:
ggplot(M, aes(x = X, y = Y)) + geom_line() +
scale_y_continuous(trans = log_trans(), breaks = base_breaks(),
labels = prettyNum) +
theme(panel.grid.minor = element_blank())
Lorsque je construis des graphiques sur l'échelle du journal, je trouve que les solutions suivantes fonctionnent assez bien:
g = ggplot(M,aes(x=X,y=Y)) + geom_line()
g + scale_y_continuous(trans = 'log10',
breaks = trans_breaks('log10', function(x) 10^x),
labels = trans_format('log10', math_format(10^.x)))
Quelques différences:
Pour donner
La fonction graphique de base axTicks()
renvoie les sauts d’axe pour le tracé actuel. Vous pouvez donc l'utiliser pour renvoyer des sauts identiques aux graphiques de base. Le seul inconvénient est que vous devez commencer par tracer le graphique de base.
library(ggplot2)
library(scales)
plot(M, type="l",log="y")
breaks <- axTicks(side=2)
ggplot(M,aes(x=X,y=Y)) + geom_line() +
scale_y_continuous(breaks=breaks) +
coord_trans(y="log")
Cette fonction permet de spécifier le nombre souhaité de ticks majeurs et mineurs. Il doit être spécifié deux fois à cet effet:
#' log scale
#'
#' Creates a function which returns ticks for a given data range. It uses some
#' code from scales::log_breaks, but in contrast to that function it not only
#' the exponentials of the base b, but log minor ticks (f*b^i, where f and i are
#' integers), too.
#'
#' @param n Approximate number of ticks to produce
#' @param base Logarithm base
#'
#' @return
#'
#' A function which expects one parameter:
#'
#' * **x**: (numeric vector) The data for which to create a set of ticks.
#'
#' @export
logTicks <- function(n = 5, base = 10){
# Divisors of the logarithm base. E.g. for base 10: 1, 2, 5, 10.
divisors <- which((base / seq_len(base)) %% 1 == 0)
mkTcks <- function(min, max, base, divisor){
f <- seq(divisor, base, by = divisor)
return(unique(c(base^min, as.vector(outer(f, base^(min:max), `*`)))))
}
function(x) {
rng <- range(x, na.rm = TRUE)
lrng <- log(rng, base = base)
min <- floor(lrng[1])
max <- ceiling(lrng[2])
tck <- function(divisor){
t <- mkTcks(min, max, base, divisor)
t[t >= rng[1] & t <= rng[2]]
}
# For all possible divisors, produce a set of ticks and count how many ticks
# result
tcks <- lapply(divisors, function(d) tck(d))
l <- vapply(tcks, length, numeric(1))
# Take the set of ticks which is nearest to the desired number of ticks
i <- which.min(abs(n - l))
if(l[i] < 2){
# The data range is too small to show more than 1 logarithm tick, fall
# back to linear interpolation
ticks <- pretty(x, n = n, min.n = 2)
}else{
ticks <- tcks[[i]]
}
return(ticks)
}
}
Votre exemple:
library(ggplot2)
library(scales)
# fix RNG
set.seed(seed=1)
# simulate returns
y=rnorm(999,0.02,0.2)
# M$Y are the cummulative returns (like an index)
M=data.frame(X=1:1000,Y=100)
for (i in 2:1000)
M[i,"Y"]=M[i-1,"Y"]*(1+y[i-1])
ggplot(M,aes(x=X,y=Y))+geom_line()+
scale_y_log10(breaks = logTicks(n = 4), minor_breaks = logTicks(n = 40))