Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve display of date/time tick labels #108

Closed
swharden opened this issue Aug 20, 2019 · 22 comments
Closed

improve display of date/time tick labels #108

swharden opened this issue Aug 20, 2019 · 22 comments
Assignees

Comments

@swharden
Copy link
Member

Now that the tick module has been refactored, simplified (<200 lines), and is working well, the time has come to add support to display tick labels as date and time. This can probably done in just a few lines of new code by intercepting the function which populates TickCollection.tickLabels:

https://github.com/swharden/ScottPlot/blob/8239f72a94da61aa5c558650ec526ad61732d243/src/ScottPlot/TickCollection.cs#L56-L57

Hopefully we can get this working with as few lines of code as possible, then we can always add complexity later.

A logical next step is to provide smart tick spacing for weeks, days, hours, and minutes (not always multiples of 2 or 5). @Padanian made some excellent progress toward this end, but the code was moved to /dev/code/TickExperimental.cs to be brought out again when date support was added.

@swharden
Copy link
Member Author

swharden commented Aug 21, 2019

Working Solution

  • Make a ScottPlot plotting the time as a double array (times are in OADate notation)
  • Turn on date tick labels by calling Ticks()
plt.Ticks(dateTimeX: true);

image

plt.Ticks(dateTimeX: true, dateTimeY: true);

image

Improvements

  • Numeric Representation of Date: Is OADate the best way to represent time as a floating point? Should Linux Epoch time be used instead?
    • An OLE Automation date is implemented as a floating-point number whose integral component is the number of days before or after midnight, 30 December 1899, and whose fractional component represents the time on that day divided by 24.
  • TickSpacing: The spaces between ticks are multiples of 2 and 5 (like numeric ranges). The ideal solution would be to place separators at even minutes, hours, etc. @Padanian has some functions that do this in /dev/code/TickExperimental.cs which could be helpful.
  • Custom format: it might be nice for the user to be able to use a custom string format for the date.

@swharden swharden changed the title option to display tick labels as date and time improve display of date/time tick labels Aug 22, 2019
@Bhandejiya
Copy link

Thanks Scott, I will test this

@Padanian
Copy link
Contributor

Back at my desk, just pulled and synched the 100k+ additions.
For your question: "Numeric Representation of Date", my choice of election is the natural DateTime type.
The DateTime value type represents dates and times with values ranging from 00:00:00 (midnight), January 1, 0001 Anno Domini (Common Era) through 11:59:59 P.M., December 31, 9999 A.D. (C.E.) in the Gregorian calendar.
Time values are measured in 100-nanosecond units called ticks, so it is always possible to convert a long to a DateTime, knowing there are 864000000000 TicksPerDay, with an exact representation, that floats can't have.

@swharden
Copy link
Member Author

@Padanian your points about the convenience and accuracy of using DateTime are true. If I were going to design an important data analysis routine, use of the DateTime type is an excellent choice.

However, for plotting on a graph we don't need this level accuracy. A big win comes from using double to represent date and time in this special case: Since all plot types support double, all plot types support dates (no modifications or function overloads required). You can toggle date display with:

plt.Ticks(dateTimeX: true);

I added an example to the cookbook:
https://github.com/swharden/ScottPlot/tree/master/cookbook#date-axis

Currently date ticks display surprisingly well considering how simple the code is: it just changes the string labels of the ticks. Usually ticks are just double.ToString(), but if a date format is indicated it converts the double to a DateTime and formats it appropriately (based upon the tick spacing). I think the only task that remains is choosing better tick spacing for these cases (such as multiples of 60, for example). Currently, all the code which allows date axis labels is here:

https://github.com/swharden/ScottPlot/blob/af102c96013e37e42e924c53eccf0daaa759e2b9/src/ScottPlot/TickCollection.cs#L168-L208

@Padanian
Copy link
Contributor

Padanian commented Aug 26, 2019 via email

@swharden
Copy link
Member Author

not every double precision number has a correct conversion to Datetime

Unix time may be a better option. With Unix time the numbers are the number of seconds since January 1st, 1970. I don't think this time format has limits.

Minutes and hours area much easier in Unix time (multipliers of 60 and 60*60) as opposed to DateTime (where an hour is 1/24)

@Padanian
Copy link
Contributor

Padanian commented Aug 26, 2019 via email

@swharden
Copy link
Member Author

swharden commented Aug 26, 2019

God forbid, what if one needs to plot events in the past, like historical or climatological centuries-long data?

That person would probably plot year on the horizontal axis. You don't need a time system that supports milliseconds when plotting centuries-long data.

I think Unix time is commonly used in internet programming. I run across it a lot in PHP and Python. It seems to be supported by .NET but only int (not double)

EDIT: Rather than supporting double, they have separate functions for millisecond conversion

@swharden

This comment has been minimized.

@swharden swharden added the v4 label Aug 28, 2019
@ghost
Copy link

ghost commented Nov 11, 2019

Hallo,
I have two points concerning the ticks:

  1. I am developing an application which shipped in 2 languages, is it possible to make the DateTime axis localizable ? in other words, to allow for cutom formatting the Date according to the culture info of the app, somthing like plt.Ticks(dateTimeX: true, datetimeFormat: "here goes the desired format" );?
  2. Grid Spacing after zooming is diaplaying the wrong ticks, for example: I have a time series that has a point each 1 hour, the spacing after zooming is shown like this:
    grafik

would be great if tick spacing is in minutes or seconds.

Thanks a lot in advance for your patience and help.

@swharden
Copy link
Member Author

