Makie.jl icon indicating copy to clipboard operation
Makie.jl copied to clipboard

Implement time axis

Open SimonDanisch opened this issue 3 years ago • 19 comments

I noticed, that we can hack together a simple time aware axis as a small wrapper type around Axis... We may even be able to integrate this into the Axis code itself, so that we don't need a wrapper, and the axis will just change to the correct conversion + formatting functions, depending on what you plot into it.

This would basically add a pre convert_arguments conversion, that is axis aware and can store axis local state (e.g. target unit, target range, etc).

We could also use this for categorical values and Float32 conversion, I think. Still pretty early to tell, but I will use the TimeAxis wrapper to figure out the interface and add tests + proper error handling for the myriad of time conversions we may run into. If this works out nicely, we can think about removing TimeAxis and add it to the standard Axis code.

But the simple mvp already works as intended:

f = Figure()
ax = TimeAxis(f[1,1])
scatter!(ax, rand(Hour(1):Hour(1):Hour(20), 10), 1:10)
f

image

scatter!(ax, rand(Second(1):Second(60*60):Second(20*60*60), 10), 1:10)

image

This currently uses promote_type to figure out the conversion target, which isn't ideal since we should rather chose the unit from the range of time values we want to display...

SimonDanisch avatar Sep 29 '21 15:09 SimonDanisch

Ultrafast laser pulses seem to be resolved on a fs scale, so maybe it's worth going down to that level? For reference: https://www.newport.com/n/ultrafast-pulse-characterization https://www.dickinson.edu/download/downloads/id/25/ultrafastlaserpulses

ffreyer avatar Oct 01 '21 17:10 ffreyer

Yeah makes sense - that was just an oversight ... Still getting familiar with Unitful.jl and how to discover things...

SimonDanisch avatar Oct 04 '21 14:10 SimonDanisch

I first wanted to implement this as unobtrusive as possible by introducing a new axis wrapper type (TimeAxis), but the more I worked on the implementation, the clearer it became, that the wrapper isn't needed at all and that I really just need to spice up the tick formatter a bit to integrate this into the standard axis. At that point it seemed pretty silly to not do that, since then we'd introduce a new TimeAxis type, just to deprecate it a few versions later... It will also be very easy to add new Tick types e.g. for categorical values etc...

This is pretty close to being mergeable:

  • [x] new axis conversion & tick formatter finding API
  • [x] Unitful integration, introducing a UnitfulTicks type, that gets chosen for x/yticks whenever you plot unitful numbers to either axis
  • [x] some tests
  • [ ] clean up & document new APIs

SimonDanisch avatar Oct 07 '21 09:10 SimonDanisch

Great to see this! (I assume this) fixes #442.

visr avatar Oct 11 '21 15:10 visr

Does this work for DateTime, like:

f = Figure()
ax = Axis(f[1,1])
scatter!(ax, rand(DateTime(2021,1,1):Second(900):DateTime(2021,2,1), 10), 1:10)

ValentinKaisermayer avatar Oct 22 '21 15:10 ValentinKaisermayer

Yeah:

using CairoMakie, Dates
f = Figure()
ax = Axis(f[1,1])
scatter!(ax, rand(DateTime(2021,1,1):Second(900):DateTime(2021,2,1), 10), 1:10)

image Although it's cut off... @jkrumbiegel can we chose ticks closer to the middle if we know that the ticklabels are going to be long?

SimonDanisch avatar Oct 22 '21 15:10 SimonDanisch

Very nice but the chosen ticks have to be improved. The timestamps are:

[
       DateTime(2021,1,3,14,30),
       DateTime(2021,1,4,9,23,20),
       DateTime(2021,1,5,4,16,40),
       DateTime(2021,1,5,23,10),
       DateTime(2021,1,6,18,3,20),
]

