Bug 141448

Summary: No numbers on axes when zooming a log-scale plot
Product: [Applications] kst Reporter: Eli Fidler <eli>
Component: generalAssignee: kst
Status: RESOLVED FIXED    
Severity: normal    
Priority: NOR    
Version: 1.x   
Target Milestone: ---   
Platform: unspecified   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description Eli Fidler 2007-02-09 18:33:33 UTC
Version:           1.4.0_devel (using KDE 3.5.6 "release 25.2" , openSUSE )
Compiler:          Target: i586-suse-linux
OS:                Linux (i686) release 2.6.16.27-0.6-smp

When zooming in on a log-scale plot (e.g. the PSD in demo.kst), if the zoom area is between numbers on either axis, no numbers appear on the axis of the zoomed-in plot.

For example, zoom in on a box where the Y-axis is just above 0.01 to just below 0.1 and the X-axis is just above 0.001 to just below 0.01. There will be no numbers on either axis.
Comment 1 Netterfield 2007-02-09 18:55:13 UTC
The solution I have seen on the net is to label some of the minor ticks in 
this situation.  If the user insists on a log plot with small enough dynamic 
range, eventually it will be impossible to do much of anything with it... and 
we might wonder why they are using a log plot.

In the past we have tried
	-linear ticks, labelled accurately (*very* ugly and hard to use)
	-log2 ticks (minor ticks don't make sense, and only gives a small amount of 
extra dynamic range).
Comment 2 Andrew Walker 2007-02-12 20:16:08 UTC
It is surely better to have some labels (no matter how ugly) than nothing. I think most people appreciate the former and understand why they are necessarily "ugly" while the latter approach looks more like a poorly implemented feature or bug.
Comment 3 Netterfield 2007-03-28 20:43:33 UTC
The 'right' solution, based on google images, is:
-always label at least to tick marks.
-Prefer major ticks
-revert to minor ticks if you have to.
-when reverting to minor ticks, chose them maximally far apart.

If no ticks are visible, then log plot makes not sense, and you deserve to have a whacked looking plot :-)

The architecture of 2dplot currently makes this painful.
Comment 4 Andrew Walker 2007-06-28 21:07:37 UTC
SVN commit 681380 by arwalker:

CCBUG:141448 First draft of labelling minor ticks

 M  +323 -261  libkstapp/kst2dplot.cpp  
 M  +6 -7      libkstapp/kst2dplot.h  
 M  +11 -5     libkstmath/kstplotdefines.h  
Comment 5 Andrew Walker 2007-06-28 23:38:00 UTC
SVN commit 681426 by arwalker:

BUG:141448 Label minor ticks maximally far apart

 M  +54 -34    kst2dplot.cpp  


--- branches/work/kst/1.5/kst/src/libkstapp/kst2dplot.cpp #681425:681426
@@ -1931,21 +1931,21 @@
   QString strPrefix;
   double range;
   double scale = 1.0;
-  double value;
+  double value = 0.0;
   bool bDuplicate = false;
   uint uiShortestLength = 1000;
   uint length;
   int minorTicks;
   int iShort = 0;
   int base = 60;
-  KstPlotLabel *tick_label;
+  KstPlotLabel *tickLabel;
   TickLabelDescription labelDescr;
 
   if (isX) {
-    tick_label = _xTickLabel;
+    tickLabel = _xTickLabel;
     minorTicks = _xMinorTicks;
   } else {
-    tick_label = _yTickLabel;
+    tickLabel = _yTickLabel;
     minorTicks = _yMinorTicks;
   }
 
