Skip to content

Commit

Permalink
Quantile function for graduated symbol dialog
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@6826 c8812cc2-4d05-0410-92ff-de0c093fc19c
  • Loading branch information
mhugent committed Mar 23, 2007
1 parent b890bc5 commit dfafc41
Show file tree
Hide file tree
Showing 2 changed files with 164 additions and 51 deletions.
205 changes: 154 additions & 51 deletions src/app/qgsgraduatedsymboldialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@
/* $Id$ */

#include "qgsgraduatedsymboldialog.h"
#include "qgsfeatureattribute.h"
#include "qgsfield.h"
#include "qgsgraduatedsymbolrenderer.h"
#include "qgsludialog.h"
#include "qgssymbol.h"
#include "qgsvectordataprovider.h"
#include "qgsvectorlayer.h"
#include <algorithm>
#include <cmath>


QgsGraduatedSymbolDialog::QgsGraduatedSymbolDialog(QgsVectorLayer * layer): QDialog(), mVectorLayer(layer), sydialog(layer)
Expand Down Expand Up @@ -64,6 +67,7 @@ QgsGraduatedSymbolDialog::QgsGraduatedSymbolDialog(QgsVectorLayer * layer): QDia
}

modeComboBox->insertItem("Equal Interval");
modeComboBox->insertItem("Quantiles");
modeComboBox->insertItem("Empty");

//restore the correct settings
Expand Down Expand Up @@ -248,6 +252,7 @@ void QgsGraduatedSymbolDialog::adjustClassification()
std::map < QString, int >::iterator iter = mFieldMap.find(fieldstring);
int field = iter->second;


if (provider)
{
if (modeComboBox->currentText() == "Equal Interval")
Expand All @@ -261,23 +266,78 @@ void QgsGraduatedSymbolDialog::adjustClassification()
maximum = 0;
}
}

QString listboxtext;
for(int i=0;i<numberofclassesspinbox->value();++i)
{

//todo: setup a data structure which holds the symbols
std::list<QgsSymbol*> symbolList;
for(int i = 0; i < numberofclassesspinbox->value(); ++i)
{
QgsSymbol* symbol = new QgsSymbol(m_type);
symbol->setLabel("");
QPen pen;
QBrush brush;

if (modeComboBox->currentText() == "Empty")
{
listboxtext="Empty"+QString::number(i+1);
mClassListWidget->addItem(listboxtext);
}
else if(modeComboBox->currentText() == "Equal Interval")
{
//apply a nice color range from red to green as default
//todo: make other color ranges available
if (i == 0)
{
if (m_type == QGis::Line)
{
pen.setColor(QColor(255, 0, 0));
}
else //point or polygon
{
brush.setColor(QColor(255, 0, 0));
pen.setColor(Qt::black);
}
}
else
{
if (m_type == QGis::Line)
{
pen.setColor(QColor(255 - (255 / numberofclassesspinbox->value() * (i+1)), 255 / numberofclassesspinbox->value() * (i+1), 0));
}
else //point or polygon
{
brush.setColor(QColor(255 - (255 / numberofclassesspinbox->value() * (i+1)), 255 / numberofclassesspinbox->value() * (i+1), 0));
pen.setColor(Qt::black);
}
}
pen.setWidth(1);
brush.setStyle(Qt::SolidPattern);
symbol->setPen(pen);
symbol->setBrush(brush);
symbolList.push_back(symbol);
}

QString listBoxText;
if(modeComboBox->currentText() == "Quantiles")
{
//test: insert the values into mClassListWidget
std::list<double> quantileBorders;
quantilesFromVectorLayer(quantileBorders, field, numberofclassesspinbox->value());

std::list<double>::const_iterator it;
std::list<double>::const_iterator last_it = quantileBorders.end();
std::list<QgsSymbol*>::const_iterator symbol_it = symbolList.begin();
for(it = quantileBorders.begin(); it != quantileBorders.end(); ++it)
{
if(last_it != quantileBorders.end())
{
listBoxText = QString::number(*last_it, 'f') + " - " + QString::number(*it, 'f');
mClassListWidget->addItem(listBoxText);
(*symbol_it)->setLowerValue(QString::number(*last_it, 'f'));
(*symbol_it)->setUpperValue(QString::number(*it, 'f'));
mEntries.insert(std::make_pair(listBoxText,*symbol_it));
++symbol_it;
}
last_it = it;
}
}
else if(modeComboBox->currentText() == "Equal Interval")
{
std::list<QgsSymbol*>::const_iterator symbol_it = symbolList.begin();
for(int i=0;i<numberofclassesspinbox->value();++i)
{
double lower=minimum + (maximum - minimum) / numberofclassesspinbox->value() * i;
double upper=minimum + (maximum - minimum) / numberofclassesspinbox->value() * (i+1);
if(i==0)//make sure all feature attributes are between minimum and maximum value (round off problem)
Expand All @@ -288,45 +348,27 @@ void QgsGraduatedSymbolDialog::adjustClassification()
{
upper+=0.001;
}
symbol->setLowerValue(QString::number(lower,'f',3));
symbol->setUpperValue(QString::number(upper,'f',3));
listboxtext=QString::number(lower,'f',3)+" - " +QString::number(upper,'f',3);
mClassListWidget->addItem(listboxtext);
}
//set default symbology

//apply a nice color range from red to green as default
if (i == 0)
{
if (m_type == QGis::Line)
{
pen.setColor(QColor(255, 0, 0));
}
else //point or polygon
{
brush.setColor(QColor(255, 0, 0));
pen.setColor(Qt::black);
}
}
else
{
if (m_type == QGis::Line)
{
pen.setColor(QColor(255 - (255 / numberofclassesspinbox->value() * (i+1)), 255 / numberofclassesspinbox->value() * (i+1), 0));
}
else //point or polygon
{
brush.setColor(QColor(255 - (255 / numberofclassesspinbox->value() * (i+1)), 255 / numberofclassesspinbox->value() * (i+1), 0));
pen.setColor(Qt::black);
}
}
pen.setWidth(1);
brush.setStyle(Qt::SolidPattern);
symbol->setPen(pen);
symbol->setBrush(brush);

mEntries.insert(std::make_pair(listboxtext,symbol));
}
(*symbol_it)->setLowerValue(QString::number(lower,'f',3));
(*symbol_it)->setUpperValue(QString::number(upper,'f',3));
listBoxText=QString::number(lower,'f',3)+" - " +QString::number(upper,'f',3);
mClassListWidget->addItem(listBoxText);

mEntries.insert(std::make_pair(listBoxText,*symbol_it));
++symbol_it;
}
}
else if(modeComboBox->currentText() == "Empty")
{
std::list<QgsSymbol*>::const_iterator symbol_it = symbolList.begin();
for(int i=0;i<numberofclassesspinbox->value();++i)
{
listBoxText="Empty"+QString::number(i+1);
mClassListWidget->addItem(listBoxText);
mEntries.insert(std::make_pair(listBoxText,*symbol_it));
++symbol_it;
}
}

