DearPyGui icon indicating copy to clipboard operation
DearPyGui copied to clipboard

Updating x-axis minimum and maximum value with time data

Open skjelanger opened this issue 2 years ago • 12 comments

Hello,

As far as I can tell from the documentation, it is not possible to fix the maximum and minimum values of an x-axis for an line_series plot, if the x-axis has time=True. The closest I get is dpg.set_axis_limits(axis, ymin, ymax), however it does not work properly on x-axis objects, when it is formatted as a time series.

I would like to be able to do this.

Minimum reproducible code

import dearpygui.dearpygui as dpg
import time
from math import sin

dpg.create_context()
dpg.create_viewport(title='CSV Reader', width=1020, height=580)

time_now = time.time()
tmin = time_now-20
tmax = time_now+20

def sindata():
    sindatax = []
    sindatay = []
    for i in range(0, 100):
        sindatax.append(time_now+i)
        sindatay.append(0.5 + 0.5 * sin(50 * i / 100))
    return sindatax, sindatay
        

sindatax, sindatay = sindata()

with dpg.window(label="Main Window", width=1080, height=500):
    with dpg.plot(label="Plot",height=490, width=900):                    
        dpg.add_plot_axis(dpg.mvXAxis, label="x", tag='xaxis', time=True)
        ax_y1 = dpg.add_plot_axis(dpg.mvYAxis, tag='yaxis')
        dpg.add_line_series(sindatax, sindatay, label="sin", tag='datay', parent=dpg.last_item())
        dpg.set_axis_limits('xaxis', tmin,tmax)

                                        
dpg.setup_dearpygui()
dpg.show_viewport(maximized=True)
dpg.start_dearpygui()
dpg.destroy_context()

skjelanger avatar Aug 15 '23 14:08 skjelanger

Can you format your code sample as "code" so that we can read and copy it? (the <> button on the formatting panel).

v-ein avatar Aug 15 '23 20:08 v-ein

Apoliges @v-ein ,now it should be formatted as code.

skjelanger avatar Aug 15 '23 20:08 skjelanger

It looks to me like a precision issue, somewhat similar to #386 and #2067. Axis limits are float fields in C++. The number of seconds returned by time.time() is around 1.6e9. I've played with numbers a little bit, trying to display a sin() graph in the range (x, x+20), and found that up to x == 1e7 it all looks the same, while with x == 1e8 and above it starts drifting or completely disappearing.

As always with precision errors, it depends on your numbers, and you can get completely different behavior for close numbers. That is, when you use time.time(), it might be that some runs will show something and others will show a blank plot.

BTW #386 and #2067 deal with timestamps, too, that is, the numbers there are of the same scale as what you get from time.time() here. Same kind of issues.

v-ein avatar Aug 15 '23 20:08 v-ein

The bad news are: there's no workaround until somebody fixes these precision issues.

Also, set_axis_limits is mentioned in #1847: same issue there.

v-ein avatar Aug 15 '23 20:08 v-ein

But it is also a 'problem' that you can not manually set the limits of the x-axis?

skjelanger avatar Aug 16 '23 05:08 skjelanger

You can. Try to use dates around May or June 1970 - it will work just fine.

v-ein avatar Aug 16 '23 11:08 v-ein

Technically, a date is just a number -- the number of seconds since Jan 1, 1970. As long as it's smaller than 1e7, you'll be just fine, whether you use the time format for x axis or regular numeric format. But, 1e7 seconds is only about 115 days, or 4 months. So even June 1970 is probably risky (though it works for me).

v-ein avatar Aug 16 '23 11:08 v-ein

Thank you for the help. What I am trying to do is to plot the last 60 seconds of data, in a sliding window. I can therefore make a work-around by subtracting '1692000000' from all of my timestamps and setting no_tick_labels=True :)

skjelanger avatar Aug 16 '23 12:08 skjelanger

Is this precision issue scheduled to be fixed at some point? I can probably work around it by setting the day to be Jan 1st 1970 as suggested, but I'd rather not have to if I don't need to. Ideally I'd like to be able to work with nanosecond level precision for current dates. An underlying uint64 datatype representing ns from epoch would work.

nkraemer2 avatar Jun 01 '24 00:06 nkraemer2

Unlikely to be fixed before #2275 (just because #2275 is huge and everything else is being held up). You can also fix it on your own and push a PR. (Note: I'm not one of DPG developers and my comment here does not reflect their position).

Talking about nanoseconds, double doesn't seem to be sufficient for that. It only provides ~16 digit precision (per Wikipedia), whereas for current dates and nanosecond precision you'd need 18 digits.

v-ein avatar Jun 01 '24 06:06 v-ein

Thanks for quick input. Agreed, just moving to double would be insufficient for ns precision. I'm suggesting using a 64 bit signed or unsigned integer with units of 1 = 1ns as the basis for time instead of floating point values. I'm don't think I'll have time to fix it myself, but if I do I'll should be able to share the results.

nkraemer2 avatar Jun 03 '24 17:06 nkraemer2

Changing it to int64 for X values and double for Y values won't be trivial, if it's doable at all. DPG relies on ImPlot to render plots. You can probably create your own ImPlotGetter as well as your own heterogeneous point type (with x being int64 and y being double). Then, fingers crossed, ImPlot::PlotLineG might be able to render that. So it's more than just changing type name here and there.

BTW I'm talking about the modern version of ImPlot, which #2275 brings to DPG.

v-ein avatar Jun 03 '24 21:06 v-ein