qgis / QGIS-Enhancement-Proposals

QEP's (QGIS Enhancement Proposals) are used in the process of creating and discussing new enhancements for QGIS
118 stars 37 forks source link

Temporal support in QGIS map renderer/application #128

Closed nyalldawson closed 4 years ago

nyalldawson commented 6 years ago

QGIS Enhancement: Temporal support in QGIS map renderer/application

Date 2018/07/12

Author Nyall Dawson (@nyalldawson)

Contact nyall dot dawson at gmail dot com

Version QGIS 3.4 (or later)

Summary

A number of different areas and projects relating to QGIS have long been involved with exposing temporal and animation support to QGIS. These include:

Current projects:

Potential future work:

This QEP is intended as a "gathering place" to discuss a unified approach toward temporal and animation handling within QGIS. A unified approach is desired, as it would allow these different animation related components to work together. For instance, a mesh layer animation which also uses Time Manager to filter a set of vector point events, which are dynamically styled/animated using data defined symbology based on time.

Use cases

Potential use cases include:

Vectors

Rasters

Meshes

Proposed Solution

Map Rendering

Initially, the QGIS core map rendering classes need modification to handle the desired timeframe corresponding to a map render. This could be done by exposing a new date time range member within QgsMapSettings.

E.g.

void setTemporalRange( const QgsDateTimeRange& range );

Using QgsDateTimeRange allows for either a range of times (i.e. start to end time) or a single "moment" in time (by specifying an equal start/end time for the range).

This would allow standalone scripts and plugins which render maps to specify the time slice for which the map should be rendered. Additionally, it will allow server to render responses for a specific time range, which is a pre-requisite for server WMS-T support (see #110).

The temporal range would also be added as a member within QgsRenderContext (and copied from the map settings in QgsRenderContext::fromMapSettings). This would allow individual map layer renderers access to the desired temporal range, so that e..g QgsMeshLayerRenderer can utilise the time range within the passed QgsRenderContext to render the correct dataset.

The temporal range would also be exposed as new variables (e.g. @map_timestamp_begin and @map_timestamp_end) within the map settings expression context scope (see QgsExpressionContextUtils::mapSettingsScope()). This would allow expressions to access the current map temporal range, allowing for data defined symbology and labeling to respond the current time slice. (Much like how Time Manager currently exposes the animation_datetime() function).

QgsMapCanvas (and setting the current time slice)

The current temporal range for the map canvas would be exposed via methods within QgsMapCanvas.

Time Manager (and other plugins) would be able to access the current canvas temporal range through QgsMapCanvas::mapSettings().

A new setter could be added to QgsMapCanvas to allow plugins to specify the current time slice shown in the canvas, e.g.

void setTemporalRange( const QgsDateTimeRange& range );

Calling this would update the canvas' internal map settings' temporal range and cause a re-render of the canvas. (A temporalRangeChanged signal would also be fired prior to re-rendering the canvas).

GUI control for time/animation

Lastly, a new gui widget for controlling the current temporal range displayed in the map canvas would need to be created. This could be based heavily off Time Manager's widget (see https://underdark.files.wordpress.com/2011/09/timemanager.png ), which allows both the start time stamp and duration of the range to be set (i.e. allows for both the start and end timestamps required for QgsDateTimeRange to be controlled).

Ideally, a common base class should be created to allow the 3d animation widget to share common code/functionality with the 2d canvas widget.

Further Considerations/Improvements

This is just an early prototype design, intended for discussion amongst interested parties!

Backwards Compatibility

N/A

Votes

(required)

nyalldawson commented 6 years ago

Ping @wonder-sk @anitagraser

PeterPetrik commented 6 years ago

Animation and temporal support is also planned for mesh layer & MDAL QEP 119

haubourg commented 6 years ago

ping @vmora, I bet this is of high interest for you

nyalldawson commented 6 years ago

@peterpetrik

From #119:

"This QEP intentionally tries to stay away from dealing with time component as that is quite a large topic itself. We assume that plugins may introduce convenience functionality for handling of the temporal nature of mesh layers (e.g. easy moving between time steps, animation, export of videos). In the future we would like to look into having a separate QEP to cover time component within QGIS for all types of map layers."

Consider this that separate PR ;)

nyalldawson commented 6 years ago

It's been pointed out that #110 also relates - I'll include that as another component in this qep

PeterPetrik commented 6 years ago

@nyalldawson Thanks for starting this discussion, it would be great to have common code and widgets. We thought at the beginning that handling of time (steps) will be fully handled by external plugins, but now it seems that we slightly shifted as we already have "time" slider in the mesh layer styling panel.