But only showing the time completely throws you off when trying to read the figure. Also a distance of 68000 seconds between the ticks is not intuitive. The ticks could be borrowed from: https://github.com/JuliaPlots/PlotUtils.jl/blob/c2cf71981ac5bec28b040a545335f7ffa2506c53/src/ticks.jl#L471

A reference from Plots.jl

using Plots, Dates
t, y = rand(DateTime(2021,1,1):Second(900):DateTime(2021,2,1), 10), 1:10
scatter(t,y)

test

ValentinKaisermayer avatar Oct 22 '21 16:10 ValentinKaisermayer

Hm, I guess I should just use PlotUtils.optimize_datetime_ticks like Plots.jl and be done with it ;)

t, y = rand(DateTime(2021,1,1):Second(900):DateTime(2021,2,1), 10), 1:10
scatter(t,y)

test

SimonDanisch avatar Oct 22 '21 17:10 SimonDanisch

Cool! What about Date and Time?

ValentinKaisermayer avatar Oct 22 '21 19:10 ValentinKaisermayer

Fixes: https://github.com/JuliaPlots/Makie.jl/issues/442

SimonDanisch avatar Nov 02 '21 12:11 SimonDanisch

I'm really looking forward to this. When do you expect this to be ready for release?

ValentinKaisermayer avatar Nov 10 '21 10:11 ValentinKaisermayer

Will this also allow setting an axis to categorical data in recipes?

rapus95 avatar Jan 10 '22 19:01 rapus95

Will this also allow setting an axis to categorical data in recipes?

Yes it should!

SimonDanisch avatar Jan 10 '22 21:01 SimonDanisch

Great work! I consider dropping Plots for Makie if this lands. Any time prediction on when this will happen?

laborg avatar Jan 14 '22 10:01 laborg

In principle this PR is feature complete and works, but I will need some more time to finish up developer docs and clean up some hacks. E.g., I noticed that this PR doubles CI times for docs and adds at least 10min to the tests...Which is pretty unacceptable and I need to debug why that happens... Also, the conversion pipeline got even more confusing and I still hope to find a cleaner implementation for the axis converts.

SimonDanisch avatar Jan 14 '22 13:01 SimonDanisch

Although, I just noticed, that RPRMakie goes from 5min to 23min... Which is a bit suspicious, since the one test right now in RPRMakie is super simple, and seeing that Makie CI is even faster than in other PRs, this all doesn't make much sense :D Maybe it's just a fluke of the CI. I also just tested this code piece, which should give a good idea of any large scale regression, and that comes out with exactly the same number as on master (1s faster even):

 @time begin
       using GLMakie
       display(scatter(1:4))
       end

So maybe this was really just a CI fluke, or there is one super slow code path - both should be good news, since those should then be much easier to fix than all of Makie becoming much slower (by the new deps, or new type unstable code).

SimonDanisch avatar Jan 14 '22 14:01 SimonDanisch

Aha...restarting the CI: image Other PRs are also around 20 min, so seems really just like a fluke :)

SimonDanisch avatar Jan 14 '22 14:01 SimonDanisch

If I wanted to use/test this already, what would be the easiest way to do so? It'd be so cool if there was an insider/experimental release.

Edit: Regarding the

Also, the conversion pipeline got even more confusing and I still hope to find a cleaner implementation for the axis converts.

What's the circumstance with that? Maybe a new perspective might help 🙈 😀

rapus95 avatar Jan 18 '22 10:01 rapus95

@SimonDanisch Sorry for the bump, I was wondering if there was anything left blocking? Having direct support for dates would be great feature!

jeremiedb avatar Jul 12 '22 06:07 jeremiedb

Ultrafast laser pulses seem to be resolved on a fs scale, so maybe it's worth going down to that level? For reference: https://www.newport.com/n/ultrafast-pulse-characterization https://www.dickinson.edu/download/downloads/id/25/ultrafastlaserpulses

Considering that quantities measured in femtoseconds generally don't require use of the Julian calendar, you can probably make do without femtosecond support here. fwiw

