Skip to content

Add Milliseconds unit to DateTime Axis#539

Merged
swharden merged 19 commits intoScottPlot:masterfrom
StendProg:DateTimeRefactor
Sep 19, 2020
Merged

Add Milliseconds unit to DateTime Axis#539
swharden merged 19 commits intoScottPlot:masterfrom
StendProg:DateTimeRefactor

Conversation

@StendProg
Copy link
Contributor

@StendProg StendProg commented Sep 10, 2020

Purpose:
Current DateTime Axis minimal unit is second.
This PR add decisecond, centisecond and millisecond units to DateTimeAxis.
There is possible to zoom into second interval and get millisecond ticks on DateTimeAxis. #537
There is no culture invariant time specifier to display milliseconds, so i hardcoded this formats:
hh:mm:ss.f - decisecond
hh:mm:ss.ff - centisecond
hh:mm:ss.fff - millisecond

Additional refactor DateTime Ticks module.

New functionality (code):
There is no new API in this PR.

New functionality (image):

image

@StendProg
Copy link
Contributor Author

After a little thought I came up with the idea that it would be nice to split the millisecond into hundredsOfMilliseconds, TensOfMilliseconds and Millisecond. This allow remove ugly zeroes at the end. 1.500, 1.600, 1.700 for now, will be 1.5, 1.6, 1.7. And will return small arrays in intermediate calculations. Up to 1000 ticks intermediate arrays for now in worst case.

I'm ready to do this, but I can't decide how best. I'm waiting for your input.

@swharden
Copy link
Member

swharden commented Sep 10, 2020

Hi @StendProg, your idea to add subdivisions of seconds to the DateTimeUnit enum is perfect. I was not familiar with these words (I had to look them up to be sure they were real), but it appears these units of time have names we can use:

Thank you for working on this! I see how this PR relates to #537, and I also very much appreciate your recent efforts responding to issues while I was busy over the last few days.

@StendProg
Copy link
Contributor Author

The naming system you suggested made the confusion in my head surprisingly simple.
We can, of course, go down to nanoseconds, I often deal with this, but personally I am satisfied with the usual numerical values.

@bclehmann
Copy link
Member

I would have use for microseconds (µs) at 10^-6 seconds.

And since this library is targeted towards science I expect that nano (10^-9), pico, femto (10^-12), and atto (10^-15) prefices are likely to be useful. There are prefices for even smaller numbers but I've never seen them used. It's also worth noting that in some contexts it's more clear to write x * 10^6 µs than it is to write x fs. So this should probably be configurable.

I don't think you can even go to attosecond precision thanks to the width of a double, which means anyone going this precise should probably use a conventional axis and rescale it (i.e. multiply by 10^-x) instead of using a DateTime axis. I don't know how OLE Date runs its affairs and I would suggest not changing to another system (e.g. Unix time) for backwards compatibility. So my recommendation is to support the smallest prefix that can be reliably expressed as an OLE Date with an FP64 double. If it's a very small prefix it might need configuration so people don't get confused by attoseconds.

@swharden
Copy link
Member

swharden commented Sep 10, 2020

anyone going this precise should probably use a conventional axis ... instead of using a DateTime axis

☝️ this! I agree that some scientists may want to plot data with femtosecond precision. They will probably use double[] to store time points, not DateTime[] 🙃

This raises an interesting question though, how precise is a DateTime? I looked it up: The DateTime Struct stores ticks which are accurate to one ten-millionth of a second.

DateTime.Ticks documentation says, "The value of this property represents the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001 in the Gregorian calendar"

@swharden

This comment has been minimized.

@bclehmann

This comment has been minimized.

@vrdriver
Copy link

I'll just add my little bit, since my suggestion surprisingly kicked off this thread. I'm presently working in samples of audio, which when displayed should labelled as hours, minutes, seconds and milliseconds - with the leading zeros included.

Regardless of the file format (MP3 or wave), the samples rates of audio files can vary anywhere from the common ones as 48000, 44100 and all the way up to 192kHz per second.

I would think that the display conversion for only the X-axis text label should be enough, while still keeping the plot unchanged while still being able to show and zoom in to the individual samples.

