mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[apps] Fix Statistics: now displays three series
This commit is contained in:
@@ -32,7 +32,7 @@ App * App::Snapshot::unpack(Container * container) {
|
||||
}
|
||||
|
||||
void App::Snapshot::reset() {
|
||||
m_store.deleteAllPairs();
|
||||
m_store.deleteAllPairsOfAllSeries();
|
||||
m_store.setDefault();
|
||||
m_modelVersion = 0;
|
||||
m_rangeVersion = 0;
|
||||
|
||||
@@ -12,13 +12,21 @@ void FloatPairStore::set(double f, int series, int i, int j) {
|
||||
return;
|
||||
}
|
||||
m_data[series][i][j] = f;
|
||||
if (j >= m_numberOfPairs) {
|
||||
if (j >= m_numberOfPairs[series]) {
|
||||
int otherI = i == 0 ? 1 : 0;
|
||||
m_data[series][otherI][j] = defaultValue(otherI, j);
|
||||
m_data[series][otherI][j] = defaultValue(series, otherI, j);
|
||||
m_numberOfPairs[series]++;
|
||||
}
|
||||
}
|
||||
|
||||
int FloatPairStore::numberOfPairs() const {
|
||||
int result = 0;
|
||||
for (int i = 0; i < k_numberOfSeries; i++) {
|
||||
result += m_numberOfPairs[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void FloatPairStore::deletePairAtIndex(int series, int j) {
|
||||
m_numberOfPairs[series]--;
|
||||
for (int k = j; k < m_numberOfPairs[series]; k++) {
|
||||
@@ -27,8 +35,8 @@ void FloatPairStore::deletePairAtIndex(int series, int j) {
|
||||
}
|
||||
/* We reset the values of the empty row to ensure the correctness of the
|
||||
* checksum. */
|
||||
m_data[series][0][m_numberOfPairs] = 0;
|
||||
m_data[series][1][m_numberOfPairs] = 0;
|
||||
m_data[series][0][m_numberOfPairs[series]] = 0;
|
||||
m_data[series][1][m_numberOfPairs[series]] = 0;
|
||||
}
|
||||
|
||||
void FloatPairStore::deleteAllPairs(int series) {
|
||||
@@ -41,15 +49,21 @@ void FloatPairStore::deleteAllPairs(int series) {
|
||||
m_numberOfPairs[series] = 0;
|
||||
}
|
||||
|
||||
void FloatPairStore::deleteAllPairsOfAllSeries() {
|
||||
for (int i = 0; i < k_numberOfSeries; i ++) {
|
||||
deleteAllPairs(i);
|
||||
}
|
||||
}
|
||||
|
||||
void FloatPairStore::resetColumn(int series, int i) {
|
||||
assert(series >= 0 && series < k_numberOfSeries);
|
||||
assert(i == 0 || i == 1);
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
m_data[series][i][k] = defaultValue(i, k);
|
||||
m_data[series][i][k] = defaultValue(series, i, k);
|
||||
}
|
||||
}
|
||||
|
||||
double FloatPairStore::sumOfColumn(int series, int i) {
|
||||
double FloatPairStore::sumOfColumn(int series, int i) const {
|
||||
assert(series >= 0 && series < k_numberOfSeries);
|
||||
assert(i == 0 || i == 1);
|
||||
double result = 0;
|
||||
@@ -72,7 +86,7 @@ uint32_t FloatPairStore::storeChecksum() {
|
||||
double FloatPairStore::defaultValue(int series, int i, int j) {
|
||||
assert(series >= 0 && series < k_numberOfSeries);
|
||||
if(i == 0 && j > 1) {
|
||||
return 2*m_data[series][i][j-1]-m_data[i][j-2];
|
||||
return 2*m_data[series][i][j-1]-m_data[series][i][j-2];
|
||||
} else {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
@@ -21,11 +21,12 @@ public:
|
||||
return m_data[series][i][j];
|
||||
}
|
||||
void set(double f, int series, int i, int j);
|
||||
int numberOfPairsOfSeries(int series) const { return m_numberOfPairs[series]; }
|
||||
int numberOfPairs() const;
|
||||
void deletePairAtIndex(int series, int j);
|
||||
void deleteAllPairs(int series);
|
||||
void deleteAllPairsOfAllSeries();
|
||||
void resetColumn(int series, int i);
|
||||
double sumOfColumn(int series, int i);
|
||||
double sumOfColumn(int series, int i) const;
|
||||
uint32_t storeChecksum();
|
||||
protected:
|
||||
virtual double defaultValue(int series, int i, int j);
|
||||
|
||||
@@ -21,7 +21,7 @@ const char * StoreController::title() {
|
||||
}
|
||||
|
||||
int StoreController::numberOfColumns() {
|
||||
return k_numberOfColumnsPerSeries * k_numberOfSeries;
|
||||
return k_numberOfColumnsPerSeries * FloatPairStore::k_numberOfSeries;
|
||||
}
|
||||
|
||||
KDCoordinate StoreController::columnWidth(int i) {
|
||||
@@ -52,10 +52,7 @@ HighlightCell * StoreController::reusableCell(int index, int type) {
|
||||
}
|
||||
|
||||
int StoreController::reusableCellCount(int type) {
|
||||
if (type == k_titleCellType) {
|
||||
return k_numberOfTitleCells;
|
||||
}
|
||||
return k_maxNumberOfEditableCells;
|
||||
return type == k_titleCellType ? k_numberOfTitleCells : k_maxNumberOfEditableCells;
|
||||
}
|
||||
|
||||
int StoreController::typeAtLocation(int i, int j) {
|
||||
@@ -81,8 +78,10 @@ bool StoreController::handleEvent(Ion::Events::Event event) {
|
||||
return true;
|
||||
}
|
||||
assert(selectedColumn() >= 0 && selectedColumn() < numberOfColumns());
|
||||
int series = selectedColumn()/k_numberOfColumnsPerSeries;
|
||||
if ((event == Ion::Events::OK || event == Ion::Events::EXE) && selectedRow() == 0) {
|
||||
m_storeParameterController.selectXColumn(selectedColumn()%k_numberOfColumnsPerSeries == 0);
|
||||
m_storeParameterController.selectSeries(series);
|
||||
StackViewController * stack = ((StackViewController *)parentResponder()->parentResponder());
|
||||
stack->push(&m_storeParameterController);
|
||||
return true;
|
||||
@@ -91,7 +90,7 @@ bool StoreController::handleEvent(Ion::Events::Event event) {
|
||||
if (selectedRow() == 0 || selectedRow() == numberOfRows()-1) {
|
||||
return false;
|
||||
}
|
||||
m_store->deletePairAtIndex(selectedRow()-1);
|
||||
m_store->deletePairAtIndex(series, selectedRow()-1);
|
||||
selectableTableView()->reloadData();
|
||||
return true;
|
||||
}
|
||||
@@ -110,12 +109,12 @@ bool StoreController::cellAtLocationIsEditable(int columnIndex, int rowIndex) {
|
||||
}
|
||||
|
||||
bool StoreController::setDataAtLocation(double floatBody, int columnIndex, int rowIndex) {
|
||||
m_store->set(floatBody, columnIndex, rowIndex-1);
|
||||
m_store->set(floatBody, columnIndex/k_numberOfColumnsPerSeries, columnIndex%k_numberOfColumnsPerSeries, rowIndex-1);
|
||||
return true;
|
||||
}
|
||||
|
||||
double StoreController::dataAtLocation(int columnIndex, int rowIndex) {
|
||||
return m_store->get(columnIndex, rowIndex-1);
|
||||
return m_store->get(columnIndex/k_numberOfColumnsPerSeries, columnIndex%k_numberOfColumnsPerSeries, rowIndex-1);
|
||||
}
|
||||
|
||||
int StoreController::numberOfElements() {
|
||||
@@ -123,7 +122,7 @@ int StoreController::numberOfElements() {
|
||||
}
|
||||
|
||||
int StoreController::maxNumberOfElements() const {
|
||||
return FloatPairStore::k_maxNumberOfPairs;
|
||||
return FloatPairStore::k_numberOfSeries * FloatPairStore::k_maxNumberOfPairs;
|
||||
}
|
||||
|
||||
View * StoreController::loadView() {
|
||||
|
||||
@@ -23,11 +23,10 @@ public:
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
void didBecomeFirstResponder() override;
|
||||
protected:
|
||||
static constexpr KDCoordinate k_cellWidth = Ion::Display::Width/2 - Metric::CommonRightMargin/2 - Metric::CommonLeftMargin/2;
|
||||
constexpr static int k_numberOfSeries = 3;
|
||||
static constexpr KDCoordinate k_cellWidth = 80; //TODO
|
||||
constexpr static int k_numberOfColumnsPerSeries = 2;
|
||||
constexpr static int k_maxNumberOfEditableCells = 22 * k_numberOfSeries;
|
||||
constexpr static int k_numberOfTitleCells = k_numberOfColumnsPerSeries * k_numberOfSeries;
|
||||
constexpr static int k_maxNumberOfEditableCells = 22 * FloatPairStore::k_numberOfSeries;
|
||||
constexpr static int k_numberOfTitleCells = k_numberOfColumnsPerSeries * FloatPairStore::k_numberOfSeries;
|
||||
// TODO Put finer number of cells
|
||||
static constexpr int k_titleCellType = 0;
|
||||
static constexpr int k_editableCellType = 1;
|
||||
|
||||
@@ -12,7 +12,8 @@ StoreParameterController::StoreParameterController(Responder * parentResponder,
|
||||
#endif
|
||||
m_selectableTableView(this, this, this),
|
||||
m_store(store),
|
||||
m_xColumnSelected(true)
|
||||
m_xColumnSelected(true),
|
||||
m_series(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,9 +32,9 @@ bool StoreParameterController::handleEvent(Ion::Events::Event event) {
|
||||
case 0:
|
||||
{
|
||||
if (m_xColumnSelected) {
|
||||
m_store->deleteAllPairs();
|
||||
m_store->deleteAllPairs(m_series);
|
||||
} else {
|
||||
m_store->resetColumn(!m_xColumnSelected);
|
||||
m_store->resetColumn(m_series, !m_xColumnSelected);
|
||||
}
|
||||
StackViewController * stack = ((StackViewController *)parentResponder());
|
||||
stack->pop();
|
||||
|
||||
@@ -11,6 +11,7 @@ class StoreParameterController : public ViewController, public SimpleListViewDat
|
||||
public:
|
||||
StoreParameterController(Responder * parentResponder, FloatPairStore * store);
|
||||
void selectXColumn(bool xColumnSelected) { m_xColumnSelected = xColumnSelected; }
|
||||
void selectSeries(int series) { m_series = series; }
|
||||
View * view() override { return &m_selectableTableView; }
|
||||
const char * title() override;
|
||||
bool handleEvent(Ion::Events::Event event) override;
|
||||
@@ -31,6 +32,7 @@ private:
|
||||
SelectableTableView m_selectableTableView;
|
||||
FloatPairStore * m_store;
|
||||
bool m_xColumnSelected;
|
||||
int m_series;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ App * App::Snapshot::unpack(Container * container) {
|
||||
}
|
||||
|
||||
void App::Snapshot::reset() {
|
||||
m_store.deleteAllPairs();
|
||||
m_store.deleteAllPairsOfAllSeries();
|
||||
m_storeVersion = 0;
|
||||
m_barVersion = 0;
|
||||
m_rangeVersion = 0;
|
||||
|
||||
@@ -11,7 +11,8 @@ BoxController::BoxController(Responder * parentResponder, ButtonRowController *
|
||||
ButtonRowDelegate(header, nullptr),
|
||||
m_boxBannerView(),
|
||||
m_view(store, &m_boxBannerView, selectedQuantile),
|
||||
m_store(store)
|
||||
m_store(store),
|
||||
m_selectedSeries(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -46,8 +47,10 @@ void BoxController::didBecomeFirstResponder() {
|
||||
}
|
||||
|
||||
bool BoxController::isEmpty() const {
|
||||
if (m_store->sumOfColumn(1) == 0) {
|
||||
return true;
|
||||
for (int i = 0; i < Shared::FloatPairStore::k_numberOfSeries; i++) {
|
||||
if (m_store->sumOfOccurrences(i) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -70,7 +73,7 @@ void BoxController::reloadBannerView() {
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
CalculPointer calculationMethods[5] = {&Store::minValue, &Store::firstQuartile, &Store::median, &Store::thirdQuartile,
|
||||
&Store::maxValue};
|
||||
double calculation = (m_store->*calculationMethods[(int)m_view.selectedQuantile()])();
|
||||
double calculation = (m_store->*calculationMethods[(int)m_view.selectedQuantile()])(m_selectedSeries);
|
||||
PrintFloat::convertFloatToText<double>(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
m_boxBannerView.setLegendAtIndex(buffer, 1);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ private:
|
||||
BoxBannerView m_boxBannerView;
|
||||
BoxView m_view;
|
||||
Store * m_store;
|
||||
int m_selectedSeries;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ BoxRange::BoxRange(Store * store) :
|
||||
}
|
||||
|
||||
float BoxRange::xMin() {
|
||||
float min = m_store->minValue();
|
||||
float max = m_store->maxValue();
|
||||
float min = m_store->minValueForAllSeries();
|
||||
float max = m_store->maxValueForAllSeries();
|
||||
max = min >= max ? min + 1 : max;
|
||||
return min - k_displayLeftMarginRatio*(max-min);
|
||||
}
|
||||
|
||||
float BoxRange::xMax() {
|
||||
float min = m_store->minValue();
|
||||
float max = m_store->maxValue();
|
||||
float min = m_store->minValueForAllSeries();
|
||||
float max = m_store->maxValueForAllSeries();
|
||||
max = min >= max ? min + 1 : max;
|
||||
return max + k_displayRightMarginRatio*(max - min);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ BoxView::BoxView(Store * store, BannerView * bannerView, Quantile * selectedQuan
|
||||
m_store(store),
|
||||
m_boxRange(BoxRange(store)),
|
||||
m_labels{},
|
||||
m_selectedQuantile(selectedQuantile)
|
||||
m_selectedQuantile(selectedQuantile),
|
||||
m_series(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -19,7 +20,7 @@ void BoxView::reload() {
|
||||
CurveView::reload();
|
||||
CalculPointer calculationMethods[5] = {&Store::minValue, &Store::firstQuartile, &Store::median, &Store::thirdQuartile,
|
||||
&Store::maxValue};
|
||||
float calculation = (m_store->*calculationMethods[(int)*m_selectedQuantile])();
|
||||
float calculation = (m_store->*calculationMethods[(int)*m_selectedQuantile])(m_series);
|
||||
float pixelUpperBound = floatToPixel(Axis::Vertical, 0.2f)+1;
|
||||
float pixelLowerBound = floatToPixel(Axis::Vertical, 0.8)-1;
|
||||
float selectedValueInPixels = floatToPixel(Axis::Horizontal, calculation)-1;
|
||||
@@ -49,18 +50,23 @@ void BoxView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
drawLabels(ctx, rect, Axis::Horizontal, false);
|
||||
float lowBound = 0.35f;
|
||||
float upBound = 0.65f;
|
||||
double minVal = m_store->minValue(m_series);
|
||||
double firstQuart = m_store->firstQuartile(m_series);
|
||||
double thirdQuart = m_store->thirdQuartile(m_series);
|
||||
double maxVal = m_store->maxValue(m_series);
|
||||
|
||||
// Draw the main box
|
||||
KDCoordinate firstQuartilePixels = std::round(floatToPixel(Axis::Horizontal, m_store->firstQuartile()));
|
||||
KDCoordinate thirdQuartilePixels = std::round(floatToPixel(Axis::Horizontal, m_store->thirdQuartile()));
|
||||
KDCoordinate firstQuartilePixels = std::round(floatToPixel(Axis::Horizontal, firstQuart));
|
||||
KDCoordinate thirdQuartilePixels = std::round(floatToPixel(Axis::Horizontal, thirdQuart));
|
||||
KDCoordinate lowBoundPixel = std::round(floatToPixel(Axis::Vertical, upBound));
|
||||
KDCoordinate upBoundPixel = std::round(floatToPixel(Axis::Vertical, lowBound));
|
||||
ctx->fillRect(KDRect(firstQuartilePixels, lowBoundPixel, thirdQuartilePixels - firstQuartilePixels+2,
|
||||
upBoundPixel-lowBoundPixel), Palette::GreyWhite);
|
||||
// Draw the horizontal lines linking the box to the extreme bounds
|
||||
drawSegment(ctx, rect, Axis::Horizontal, 0.5f, m_store->minValue(), m_store->firstQuartile(), Palette::GreyDark);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, 0.5f, m_store->thirdQuartile(), m_store->maxValue(), Palette::GreyDark);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, 0.5f, minVal, firstQuart, Palette::GreyDark);
|
||||
drawSegment(ctx, rect, Axis::Horizontal, 0.5f, thirdQuart, maxVal, Palette::GreyDark);
|
||||
|
||||
double calculations[5] = {m_store->minValue(), m_store->firstQuartile(), m_store->median(), m_store->thirdQuartile(), m_store->maxValue()};
|
||||
double calculations[5] = {minVal, firstQuart, m_store->median(m_series), thirdQuart, maxVal};
|
||||
/* We then draw all the vertical lines of the box and then recolor the
|
||||
* the selected quantile (if there is one). As two quantiles can have the same
|
||||
* value, we cannot choose line colors and then color only once the vertical
|
||||
|
||||
@@ -23,6 +23,7 @@ public:
|
||||
void reload() override;
|
||||
Quantile selectedQuantile();
|
||||
bool selectQuantile(int selectedQuantile);
|
||||
void setSeries(int series) { m_series = series; }
|
||||
void drawRect(KDContext * ctx, KDRect rect) const override;
|
||||
private:
|
||||
char * label(Axis axis, int index) const override;
|
||||
@@ -30,6 +31,7 @@ private:
|
||||
BoxRange m_boxRange;
|
||||
char m_labels[k_maxNumberOfXLabels][Poincare::PrintFloat::bufferSizeForFloatsWithPrecision(Constant::ShortNumberOfSignificantDigits)];
|
||||
Quantile * m_selectedQuantile;
|
||||
int m_series;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -47,10 +47,7 @@ void CalculationController::didBecomeFirstResponder() {
|
||||
}
|
||||
|
||||
bool CalculationController::isEmpty() const {
|
||||
if (m_store->sumOfColumn(1) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return m_store->isEmpty();
|
||||
}
|
||||
|
||||
I18n::Message CalculationController::emptyMessage() {
|
||||
@@ -81,7 +78,7 @@ void CalculationController::willDisplayCellAtLocation(HighlightCell * cell, int
|
||||
CalculPointer calculationMethods[k_totalNumberOfRows] = {&Store::sumOfOccurrences, &Store::minValue,
|
||||
&Store::maxValue, &Store::range, &Store::mean, &Store::standardDeviation, &Store::variance, &Store::firstQuartile,
|
||||
&Store::thirdQuartile, &Store::median, &Store::quartileRange, &Store::sum, &Store::squaredValueSum, &Store::sampleStandardDeviation};
|
||||
double calculation = (m_store->*calculationMethods[j])();
|
||||
double calculation = (m_store->*calculationMethods[j])(0); //TODO
|
||||
EvenOddBufferTextCell * myCell = (EvenOddBufferTextCell *)cell;
|
||||
char buffer[PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits)];
|
||||
PrintFloat::convertFloatToText<double>(calculation, buffer, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
|
||||
@@ -100,7 +100,7 @@ void HistogramController::didBecomeFirstResponder() {
|
||||
if (!m_view.isMainViewSelected()) {
|
||||
header()->setSelectedButton(0);
|
||||
} else {
|
||||
m_view.setHighlight(m_store->startOfBarAtIndex(*m_selectedBarIndex), m_store->endOfBarAtIndex(*m_selectedBarIndex));
|
||||
m_view.setHighlight(m_store->startOfBarAtIndex(0, *m_selectedBarIndex), m_store->endOfBarAtIndex(0, *m_selectedBarIndex)); //TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,10 +115,7 @@ Button * HistogramController::buttonAtIndex(int index, ButtonRowController::Posi
|
||||
}
|
||||
|
||||
bool HistogramController::isEmpty() const {
|
||||
if (m_store->sumOfColumn(1) == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return m_store->isEmpty();
|
||||
}
|
||||
|
||||
I18n::Message HistogramController::emptyMessage() {
|
||||
@@ -161,13 +158,13 @@ void HistogramController::reloadBannerView() {
|
||||
numberOfChar += legendLength;
|
||||
|
||||
// Add lower bound
|
||||
double lowerBound = m_store->startOfBarAtIndex(*m_selectedBarIndex);
|
||||
double lowerBound = m_store->startOfBarAtIndex(0, *m_selectedBarIndex); //TODO
|
||||
numberOfChar += PrintFloat::convertFloatToText<double>(lowerBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
|
||||
buffer[numberOfChar++] = ';';
|
||||
|
||||
// Add upper bound
|
||||
double upperBound = m_store->endOfBarAtIndex(*m_selectedBarIndex);
|
||||
double upperBound = m_store->endOfBarAtIndex(0, *m_selectedBarIndex); //TODO
|
||||
numberOfChar += PrintFloat::convertFloatToText<double>(upperBound, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
|
||||
buffer[numberOfChar++] = '[';
|
||||
@@ -185,7 +182,7 @@ void HistogramController::reloadBannerView() {
|
||||
legendLength = strlen(legend);
|
||||
strlcpy(buffer, legend, legendLength+1);
|
||||
numberOfChar += legendLength;
|
||||
double size = m_store->heightOfBarAtIndex(*m_selectedBarIndex);
|
||||
double size = m_store->heightOfBarAtIndex(0, *m_selectedBarIndex); //TODO
|
||||
numberOfChar += PrintFloat::convertFloatToText<double>(size, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
// Padding
|
||||
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
|
||||
@@ -200,7 +197,7 @@ void HistogramController::reloadBannerView() {
|
||||
legendLength = strlen(legend);
|
||||
strlcpy(buffer, legend, legendLength+1);
|
||||
numberOfChar += legendLength;
|
||||
double frequency = size/m_store->sumOfColumn(1);
|
||||
double frequency = size/m_store->sumOfOccurrences(0); //TODO
|
||||
numberOfChar += PrintFloat::convertFloatToText<double>(frequency, buffer+numberOfChar, PrintFloat::bufferSizeForFloatsWithPrecision(Constant::LargeNumberOfSignificantDigits), Constant::LargeNumberOfSignificantDigits);
|
||||
// Padding
|
||||
for (int i = numberOfChar; i < k_maxLegendLength; i++) {
|
||||
@@ -215,16 +212,16 @@ bool HistogramController::moveSelection(int deltaIndex) {
|
||||
if (deltaIndex > 0) {
|
||||
do {
|
||||
newSelectedBarIndex++;
|
||||
} while (m_store->heightOfBarAtIndex(newSelectedBarIndex) == 0 && newSelectedBarIndex < m_store->numberOfBars());
|
||||
} while (m_store->heightOfBarAtIndex(0, newSelectedBarIndex) == 0 && newSelectedBarIndex < m_store->numberOfBars(0)); //TODO
|
||||
} else {
|
||||
do {
|
||||
newSelectedBarIndex--;
|
||||
} while (m_store->heightOfBarAtIndex(newSelectedBarIndex) == 0 && newSelectedBarIndex >= 0);
|
||||
} while (m_store->heightOfBarAtIndex(0, newSelectedBarIndex) == 0 && newSelectedBarIndex >= 0); //TODO
|
||||
}
|
||||
if (newSelectedBarIndex >= 0 && newSelectedBarIndex < m_store->numberOfBars() && *m_selectedBarIndex != newSelectedBarIndex) {
|
||||
if (newSelectedBarIndex >= 0 && newSelectedBarIndex < m_store->numberOfBars(0) && *m_selectedBarIndex != newSelectedBarIndex) {//TODO
|
||||
*m_selectedBarIndex = newSelectedBarIndex;
|
||||
m_view.setHighlight(m_store->startOfBarAtIndex(*m_selectedBarIndex), m_store->endOfBarAtIndex(*m_selectedBarIndex));
|
||||
m_store->scrollToSelectedBarIndex(*m_selectedBarIndex);
|
||||
m_view.setHighlight(m_store->startOfBarAtIndex(0, *m_selectedBarIndex), m_store->endOfBarAtIndex(0, *m_selectedBarIndex)); //TODO
|
||||
m_store->scrollToSelectedBarIndex(0, *m_selectedBarIndex);//TODO
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -232,7 +229,7 @@ bool HistogramController::moveSelection(int deltaIndex) {
|
||||
|
||||
void HistogramController::initRangeParameters() {
|
||||
float min = m_store->firstDrawnBarAbscissa();
|
||||
float max = m_store->maxValue();
|
||||
float max = m_store->maxValue(0); //TODO
|
||||
float barWidth = m_store->barWidth();
|
||||
float xMin = min;
|
||||
float xMax = max + barWidth;
|
||||
@@ -247,21 +244,21 @@ void HistogramController::initRangeParameters() {
|
||||
m_store->setXMin(xMin - Store::k_displayLeftMarginRatio*(xMax-xMin));
|
||||
m_store->setXMax(xMax + Store::k_displayRightMarginRatio*(xMax-xMin));
|
||||
float yMax = -FLT_MAX;
|
||||
for (int index = 0; index < m_store->numberOfBars(); index++) {
|
||||
float size = m_store->heightOfBarAtIndex(index);
|
||||
for (int index = 0; index < m_store->numberOfBars(0); index++) { //TODO
|
||||
float size = m_store->heightOfBarAtIndex(0, index); //TODO
|
||||
if (size > yMax) {
|
||||
yMax = size;
|
||||
}
|
||||
}
|
||||
yMax = yMax/m_store->sumOfColumn(1);
|
||||
yMax = yMax/m_store->sumOfOccurrences(0); //TODO
|
||||
yMax = yMax < 0 ? 1 : yMax;
|
||||
m_store->setYMin(-Store::k_displayBottomMarginRatio*yMax);
|
||||
m_store->setYMax(yMax*(1.0f+Store::k_displayTopMarginRatio));
|
||||
}
|
||||
|
||||
void HistogramController::initBarParameters() {
|
||||
float min = m_store->minValue();
|
||||
float max = m_store->maxValue();
|
||||
float min = m_store->minValue(0); //TODO
|
||||
float max = m_store->maxValue(0); //TODO
|
||||
max = min >= max ? min + std::pow(10.0f, std::floor(std::log10(std::fabs(min)))-1.0f) : max;
|
||||
m_store->setFirstDrawnBarAbscissa(min);
|
||||
float barWidth = m_store->computeGridUnit(CurveViewRange::Axis::X, min, max);
|
||||
@@ -273,18 +270,18 @@ void HistogramController::initBarParameters() {
|
||||
|
||||
void HistogramController::initBarSelection() {
|
||||
*m_selectedBarIndex = 0;
|
||||
while ((m_store->heightOfBarAtIndex(*m_selectedBarIndex) == 0 ||
|
||||
m_store->startOfBarAtIndex(*m_selectedBarIndex) < m_store->firstDrawnBarAbscissa()) && *m_selectedBarIndex < m_store->numberOfBars()) {
|
||||
while ((m_store->heightOfBarAtIndex(0, *m_selectedBarIndex) == 0 || //TODO
|
||||
m_store->startOfBarAtIndex(0, *m_selectedBarIndex) < m_store->firstDrawnBarAbscissa()) && *m_selectedBarIndex < m_store->numberOfBars(0)) {//TODO
|
||||
*m_selectedBarIndex = *m_selectedBarIndex+1;
|
||||
}
|
||||
if (*m_selectedBarIndex >= m_store->numberOfBars()) {
|
||||
if (*m_selectedBarIndex >= m_store->numberOfBars(0)) { //TODO
|
||||
/* No bar is after m_firstDrawnBarAbscissa, so we select the first bar */
|
||||
*m_selectedBarIndex = 0;
|
||||
while (m_store->heightOfBarAtIndex(*m_selectedBarIndex) == 0 && *m_selectedBarIndex < m_store->numberOfBars()) {
|
||||
while (m_store->heightOfBarAtIndex(0, *m_selectedBarIndex) == 0 && *m_selectedBarIndex < m_store->numberOfBars(0)) { //TODO
|
||||
*m_selectedBarIndex = *m_selectedBarIndex+1;
|
||||
}
|
||||
}
|
||||
m_store->scrollToSelectedBarIndex(*m_selectedBarIndex);
|
||||
m_store->scrollToSelectedBarIndex(0, *m_selectedBarIndex);//TODO
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -43,18 +43,62 @@ double HistogramParameterController::parameterAtIndex(int index) {
|
||||
bool HistogramParameterController::setParameterAtIndex(int parameterIndex, double f) {
|
||||
assert(parameterIndex >= 0 && parameterIndex < k_numberOfCells);
|
||||
if (parameterIndex == 0) {
|
||||
double newNumberOfBars = std::ceil((m_store->maxValue() - m_store->minValue())/f);
|
||||
if (f <= 0.0f || newNumberOfBars > Store::k_maxNumberOfBars || m_store->firstDrawnBarAbscissa() > m_store->maxValue()+f) {
|
||||
// The bar width cannot be negative
|
||||
if (f <= 0.0f) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
// There should be at least one value in the drawn bin
|
||||
for (int i = 0; i < FloatPairStore::k_numberOfSeries; i++) {
|
||||
if (m_store->firstDrawnBarAbscissa() <= m_store->maxValue(i)+f) {
|
||||
break;
|
||||
} else if (i == FloatPairStore::k_numberOfSeries - 1) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The number of bars cannot be above the max
|
||||
assert(FloatPairStore::k_numberOfSeries > 0);
|
||||
double maxNewNumberOfBars = std::ceil((m_store->maxValue(0) - m_store->minValue(0))/f);
|
||||
for (int i = 1; i < FloatPairStore::k_numberOfSeries; i++) {
|
||||
double numberOfBars = std::ceil((m_store->maxValue(i) - m_store->minValue(i))/f);
|
||||
if (maxNewNumberOfBars < numberOfBars) {
|
||||
maxNewNumberOfBars = numberOfBars;
|
||||
}
|
||||
}
|
||||
if (maxNewNumberOfBars > Store::k_maxNumberOfBars) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the bar width
|
||||
m_store->setBarWidth(f);
|
||||
} else {
|
||||
double newNumberOfBars = ceilf((m_store->maxValue() - f)/m_store->barWidth());
|
||||
if (newNumberOfBars > Store::k_maxNumberOfBars || f > m_store->maxValue()+m_store->barWidth()) {
|
||||
// The number of bars cannot be above the max
|
||||
assert(FloatPairStore::k_numberOfSeries > 0);
|
||||
double maxNewNumberOfBars = ceilf((m_store->maxValue(0) - f)/m_store->barWidth());
|
||||
for (int i = 1; i < FloatPairStore::k_numberOfSeries; i++) {
|
||||
double numberOfBars = ceilf((m_store->maxValue(i) - f)/m_store->barWidth());
|
||||
if (maxNewNumberOfBars < numberOfBars) {
|
||||
maxNewNumberOfBars = numberOfBars;
|
||||
}
|
||||
}
|
||||
if (maxNewNumberOfBars > Store::k_maxNumberOfBars) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
// There should be at least one value in the drawn bin
|
||||
for (int i = 0; i < FloatPairStore::k_numberOfSeries; i++) {
|
||||
if (f <= m_store->maxValue(i)+m_store->barWidth()) {
|
||||
break;
|
||||
} else if (i == FloatPairStore::k_numberOfSeries - 1) {
|
||||
app()->displayWarning(I18n::Message::ForbiddenValue);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Set the first drawn bar abscissa
|
||||
m_store->setFirstDrawnBarAbscissa(f);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -32,11 +32,12 @@ void HistogramView::drawRect(KDContext * ctx, KDRect rect) const {
|
||||
drawLabels(ctx, rect, Axis::Horizontal, false);
|
||||
/* We memoize the total size to avoid recomputing it in double precision at
|
||||
* every call to EvaluateHistogramAtAbscissa() */
|
||||
float totalSize = m_store->sumOfColumn(1);
|
||||
float totalSize = m_store->sumOfColumn(0, 1); // TODO Draw all the histograms
|
||||
float context[] = {totalSize, 0};
|
||||
if (isMainViewSelected()) {
|
||||
drawHistogram(ctx, rect, EvaluateHistogramAtAbscissa, m_store, &totalSize, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::Select, Palette::YellowDark, m_highlightedBarStart, m_highlightedBarEnd);
|
||||
drawHistogram(ctx, rect, EvaluateHistogramAtAbscissa, m_store, context, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::Select, Palette::YellowDark, m_highlightedBarStart, m_highlightedBarEnd);
|
||||
} else {
|
||||
drawHistogram(ctx, rect, EvaluateHistogramAtAbscissa, m_store, &totalSize, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::GreyMiddle, Palette::YellowDark);
|
||||
drawHistogram(ctx, rect, EvaluateHistogramAtAbscissa, m_store, context, m_store->firstDrawnBarAbscissa(), m_store->barWidth(), true, Palette::GreyMiddle, Palette::YellowDark);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,8 +59,9 @@ char * HistogramView::label(Axis axis, int index) const {
|
||||
|
||||
float HistogramView::EvaluateHistogramAtAbscissa(float abscissa, void * model, void * context) {
|
||||
Store * store = (Store *)model;
|
||||
float * totalSize = (float *)context;
|
||||
return store->heightOfBarAtValue(abscissa)/(*totalSize);
|
||||
float totalSize = ((float *)context)[0];
|
||||
int series = ((float *)context)[1];
|
||||
return store->heightOfBarAtValue(series, abscissa)/(totalSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ void Store::setBarWidth(double barWidth) {
|
||||
}
|
||||
|
||||
double Store::heightOfBarAtIndex(int series, int index) {
|
||||
return sumOfValuesBetween(startOfBarAtIndex(series, index), endOfBarAtIndex(series, index));
|
||||
return sumOfValuesBetween(series, startOfBarAtIndex(series, index), endOfBarAtIndex(series, index));
|
||||
}
|
||||
|
||||
double Store::heightOfBarAtValue(int series, double value) {
|
||||
@@ -76,15 +76,48 @@ bool Store::scrollToSelectedBarIndex(int series, int index) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Store::isEmpty() {
|
||||
for (int i = 0; i < k_numberOfSeries; i ++) {
|
||||
if (sumOfOccurrences(i) > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Calculation */
|
||||
|
||||
double Store::sumOfOccurrences(int series) {
|
||||
return sumOfColumn(series, 1);
|
||||
}
|
||||
|
||||
double Store::maxValueForAllSeries() {
|
||||
assert(FloatPairStore::k_numberOfSeries > 0);
|
||||
double result = maxValue(0);
|
||||
for (int i = 1; i < FloatPairStore::k_numberOfSeries; i++) {
|
||||
double maxCurrentSeries = maxValue(i);
|
||||
if (result < maxCurrentSeries) {
|
||||
result = maxCurrentSeries;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double Store::minValueForAllSeries() {
|
||||
assert(FloatPairStore::k_numberOfSeries > 0);
|
||||
double result = minValue(0);
|
||||
for (int i = 1; i < FloatPairStore::k_numberOfSeries; i++) {
|
||||
double minCurrentSeries = minValue(i);
|
||||
if (result > minCurrentSeries) {
|
||||
result = minCurrentSeries;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
double Store::maxValue(int series) {
|
||||
double max = -DBL_MAX;
|
||||
for (int k = 0; k < m_numberOfPairs; k++) {
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
if (m_data[series][0][k] > max && m_data[series][1][k] > 0) {
|
||||
max = m_data[series][0][k];
|
||||
}
|
||||
@@ -94,7 +127,7 @@ double Store::maxValue(int series) {
|
||||
|
||||
double Store::minValue(int series) {
|
||||
double min = DBL_MAX;
|
||||
for (int k = 0; k < m_numberOfPairs; k++) {
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
if (m_data[series][0][k] < min && m_data[series][1][k] > 0) {
|
||||
min = m_data[series][0][k];
|
||||
}
|
||||
@@ -136,7 +169,7 @@ double Store::thirdQuartile(int series) {
|
||||
}
|
||||
|
||||
double Store::quartileRange(int series) {
|
||||
return thirdQuartile()-firstQuartile();
|
||||
return thirdQuartile(series)-firstQuartile(series);
|
||||
}
|
||||
|
||||
double Store::median(int series) {
|
||||
@@ -154,7 +187,7 @@ double Store::median(int series) {
|
||||
|
||||
double Store::sum(int series) {
|
||||
double result = 0;
|
||||
for (int k = 0; k < m_numberOfPairs; k++) {
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
result += m_data[series][0][k]*m_data[series][1][k];
|
||||
}
|
||||
return result;
|
||||
@@ -162,7 +195,7 @@ double Store::sum(int series) {
|
||||
|
||||
double Store::squaredValueSum(int series) {
|
||||
double result = 0;
|
||||
for (int k = 0; k < m_numberOfPairs; k++) {
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
result += m_data[series][0][k]*m_data[series][0][k]*m_data[series][1][k];
|
||||
}
|
||||
return result;
|
||||
@@ -174,7 +207,7 @@ double Store::defaultValue(int series, int i, int j) {
|
||||
return i == 0 ? FloatPairStore::defaultValue(series, i, j) : 1.0;
|
||||
}
|
||||
|
||||
double Store::sumOfValuesBetween(double x1, double x2) {
|
||||
double Store::sumOfValuesBetween(int series, double x1, double x2) {
|
||||
double result = 0;
|
||||
for (int k = 0; k < m_numberOfPairs[series]; k++) {
|
||||
if (m_data[series][0][k] < x2 && x1 <= m_data[series][0][k]) {
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
double barWidth() const { return m_barWidth; }
|
||||
void setBarWidth(double barWidth);
|
||||
double firstDrawnBarAbscissa() const { return m_firstDrawnBarAbscissa; }
|
||||
void setFirstDrawnBarAbscissa(double firstDrawnBarAbscissa) { m_firstDrawnBarAbscissa = firstBarAbscissa;}
|
||||
void setFirstDrawnBarAbscissa(double firstDrawnBarAbscissa) { m_firstDrawnBarAbscissa = firstDrawnBarAbscissa;}
|
||||
double heightOfBarAtIndex(int series, int index);
|
||||
double heightOfBarAtValue(int series, double value);
|
||||
double startOfBarAtIndex(int series, int index);
|
||||
@@ -22,9 +22,12 @@ public:
|
||||
double numberOfBars(int series);
|
||||
// return true if the window has scrolled
|
||||
bool scrollToSelectedBarIndex(int series, int index);
|
||||
bool isEmpty();
|
||||
|
||||
// Calculation
|
||||
double sumOfOccurrences(int series);
|
||||
double maxValueForAllSeries();
|
||||
double minValueForAllSeries();
|
||||
double maxValue(int series);
|
||||
double minValue(int series);
|
||||
double range(int series);
|
||||
@@ -53,7 +56,7 @@ private:
|
||||
double m_firstDrawnBarAbscissa;
|
||||
};
|
||||
|
||||
typedef double (Store::*CalculPointer)();
|
||||
typedef double (Store::*CalculPointer)(int);
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user