Besides rendering, we need to solve how individual layers/bands form temporal group and how it is represented in the GUI (in layer tree?). Crayfish (MDAL) does some magic to guess which layers/gdal bands/files represents same data but in various times and GUI uses "active dataset" to select time to render (QgsMeshRendererActiveDatasetWidget).

saberraz commented 6 years ago

I think in addition to rendering, we probably need to consider analytical side of temporal data for the Processing toolbox: e.g. aggregate functions and temporal data calculator.

wonder-sk commented 6 years ago

Great to see some action towards temporal data support in QGIS :-)

I think it would be good to start with a bunch of use cases that we would like to cover under the temporal framework (and maybe even a list of use cases we explicitly decide to ignore). Various types of temporal data sources:

The next thing is what the timestamps actually mean - are they concrete instances of time ("absolute") or are they relative times that do not have a reference time? Relative times are common for simulations.

While the most common case of a vector with an attribute having absolute timestamps can be handled easily even without explicitly defining its temporal domain, I think it will be an important part of the implementation to have some temporal metadata assigned to layers (and maybe go as far as grouping e.g. a bunch of "ordinary" map layers into a single "temporal" layer that would be shown in the layer tree and its sub-layers would share style etc.)

It may be good to get some inspiration from GRASS GIS and how temporal data support is implemented there: https://grass.osgeo.org/grass74/manuals/temporalintro.html

Things get more interesting when there are multiple temporally enabled layers in a project, possibly with different temporal domains - how do we work with them? I assume there would be just one time slider, and users would pick which temporal layers are static (fixed to a time instance/interval) and which are transient (moving with the time slider).

It may be good to think about what time ranges / precision are we going to support - I suppose there will be people requiring second/millisecond precision, as well as geologists going some billions of years there and back :-)

When we get to animating things, it will be probably also good to make distinction between the animation time and the current map time (or interval). For example the animation for 3D view does not need to be related to temporal data - it can simply animate camera within one time instance of the map (a static scene).

It would be really cool if we also had support for interpolation of temporal data in between time instances:

Those who will be using temporal rasters will be probably very keen to have a profile tool to be able to visualize changes in one or more points (think a graph of precipitations in London over last 30 years).

Support for processing algorithms would be another big topic I do not want to dig into, but for those algorithms I can see there is a strong need to have a QGIS wide temporal metadata defined for temporal layers, so that the algorithms can use that information (and the temporal metadata do not need to be defined separately every time).

OK I will stop here :-)

wonder-sk commented 6 years ago

The workshop for working with temporal data in GRASS is also worth checking out: http://ncsu-geoforall-lab.github.io/grass-temporal-workshop/

nyalldawson commented 6 years ago

@wonder-sk

The next thing is what the timestamps actually mean - are they concrete instances of time ("absolute") or are they relative times that do not have a reference time? Relative times are common for simulations.

I would say we always use absolute time. For sources with relative time, you could either

  1. Set a time adjustment via the layer properties, e.g. set the "start" or "end" time for the layer. or
  2. Leave the time as completely relative, in which case the times are made absolute by adding them to an "origin" time for the project. (So e.g. changing the "start" time for the project time slider would then shift all relative data source times accordingly.)

But ultimately, we should transform all relative time values into an absolute time to allow a common timeframe across all project sources.

Things get more interesting when there are multiple temporally enabled layers in a project, possibly with different temporal domains - how do we work with them? I assume there would be just one time slider, and users would pick which temporal layers are static (fixed to a time instance/interval) and which are transient (moving with the time slider).

I might be misinterpreting, but I'd envisage temporal support will always be "opt in" for layers. E.g. you'd go to layer properties, and tick a "temporal" check box (and then setup start time/end time fields, time offsets, time zones, etc). And ANY layer which has been temporally enabled would be affected by the time slider. Non-temporal enabled data sources would be handled manually, e.g. like how mesh datasets are currently handled in master. These are static and not impacted by the time slider. So basically we have a single temporal domain per project.

a temporal point layer with vehicle movement where point positions would get interpolated

For reference, the Time Manager plugin currently supports this.

When we get to animating things, it will be probably also good to make distinction between the animation time and the current map time (or interval). For example the animation for 3D view does not need to be related to temporal data - it can simply animate camera within one time instance of the map (a static scene).

Good point!

kbevers commented 6 years ago

I think this is a very interesting proposal. I also think that it goes a bit deeper than initially suggested, although the discussion is starting to unveil the depths of what is needed for temporal support. So here's something that falls under the "further considerations/improvements" category. I have previously been advocating for QGIS adopting spatiotemporal coordinates. It seems to me that doing so would help implement some of the ideas presented here. You would get an obvious place to put the timestamps and you would be able to delegate most of the work to PROJ. After all, keeping track of time is one of the core disciplines within geodesy.