@@ -1979,8 +1979,8 @@
       value = (double)i * tp.tick + tp.org;
       if (value >= Min && value <= Max) {
         genAxisTickLabel(strTmp, value, isLog, logBase, false);
-        tick_label->setText(strTmp);
-        QSize lsize = tick_label->size();
+        tickLabel->setText(strTmp);
+        QSize lsize = tickLabel->size();
 
         tp.maxWidth = kMax(tp.maxWidth, double(lsize.width()));
         tp.maxHeight = kMax(tp.maxHeight, double(lsize.height()));
@@ -2004,9 +2004,32 @@
 
     if (isLog && tp.labelMinor) {
       double step = (pow(logBase, (double)(i+1) * tp.tick + tp.org) - pow(logBase, (double)i * tp.tick + tp.org)) / minorTicks;
+      bool labelFirst = false;
       int j;
 
       for (j = 1; j < minorTicks; j++) {
+        if (labelFirst) {
+          if (j == minorTicks - 1) {
+            // value of next major tick...
+            value = (double)(i+1) * tp.tick + tp.org;
+            if (value >= Min && value <= Max) {
+              // don't label the current minor tick if we're about to label the next minor tick
+              continue;
+            }
+          } else {
+            // value of next minor tick...
+            if (isX) {
+              value = logXLo(pow(logBase, (double)i * tp.tick + tp.org) + ((double)(j+1) * step));
+            } else {
+              value = logYLo(pow(logBase, (double)i * tp.tick + tp.org) + ((double)(j+1) * step));
+            }
+            if (value > Min && value < Max) {
+              // don't label the current minor tick if we're about to label the next minor tick
+              continue;
+            }
+          }
+        }
+
         if (isX) {
           value = logXLo(pow(logBase, (double)i * tp.tick + tp.org) + ((double)j * step));
         } else {
@@ -2015,8 +2038,8 @@
 
         if (value > Min && value < Max) {
           genAxisTickLabel(strTmp, value, true, logBase, true);
-          tick_label->setText(strTmp);
-          QSize lsize = tick_label->size();
+          tickLabel->setText(strTmp);
+          QSize lsize = tickLabel->size();
 
           tp.maxWidth = kMax(tp.maxWidth, double(lsize.width()));
           tp.maxHeight = kMax(tp.maxHeight, double(lsize.height()));
@@ -2025,6 +2048,8 @@
           labelDescr.position = value;
           labelDescr.minorTick = true;
           tp.labels.append(labelDescr);
+
+          labelFirst = true;
         }
       }
     }
@@ -2032,33 +2057,28 @@
 
   // also generate labels for opposite axis if needed
   if ((isX && _xTransformed) || (!isX && _yTransformed)) {
-    for (int i = tp.iLo; i < tp.iHi; i++) {
+    for (QValueList<TickLabelDescription>::ConstIterator iter = tp.labels.begin(); iter != tp.labels.end(); ++iter) {
       double transformedNumber;
       bool transformedOK = false;
-      double originalNumber = (double)i * tp.tick + tp.org;
+      double originalNumber = (*iter).position;
 
-      if (originalNumber > Min && originalNumber < Max) {
-        if (isLog) {
-          originalNumber = pow(logBase, originalNumber);
-        }
-        // case insensitive replace
-        QString replacedExp = isX ? _xTransformedExp : _yTransformedExp;
-        replacedExp.replace(isX ? "x" : "y", QString::number(originalNumber), false);
-        transformedNumber = Equation::interpret(replacedExp.latin1(), &transformedOK, replacedExp.length());
-        tick_label->setText(QString::number(transformedNumber, 'g', LABEL_PRECISION));
-        if (!transformedOK) {
-          tick_label->setText("NaN");
-        }
-        labelDescr.label = tick_label->text();
-        labelDescr.position = originalNumber;
-        labelDescr.minorTick = false;
-        tp.labelsOpposite.append(labelDescr);
+      // case insensitive replace
+      QString replacedExp = isX ? _xTransformedExp : _yTransformedExp;
+      replacedExp.replace(isX ? "x" : "y", QString::number(originalNumber), false);
+      transformedNumber = Equation::interpret(replacedExp.latin1(), &transformedOK, replacedExp.length());
+      tickLabel->setText(QString::number(transformedNumber, 'g', LABEL_PRECISION));
+      if (!transformedOK) {
+        tickLabel->setText("NaN");
+      }
+      labelDescr.label = tickLabel->text();
+      labelDescr.position = originalNumber;
+      labelDescr.minorTick = false;
+      tp.labelsOpposite.append(labelDescr);
 
-        // update the max height and width of opposite labels
-        QSize lsize = tick_label->size();
-        tp.oppMaxWidth = kMax(tp.oppMaxWidth, double(lsize.width()));
-        tp.oppMaxHeight = kMax(tp.oppMaxHeight, double(lsize.height()));
-      }
+      // update the max height and width of opposite labels
+      QSize lsize = tickLabel->size();
+      tp.oppMaxWidth = kMax(tp.oppMaxWidth, double(lsize.width()));
+      tp.oppMaxHeight = kMax(tp.oppMaxHeight, double(lsize.height()));
     }
   }
 
@@ -2090,12 +2110,12 @@
       value = (double)i * tp.tick + tp.org;
       if (value > Min && value < Max) {
         labelDescr.label = strTmp;
-        labelDescr.position = (double)i * tp.tick + tp.org;
+        labelDescr.position = value;
         labelDescr.minorTick = false;
         tp.labels.append(labelDescr);
 
-        tick_label->setText(strTmp);
-        QSize lsize = tick_label->size();
+        tickLabel->setText(strTmp);
+        QSize lsize = tickLabel->size();
         tp.maxWidth = kMax(tp.maxWidth, double(lsize.width()));
         tp.maxHeight = kMax(tp.maxHeight, double(lsize.height()));
       }