【问题标题】:ggplot2: remove blank space for weekends and holidays from x-axis datesggplot2:从 x 轴日期中删除周末和节假日的空格
【发布时间】:2015-12-29 20:06:45
【问题描述】:

在 ggplot2 中绘制股票数据时遇到问题,x 轴包含周末和节假日的间隙。 this 的帖子非常有帮助,但我在尝试使用有序因子时遇到了各种问题。

library(xts)
library(grid)
library(dplyr)
library(scales)
library(bdscale)
library(ggplot2)
library(quantmod)

getSymbols("SPY", from = Sys.Date() - 1460, to = Sys.Date(), adjust = TRUE, auto.assign = TRUE)

input <- data.frame(SPY["2015/"])
names(input) <- c("Open", "High", "Low", "Close", "Volume", "Adjusted")

# i've tried changing rownames() to index(), and the plot looks good, but the x-axis is inaccurate
# i've also tried as.factor()
xaxis <- as.Date(rownames(input)) 
input$xaxis <- xaxis

p <- ggplot(input)
p <- p + geom_segment(aes(x = xaxis, xend = xaxis, y = Low, yend = High), size = 0.50)           # body
p <- p + geom_segment(aes(x = xaxis - 0.4, xend = xaxis, y = Open, yend = Open), size = 0.90)    # open
p <- p + geom_segment(aes(x = xaxis, xend = xaxis + 0.4, y = Close, yend = Close), size = 0.90)  # close
p <- p + scale_y_continuous(scale_y_log10())
p + ggtitle("SPY: 2015")

上面的图(没有红色框)是用上面的代码段生成的。以下图表是尝试某些解决方案时的一些问题。首先,如果我尝试使用数据框的索引,我会生成漂亮的图形,但是 x 轴不准确;数据目前在 10 月结束,但在下图中,它在 7 月结束:

xaxis <- as.Date(index(input))

其次,如果我尝试将行名强制为有序因子,我会丢失水平刻度数据(代表开盘和收盘)。

xaxis <- factor(rownames(input), ordered = TRUE) 

如果我使用包 bdscale,也会出现删除水平刻度的相同问题,但网格线更清晰:

p <- p + scale_x_bd(business.dates = xaxis)

【问题讨论】:

  • 在您上面的问题中,“上图(无红框)”中产生的 X 轴有什么不准确之处?
  • 红色框突出显示了我要移除的 x 轴间隙。我想要一个看起来像第二个图(没有间隙)的图,但是第一个图的 x 轴
  • 那么,问题在于自动识别哪些日期是假期或周末,因为如果您这样做了,您可以将input 子集化为仅保留工作日,对吗?
  • 好吧,如果您检查数据,则该系列中没有周末或节假日。只是有差距。输入已经只保留工作日

标签: r date ggplot2


【解决方案1】:

您可能需要将日期视为离散值而不是连续值。这种带有稍微简化的代码版本的方法可能如下所示:

getSymbols("SPY", from = Sys.Date() - 1460, to = Sys.Date(), adjust = TRUE, auto.assign = TRUE)
SPY <- SPY["2015/"]
colnames(SPY) <- sub("SPY.","", colnames(SPY))
month_brks <- c(1,endpoints(SPY, "months")[-1])

p <- ggplot(data.frame(xaxis=seq(nrow(SPY)), SPY))
p <- p + geom_linerange(aes(x=xaxis, ymin=Low, ymax=High), size=.5)
p <- p + geom_text(aes(x = xaxis,  y = Open), size = 4., label="-", hjust=.7, vjust=0)  # Open
p <- p + geom_text(aes(x = xaxis,  y = Close), size = 4., label="-", hjust=-.1, vjust=0)  # close
p <- p + scale_x_continuous(breaks=month_brks, labels=format(index(SPY)[month_brks], "%d %b %Y"))
p <- p + labs(title="SPY: 2015", x="Date", y="Price")

更新

更新了轴标签的处理方式。

【讨论】:

  • 这太好了,谢谢!我将不得不使用轴标签
【解决方案2】:

嗯,你可以手动调整它,但它有点老套。首先,您应该使用索引,以便您的观察结果编号为 1 到 188。

   input$xaxis <-index(as.Date(rownames(input)))

然后你自己的情节代码:

p <- ggplot(input)
p <- p + geom_segment(aes(x = xaxis, xend = xaxis, y = Low, yend = High), size = 0.50)           # body
p <- p + geom_segment(aes(x = xaxis - 0.4, xend = xaxis, y = Open, yend = Open), size = 0.90)    # open
p <- p + geom_segment(aes(x = xaxis, xend = xaxis + 0.4, y = Close, yend = Close), size = 0.90)  # close
p <- p + scale_y_continuous(scale_y_log10()) + ggtitle("SPY: 2015") 

