QGIS API Documentation  3.14.0-Pi (9f7028fd23)
qgsclassificationjenks.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsclassificationjenks.h
3  ---------------------
4  begin : September 2019
5  copyright : (C) 2019 by Denis Rouzaud
6  email : [email protected]
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include <limits>
17 #include "qgsclassificationjenks.h"
18 #include "qgsapplication.h"
19 
22 {
23 
24 }
25 
27 {
28  return QObject::tr( "Natural Breaks (Jenks)" );
29 }
30 
32 {
33  return QStringLiteral( "Jenks" );
34 }
35 
37 {
39  copyBase( c );
40  return c;
41 }
42 
44 {
45  return QgsApplication::getThemeIcon( "classification_methods/mClassificationNaturalBreak.svg" );
46 }
47 
48 
49 QList<double> QgsClassificationJenks::calculateBreaks( double &minimum, double &maximum,
50  const QList<double> &values, int nclasses )
51 {
52  // Jenks Optimal (Natural Breaks) algorithm
53  // Based on the Jenks algorithm from the 'classInt' package available for
54  // the R statistical prgramming language, and from Python code from here:
55  // http://danieljlewis.org/2010/06/07/jenks-natural-breaks-algorithm-in-python/
56  // and is based on a JAVA and Fortran code available here:
57  // https://stat.ethz.ch/pipermail/r-sig-geo/2006-March/000811.html
58 
59  // Returns class breaks such that classes are internally homogeneous while
60  // assuring heterogeneity among classes.
61 
62  if ( values.isEmpty() )
63  return QList<double>();
64 
65  if ( nclasses <= 1 )
66  {
67  return QList<double>() << maximum;
68  }
69 
70  if ( nclasses >= values.size() )
71  {
72  return values;
73  }
74 
75  QVector<double> sample;
76 
77  // if we have lots of values, we need to take a random sample
78  if ( values.size() > mMaximumSize )
79  {
80  // for now, sample at least maximumSize values or a 10% sample, whichever
81  // is larger. This will produce a more representative sample for very large
82  // layers, but could end up being computationally intensive...
83 
84  sample.resize( std::max( mMaximumSize, values.size() / 10 ) );
85 
86  QgsDebugMsgLevel( QStringLiteral( "natural breaks (jenks) sample size: %1" ).arg( sample.size() ), 2 );
87  QgsDebugMsgLevel( QStringLiteral( "values:%1" ).arg( values.size() ), 2 );
88 
89  sample[ 0 ] = minimum;
90  sample[ 1 ] = maximum;
91  for ( int i = 2; i < sample.size(); i++ )
92  {
93  // pick a random integer from 0 to n
94  double r = qrand();
95  int j = std::floor( r / RAND_MAX * ( values.size() - 1 ) );
96  sample[ i ] = values[ j ];
97  }
98  }
99  else
100  {
101  sample = values.toVector();
102  }
103 
104  int n = sample.size();
105 
106  // sort the sample values
107  std::sort( sample.begin(), sample.end() );
108 
109  QVector< QVector<int> > matrixOne( n + 1 );
110  QVector< QVector<double> > matrixTwo( n + 1 );
111 
112  for ( int i = 0; i <= n; i++ )
113  {
114  matrixOne[i].resize( nclasses + 1 );
115  matrixTwo[i].resize( nclasses + 1 );
116  }
117 
118  for ( int i = 1; i <= nclasses; i++ )
119  {
120  matrixOne[0][i] = 1;
121  matrixOne[1][i] = 1;
122  matrixTwo[0][i] = 0.0;
123  for ( int j = 2; j <= n; j++ )
124  {
125  matrixTwo[j][i] = std::numeric_limits<double>::max();
126  }
127  }
128 
129  for ( int l = 2; l <= n; l++ )
130  {
131  double s1 = 0.0;
132  double s2 = 0.0;
133  int w = 0;
134 
135  double v = 0.0;
136 
137  for ( int m = 1; m <= l; m++ )
138  {
139  int i3 = l - m + 1;
140 
141  double val = sample[ i3 - 1 ];
142 
143  s2 += val * val;
144  s1 += val;
145  w++;
146 
147  v = s2 - ( s1 * s1 ) / static_cast< double >( w );
148  int i4 = i3 - 1;
149  if ( i4 != 0 )
150  {
151  for ( int j = 2; j <= nclasses; j++ )
152  {
153  if ( matrixTwo[l][j] >= v + matrixTwo[i4][j - 1] )
154  {
155  matrixOne[l][j] = i4;
156  matrixTwo[l][j] = v + matrixTwo[i4][j - 1];
157  }
158  }
159  }
160  }
161  matrixOne[l][1] = 1;
162  matrixTwo[l][1] = v;
163  }
164 
165  QVector<double> breaks( nclasses );
166  breaks[nclasses - 1] = sample[n - 1];
167 
168  for ( int j = nclasses, k = n; j >= 2; j-- )
169  {
170  int id = matrixOne[k][j] - 1;
171  breaks[j - 2] = sample[id];
172  k = matrixOne[k][j] - 1;
173  }
174 
175  return breaks.toList();
176 }
QgsClassificationMethod
Definition: qgsclassificationmethod.h:87
QgsApplication::getThemeIcon
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
Definition: qgsapplication.cpp:605
QgsDebugMsgLevel
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
QgsClassificationJenks::name
QString name() const override
The readable and translate name of the method.
Definition: qgsclassificationjenks.cpp:26
qgsapplication.h
QgsClassificationJenks::QgsClassificationJenks
QgsClassificationJenks()
Definition: qgsclassificationjenks.cpp:20
qgsclassificationjenks.h
QgsClassificationJenks::icon
QIcon icon() const override
The icon of the method.
Definition: qgsclassificationjenks.cpp:43
QgsClassificationMethod::copyBase
void copyBase(QgsClassificationMethod *c) const
Copy the parameters (shall be used in clone implementation)
Definition: qgsclassificationmethod.cpp:52
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsClassificationJenks
Definition: qgsclassificationjenks.h:28
QgsClassificationJenks::id
QString id() const override
The id of the method as saved in the project, must be unique in registry.
Definition: qgsclassificationjenks.cpp:31
QgsClassificationJenks::clone
QgsClassificationMethod * clone() const override
Returns a clone of the method.
Definition: qgsclassificationjenks.cpp:36