swharden commented Nov 11, 2019

Hi @FadyDev2, as you can see this topic was actively discussed a few months ago, but hasn't been worked on much since then. If I remember correctly some very fancy date support was added, but the code exploded in complexity (100s of lines of code), then those features got cut out when refactoring required rewriting the axis/tick system. I'll reopen this issue to remind myself to review what it would take to add improved date support to axis labels.

@swharden swharden reopened this Nov 11, 2019
@swharden swharden removed the v4 label Nov 11, 2019
@swharden swharden self-assigned this Nov 17, 2019
swharden added a commit that referenced this issue Nov 17, 2019
DateTimeTicks.GetTicks() is now used to generate tick positions and labels when "dateTimeX" or "dateTimeY" is in use. Currently this method is dumb, but it can be improved by adding private methods to this class. This is part of #108
@swharden
Copy link
Member Author

Currently users can turn DateTime display on like this:

plt.Ticks(dateTimeX: true);

There is now a DateTimeTicks module (with a GetTicks() method) which is devoted exclusively to choosing ideal DateTime tick positions and labels:

https://github.com/swharden/ScottPlot/blob/4127236c67e2be18889cf725b7af599110d4f695/src/ScottPlot/Config/DateTimeTicks.cs#L1-L51

Currently, the display of DateTime ticks is still very poor. However, this new class is now a single place which can be modified (using only private methods) to provide excellent DateTime tick display.

@Padanian contributed some code previously (TickExperimental.cs) which may be useful.

swharden added a commit that referenced this issue Nov 19, 2019
@swharden
Copy link
Member Author

I ended-up writing the DateTime tick calculator from scratch (DateTimeTicks.cs). It's a lot of lines but I think it's easy to read. Anyone wanting to improve the DateTime tick display can do so by modifying this file (and not worry about breaking anything else).

The result looks great! I'll issue a NuGet release containing these updates shortly.

dateAxis

@ghost
Copy link

ghost commented Nov 22, 2019

Dear Scott,
when to expect the new Nuget package update of Scottplot with the last modifications (Zoom controls and Datetime axis)?

@swharden
Copy link
Member Author

hey @FadyDev2, I'll fix a last couple things then publish this on NuGet tonight and update this issue when I do.

@swharden
Copy link
Member Author

@FadyDev2 this is live on NuGet now (ScottPlot 4.0.3)

@ghost
Copy link

ghost commented Nov 25, 2019

@swharden

Thanks a lot for your quick implementation and replies :)

I have another idea that may be of a good use.
I am working on an app which used in different languages. I used to use an old ploting library (ScottPlott is really better than it ;) ) but it has a good feature; it was adapting itself to the current app culture and show the dateTime in the corresponding format.

I hope something like that could be add to ScottPlot.

Thanks in advance for your creativity :)

@swharden swharden reopened this Nov 25, 2019
@swharden
Copy link
Member Author

I like the idea - I’ll look into it!

swharden added a commit that referenced this issue Nov 27, 2019
swharden added a commit that referenced this issue Nov 27, 2019
after upgrading local DateTime display format #108
@swharden
Copy link
Member Author

It seems the best way to do this is to use the DateTime.ToString() functions:
https://docs.microsoft.com/en-us/dotnet/api/system.datetime.tostring

I made everything locale based simply using ToString("d"), ToString("t"), or ToString("t"). This improved things for me because it neatly switched to AM/PM format rather than 24-hour time format.

image

@ghost
Copy link

ghost commented Dec 3, 2019

Well done @swharden
Thanks a lot, I like the new adjustments and now we have it almost localizable.
I just noticed a small problem, if the current culture is not english, when zooming out, the months names are displayed in english appreviations (Jan, Feb, ...). I think its because they are hard coded in DateTimeTicks.cs

I wonder if that also could be localized.

Thanks and have a nice day.

@swharden
Copy link
Member Author

swharden commented Dec 3, 2019

I just noticed a small problem, if the current culture is not english, when zooming out, the months names are displayed in english appreviations (Jan, Feb, ...). I think its because they are hard coded in DateTimeTicks.cs

You're right! I changed the hard-coded format to use DateTime.ToString() everywhere but overlooked one place. That error is here:

https://github.com/swharden/ScottPlot/blob/b2f754ffdfeeef3319dbcd853d53bbc372c08dcb/src/ScottPlot/Config/DateTimeTicks.cs#L71

The fix is to change this line to:

labels[i] = ticks[i].ToString("MMM yyyy");

@swharden swharden reopened this Dec 3, 2019
swharden added a commit that referenced this issue Dec 3, 2019
@swharden
Copy link
Member Author

swharden commented Dec 4, 2019

Fixed in ScottPlot 4.0.9 (live on NuGet)

@swharden swharden closed this as completed Dec 4, 2019
StendProg pushed a commit to StendProg/ScottPlot that referenced this issue Mar 16, 2020
DateTimeTicks.GetTicks() is now used to generate tick positions and labels when "dateTimeX" or "dateTimeY" is in use. Currently this method is dumb, but it can be improved by adding private methods to this class. This is part of ScottPlot#108
StendProg pushed a commit to StendProg/ScottPlot that referenced this issue Mar 16, 2020
StendProg pushed a commit to StendProg/ScottPlot that referenced this issue Mar 16, 2020
StendProg pushed a commit to StendProg/ScottPlot that referenced this issue Mar 16, 2020
after upgrading local DateTime display format ScottPlot#108
StendProg pushed a commit to StendProg/ScottPlot that referenced this issue Mar 16, 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

No branches or pull requests

3 participants