mClassListWidget->setCurrentRow(0);
}

Expand Down Expand Up @@ -419,3 +461,64 @@ void QgsGraduatedSymbolDialog::deleteCurrentClass()
mClassListWidget->setCurrentRow(currentIndex);
}
}

int QgsGraduatedSymbolDialog::quantilesFromVectorLayer(std::list<double>& result, int attributeIndex, int numQuantiles) const
{
if(mVectorLayer)
{
QgsVectorDataProvider* provider = mVectorLayer->getDataProvider();

if(provider)
{
std::vector<double> attributeValues(provider->featureCount());
QgsAttributeList attList;
attList.push_back(attributeIndex);
QgsFeature currentFeature;
QgsAttributeMap currentAttributeMap;
double currentValue;
int index = 0;

provider->reset();
while(provider->getNextFeature(currentFeature, false, attList))
{
currentAttributeMap = currentFeature.attributeMap();
currentValue = currentAttributeMap[attributeIndex].fieldValue().toDouble();
attributeValues[index] = currentValue;
++index;
}

sort(attributeValues.begin(), attributeValues.end());
return calculateQuantiles(result, attributeValues, numQuantiles);
}
}
return 1;
}

int QgsGraduatedSymbolDialog::calculateQuantiles(std::list<double>& result, const std::vector<double>& values, int numQuantiles) const
{
result.clear();

double q;
double k;
double intPart;

result.push_back(values[0]);
for(int i = 0; i < (numQuantiles - 1); ++i)
{
q = 100/numQuantiles * (i + 1);
k = values.size() * q / 100;
if(std::modf(k, &intPart) < 0.000000001)
{
result.push_back(((100 - q) * values[(int)(k - 1)] + q * values[(int)k]) / 100);
}
else
{
result.push_back(values[(int)k]);
}
}
result.push_back(values[values.size() - 1]);
return 0;
}



10 changes: 10 additions & 0 deletions src/app/qgsgraduatedsymboldialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,16 @@ class QgsGraduatedSymbolDialog: public QDialog, private Ui::QgsGraduatedSymbolDi
QgsSingleSymbolDialog sydialog;
int mClassificationField;

/**Calculates quantiles from mVectorLayer.
@return 0 in case of success*/
int quantilesFromVectorLayer(std::list<double>& result, int attributeIndex, int numQuantiles) const;
/**A function that calculates the values of the quantiles
@param result the list where the function inserts the result values
@param values a _sorted_ vector of variable values
@param numQuantiles the number of quantiles, e.g. 4 calculates the quantiles for 25%, 50%, 75%, 100%
@return 0 in case of success*/
int calculateQuantiles(std::list<double>& result, const std::vector<double>& values, int numQuantiles) const;

protected slots:
/**Removes a class from the classification*/
void deleteCurrentClass();
Expand Down

0 comments on commit dfafc41

Please sign in to comment.