Recently I installed Julia on a new computer and using code I knew that works, PyPlot displayed dates far in the future. I was plotting data from the previous week (August 2021) and plot_date
was displaying the dates in the year 3990. Previously I would just convert the dates myself.
Dates.value.(timestamp)/1000/60/60/24
The reason for the change, as far as I can tell, is that matplotlib added an epoch setting to the rcParams (matplotlib settings). The matplotlib conversion function can handle the change but is very slow.
julia> x = collect(DateTime(2021,8,1):Millisecond(1):DateTime(2021,8,2));
julia> @time y = PyPlot.matplotlib.dates.date2num(x);
270.131231 seconds (87.19 M allocations: 1.978 GiB, 1.29% gc time, 0.12% compilation time)
julia> @time y = PyPlot.matplotlib.dates.date2num(x);
265.707832 seconds (86.40 M allocations: 1.931 GiB, 0.74% gc time)
My solution proved to be much faster.
function datetime2matplotlib(timestamp::AbstractVector{DateTime})
epoch = DateTime(get(matplotlib.rcParams,"date.epoch","0000-01-01T00:00:00"),Dates.dateformat"yyyy-mm-ddTHH:MM:SS") # Check matplotlib epoch
if epoch == DateTime(0,1,1,0,0,0)
return Dates.value.(timestamp)/1000/60/60/24
else
return Dates.value.(timestamp .- epoch)/1000/60/60/24
end
end
It correctly handles both new and old versions of matplotlib. I tried a version which converted a single value and then broadcasted it but it was also very slow.
julia> x = collect(DateTime(2021,8,1):Millisecond(1):DateTime(2021,8,2));
julia> @time z = datetime2matplotlib(x);
3.003491 seconds (1.75 M allocations: 3.319 GiB, 12.45% gc time, 24.36% compilation time)
julia> @time z = datetime2matplotlib(x);
1.988773 seconds (5.64 k allocations: 3.219 GiB, 5.11% gc time)
julia> @time z = datetime2matplotlib(x);
2.094877 seconds (5.64 k allocations: 3.219 GiB, 9.69% gc time)
Old test setup:
julia> versioninfo()
Julia Version 1.6.0
Commit f9720dc2eb (2021-03-24 12:55 UTC)
Platform Info:
OS: Linux (x86_64-pc-linux-gnu)
CPU: Intel(R) Core(TM) i5-4570 CPU @ 3.20GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, haswell)
(@v1.6) pkg> status
[d330b81b] PyPlot v2.9.0
julia> PyPlot.matplotlib.__version__
"3.2.2"
New test setup:
julia> versioninfo()
Julia Version 1.6.2
Commit 1b93d53fc4 (2021-07-14 15:36 UTC)
Platform Info:
OS: Windows (x86_64-w64-mingw32)
CPU: Intel(R) Core(TM) i9-9900K CPU @ 3.60GHz
WORD_SIZE: 64
LIBM: libopenlibm
LLVM: libLLVM-11.0.1 (ORCJIT, skylake)
Environment:
JULIA_NUM_THREADS = 7
(@v1.6) pkg> status
[d330b81b] PyPlot v2.9.0
julia> PyPlot.matplotlib.__version__
"3.4.2"
Other functions if needed:
function datetime2matplotlib(timestamp::DateTime)
epoch = DateTime(get(matplotlib.rcParams,"date.epoch","0000-01-01T00:00:00"),Dates.dateformat"yyyy-mm-ddTHH:MM:SS") # Check matplotlib epoch
if epoch == DateTime(0,1,1,0,0,0)
return Dates.value(timestamp)/1000/60/60/24
else
return Dates.value(timestamp - epoch)/1000/60/60/24
end
end
function matplotlib2datetime(timestamp::Float64)
epoch = DateTime(get(matplotlib.rcParams,"date.epoch","0000-01-01T00:00:00"),Dates.dateformat"yyyy-mm-ddTHH:MM:SS") # Check matplotlib epoch
if epoch == DateTime(0,1,1,0,0,0)
return DateTime(1) - Day(1) + Millisecond(floor(timestamp*24*60*60*1000))
else
return Millisecond(round(timestamp*24*60*60*1000)) + epoch
end
end
function matplotlib2datetime(timestamp::AbstractVector{Float64})
epoch = DateTime(get(matplotlib.rcParams,"date.epoch","0000-01-01T00:00:00"),Dates.dateformat"yyyy-mm-ddTHH:MM:SS") # Check matplotlib epoch
if epoch == DateTime(0,1,1,0,0,0)
return DateTime(1) .- Day(1) .+ Millisecond.(floor.(timestamp .* 24*60*60*1000))
else
return Millisecond.(round.(timestamp .* 24*60*60*1000)) .+ epoch
end
end