I'm amazed that you are all jumping in on this. Go team!

@StendProg
Copy link
Contributor Author

StendProg commented Sep 11, 2020

FP64 gives (at least) 15 significant digits. For dates this year 5 of them are going to be taken up by the day (120 * 365 = 43800). So we can express fractions of a day to 10 significant digits, which puts the smallest amount guaranteed to be preserved 8.64 * 10^-6 seconds (86400 * 10^-10). So this means OLE dates can guarantee at best 5 significant digits for seconds (including whole seconds), which puts microseconds out of reach.

I am also thinked that precise of OA date low, but found on StackOverflow:

Near the date and time we're considering, the precision of an OA date is:
Math.Pow(2.0, -37.0) days, or circa 0.6286 µs
We conclude that in this region a DateTime is more precise than an OA date by (just over) a factor six.

https://stackoverflow.com/questions/3724355/net-datetime-different-resolution-when-converting-to-and-from-oadate

@bclehmann
Copy link
Member

bclehmann commented Sep 11, 2020

I am also thinked that precise of OA date low, but found on StackOverflow:

Near the date and time we're considering, the precision of an OA date is:
Math.Pow(2.0, -37.0) days, or circa 0.6286 µs
We conclude that in this region a DateTime is more precise than an OA date by (just over) a factor six.

I got a little bit bamboozled, but I think the difference comes from me rounding the number of significant digits midway through. If you do as he did you find that you need 16 bits for the day and that leaves 37 bits for the fractions of a day. I assumed it would always be 15 significant digits, but with FP64 it can be 15-17, so my rounding came back to bite me.

The stackoverflow answer: https://stackoverflow.com/a/13922172/3513171

@StendProg
Copy link
Contributor Author

StendProg commented Sep 11, 2020

@Benny121221 As far as I understand OA date, at one moment the accuracy will be exactly the same as you indicated initially (sooner or later this moment will come) :-)

@swharden
Copy link
Member

Hi @StendProg, this is an excellent refactor of the DateTimeTicks module! I am happy to see the factory pattern here, and these small classes really help readability and maintainability. This improvement is useful for #537 too.

It's been a few days since your last commit - is this ready for me to review and merge into master, or do you intend to continue working on it?

@StendProg
Copy link
Contributor Author

Hi Scott (@swharden),

is this ready for me to review and merge into master, or do you intend to continue working on it?

It's ready.
I decided not to introduce microsecond labels. This will increase the maxLabelSize, because of which every TickUnit will suffer. But really, microsecond ticks are unlikely to be needed by anyone.

There are 2 unresolved issues that I want to pass on to you.

  1. For now DateTimeUnit enum name may be misleading. A more accurate name should be something likeDateTimeUnitKind. And for good it would be moved to ScottPlot.Config.DateTimeTickUnits namespace/folder. But this will be a breaking API change. Anyone who has used manual ticks will have to manually apply these corrections to their projects.
  2. MothTicks return 3 lines labels, all others 2 lines. It was in the original code. Maybe just a bug, or was it intended?

@swharden
Copy link
Member

  1. MothTicks return 3 lines labels, all others 2 lines. It was in the original code. Maybe just a bug, or was it intended?

I think the line that caused that behavior is:

https://github.com/swharden/ScottPlot/blob/c5e634448ce7759ac4fd620df065f3a1549089fe/src/ScottPlot/Config/DateTimeTicks.cs#L93-L94

The 3 line behavior was not intended, and is probably the result of locales where the string contains more than 1 space. I recognize that hard-coding a string search/replace with a line break is bad practice for internationalization, and am happy the new code no longer does things like this! Thanks again for this excellent PR

https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-date-and-time-format-strings#YearMonth

@swharden swharden merged commit 83b9ffb into ScottPlot:master Sep 19, 2020
@StendProg
Copy link
Contributor Author

the new code no longer does things like this

In fact, I tried to keep the original behavior, because I did not fully understand it, and it is difficult to test for many cultures at once. I think it's a good idea to write unit tests that count the number of lines in different cultures, with the current design it should be easier. I'll do it some other day.

swharden added a commit that referenced this pull request Sep 20, 2020
swharden added a commit that referenced this pull request Sep 26, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants