Skip to content

Statistical query (group & sort)

View on GitHubSample viewer app

Query a feature table for statistics, grouping and sorting by different fields.

screenshot

Use case

You can use statistical queries, grouping and sorting to process large amounts of data saved in feature tables. This is helpful for identifying trends and relationships within the data, which can be used to support further interpretations and decisions. For example, a health agency can use information on medical conditions occurring throughout a country to identify at-risk areas or demographics, and decide on further action and preventive measures.

How to use the sample

The sample will start with some default options selected. You can immediately click the "Get Statistics" button to see the results for these options. There are several ways to customize your queries:

  • You can add statistic definitions to the top-left table using the combo boxes and "Add" button. Select a table row and click "Remove" to remove a definition.
  • To change the Group-by fields, check the box by the field you want to group by in the bottom-left list view.
  • To change the Order-by fields, select a Group-by field (it must be checked) and click the ">>" button to add it to the Order-by table. To remove a field from the Order-by table, select it and click the "<<" button. To change the sort order of the Order-by field, the cells of the "Sort Order" column are combo-boxes that may be either ASCENDING or DESCENDING.

How it works

  1. Create a ServiceFeatureTable using the URL of a feature service and load the table.
  2. Get the feature tables field names list with featureTable::getFields().
  3. Create StatisticDefinitions specifying the field to compute statistics on and the StatisticType to compute.
  4. Create StatisticsQueryParameters passing in the list of statistic definitions.
  5. To have the results grouped by fields, add the field names to the query parameters' groupByFieldNames collection.
  6. To have the results ordered by fields, create OrderBys, specifying the field name and SortOrder. Pass these OrderBys to the parameters' orderByFields collection.
  7. To execute the query, call featureTable::queryStatisticsAsync(queryParameters).
  8. Get the StatisticQueryResult. From this, you can get an iterator of StatisticRecords to loop through and display.

Relevant API

  • Field
  • OrderBy
  • QueryParameters
  • ServiceFeatureTable
  • StatisticDefinition
  • StatisticRecord
  • StatisticsQueryParameters
  • StatisticsQueryResult
  • StatisticType

About the data

This sample uses a Diabetes, Obesity, and Inactivity by US County feature layer hosted on ArcGIS Online.

Tags

correlation, data, fields, filter, group, sort, statistics, table

Sample Code

StatisticalQueryGroupSort.cppStatisticalQueryGroupSort.cppStatisticalQueryGroupSort.hOptionsPage.qmlResultsPage.qmlStatisticResultListModel.cppStatisticResultListModel.hStatisticalQueryGroupSort.qml
Use dark colors for code blocksCopy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 // [WriteFile Name=StatisticalQueryGroupSort, Category=Analysis] // [Legal] // Copyright 2017 Esri. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // [Legal]  #ifdef PCH_BUILD #include "pch.hpp" #endif // PCH_BUILD  // sample headers #include "StatisticResultListModel.h" #include "StatisticalQueryGroupSort.h"  // ArcGIS Maps SDK headers #include "CoreTypes.h" #include "Error.h" #include "Field.h" #include "OrderBy.h" #include "ServiceFeatureTable.h" #include "StatisticDefinition.h" #include "StatisticRecord.h" #include "StatisticRecordIterator.h" #include "StatisticsQueryParameters.h" #include "StatisticsQueryResult.h"  // Qt headers #include <QFuture> #include <QList> #include <QStringList> #include <QUuid> #include <QVariantList>  // STL headers #include <memory>  using namespace Esri::ArcGISRuntime;  StatisticalQueryGroupSort::StatisticalQueryGroupSort(QQuickItem* parent /* = nullptr */):  QQuickItem(parent),  m_resultsModel(new StatisticResultListModel(this)) { }  void StatisticalQueryGroupSort::init() {  qmlRegisterType<StatisticalQueryGroupSort>("Esri.Samples", 1, 0, "StatisticalQueryGroupSortSample"); }  void StatisticalQueryGroupSort::componentComplete() {  QQuickItem::componentComplete();   // Create the Service Feature Table  m_featureTable = new ServiceFeatureTable(QUrl("https://services.arcgis.com/jIL9msH9OI208GCb/arcgis/rest/services/Counties_Obesity_Inactivity_Diabetes_2013/FeatureServer/0"), this);  connectSignals();  m_featureTable->load();   // Setup default values for the Options page  addStatisticDefinition("Diabetes_Percent", "Average");  addStatisticDefinition("Diabetes_Percent", "Count");  addStatisticDefinition("Diabetes_Percent", "Standard Deviation");  addOrderBy("State", "Ascending");  m_statisticTypes << "Average" << "Count" << "Maximum" << "Minimum"  << "Standard Deviation" << "Sum" << "Variance";  emit statisticTypesChanged(); }  void StatisticalQueryGroupSort::connectSignals() {  connect(m_featureTable, &ServiceFeatureTable::doneLoading, this, [this](const Error& error)  {  if (!error.isEmpty())  return;   const auto fields = m_featureTable->fields();  for (const Field& field : fields)  {  m_fields << field.name();  }  emit fieldsChanged();  });   connect(m_featureTable, &ServiceFeatureTable::errorOccurred, this, [this](const Error& error)  {  if (error.isEmpty())  return;   m_resultsModel->clear();  addResultToModel("", QString("Error. %1").arg(error.message()));  }); }  void StatisticalQueryGroupSort::onQueryStatisticsCompleted_(StatisticsQueryResult* rawResult) {  // Delete rawResult when we leave local scope.  auto result = std::unique_ptr<StatisticsQueryResult>(rawResult);   if (!result)  return;   // clear previous results  m_resultsModel->clear();   // iterate the results and add to a model  StatisticRecordIterator iter = result->iterator();  while (iter.hasNext())  {  // get the statistic record  StatisticRecord* record = iter.next();   // get the group string  QStringList sectionStrings;  const QVariantMap& groupsMap = record->group();  for (auto it = groupsMap.cbegin(); it != groupsMap.cend(); ++it)  {  sectionStrings << QString("\"%1\":\"%2\"").arg(it.key(), it.value().toString());  }  const QString sectionString = sectionStrings.join(',');   // obtain the statistics  const QVariantMap& statsMap = record->statistics();  for (auto it = statsMap.cbegin(); it != statsMap.cend(); ++it)  {  const QString statString = QString("%1: %2").arg(it.key(), it.value().toString());  addResultToModel(sectionString, statString);  }  } }  void StatisticalQueryGroupSort::queryStatistics() {  // create the parameter object  StatisticsQueryParameters params;   // add the statistic definitions  QList<StatisticDefinition> statisticDefinitionList;  for (const QVariant& def : std::as_const(m_statisticDefinitions))  {  QVariantMap definitionMap = def.toMap();  StatisticDefinition statisticDefinition;  statisticDefinition.setOnFieldName(definitionMap["field"].toString());  statisticDefinition.setStatisticType(statisticStringToEnum(definitionMap["statistic"].toString()));  statisticDefinitionList.append(statisticDefinition);  }  params.setStatisticDefinitions(statisticDefinitionList);   // set the grouping fields  params.setGroupByFieldNames(m_groupingFields);   // add the order by objects  QList<OrderBy> orderByList;  for (const QVariant& ob : std::as_const(m_orderBys))  {  QVariantMap orderByMap = ob.toMap();  OrderBy orderBy;  orderBy.setFieldName(orderByMap["field"].toString());  orderBy.setSortOrder(orderStringToEnum(orderByMap["order"].toString()));  orderByList.append(orderBy);  }  params.setOrderByFields(orderByList);   // ignore counties with missing data  params.setWhereClause("\"State\" IS NOT NULL");   // execute the query  m_featureTable->queryStatisticsAsync(params).then(this, [this](StatisticsQueryResult* rawResult)  {  onQueryStatisticsCompleted_(rawResult);  }); }  void StatisticalQueryGroupSort::addStatisticDefinition(const QString& field, const QString& statistic) {  // only add if the definition does not already exist  for (const QVariant& def : std::as_const(m_statisticDefinitions))  {  QVariantMap definitionMap = def.toMap();  if (field == definitionMap["field"].toString())  {  if (statistic == definitionMap["statistic"].toString())  return;  }  }   // add the definition to the list  QVariantMap statisticDefinition;  statisticDefinition["field"] = field;  statisticDefinition["statistic"] = statistic;  m_statisticDefinitions.append(statisticDefinition);  emit statisticDefinitionsChanged(); }  void StatisticalQueryGroupSort::removeStatisticDefinition(int index) {  if (!m_statisticDefinitions.empty())  {  m_statisticDefinitions.removeAt(index);  emit statisticDefinitionsChanged();  } }  void StatisticalQueryGroupSort::addOrderBy(const QString& field, const QString& order) {  // only add if the orderby is not in the list  for (const QVariant& orderBy : std::as_const(m_orderBys))  {  QVariantMap orderByMap = orderBy.toMap();  if (field == orderByMap["field"].toString())  {  if (order == orderByMap["order"].toString())  {  emit orderBysChanged();  return;  }  }  }   // add the order by to the list  QVariantMap orderBy;  orderBy["field"] = field;  orderBy["order"] = order;  m_orderBys.append(orderBy);  emit orderBysChanged(); }  void StatisticalQueryGroupSort::removeOrderBy(const QString& field) {  // remove the order by if it exists in the list  for (int i = 0; i < m_orderBys.size(); i++)  {  QVariantMap orderByMap = m_orderBys.at(i).toMap();  if (field == orderByMap["field"].toString())  {  m_orderBys.removeAt(i);  emit orderBysChanged();  return;  }  } }  void StatisticalQueryGroupSort::removeOrderBy(int index) {  // remove the order by at a given index  if (!m_orderBys.empty())  {  m_orderBys.removeAt(index);  emit orderBysChanged();  } }  void StatisticalQueryGroupSort::updateOrder(int index) {  if (m_orderBys.empty())  return;   // get the existing values  QVariantMap orderByMap;  orderByMap["field"] = m_orderBys.at(index).toMap()["field"].toString();  const QString currentOrder = m_orderBys.at(index).toMap()["order"].toString();   // update the order text  if (currentOrder == "Ascending")  orderByMap["order"] = "Descending";  else  orderByMap["order"] = "Ascending";   // update the variant list with the new value  m_orderBys.removeAt(index);  m_orderBys.insert(index, orderByMap);   emit orderBysChanged(); }  void StatisticalQueryGroupSort::addGroupingField(const QString& field) {  // add a new grouping field  if (!m_groupingFields.contains(field))  {  m_groupingFields.append(field);  emit groupingFieldsChanged();  } }  void StatisticalQueryGroupSort::removeGroupingField(const QString& field) {  // remove a grouping field  if (m_groupingFields.contains(field))  {  int i = m_groupingFields.indexOf(field);  m_groupingFields.removeAt(i);  emit groupingFieldsChanged();   // also update the orderby list  removeOrderBy(field);  } }  // helper to convert from statistic type string to enum StatisticType StatisticalQueryGroupSort::statisticStringToEnum(const QString& statistic) const {  if (statistic == "Average")  return StatisticType::Average;  else if (statistic == "Count")  return StatisticType::Count;  else if (statistic == "Maximum")  return StatisticType::Maximum;  else if (statistic == "Minimum")  return StatisticType::Minimum;  else if (statistic == "Standard Deviation")  return StatisticType::StandardDeviation;  else if (statistic == "Sum")  return StatisticType::Sum;  else  return StatisticType::Variance; }  // helper to convert from sort order string to enum SortOrder StatisticalQueryGroupSort::orderStringToEnum(const QString& order) const {  if (order == "Ascending")  return SortOrder::Ascending;  else  return SortOrder::Descending; }  void StatisticalQueryGroupSort::addResultToModel(const QString& section, const QString& resultString) {  m_resultsModel->addStatisticResult(section, resultString);  emit resultsModelChanged(); }  QAbstractListModel* StatisticalQueryGroupSort::resultsModel() const {  return m_resultsModel; }

Your browser is no longer supported. Please upgrade your browser for the best experience. See our browser deprecation post for more details.