OGC Testbed 14 Demonstrator - CloudSat profiles

Welcome to the OGC Testbed 14 demonstrator showing CloudSat 2B-GEOPROF profiles via Web Coverage Service (WCS) and its Earth Observation application profile (EO-WCS) in a browser based highly interactive client.

In the following the demonstrated CloudSat Use Case is motivated, requirements derived, available standards reviewed, and updates and extensions proposed.

Use case CloudSat

In this use case we want to visualize CloudSat 2B- GEOPROF profiles in a web browser both on a globe or map as well as in an analytics, i.e., tabular view as shown in the screenshots below. The visualizations shall be highly interactive and provide the user with various options to adjust it. Just click on one of the three screenshots to try it yourself.

The OGC standardized Web Coverage Service (WCS) shall be used by the web browser to obtain the data to be displayed. The following sections motivate and derive the particular requirements for WCS, analyze existing versions and extensions for their suitability, and provide suggestions for updates and extensions where necessary. While for some use cases pre-rendered visualizations are sufficient in our use case real values are needed mainly for the analytics view.

Screenshots

Demonstration at launch

Demonstration at launch

Values filtered and different style applied

Values filtered and different style applied

2.5D view

2.5D view

General view

The main functions to adjust the visualization are the subsetting of the data to be shown. Subsetting can be performed in time via the timeslider (selected time interval in bottom in screenshots above), spatially via globe or map view (left part), and in actual parameter values via analytics view (selection on histograms in lower part of analytics view on the right).

Timeslider view

The timeslider is shown in the bottom of the above screenshots. It is highly interactive allowing to zoom and pan in time as well as to jump to particular dates via the picker (top right corner of timeslider). While navigating the timeslider it gives an indication about data availability (blue rectangles). Hovering over these indication shows the product id.

Once the time of interest is visible it allows to select the time interval for which data shall be visualized simply by click and hold on the timeslider. The current selection is highlighted with gray background and can be adjusted at the ends as needed. Alternatively the user can click on the availability indication for a quick selection.

Any change of the time selection triggers a refresh of the data visualizations and prior data download as necessary.

Globe view

The globe view is shown in the left part of the first two screenshots above. It can be changed to a 2.5D map view which is shown in the third screenshot above. As on a standard map the data would only be visible as footprint curves the map view uses a 2.5D view. Both views are highly interactive allowing to zoom, pan, tilt, and rotate the globe or map.

All data available in the selected time interval is shown. The rendering itself like selected parameter, color-scale, or opacity is configured using the product settings accessibly via the Layers button in the top menu.

The globe view is based on Cesium and geotiff.js.

Analytics view

The analytics view also shows the currently selected parameter of the product like on the globe view. It is again highly interactive allowing to zoom and pan on both or individual axes.

The parameter histograms on the bottom allow subsetting in actual parameter values. The subsetting is applied to all views particularly globe and analytics view.

By default the axes are showing time horizontally and height vertically. This can be changed to show for example the parameter values horizontally.

While it is recommended to perform the time and spatial subsets by the data interface, i.e., on the server, the parameter value subset can be performed directly in the client.

The analytics view is based on D3, graphly, and geotiff.js.

Product settings

The product settings allow to configure the rendering.

The first thing is to selected the parameter to visualize. In case of CloudSat 2B-GEOPROF this is either radar reflectivity, gaseous attenuation, or CPR cloud mask.

Second the color-scale and value range to use can be adjusted. A slider allows to configure the opacity.

In the globe view the Outline showing the footprint and direction of the curtain as well as the legend can be enabled or disabled.

The analytics view can be configured separately if needed using the cog icon.

Requirements

The following requirements for WCS as the data or download service as well as the data format to be used are derived from the above visualization client description.

Service requirements

The service shall support …

  1. … retrieval of product metadata needed to fill the timeslider view and the map view
  2. … parameter subsetting, i.e., retrieving of individual parameters
  3. … product subsetting in time
  4. … spatial product subsetting, i.e., subsetting in latitude and longitude
  5. … retrieval of “overviews” for performance optimization

Format requirements

The data format shall be …

  1. … self-describing to specify for example if the data is encoded as pixel-in-center or pixel-in-corner
  2. … readable and interpretable in modern web browsers with existing libraries

Analysis of WCS

Retrieval of metadata

The standard WCS DescribeCoverage response contains all information needed to satisfy requirement 1. However, there are two drawbacks. First, the DomainSet will be quite huge or at least equal compared to the actual data and second the DescribeCoverage operation doesn’t support searching in time and space.

The metadata needed by the client is ID, start, stop, and bounding box or better footprint. Additionally often the envelope in physical dimensions will not be sufficient and clients may need to know the grid size or size of the mathematical dimensions of the DomainSet. In case of a GeneralGrid this information is present in the GridLimits element.

To overcome the second point the DescribeEOCoverageSet request of the Earth Observation application profile of WCS can be used. All 2B-GEOPROF products are grouped in a DatasetSeries which is then used in DescribeEOCoverageSet requests to get only the metadata to fill the currently visible time interval and spatial extent.

There is currently no way to retrieve coverage metadata restricting the potentially huge DomainSet. Thus avoiding unnecessary big downloads, the client would either need to query a synchronized catalog or a change of the DescribeCoverage operation allowing to limit the response.

We propose to allow providing the DomainSet axes information as coverages themselves via OGC Web Services Context (OWC) mechanism. This way the DomainSet stays as small as possible still providing the needed metadata. Additionally by providing the axes information as coverages themselves allows to directly subset the domain. This way clients really have a means to only download the needed information at the cost of additional GetCoverage requests to the DomainSet coverages.

A discarded idea was to add a boolean parameter named restrictDomainSet to the DescribeCoverage and DescribeEOCoverageSet operations. Omitting this new parameter or using a value of False yields the current behavior whereas a value of True only returns the GridLimits part of the GeneralGrid of the DomainSet omitting the remainder.

An additional idea, obsolete with the proposed solution, is to allow the same subsetting parameters in the DescribeCoverage operation than in the GetCoverage one subsetting the DomainSet itself. This would allow to retrieve only relevant parts of the DomainSet in the same way as the RangeSet.

Note that a general XPath extension to WCS has been discussed and proposed by the WCS.SWG. This extension would allow clients to retrieve any subset of XML responses according to XPath queries. However, this proposed extension is been held back by OAB as it is seen as potentially beneficial to more OGC services and should get a broader scope.

Parameter subsetting

Requirement 2. is simply satisfied by the band subsetting extension of WCS.

Time and spatial subsetting

Trimming and slicing of any axis defined in the DomainSet is standardized in the core of WCS. The difficulty with the data at hand is to define a suitable DomainSet that contains time and spatial axes in order to support requirements 3. and 4.

The 2B-GEOPROF data provides the parameters in a 2D grid with size 125 x nray where nray is typically around 20.000. Each of the approximately 20.000 columns has latitude, longitude, and time values that are equal for the whole column. On the other side, each grid point has its own height value, i.e., there is no uniformity in the 125 height elements.

The challenge is to model the 2D data grid in the 4D CRS grid.

This is not possible using CIS 1.0, even including the ReferenceableGridCoverage extension, as there is no way to “get rid” of CRS axes in order to describe the 2D grid in the 4D CRS.

Using CIS 1.1 there is the GeneralGrid together with DisplacementAxisNest and IrregularAxis. However, only the DisplacementAxisNest supports to “get rid” of axes but which would unnecessarily blow up the DomainSet description as values for each individual 4D CRS grid element would have to explicitly be provided. Or in other words, the conformity of the 2D columns cannot be exploited and instead of providing latitude, longitude, and time each “only” approximately 20.000 times this would blow up to multiplying this 125 times:

<DomainSet>
    <GeneralGrid srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate" axisLabels="Lat Long h date">

        <DisplacementAxisNest axisLabels="Lat Long date h" uomLabels="deg deg d m">
            <P><C>-69.35112</C><C>171.2182</C><C>46293.594+0.0</C><C>24927</C></P>
            <P><C>-69.35112</C><C>171.2182</C><C>46293.594+0.0</C><C>24687</C></P>
            ...
            <P><C>-69.35112</C><C>171.2182</C><C>46293.594+0.0</C><C>-4812</C></P>

            <P><C>-69.35994</C><C>171.20651</C><C>46293.594+0.15999997</C><C>24929</C></P>
            <P><C>-69.35994</C><C>171.20651</C><C>46293.594+0.15999997</C><C>24689</C></P>
            ...
            <P><C>-69.35994</C><C>171.20651</C><C>46293.594+0.15999997</C><C>-4810</C></P>

            ... 125 x 20753 <P> elements with 4 <C> elements each in total

        </DisplacementAxisNest>

        <GridLimits srsName="http://www.opengis.net/def/crs/OGC/0/Index2D" axisLabels="i j">
            <IndexAxis axisLabel="i" lowerBound="0" upperBound="20752"/>
            <IndexAxis axisLabel="j" lowerBound="0" upperBound="124"/>
        </GridLimits>
    </GeneralGrid>
</DomainSet>

In order not to unnecessarily blow up the DomainSet an IrregularAxisNest element similar to DisplacementAxisNest and allowing to exploit the conformity of the columns is proposed as follows:

<DomainSet>
    <GeneralGrid srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate" axisLabels="Lat Long h date">

        <IrregularAxisNest axisLabels="Lat Long date" uomLabels="deg deg d">
            <P><C>-69.35112</C><C>171.2182</C><C>46293.594+0.0</C></P>
            <P><C>-69.35994</C><C>171.20651</C><C>46293.594+0.15999997</C></P>

            ... 20753 <P> elements with 3 <C> elements each in total

        </IrregularAxisNest>

        <DisplacementAxisNest axisLabels="h" uomLabels="m">
            <P><C>24927</C></P>
            <P><C>24687</C></P>

            ... 125 x 20753 <P> elements with 1 <C> element each in total

        </DisplacementAxisNest>

        <GridLimits srsName="http://www.opengis.net/def/crs/OGC/0/Index2D" axisLabels="i j">
            <IndexAxis axisLabel="i" lowerBound="0" upperBound="20752"/>
            <IndexAxis axisLabel="j" lowerBound="0" upperBound="124"/>
        </GridLimits>
    </GeneralGrid>
</DomainSet>

Using this IrregularAxisNest extension would allow instead of 125 x 20753 P elements with 4 C elements each to have only 20753 P with 3 C elements and 125 x 20753 P with one C elements, resulting in 2.656.384 instead of 10.376.500 elements or a reduction of almost 75%.

In combination with our proposal from the “Retrieval of metadata” chapter we believe to have a really elegant solution available. The DomainSet axes are provided as coverages themselves via OWC mechanism. The contents of the DisplacementAxisNest element are provided as an Index2D coverage holding all the height values and the IrregularAxisNest element as three Index1D coverages corresponding to latitude, longitude, and date. This way the reported DomainSet stays small while supporting all required functionality even subsetting in the domain.

<DomainSet>
    <GeneralGrid axisLabels="Lat Long h date" srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate">
        <DisplacementAxisNest axisLabels="h" uomLabels="m">
            <owc:offering>
                <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_height&amp;format=image/tiff" method="GET" type="image/tiff"/>
            </owc:offering>
        </DisplacementAxisNest>
        <IrregularAxisNest axisLabels="Lat Long date" uomLabels="deg deg d">
            <owc:offering>
                <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_latitude&amp;format=text/csv" method="GET" type="text/csv"/>
            </owc:offering>
            <owc:offering>
                <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_longitude&amp;format=text/csv" method="GET" type="text/csv"/>
            </owc:offering>
            <owc:offering>
                <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_profile_time&amp;format=text/csv" method="GET" type="text/csv"/>
            </owc:offering>
        </IrregularAxisNest>
        <GridLimits axisLabels="i j" srsName="http://www.opengis.net/def/crs/OGC/0/Index2D">
            <IndexAxis axisLabel="i" lowerBound="0" upperBound="124"/>
            <IndexAxis axisLabel="j" lowerBound="0" upperBound="20752"/>
        </GridLimits>
    </GeneralGrid>
</DomainSet>

Another potential option is to have only lat, long, and time in the DomainSet as subsetting in height is not needed on the service level. That would mean having a 1D data grid in a 3D CRS grid and height in the RangeType. However, this would result in 125 x 4 elements in the RangeType, 3 parameters and the height itself for 125 different heights, and a need to specify how they relate to each other, i.e., which parameter values correspond to which height value. This idea is discarded as impractical.

Overviews

Requirement 5. targets performance optimization. A critical metric for performance is “First view” but also update after user interaction. Retrieving only overviews or lower resolution of the data reduces loading and rendering time. However, defining a general downsampling or downscaling algorithm suitable for any irregular grid is not a simple task. It seems easier to define an algorithm to map the irregular grid to a regular one and use the well-known scaling and interpolation extension on them.

The converted coverage has the number of axis from the data array or the mathematical dimensions, i.e., 2 in our case. The axes mapping from data array to CRS or physical dimensions needs to be defined in the GetCoverage operation.

The coverage description needs to include these details:

The GetCoverage operation needs to be extended by these parameters:

By default each axis will use its advertised resolution. This can be overwritten by using the mechanics of the scaling extension, e.g. via the size or resolution parameters.

Via this type conversion still the original potentially interpolated values are retrieved. Another optimization is to ask for complete renderings from the server but this is out of scope here and left to the Web Map Service (WMS). An integration like this between WCS and WMS could be addressed in one of the next testbeds.

Example WCS requests and responses

GetCapabilities
Request

http://ows.eox.at/testbed-14/eoxserver/ows?service=wcs&request=getcapabilities

Response

Note that only one coverage is directly visible here, all others are only listed in the advertised DatasetSeries.

GetCapabilities response - Contents part

<wcs:Contents>
    <wcs:CoverageSummary>
        <wcs:CoverageId>_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06</wcs:CoverageId>
        <wcs:CoverageSubtype>ReferenceableDataset</wcs:CoverageSubtype>
    </wcs:CoverageSummary>
    <wcs:Extension>
        <wcseo:DatasetSeriesSummary>
            <ows:WGS84BoundingBox>
                <ows:LowerCorner>-81.826141 -179.999786</ows:LowerCorner>
                <ows:UpperCorner>81.825691 180.000000</ows:UpperCorner>
            </ows:WGS84BoundingBox>
            <wcseo:DatasetSeriesId>cloudsat-2b-geoprof</wcseo:DatasetSeriesId>
            <gml:TimePeriod gml:id="cloudsat-2b-geoprof_timeperiod">
                <gml:beginPosition>2017-11-26T01:26:03Z</gml:beginPosition>
                <gml:endPosition>2017-12-05T13:46:54Z</gml:endPosition>
            </gml:TimePeriod>
        </wcseo:DatasetSeriesSummary>
    </wcs:Extension>
</wcs:Contents>
DescribeCoverage
Request

http://ows.eox.at/testbed-14/eoxserver/ows?service=wcs&request=describecoverage&version=2.1.0&coverageid=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06

Response
<?xml version='1.0' encoding='iso-8859-1'?>
<wcs21:CoverageDescriptions xmlns:cis10="http://www.opengis.net/gmlcov/1.0" xmlns:cis11="http://www.opengis.net/cis/1.1/gml" xmlns:crs="http://www.opengis.net/wcs/crs/1.0" xmlns:eop="http://www.opengis.net/eop/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:int="http://www.opengis.net/wcs/interpolation/1.0" xmlns:ogc="http://www.opengis.net/ogc" xmlns:om="http://www.opengis.net/om/2.0" xmlns:owc="http://www.opengis.net/owc/1.0" xmlns:ows="http://www.opengis.net/ows/2.0" xmlns:rsub="http://www.opengis.net/wcs/range-subsetting/1.0" xmlns:scal="http://www.opengis.net/wcs/scaling/1.0" xmlns:swe="http://www.opengis.net/swe/2.0" xmlns:wcs20="http://www.opengis.net/wcs/2.0" xmlns:wcs21="http://www.opengis.net/wcs/2.1/gml" xmlns:wcseo="http://www.opengis.net/wcs/wcseo/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wcs/2.1/gml http://schemas.opengis.net/wcs/2.1/gml/wcsAll.xsd http://www.opengis.net/wcs/wcseo/1.1 http://schemas.opengis.net/wcs/wcseo/1.1/wcsEOAll.xsd">
    <wcs21:CoverageDescription gml:id="_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
        <cis11:Envelope axisLabels="Lat Long h date" srsDimension="4" srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate">
            <cis11:AxisExtent axisLabel="Lat" lowerBound="-81.804718005" uomLabel="deg" upperBound="81.819176005"/>
            <cis11:AxisExtent axisLabel="Long" lowerBound="-105.844330005" uomLabel="deg" upperBound="171.218201005"/>
            <cis11:AxisExtent axisLabel="h" lowerBound="-4917" uomLabel="m" upperBound="25062"/>
            <cis11:AxisExtent axisLabel="date" lowerBound="2017-12-05 12:51:34+00:00" uomLabel="d" upperBound="2017-12-05 13:46:54+00:00"/>
        </cis11:Envelope>
        <cis11:Metadata>
            <wcseo:EOMetadata>
                <eop:EarthObservation gml:id="eop__2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                    <om:phenomenonTime>
                        <gml:TimePeriod gml:id="phen_time__2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                            <gml:beginPosition>2017-12-05T12:51:34Z</gml:beginPosition>
                            <gml:endPosition>2017-12-05T13:46:54Z</gml:endPosition>
                        </gml:TimePeriod>
                    </om:phenomenonTime>
                    <om:resultTime>
                        <gml:TimeInstant gml:id="res_time__2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                            <gml:timePosition>2017-12-05T13:46:54Z</gml:timePosition>
                        </gml:TimeInstant>
                    </om:resultTime>
                    <om:procedure/>
                    <om:observedProperty/>
                    <om:featureOfInterest>
                        <eop:Footprint gml:id="footprint__2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                            <eop:multiExtentOf>
                                <gml:MultiGeometry gml:id="multi_geom__2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                                    <gml:geometryMember>
                                        <gml:LineString gml:id="line_string__2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                                            <gml:posList>-69.35112000 171.21820100 -72.20041700 166.82487500 -74.59602400 161.78387500 -76.56911500 156.05653400 -78.20853400 149.39813200 -79.54218300 141.63066100 -80.56026500 132.82167100 -81.29612700 122.66144600 -81.71841400 111.47950700 -81.80471800 98.71207400 -81.50271600 86.33461000 -80.84779400 75.18617200 -79.84094200 65.24035600 -78.51689100 56.79996100 -76.86551700 49.63352200 -74.81656600 43.41619500 -72.37244400 38.13395300 -70.43242600 34.94118900 -68.27170600 32.06703200 -65.81163800 29.40571200 -63.02435700 26.94187900 -59.90953100 24.67566100 -56.42108200 22.56763300 -52.50247200 20.58208100 -48.13398400 18.70537400 -38.92371700 15.49581600 -27.36452300 12.29165700 -14.59577400 9.28638400 21.07567600 1.50471200 31.00457800 -0.96263000 39.27206000 -3.33139700 47.68225900 -6.25287200 54.66089600 -9.35745900 57.69982900 -11.01993600 60.43932300 -12.75421800 62.92651000 -14.58539600 65.21673600 -16.55822400 67.70516200 -19.12450800 69.87683900 -21.86276600 71.83847800 -24.90299400 73.58805100 -28.26239800 75.13224800 -31.95952200 76.50169400 -36.07752200 77.67155500 -40.52152600 78.70601700 -45.53061700 79.62034600 -51.29109200 80.37684600 -57.65340000 81.41947200 -72.14802600 81.81917600 -89.00888100 81.51007800 -105.84433000</gml:posList>
                                        </gml:LineString>
                                    </gml:geometryMember>
                                </gml:MultiGeometry>
                            </eop:multiExtentOf>
                        </eop:Footprint>
                    </om:featureOfInterest>
                    <om:result/>
                    <eop:metaDataProperty>
                        <eop:EarthObservationMetaData>
                            <eop:identifier>_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06</eop:identifier>
                            <eop:acquisitionType>NOMINAL</eop:acquisitionType>
                            <eop:status>ARCHIVED</eop:status>
                        </eop:EarthObservationMetaData>
                    </eop:metaDataProperty>
                </eop:EarthObservation>
            </wcseo:EOMetadata>
        </cis11:Metadata>
        <cis11:DomainSet>
            <cis11:GeneralGrid axisLabels="Lat Long h date" srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate">
                <cis11:DisplacementAxisNest axisLabels="h" uomLabels="m">
                    <owc:offering>
                        <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_height&amp;format=image/tiff" method="GET" type="image/tiff"/>
                    </owc:offering>
                </cis11:DisplacementAxisNest>
                <cis11:IrregularAxisNest axisLabels="Lat Long date" uomLabels="deg deg d">
                    <owc:offering>
                        <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_latitude&amp;format=text/csv" method="GET" type="text/csv"/>
                    </owc:offering>
                    <owc:offering>
                        <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_longitude&amp;format=text/csv" method="GET" type="text/csv"/>
                    </owc:offering>
                    <owc:offering>
                        <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017339123204_61738_CS_2B-GEOPROF_GRANULE_P_R04_E06_profile_time&amp;format=text/csv" method="GET" type="text/csv"/>
                    </owc:offering>
                </cis11:IrregularAxisNest>
                <cis11:GridLimits axisLabels="i j" srsName="http://www.opengis.net/def/crs/OGC/0/Index2D">
                    <cis11:IndexAxis axisLabel="i" lowerBound="0" upperBound="124"/>
                    <cis11:IndexAxis axisLabel="j" lowerBound="0" upperBound="20752"/>
                </cis11:GridLimits>
            </cis11:GeneralGrid>
        </cis11:DomainSet>
        <cis11:RangeType>
            <swe:DataRecord>
                <swe:field name="Radar_Reflectivity">
                    <swe:Quantity definition="http://www.opengis.net/def/property/netcdf/1.0/short">
                        <swe:description>Radar Reflectivity Factor</swe:description>
                        <swe:nilValues>
                            <swe:NilValues>
                                <swe:nilValue reason="fill value">15360</swe:nilValue>
                                <swe:nilValue reason="missing">-8888</swe:nilValue>
                            </swe:NilValues>
                        </swe:nilValues>
                        <swe:uom code="dBZe"/>
                        <swe:constraint>
                            <swe:AllowedValues>
                                <swe:interval>-32768 32767</swe:interval>
                                <swe:significantFigures>5</swe:significantFigures>
                            </swe:AllowedValues>
                        </swe:constraint>
                    </swe:Quantity>
                </swe:field>
                <swe:field name="Gaseous_Attenuation">
                    <swe:Quantity definition="http://www.opengis.net/def/property/netcdf/1.0/short">
                        <swe:description>Gaseous Attenuation</swe:description>
                        <swe:nilValues>
                            <swe:NilValues>
                                <swe:nilValue reason="fill value">15360</swe:nilValue>
                                <swe:nilValue reason="missing">-9999</swe:nilValue>
                            </swe:NilValues>
                        </swe:nilValues>
                        <swe:uom code="dBZe"/>
                        <swe:constraint>
                            <swe:AllowedValues>
                                <swe:interval>-32768 32767</swe:interval>
                                <swe:significantFigures>5</swe:significantFigures>
                            </swe:AllowedValues>
                        </swe:constraint>
                    </swe:Quantity>
                </swe:field>
                <swe:field name="CPR_Cloud_mask">
                    <swe:Quantity definition="http://www.opengis.net/def/property/netcdf/1.0/byte">
                        <swe:description>CPR Cloud mask</swe:description>
                        <swe:nilValues>
                            <swe:NilValues>
                                <swe:nilValue reason="fill value">-99</swe:nilValue>
                                <swe:nilValue reason="missing">-9</swe:nilValue>
                            </swe:NilValues>
                        </swe:nilValues>
                        <swe:uom code="various"/>
                        <swe:constraint>
                            <swe:AllowedValues>
                                <swe:interval>-128 127</swe:interval>
                                <swe:significantFigures>3</swe:significantFigures>
                            </swe:AllowedValues>
                        </swe:constraint>
                    </swe:Quantity>
                </swe:field>
            </swe:DataRecord>
        </cis11:RangeType>
        <wcs20:ServiceParameters>
            <wcs20:CoverageSubtype>ReferenceableDataset</wcs20:CoverageSubtype>
            <wcs20:nativeFormat/>
        </wcs20:ServiceParameters>
    </wcs21:CoverageDescription>