uniment avatar Sep 23 '22 06:09 uniment

Compile Times benchmark

Note, that these numbers may fluctuate on the CI servers, so take them with a grain of salt. All benchmark results are based on the mean time and negative percent mean faster than the base branch. Note, that GLMakie + WGLMakie run on an emulated GPU, so the runtime benchmark is much slower. Results are from running:

using_time = @ctime using Backend
# Compile time
create_time = @ctime fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @ctime Makie.colorbuffer(display(fig))
# Runtime
create_time = @benchmark fig = scatter(1:4; color=1:4, colormap=:turbo, markersize=20, visible=true)
display_time = @benchmark Makie.colorbuffer(display(fig))
using create display create display
GLMakie 32.04s (31.81, 32.22) 0.15+- 16.25s (16.17, 16.33) 0.06+- 15.03s (14.92, 15.27) 0.12+- 12.13ms (11.83, 12.32) 0.17+- 138.41ms (134.74, 141.10) 2.30+-
master 31.52s (31.14, 31.65) 0.17+- 16.26s (16.17, 16.40) 0.08+- 15.24s (15.08, 15.36) 0.10+- 11.90ms (11.72, 12.11) 0.14+- 135.09ms (132.00, 136.43) 1.47+-
evaluation +1.63%, 0.52s slower X (3.20d, 0.00p, 0.16std) -0.07%, -0.01s invariant (-0.16d, 0.77p, 0.07std) -1.37%, -0.21s faster ✓ (-1.89d, 0.00p, 0.11std) +1.86%, 0.23ms slower X (1.43d, 0.02p, 0.16std) +2.40%, 3.32ms slower X (1.72d, 0.01p, 1.88std)
CairoMakie 30.78s (30.55, 31.01) 0.16+- 18.20s (18.07, 18.31) 0.10+- 2.80s (2.76, 2.84) 0.03+- 12.51ms (12.39, 12.64) 0.08+- 4.88ms (4.78, 4.93) 0.05+-
master 30.41s (30.11, 30.81) 0.23+- 17.94s (17.73, 18.10) 0.11+- 2.75s (2.72, 2.80) 0.03+- 12.48ms (12.14, 12.81) 0.21+- 5.02ms (4.86, 5.52) 0.23+-
evaluation +1.22%, 0.38s slower X (1.87d, 0.01p, 0.20std) +1.40%, 0.26s slower X (2.40d, 0.00p, 0.11std) +1.59%, 0.04s slower X (1.42d, 0.02p, 0.03std) +0.20%, 0.02ms invariant (0.15d, 0.78p, 0.15std) -2.82%, -0.14ms invariant (-0.84d, 0.16p, 0.14std)
WGLMakie 37.46s (37.18, 37.75) 0.24+- 19.22s (19.11, 19.30) 0.07+- 23.31s (22.91, 23.53) 0.21+- 14.44ms (13.53, 15.24) 0.69+- 2.36s (2.01, 2.61) 0.19+-
master 37.16s (37.07, 37.22) 0.06+- 19.85s (19.65, 20.02) 0.15+- 23.51s (23.16, 23.98) 0.28+- 14.53ms (14.12, 15.29) 0.38+- 2.37s (2.33, 2.48) 0.05+-
evaluation +0.79%, 0.3s slower X (1.67d, 0.02p, 0.15std) -3.30%, -0.63s faster ✓ (-5.55d, 0.00p, 0.11std) -0.84%, -0.2s invariant (-0.80d, 0.16p, 0.24std) -0.63%, -0.09ms invariant (-0.16d, 0.77p, 0.53std) -0.67%, -0.02s invariant (-0.11d, 0.84p, 0.12std)

MakieBot avatar Nov 14 '22 13:11 MakieBot

Closing in favor of https://github.com/MakieOrg/Makie.jl/pull/3226

SimonDanisch avatar Sep 11 '23 17:09 SimonDanisch