最后,我查看了应该在哪里进行中断的输入,并手动提供了标签:

p + scale_x_continuous(breaks=input$xaxis[c(1,62,125,188)], labels=c("jan","apr","jul","oct"))

请注意,我很懒,只选择了最近的日期为 1 月 1 日、4 月 1 日、7 月 1 日和 1 月 1 日,因为 1 月 1 日是假期,所以标签“jan”位于 1 月 2 日下方。我将标签“oct”放在 30-sep 下面,input 中的最后一个条目。您当然可以根据需要进行调整。

当然,您可以自动添加标签,添加带有日期的标签字段并提取月份。

【讨论】:

    【解决方案3】:

    如果您想为此使用bdscale,只需告诉它使用更多网格线:

    ggplot(input) + 
      geom_segment(aes(x = xaxis, xend = xaxis, y = Low, yend = High), size = 0.50) +           # body 
      geom_segment(aes(x = xaxis - 0.4, xend = xaxis, y = Open, yend = Open), size = 0.90) +    # open
      geom_segment(aes(x = xaxis, xend = xaxis + 0.4, y = Close, yend = Close), size = 0.90)  + # close
      ggtitle("SPY: 2015") +
      xlab('') + ylab('') +
      scale_x_bd(business.dates=xaxis, max.major.breaks=10, labels=date_format("%b '%y")) # <==== !!!!
    

    它应该把 10 月放在那里,但它并不那么聪明。呜呜呜。欢迎请求请求!

    【讨论】:

    • 谢谢戴夫!除了最后一个 x 轴刻度外,您的实现似乎删除了我试图保留的打开和关闭水平刻度。
    • 是的,我明白你的意思。 bdscale 的工作方式是将您的日期转换为日期数组的索引;这是一个假的连续音阶,没有任何分数。 geom_vline 允许您绕过轴缩放,让我看看geom_segment 是否有办法做同样的事情。
    【解决方案4】:

    以下方法使用分面去除缺失日期之间的空格,然后去除分面之间的空白以恢复未分面图的外观。

    首先,我们创建一个分组变量,该变量在日期每次中断时递增(代码改编自 this SO answer)。我们稍后将使用它进行刻面。

    input$group = c(0, cumsum(diff(input$xaxis) > 1))
    

    现在我们将以下代码添加到您的绘图中。 facet_grid 在日期序列因周末或节假日而中断的每个位置创建一个新构面。 scale_x_date 每周添加一次主要刻度线,每天添加次要网格线,但您可以调整它。 theme 函数去掉了分面带标签和分面之间的垂直空间:

    p + facet_grid(. ~ group, space="free_x", scales="free_x") +
      scale_x_date(breaks=seq(as.Date("2015-01-01"),max(input$xaxis), "1 week"), 
                   minor_breaks="1 day",
                   labels=date_format("%b %d, %Y")) +
      theme(axis.text.x=element_text(angle=-90, hjust=0.5, vjust=0.5, size=11),
            panel.margin = unit(-0.05, "lines"),
            strip.text=element_text(size=0),
            strip.background=element_rect(fill=NA)) +
      ggtitle("SPY: 2015")
    

    这是结果图。周末和节假日的空间消失了。每周重大突破标记。我将scale_x_date breaks 参数中的星期设置为从星期四开始,因为没有一个假期是在星期四,因此每个方面都有一个主要的日期标记。 (相比之下,默认休息时间将在星期一。由于假期通常在星期一,因此星期一假期的周不会有默认休息时间的主要刻度线。)但是请注意,主要休息时间之间的间隔本质上是根据该周市场开放的天数而有所不同。

    【讨论】:

      【解决方案5】:

      无法让 OHLC 工作 - 认为您需要自定义 geom

      我知道这不是您所要求的,但我可以用美味的蜡烛图来诱惑您吗?

      library(dplyr)
      library(bdscale)
      library(ggplot2)
      library(quantmod)
      library(magrittr)
      library(scales)
      
      getSymbols("SPY", from = Sys.Date() - 1460, to = Sys.Date(), adjust = TRUE, auto.assign = TRUE)
      
      input <- data.frame(SPY["2015/"]) %>% 
        set_names(c("open", "high", "low", "close", "volume", "adjusted")) %>%
        mutate(date=as.Date(rownames(.)))
      
      input %>% ggplot(aes(x=date, ymin=low, ymax=high, lower=pmin(open,close), upper=pmax(open,close), 
                           fill=open<close, group=date, middle=pmin(open,close))) + 
        geom_boxplot(stat='identity') +
        ggtitle("SPY: 2015") +
        xlab('') + ylab('') + theme(legend.position='none') +
        scale_x_bd(business.dates=input$date, max.major.breaks=10, labels=date_format("%b '%y"))
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-03-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多