The next thing is what the timestamps actually mean - are they concrete instances of time ("absolute") or are they relative times that do not have a reference time? Relative times are common for simulations.

This is the sort of stuff that the GDALbarn work will make it simpler to deal with. WKT2 CRS descriptions include options for describing the temporal reference frame.

But ultimately, we should transform all relative time values into an absolute time to allow a common timeframe across all project sources.

This is an obvious job for PROJ, handling transformations between different time frames. Of course this is not something we can do just yet but if it is necessary for QGIS and other projects it can be prioritized. I am happy to mentor this if someone from the QGIS community should have an interest in contribution such code.

Of course I am aware that what I am proposing will be slowing development down so I don't expect it to happen at this time. I just want to highlight the potential synergies here and let you know what's to come in the future for PROJ, in case you were not aware.

anitagraser commented 6 years ago

I have previously been advocating for QGIS adopting spatiotemporal coordinates.

Thanks @kbevers, I just wanted to suggest the same thing and add to @wonder-sk's list that a vector layer use case can also be trajectories of moving objects. If we could work out how to deal with spatio-temporal features, such as trajectories, that would be a huge step forward for GIS.

QGIS Desktop WMS-T client support

TimeManager does support WMS-T but it's not pretty :-|

pcav commented 6 years ago

timestamptz? https://www.postgresql.org/docs/11/static/datatype-datetime.html

nyalldawson commented 6 years ago

@kbevers

I think this is a very interesting proposal. I also think that it goes a bit deeper than initially suggested, although the discussion is starting to unveil the depths of what is needed for temporal support. So here's something that falls under the "further considerations/improvements" category. I have previously been advocating for QGIS adopting spatiotemporal coordinates. It seems to me that doing so would help implement some of the ideas presented here. You would get an obvious place to put the timestamps and you would be able to delegate most of the work to PROJ. After all, keeping track of time is one of the core disciplines within geodesy.

Good point -- I'd neglected the potential requirement for dynamic transforms to also consider timestamps. I'll add it to the QEP text.

nyalldawson commented 6 years ago

@anitagraser

I just wanted to suggest the same thing and add to @wonder-sk's list that a vector layer use case can also be trajectories of moving objects. If we could work out how to deal with spatio-temporal features, such as trajectories, that would be a huge step forward for GIS.

Also added, thanks!

nyalldawson commented 6 years ago

Ok, in order to keep this moving and avoid it becoming just a wishlist dumping ground, I'd like to propose that as a first step toward time handling we:

    /**
     * Sets a temporal \a range to restrict the data displayed within map renders to a specific time range.
     *
     * If no temporal range is set, or if a default constructed QgsDataTimeRange is used, then data from
     * all time periods will be included. 
     *
     * \see temporalRange()
     * \since QGIS 3.4
    */
    void setTemporalRange( const QgsDateTimeRange& range );

    /**
     * Returns the current temporal range used to restrict the data displayed within map renders to a specific time range.
     *
     * If no temporal range is set a default constructed QgsDataTimeRange will be returned, and data from
     * all time periods will be included.
     *
     * \see setTemporalRange()
     * \since QGIS 3.4
    */
    const QgsDateTimeRange& temporalRange() const;
    /**
     * Sets the map layer as a temporal layer, which will be considered when rendering maps with a specific time range set.
     *
     * If the map layer is not set as temporal, then any other temporal settings relating to the map will be ignored during rendering.
     *
     * \see isTemporal()
     * \since QGIS 3.4
    */
    void setIsTemporal( bool enabled );

    /**
     * Returns true if the map layer is a temporal layer, and will be filtered when rendering maps with a specific time range set.
     *
     * If false is returned, then any other temporal settings relating to the map will be ignored during rendering.
     *
     * \see setIsTemporal()
     * \since QGIS 3.4
    */
    bool isTemporal() const;
    /**
     * Sets a temporal \a range to restrict the layer visibility only for map renders which intersect this time range.
     *
     * \note Temporal based visibility is only considered when isTemporal() returns true.
     *
     * \see temporalRange()
     * \since QGIS 3.4
    */
    void setTemporalRange( const QgsDateTimeRange& range );

    /**
     * Returns the temporal range used to restrict the layer visibility only for map renders which intersect this time range.
     *
     * \note Temporal based visibility is only considered when isTemporal() returns true.
     *
     * \see setTemporalRange()
     * \since QGIS 3.4
    */
    const QgsDateTimeRange& temporalRange() const;

This would initially meet the use cases of:

(Obviously, this is the core API changes only - and we'd need to expose these settings in the UI and implement the time slider).

Any objections to locking this in as a first step?

pcav commented 6 years ago

No objection from my side.

anitagraser commented 6 years ago

This means that the whole layer will have a timestamp or timerange, instead of each feature having its own timestamp, right?

Vectors: several layers with the same attributes, recording state of objects at the time (or interval) of the layer (the time may come from layer's name or metadata)

nyalldawson commented 6 years ago

@anitagraser

This means that the whole layer will have a timestamp or timerange, instead of each feature having its own timestamp, right?

Correct - I'm just trying here to address the simplest use case first so that we can get the fundamental questions decided (like absolute vs relative time) without getting bogged down on the details of the more complex use cases. API for per feature timestamps will be on top of the per layer timestamp API.

nyalldawson commented 6 years ago

@wonder-sk @PeterPetrik please speak up quickly if you have feedback regarding https://github.com/qgis/QGIS-Enhancement-Proposals/issues/128#issuecomment-406470936 - I don't want work to commence on this if you have objections

PeterPetrik commented 6 years ago

@nyalldawson looks good +1

As a side note I am not sure about the mesh and raster layers and situation when QgsDateTimeRange is range of times (i.e. start to end time). I can imagine that when you have a vector layer with earthquakes (location + time), you can nicely display all earthquakes in last 2 years on the map. I am not that sure what would be the result for raster layers or mesh layers.

rduivenvoorde commented 6 years ago

@PeterPetrik I do not get your point, if I'm correct a QgsDateTimeRange can hold both a range OR one timestamp (when both start and and are identical).

So in that case it can be used for eg weather grib files isn't it? Or for wmts services or even for raster image mosaics with a timestamp in their filename?

Or are you referring to the fact that a TimeRange can only hold start and end? And is not aware (yet) of the good or possible 'timesteps' (eg is in case of distinct, not even distributed time points). This wmts leaflet plugin has some pointers to ISO_8601 standard notations and forms for Time Intervals and Time Durations.

I would think that in future QgsDateTimeRange (or an higher order object) will get more and more able to hold all those use cases?

PeterPetrik commented 6 years ago

Let say I have 30 weather GRIB files, each representing a temperature of the same area in different days during one month. It is obvious what I get when I want to render QgsDateTimeRange=timestamp(10.Jan.2018). But what is the resulting image when I want to render first week QgsDateTimeRange=range(1.Jan.2018-7.Jan.2018)? Is it some kind of animation or merge of all individual images?

rduivenvoorde commented 6 years ago

@PeterPetrik @nyalldawson I think how the resulting image (aka the mapcanvas via the mapsettings) is handling all the different use cases, is up to some intelligent 'player/timehandler'.

That object has to be able to decide what to do when you have several layers with different kind of time ranges OR points in time. The above leaflet plugin for example has possibilities to either find out the max and min, or do an union of the times or a slice etc. And myself I had use cases where I needed a player (aka the time slider) in which I could set and change the range (so individually move the start and time gripper) and after that move the resulting range as a whole on distinct time points.

The case you describe above could be handled in the same way as Geoserver handles an 'image mosaic', that is if you sent one TimeStamp it will only show you those gribs/rasters which have exact that TimeStamp in their layer info. If you sent a TimeRange, it will collect all gribs/rasters and merge them. OR IF you want (now looking at you grib) an animation you have to have some 'player' which shows only one (or a small set) of layers at a time, by showing a moving range (see the LeafLet plugin examples for some nice use cases and examples).

Handling time data is a box of pandora :-)

nyalldawson commented 4 years ago

Following on from a joint conference call last week with myself, @PeterPetrik , @timlinux , @anitagraser and @saberraz and @samweli - it was agreed that the core changes described in this QEP were acceptable and that requiring an absolute datetime range on the QgsMapSettings/QgsRenderContext level is appropriate.

It will be the individual map layer subclass' responsibility to transform any relative datetimes (or non-datetime values) into an absolute datetime for use in map renders, using a method which is suitable for that layer type (and exposing any user-facing settings for controlling this behavior as deemed necessary)

whatnick commented 4 years ago

I have a lot of WMS Time Based servers running in OWS. Keen to test and contribute.

Here is a sample one from the Digital Earth Africa project : https://ows.digitalearth.africa/?request=getcapabilities&service=wms

Nic-Rosengren commented 4 years ago

Is there any possibility of addition of time in Millions of years before present? Geochronological data its typically presented in the form XXX.xx Ma (eg 144.7 Ma) being 144.7 million years ago. It would be great to be able to step through this data which i currently cant see how to do?

vmora commented 4 years ago

Thanks @Nic-Rosengren, I had fun trying to go back in time with postgresql date type and overflowed at '4714-12-31 BC', even archeologists will be frustrated with that.