</wcs21:CoverageDescriptions>
DescribeEOCoverageSet
Request

http://ows.eox.at/testbed-14/eoxserver/ows?service=wcs&request=describeeocoverageset&version=2.1.0&eoid=cloudsat-2b-geoprof&count=2

Response
<?xml version='1.0' encoding='iso-8859-1'?>
<wcseo:EOCoverageSetDescription numberMatched="110" numberReturned="2" xmlns:cis10="http://www.opengis.net/gmlcov/1.0" xmlns:cis11="http://www.opengis.net/cis/1.1/gml" xmlns:crs="http://www.opengis.net/wcs/crs/1.0" xmlns:eop="http://www.opengis.net/eop/2.0" xmlns:gml="http://www.opengis.net/gml/3.2" xmlns:int="http://www.opengis.net/wcs/interpolation/1.0" xmlns:ogc="http://www.opengis.net/ogc" xmlns:om="http://www.opengis.net/om/2.0" xmlns:owc="http://www.opengis.net/owc/1.0" xmlns:ows="http://www.opengis.net/ows/2.0" xmlns:rsub="http://www.opengis.net/wcs/range-subsetting/1.0" xmlns:scal="http://www.opengis.net/wcs/scaling/1.0" xmlns:swe="http://www.opengis.net/swe/2.0" xmlns:wcs20="http://www.opengis.net/wcs/2.0" xmlns:wcs21="http://www.opengis.net/wcs/2.1/gml" xmlns:wcseo="http://www.opengis.net/wcs/wcseo/1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.opengis.net/wcs/2.1/gml http://schemas.opengis.net/wcs/2.1/gml/wcsAll.xsd http://www.opengis.net/wcs/wcseo/1.1 http://schemas.opengis.net/wcs/wcseo/1.1/wcsEOAll.xsd">
  <wcs21:CoverageDescriptions>
    <wcs21:CoverageDescription gml:id="_2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
      <cis11:Envelope axisLabels="Lat Long h date" srsDimension="4" srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate">
        <cis11:AxisExtent axisLabel="Lat" lowerBound="-81.809029005" uomLabel="deg" upperBound="81.747520005"/>
        <cis11:AxisExtent axisLabel="Long" lowerBound="-179.997971005" uomLabel="deg" upperBound="179.999924005"/>
        <cis11:AxisExtent axisLabel="h" lowerBound="-4917" uomLabel="m" upperBound="25062"/>
        <cis11:AxisExtent axisLabel="date" lowerBound="2017-11-26 01:26:03+00:00" uomLabel="d" upperBound="2017-11-26 02:21:23+00:00"/>
      </cis11:Envelope>
      <cis11:Metadata>
        <wcseo:EOMetadata>
          <eop:EarthObservation gml:id="eop__2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
            <om:phenomenonTime>
              <gml:TimePeriod gml:id="phen_time__2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                <gml:beginPosition>2017-11-26T01:26:03Z</gml:beginPosition>
                <gml:endPosition>2017-11-26T02:21:23Z</gml:endPosition>
              </gml:TimePeriod>
            </om:phenomenonTime>
            <om:resultTime>
              <gml:TimeInstant gml:id="res_time__2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                <gml:timePosition>2017-11-26T02:21:23Z</gml:timePosition>
              </gml:TimeInstant>
            </om:resultTime>
            <om:procedure/>
            <om:observedProperty/>
            <om:featureOfInterest>
              <eop:Footprint gml:id="footprint__2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                <eop:multiExtentOf>
                  <gml:MultiGeometry gml:id="multi_geom__2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                    <gml:geometryMember>
                      <gml:LineString gml:id="line_string__2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06">
                        <gml:posList>-70.57107500 -19.02876500 -72.95608500 -23.12391300 -74.96965800 -27.68832600 -76.68452500 -32.86287300 -78.14092300 -38.79295700 -79.36860700 -45.68719900 -80.32445500 -53.28407300 -81.05862400 -61.91464200 -81.55524400 -71.47969100 -81.80902900 -82.72042100 -81.74195900 -94.42089800 -81.35762000 -105.44789900 -80.67722300 -115.45625300 -79.72912600 -124.18916300 -78.50637100 -131.81683300 -76.99546800 -138.44665500 -75.19721200 -144.13668800 -73.72017700 -147.72169500 -72.03339400 -151.02590900 -70.14587400 -154.02436800 -68.04177100 -156.75308200 -65.67740600 -159.27084400 -63.00725200 -161.61686700 -60.04938500 -163.77551300 -56.72987400 -165.80380200 -53.06691700 -167.69465600 -48.99454100 -169.48965500 -44.41706800 -171.23025500 -39.31382000 -172.92388900 -27.32359500 -176.25831600 -11.21291900 -179.99797100 -11.20326200 179.99992400 13.26330500 174.74099700 25.79866400 171.83317600 36.86013800 168.86434900 45.82065600 165.92021200 49.93270500 164.29847700 53.61832000 162.62858600 56.95401000 160.87780800 59.97777200 159.02427700 62.72701600 157.04064900 65.18359400 154.94178800 67.39399000 152.69561800 69.40323600 150.25389100 71.32357800 147.43067900 73.04538700 144.33277900 74.59246100 140.90319800 75.95484200 137.15957600 77.14787300 133.07644700 78.19279500 128.59262100 79.10068500 123.66085100 79.89111300 118.13572700 81.11864500 104.80731200 81.74752000 89.32199900 81.73171200 72.74892400 81.05502300 57.08217600</gml:posList>
                      </gml:LineString>
                    </gml:geometryMember>
                  </gml:MultiGeometry>
                </eop:multiExtentOf>
              </eop:Footprint>
            </om:featureOfInterest>
            <om:result/>
            <eop:metaDataProperty>
              <eop:EarthObservationMetaData>
                <eop:identifier>_2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06</eop:identifier>
                <eop:acquisitionType>NOMINAL</eop:acquisitionType>
                <eop:status>ARCHIVED</eop:status>
              </eop:EarthObservationMetaData>
            </eop:metaDataProperty>
          </eop:EarthObservation>
        </wcseo:EOMetadata>
      </cis11:Metadata>
      <cis11:DomainSet>
        <cis11:GeneralGrid axisLabels="Lat Long h date" srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate">
          <cis11:DisplacementAxisNest axisLabels="h" uomLabels="m">
            <owc:offering>
              <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06_height&amp;format=image/tiff" method="GET" type="image/tiff"/>
            </owc:offering>
          </cis11:DisplacementAxisNest>
          <cis11:IrregularAxisNest axisLabels="Lat Long date" uomLabels="deg deg d">
            <owc:offering>
              <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06_latitude&amp;format=text/csv" method="GET" type="text/csv"/>
            </owc:offering>
            <owc:offering>
              <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06_longitude&amp;format=text/csv" method="GET" type="text/csv"/>
            </owc:offering>
            <owc:offering>
              <owc:operation code="GetCoverage" href="http://ows.eox.at/testbed-14/eoxserver/ows?service=WCS&amp;version=2.1.0&amp;request=GetCoverage&amp;coverageId=_2017330010611_61600_CS_2B-GEOPROF_GRANULE_P_R04_E06_profile_time&amp;format=text/csv" method="GET" type="text/csv"/>
            </owc:offering>
          </cis11:IrregularAxisNest>
          <cis11:GridLimits axisLabels="i j" srsName="http://www.opengis.net/def/crs/OGC/0/Index2D">
            <cis11:IndexAxis axisLabel="i" lowerBound="0" upperBound="124"/>
            <cis11:IndexAxis axisLabel="j" lowerBound="0" upperBound="20752"/>
          </cis11:GridLimits>
        </cis11:GeneralGrid>
      </cis11:DomainSet>
      <cis11:RangeType>
        <swe:DataRecord>
          <swe:field name="Radar_Reflectivity">
            <swe:Quantity definition="http://www.opengis.net/def/property/netcdf/1.0/short">
              <swe:description>Radar Reflectivity Factor</swe:description>
              <swe:nilValues>
                <swe:NilValues>
                  <swe:nilValue reason="fill value">15360</swe:nilValue>
                  <swe:nilValue reason="missing">-8888</swe:nilValue>
                </swe:NilValues>
              </swe:nilValues>
              <swe:uom code="dBZe"/>
              <swe:constraint>
                <swe:AllowedValues>
                  <swe:interval>-32768 32767</swe:interval>
                  <swe:significantFigures>5</swe:significantFigures>
                </swe:AllowedValues>
              </swe:constraint>
            </swe:Quantity>
          </swe:field>
          <swe:field name="Gaseous_Attenuation">
            <swe:Quantity definition="http://www.opengis.net/def/property/netcdf/1.0/short">
              <swe:description>Gaseous Attenuation</swe:description>
              <swe:nilValues>
                <swe:NilValues>
                  <swe:nilValue reason="fill value">15360</swe:nilValue>
                  <swe:nilValue reason="missing">-9999</swe:nilValue>
                </swe:NilValues>
              </swe:nilValues>
              <swe:uom code="dBZe"/>
              <swe:constraint>
                <swe:AllowedValues>
                  <swe:interval>-32768 32767</swe:interval>
                  <swe:significantFigures>5</swe:significantFigures>
                </swe:AllowedValues>
              </swe:constraint>
            </swe:Quantity>
          </swe:field>
          <swe:field name="CPR_Cloud_mask">
            <swe:Quantity definition="http://www.opengis.net/def/property/netcdf/1.0/byte">
              <swe:description>CPR Cloud mask</swe:description>
              <swe:nilValues>
                <swe:NilValues>
                  <swe:nilValue reason="fill value">-99</swe:nilValue>
                  <swe:nilValue reason="missing">-9</swe:nilValue>
                </swe:NilValues>
              </swe:nilValues>
              <swe:uom code="various"/>
              <swe:constraint>
                <swe:AllowedValues>
                  <swe:interval>-128 127</swe:interval>
                  <swe:significantFigures>3</swe:significantFigures>
                </swe:AllowedValues>
              </swe:constraint>
            </swe:Quantity>
          </swe:field>
        </swe:DataRecord>
      </cis11:RangeType>
      <wcs20:ServiceParameters>
        <wcs20:CoverageSubtype>ReferenceableDataset</wcs20:CoverageSubtype>
        <wcs20:nativeFormat/>
      </wcs20:ServiceParameters>
    </wcs21:CoverageDescription>
  </wcs21:CoverageDescriptions>
  <wcseo:DatasetSeriesDescriptions>
    <wcseo:DatasetSeriesDescription gml:id="cloudsat-2b-geoprof">
      <cis11:Envelope axisLabels="Lat Long h date" srsDimension="4" srsName="http://www.opengis.net/def/crs-compound?1=http://www.opengis.net/def/crs/EPSG/0/4979&amp;amp;2=http://www.opengis.net/def/crs/OGC/0/AnsiDate">
        <cis11:AxisExtent axisLabel="Lat" lowerBound="-81.826141005" uomLabel="deg" upperBound="81.825691005"/>
        <cis11:AxisExtent axisLabel="Long" lowerBound="-179.999786005" uomLabel="deg" upperBound="180.000000005"/>
        <cis11:AxisExtent axisLabel="h" lowerBound="-4917" uomLabel="m" upperBound="25062"/>
        <cis11:AxisExtent axisLabel="date" lowerBound="2017-11-26 01:26:03+00:00" uomLabel="d" upperBound="2017-12-05 13:46:54+00:00"/>
      </cis11:Envelope>
      <wcseo:DatasetSeriesId>cloudsat-2b-geoprof</wcseo:DatasetSeriesId>
      <gml:TimePeriod gml:id="cloudsat-2b-geoprof_timeperiod">
        <gml:beginPosition>2017-11-26T01:26:03Z</gml:beginPosition>
        <gml:endPosition>2017-12-05T13:46:54Z</gml:endPosition>
      </gml:TimePeriod>
    </wcseo:DatasetSeriesDescription>
  </wcseo:DatasetSeriesDescriptions>
</wcseo:EOCoverageSetDescription>
GetCoverage for DomainSet coverages
GetCoverage

A list of various GetCoverage requests needed for the use case is provided below.

Analysis of data formats

It seems any 2D raster data format would be suitable to transport the 2D data grid.

The first requirement of a self-describing format can be satisfied by including the coverage description. Together with the coverage description particularly the DomainSet clients need to interpret the data in order to display it correctly, i.e., not using square pixels. An alternative is the usage of HDF or NetCDF.

To comply with the second requirement, the usage in web browsers, any standard image format like JPEG or PNG can be used but also GeoTIFF and with limited support HDF or NetCDF. While JPEG or PNG can be interpreted by web browsers natively for GeoTIFF, HDF, and NetCDF Javascript libraries are needed like geotiff.js or ncjs.

Thus the actual choice is mainly based on performance considerations like compression ratio or file size for minimal bandwidth needs as well as time and effort needed to encode and decode.

Suggestions for extensions