使用 POSIXct 和夏令时绘制条形图

Posted

技术标签:

【中文标题】使用 POSIXct 和夏令时绘制条形图【英文标题】:Plotly barcharts with POSIXct and daylight-savings-time 【发布时间】:2021-02-24 07:12:37 【问题描述】:

我想在 x 轴上绘制带有时间戳的条形图时间序列。我的问题是 10 月的夏令时,因为 02:00 有 2 个时间戳,一个带有 CEST 时区,一个带有 CET

plotly-barchart 叠加了这些值,当您将鼠标悬停在 barchart 上时,很难发现并且看起来像错误,因为您会发现该值与 y 轴不对应。

如何在不将tickmode 更改为“数组”并定义tickvals/ticktext 的情况下并排显示这两个条形

library(plotly)

df <- structure(list(value = round(runif(46, 20, 26), 3), 
                     timestamp = structure(c(1603576800, 1603584000, 1603587600, 1603591200, 1603594800, 1603598400, 
                                             1603602000, 1603605600, 1603609200, 1603612800, 1603616400, 1603620000,
                                             1603623600, 1603627200, 1603630800, 1603634400, 1603638000, 1603641600,
                                             1603645200, 1603648800, 1603652400, 1603656000, 1603659600, 1603576800,
                                             1603584000, 1603587600, 1603591200, 1603594800, 1603598400, 1603602000, 
                                             1603605600, 1603609200, 1603612800, 1603616400, 1603620000, 1603623600,
                                             1603627200, 1603630800, 1603634400, 1603638000, 1603641600, 1603645200,
                                             1603648800, 1603652400, 1603656000, 1603659600), 
                                           class = c("POSIXct", "POSIXt"), tzone = "Europe/Berlin"), 
                     col = c(rep("#FFBA00", 23), rep("#B9CC2E", 23)), 
                     name = c(rep("Grp1", 23), rep("Grp2", 23))), 
                row.names = 1:46, class = "data.frame")

plot_ly(data = df, text = "text") %>%
  add_trace(x = ~timestamp, y = ~value, type = "bar",
            marker = list(color = ~col),
            text = ~sprintf("Time: %s<br>Value: %s", timestamp, value),
            hoverinfo = "text",
            name = ~name) %>% 
  plotly::layout(xaxis = list(title = 'Time', type = "date"),
                 barmode = 'group')

【问题讨论】:

为什么排除tickvals/ticktext的使用?我会使用 UTC tickvals 和 CET/CEST ticktext 因为我想保持 plotly 的动态刻度创建,因为地块也可能有 1000 个单独的条形图。 很遗憾,我认为您目前没有其他选择。 Here 是一个非常古老的 GitHub 问题 - 已关闭但似乎没有得到解决。如果您确实找到了其他东西,请告诉我。 相关声明:Changes our internal date linearization to use UTC rather than local milliseconds. Every day on a Plotly graph will now be 24 hours long, with no daylight shifts. from here 【参考方案1】:

总结我的 cmets 为未来的读者提供答案:

plotly 目前不支持原生显示夏令时:

将我们的内部日期线性化更改为使用 UTC 而不是本地 毫秒。现在,Plotly 图表上的每一天都是 24 小时, 没有白昼变化。

来源:https://github.com/plotly/plotly.js/pull/1194#issue-95087563

因此,我知道解决此问题的唯一可能性是在 plotly 的 layout 函数中使用 tickvalsticktext 参数(@SeGa 不需要,这是合理的,因为我们将有重复的刻度标签。不过,以下内容可能对其他人有帮助)。

library(plotly)

DF <- structure(list(value = round(runif(46, 20, 26), 3), 
                     timestamp = structure(c(1603576800, 1603584000, 1603587600, 1603591200, 1603594800, 1603598400, 
                                             1603602000, 1603605600, 1603609200, 1603612800, 1603616400, 1603620000,
                                             1603623600, 1603627200, 1603630800, 1603634400, 1603638000, 1603641600,
                                             1603645200, 1603648800, 1603652400, 1603656000, 1603659600, 1603576800,
                                             1603584000, 1603587600, 1603591200, 1603594800, 1603598400, 1603602000, 
                                             1603605600, 1603609200, 1603612800, 1603616400, 1603620000, 1603623600,
                                             1603627200, 1603630800, 1603634400, 1603638000, 1603641600, 1603645200,
                                             1603648800, 1603652400, 1603656000, 1603659600), 
                                           class = c("POSIXct", "POSIXt"), tzone = "Europe/Berlin"), 
                     col = c(rep("#FFBA00", 23), rep("#B9CC2E", 23)), 
                     name = c(rep("Grp1", 23), rep("Grp2", 23))), 
                row.names = 1:46, class = "data.frame")

# DF$timestamp_utc <- DF$timestamp
# attr(DF$timestamp_utc, "tzone") <- "UTC" 

plot_ly(data = DF, text = "text") %>%
  add_trace(x = ~as.numeric(timestamp), y = ~value, type = "bar",
            marker = list(color = ~col),
            text = ~sprintf("Time: %s<br>Value: %s", timestamp, value),
            hoverinfo = "text",
            name = ~name) %>% 
  plotly::layout(xaxis = list(title = 'Time',
                              ticktext = ~timestamp, 
                              tickvals = ~as.numeric(timestamp),
                              tickmode = "array"),
                 barmode = 'group')


小修改:如果我们想不费吹灰之力地减少刻度标签的数量,我们可以在ticktexttickvals 中使用pretty

ticktext = ~pretty(timestamp), 
tickvals = ~as.numeric(pretty(timestamp))

相关文档:Formatting Ticks in R

【讨论】:

以上是关于使用 POSIXct 和夏令时绘制条形图的主要内容,如果未能解决你的问题,请参考以下文章

Python使用matplotlib绘制柱状图(bar plot)实战:水平条形图垂直条形图分组条形图堆叠条形图

matlab 绘制条形图

绘制堆积条形图

R绘制发散型条形图(Diverging Bars)

python使用matplotlib绘制水平条形图并在条形图上添加实际数值标签实战

如何使用 Pandas 绘制条形图?