Commit 1412cda2 authored by David Thompson's avatar David Thompson

Fix LogScale mode of vtkAxis.

This change is to address ParaView bugs 13876, 13877, and 13899.
It removes LogScaleReasonable and the associated logic which was
contributing to nonsensical ranges for logarithmic axes.

This patch also adds methods {Get,Set}Unscaled{Minimum,Maximum,Range}()
so that fixed ranges may be specified in the same coordinate
system as the source data. The versions of these methods without
"Unscaled" in their names expect log-values to be passed or
returned when LogScale is true, which is difficult for user-interface
code to track.

Additional changes are required to address the test case of
ParaView bug 13899. With these changes, the minimum and maximum
limit values are properly transformed when switching to and from
log-scaled axes.

Plots that rely on axes to determine scaling are fixed
to refer to the active scaling (GetLogScaleActive) instead of
the desired scaling (GetLogScale)..

Change-Id: I1a4a3882bbeab2484145f4a75a6430cf6a0cea42
parent 462c2c15
......@@ -29,6 +29,8 @@
//----------------------------------------------------------------------------
int TestAxes(int , char * [])
{
int status = EXIT_SUCCESS;
// Set up a 2D scene, add an XY chart to it
vtkNew<vtkContextView> view;
view->GetRenderWindow()->SetSize(500, 300);
......@@ -54,6 +56,7 @@ int TestAxes(int , char * [])
axis->SetPoint1(vtkVector2f(i * 69 + 30, 10));
axis->SetPoint2(vtkVector2f(i * 69 + 30, 290));
axis->SetPosition(i % 2 ? vtkAxis::LEFT : vtkAxis::RIGHT);
axis->SetRange(NULL); // check that NULL pointers don't cause trouble
axis->SetRange(-1, 50);
view->GetScene()->AddItem(axis);
......@@ -98,7 +101,38 @@ int TestAxes(int , char * [])
}
// Now to test some of the API in the horizontal axes.
axesHorizontal[0]->LogScaleOn(); // LogScaleActive=false because min*max<0
axesHorizontal[0]->SetUnscaledRange(1,100); // LogScaleActive becomes true
double range[2];
axesHorizontal[0]->GetRange(range);
if (!axesHorizontal[0]->GetLogScaleActive() ||
fabs(range[0]) > 1e-8 || fabs(range[1] - 2.) > 1e-8)
{
cerr << "ERROR: did not transition to log scaling when range changed.\n";
status = EXIT_FAILURE;
}
// Now change the axis limits in log-space...
axesHorizontal[0]->SetMinimumLimit(-1.);
axesHorizontal[0]->SetMaximumLimit(3.);
// ... and verify that the unscaled limits have changed:
if (
fabs(axesHorizontal[0]->GetUnscaledMinimumLimit()-0.1) > 1e-8 ||
fabs(axesHorizontal[0]->GetUnscaledMaximumLimit()-1000.0) > 1e-8)
{
cerr
<< "ERROR: did not update unscaled limits when scaled limits changed.\n";
status = EXIT_FAILURE;
}
axesHorizontal[0]->LogScaleOff();
if (axesHorizontal[0]->GetLogScaleActive() ||
-axesHorizontal[0]->GetMinimumLimit() ==
axesHorizontal[0]->GetMaximumLimit())
{
cerr << "ERROR: did not transition from log scaling or reset limits.\n";
status = EXIT_FAILURE;
}
axesHorizontal[0]->AutoScale();
axesHorizontal[0]->SetRange(20, 60); // restore range so rest of test can proceed
axesHorizontal[1]->SetRange(10, -5);
axesHorizontal[1]->AutoScale();
......@@ -123,11 +157,50 @@ int TestAxes(int , char * [])
axesHorizontal[i]->Update();
}
// Test LogScale and UnscaledRange methods
vtkNew<vtkAxis> logAxis;
double plainRange[2] = {0.1, 1000.0};
double logRange[2];
logAxis->SetUnscaledRange(plainRange);
logAxis->LogScaleOn();
logAxis->GetUnscaledRange(NULL); // Insure NULL pointers are ignored.
logAxis->GetUnscaledRange(logRange);
if ((logRange[0] != plainRange[0]) || (logRange[1] != plainRange[1]))
{
vtkGenericWarningMacro(
<< "Error: expected unscaled range to be unchanged but got ["
<< logRange[0] << ", " << logRange[1] << "].");
}
logAxis->GetRange(logRange);
if (
(fabs((pow(10., logRange[0]) - plainRange[0])) > 1e-6) ||
(fabs((pow(10., logRange[1]) - plainRange[1])) > 1e-6))
{
vtkGenericWarningMacro(
<< "Error: expected scaled range to be [-1, 3] but got ["
<< logRange[0] << ", " << logRange[1] << "].");
}
if (
(logAxis->GetMinimum() != logRange[0]) ||
(logAxis->GetMaximum() != logRange[1]) ||
(logAxis->GetUnscaledMinimum() != plainRange[0]) ||
(logAxis->GetUnscaledMaximum() != plainRange[1]))
{
vtkGenericWarningMacro(
"Error: returned ranges do not match returned min/max.");
}
logAxis->SetMinimum(logRange[0]);
logAxis->SetMaximum(logRange[1]);
logAxis->Update();
logAxis->SetUnscaledMinimum(plainRange[0]);
logAxis->SetUnscaledMaximum(plainRange[1]);
logAxis->Update();
// Finally render the scene and compare the image to a reference image, or
// start the main interactor loop if the test is interactive.
view->GetRenderWindow()->SetMultiSamples(0);
view->GetInteractor()->Initialize();
view->GetInteractor()->Start();
return EXIT_SUCCESS;
return status;
}
This diff is collapsed.
......@@ -19,6 +19,31 @@
// The vtkAxis is drawn in screen coordinates. It is usually one of the last
// elements of a chart to be drawn. It renders the axis label, tick marks and
// tick labels.
// The tick marks and labels span the range of values between
// \a Minimum and \a Maximum.
// The \a Minimum and \a Maximum values are not allowed to extend beyond the
// \a MinimumLimit and \a MaximumLimit values, respectively.
//
// Note that many other chart elements (e.g., vtkPlotPoints) refer to
// vtkAxis instances to determine how to scale raw data for presentation.
// In particular, care must be taken with logarithmic scaling.
// The axis Minimum, Maximum, and Limit values are stored both unscaled
// and scaled (with log(x) applied when GetLogScaleActive() returns true).
// User interfaces will most likely present the unscaled values as they
// represent the values provided by the user.
// Other chart elements may need the scaled values in order to draw
// in the same coordinate system.
//
// Just because LogScale is set to true does not guarantee that the axis
// will use logarithmic scaling -- the Minimum and Maximum values for the
// axis must both lie to the same side of origin (and not include the origin).
// Also, this switch from linear- to log-scaling may occur during a rendering
// pass if autoscaling is enabled.
// Because the log and pow functions are not invertible and the axis itself
// decides when to switch between them without offering any external class
// managing the axis a chance to save the old values, it saves
// old Limit values in NonLogUnscaled{Min,Max}Limit so that behavior is
// consistent when LogScale is changed from false to true and back again.
#ifndef __vtkAxis_h
#define __vtkAxis_h
......@@ -104,28 +129,67 @@ public:
// Description:
// Set the logical minimum value of the axis, in plot coordinates.
// If LogScaleActive is true (not just LogScale), then this
// sets the minimum base-10 <b>exponent</b>.
virtual void SetMinimum(double minimum);
// Description:
// Get the logical minimum value of the axis, in plot coordinates.
// If LogScaleActive is true (not just LogScale), then this
// returns the minimum base-10 <b>exponent</b>.
vtkGetMacro(Minimum, double);
// Description:
// Set the logical maximum value of the axis, in plot coordinates.
// If LogScaleActive is true (not just LogScale), then this
// sets the maximum base-10 <b>exponent</b>.
virtual void SetMaximum(double maximum);
// Description:
// Get the logical maximum value of the axis, in plot coordinates.
// If LogScaleActive is true (not just LogScale), then this
// returns the maximum base-10 <b>exponent</b>.
vtkGetMacro(Maximum, double);
// Description:
// Set the logical, unscaled minimum value of the axis, in plot coordinates.
// Use this instead of SetMinimum() if you wish to provide the actual minimum
// instead of log10(the minimum) as part of the axis scale.
virtual void SetUnscaledMinimum(double minimum);
// Description:
// Get the logical minimum value of the axis, in plot coordinates.
vtkGetMacro(UnscaledMinimum, double);
// Description:
// Set the logical maximum value of the axis, in plot coordinates.
virtual void SetUnscaledMaximum(double maximum);
// Description:
// Get the logical maximum value of the axis, in plot coordinates.
vtkGetMacro(UnscaledMaximum, double);
// Description:
// Set the logical range of the axis, in plot coordinates.
//
// The unscaled range will always be in the same coordinate system of
// the data being plotted, regardless of whether LogScale is true or false.
// When calling SetRange() and LogScale is true, the range must be specified
// in logarithmic coordinates.
// Using SetUnscaledRange(), you may ignore the value of LogScale.
virtual void SetRange(double minimum, double maximum);
virtual void SetRange(double range[2]);
virtual void SetUnscaledRange(double minimum, double maximum);
virtual void SetUnscaledRange(double range[2]);
// Description:
// Get the logical range of the axis, in plot coordinates.
//
// The unscaled range will always be in the same coordinate system of
// the data being plotted, regardless of whether LogScale is true or false.
// Calling GetRange() when LogScale is true will return the log10({min, max}).
virtual void GetRange(double *range);
virtual void GetUnscaledRange(double *range);
// Description:
// Set the logical lowest possible value for \a Minimum, in plot coordinates.
......@@ -143,6 +207,22 @@ public:
// Get the logical highest possible value for \a Maximum, in plot coordinates.
vtkGetMacro(MaximumLimit, double);
// Description:
// Set the logical lowest possible value for \a Minimum, in plot coordinates.
virtual void SetUnscaledMinimumLimit(double lowest);
// Description:
// Get the logical lowest possible value for \a Minimum, in plot coordinates.
vtkGetMacro(UnscaledMinimumLimit, double);
// Description:
// Set the logical highest possible value for \a Maximum, in plot coordinates.
virtual void SetUnscaledMaximumLimit(double highest);
// Description:
// Get the logical highest possible value for \a Maximum, in plot coordinates.
vtkGetMacro(UnscaledMaximumLimit, double);
// Description:
// Get the margins of the axis, in pixels.
vtkGetVector2Macro(Margins, int);
......@@ -161,9 +241,26 @@ public:
vtkGetObjectMacro(TitleProperties, vtkTextProperty);
// Description:
// Get/set whether the axis should use a log scale, default is false.
vtkSetMacro(LogScale, bool);
// Get whether the axis is using a log scale.
// This will always be false when LogScale is false.
// It is only true when LogScale is true <b>and</b> the \a UnscaledRange
// does not cross or include the origin (zero).
//
// The limits (\a MinimumLimit, \a MaximumLimit, and their
// unscaled counterparts) do not prevent LogScaleActive from becoming
// true; they are adjusted if they cross or include the origin
// and the original limits are preserved for when LogScaleActive
// becomes false again.
vtkGetMacro(LogScaleActive, bool);
// Description:
// Get/set whether the axis should <b>attempt</b> to use a log scale.
//
// The default is false.
// \sa{LogScaleActive}.
vtkGetMacro(LogScale, bool);
virtual void SetLogScale(bool logScale);
vtkBooleanMacro(LogScale,bool);
// Description:
// Get/set whether the axis grid lines should be drawn, default is true.
......@@ -311,6 +408,15 @@ protected:
vtkAxis();
~vtkAxis();
// Description:
// Update whether log scaling will be used for layout and rendering.
//
// Log scaling is only active when LogScaling is true <b>and</b> the closed,
// unscaled range does not contain the origin.
// The boolean parameter determines whether the minimum and maximum values
// are set from their unscaled counterparts.
void UpdateLogScaleActive(bool updateMinMaxFromUnscaled);
// Description:
// Calculate and assign nice labels/logical label positions.
void GenerateTickLabels(double min, double max);
......@@ -339,6 +445,18 @@ protected:
bool &niceValue,
int &order);
// Description:
// Generate logarithmically-spaced tick marks with linear-style labels.
//
// This is for the case when log scaling is active, but the axis min and max
// span less than an order of magnitude.
// In this case, the most significant digit that varies is identified and
// ticks generated for each value that digit may take on. If that results
// in only 2 tick marks, the next-most-significant digit is varied.
// If more than 20 tick marks would result, the stride for the varying digit
// is increased.
void GenerateLogSpacedLinearTicks(int order, double min, double max);
// Description:
// Generate tick marks for logarithmic scale for specific order of magnitude.
// Mark generation is limited by parameters min and max.
......@@ -364,10 +482,17 @@ protected:
double Maximum; // Maximum values of the axis
double MinimumLimit; // Lowest possible value for Minimum
double MaximumLimit; // Highest possible value for Maximum
double UnscaledMinimum; // UnscaledMinimum value of the axis
double UnscaledMaximum; // UnscaledMaximum values of the axis
double UnscaledMinimumLimit; // Lowest possible value for UnscaledMinimum
double UnscaledMaximumLimit; // Highest possible value for UnscaledMaximum
double NonLogUnscaledMinLimit; // Saved UnscaledMinimumLimit (when !LogActive)
double NonLogUnscaledMaxLimit; // Saved UnscaledMinimumLimit (when !LogActive)
int Margins[2]; // Horizontal/vertical margins for the axis
vtkStdString Title; // The text label drawn on the axis
vtkTextProperty* TitleProperties; // Text properties for the axis title
bool LogScale; // Should the axis use a log scale
bool LogScale; // *Should* the axis use a log scale?
bool LogScaleActive; // *Is* the axis using a log scale?
bool GridVisible; // Whether the grid for the axis should be drawn
bool LabelsVisible; // Should the axis labels be visible
bool TicksVisible; // Should the tick marks be visible.
......@@ -415,10 +540,6 @@ protected:
// Flag to indicate that the axis has been resized.
bool Resized;
// Description:
// Hint as to whether a logarithmic scale is reasonable or not.
bool LogScaleReasonable;
// Description:
// The algorithm being used to tick label placement.
int TickLabelAlgorithm;
......
......@@ -14,6 +14,8 @@
=========================================================================*/
#include "vtkAxisExtended.h"
#include "vtkMath.h" // for VTK_DBL_EPSILON
#include "vtkStdString.h"
#include "vtkObjectFactory.h"
......
......@@ -29,12 +29,6 @@
#include "vtkChartsCoreModule.h" // For export macro
#include "vtkObject.h"
#include "vtkVector.h" // Needed for vtkVector
//
#ifndef DBL_EPSILON
# define VTK_DBL_EPSILON 2.2204460492503131e-16
#else // DBL_EPSILON
# define VTK_DBL_EPSILON DBL_EPSILON
#endif // DBL_EPSILON
class VTKCHARTSCORE_EXPORT vtkAxisExtended : public vtkObject
{
......
......@@ -192,7 +192,7 @@ void vtkChartXY::Update()
{
this->AnnotationLink->Update();
vtkSelection *selection =
vtkSelection::SafeDownCast(this->AnnotationLink->GetOutputDataObject(2));
vtkSelection::SafeDownCast(this->AnnotationLink->GetOutputDataObject(2));
if (selection->GetNumberOfNodes())
{
vtkSelectionNode *node = selection->GetNode(0);
......@@ -466,11 +466,11 @@ void vtkChartXY::RecalculatePlotTransforms()
yAxis = this->ChartPrivate->axes[vtkAxis::LEFT];
break;
default:
vtkWarningMacro("Error: default case in recalculate plot transforms.");
vtkWarningMacro(
"Error: default case in recalculate plot transforms.");
}
this->CalculatePlotTransform(xAxis, yAxis,
this->ChartPrivate
->PlotCorners[i]->GetTransform());
this->CalculatePlotTransform(
xAxis, yAxis, this->ChartPrivate->PlotCorners[i]->GetTransform());
}
}
this->PlotTransformValid = true;
......
......@@ -193,7 +193,7 @@ void vtkChartXYZ::RecalculateBounds()
}
for (int i = 0; i < 3; ++i)
{
this->Axes[i]->SetRange(&bounds[2*i]);
this->Axes[i]->SetUnscaledRange(&bounds[2*i]);
}
// Recalculate transform since axes' ranges were modified
......@@ -1531,7 +1531,8 @@ bool vtkChartXYZ::CalculatePlotTransform(vtkAxis *x, vtkAxis *y, vtkAxis *z,
{
return false;
}
float xScale = (x->GetMaximum() - x->GetMinimum()) / (max[0] - min[0]);
float xScale =
(x->GetUnscaledMaximum() - x->GetUnscaledMinimum()) / (max[0] - min[0]);
// Now the y axis
min = y->GetPoint1();
......@@ -1540,7 +1541,8 @@ bool vtkChartXYZ::CalculatePlotTransform(vtkAxis *x, vtkAxis *y, vtkAxis *z,
{
return false;
}
float yScale = (y->GetMaximum() - y->GetMinimum()) / (max[1] - min[1]);
float yScale =
(y->GetUnscaledMaximum() - y->GetUnscaledMinimum()) / (max[1] - min[1]);
// Now the z axis
min = z->GetPoint1();
......@@ -1549,13 +1551,17 @@ bool vtkChartXYZ::CalculatePlotTransform(vtkAxis *x, vtkAxis *y, vtkAxis *z,
{
return false;
}
float zScale = (z->GetMaximum() - z->GetMinimum()) / (max[1] - min[1]);
float zScale =
(z->GetUnscaledMaximum() - z->GetUnscaledMinimum()) / (max[1] - min[1]);
transform->Identity();
transform->Translate(this->Geometry.GetX(), this->Geometry.GetY(), 0);
// Get the scale for the plot area from the x and y axes
transform->Scale(1.0 / xScale, 1.0 / yScale, 1.0 / zScale);
transform->Translate(-x->GetMinimum(), -y->GetMinimum(), -z->GetMinimum());
transform->Translate(
-x->GetUnscaledMinimum(),
-y->GetUnscaledMinimum(),
-z->GetUnscaledMinimum());
return true;
}
......
......@@ -160,7 +160,7 @@ void vtkColorLegend::ComputeTexture()
}
// Set the axis up
this->Axis->SetRange(bounds[0], bounds[1]);
this->Axis->SetUnscaledRange(bounds[0], bounds[1]);
//this->Axis->AutoScale();
// Could depend of the screen resolution
......
......@@ -148,7 +148,7 @@ vtkStdString vtkPlot::GetNumber(double position, vtkAxis *axis)
ostr.setf(ios::fixed, ios::floatfield);
}
if (axis && axis->GetLogScale())
if (axis && axis->GetLogScaleActive())
{
// If axes are set to logarithmic scale we need to convert the
// axis value using 10^(axis value)
......
......@@ -15,6 +15,7 @@
#include "vtkPlotBar.h"
#include "vtkAxis.h"
#include "vtkContext2D.h"
#include "vtkRect.h"
#include "vtkPen.h"
......@@ -45,7 +46,7 @@ namespace {
// Copy the two arrays into the points array
template<class A, class B>
void CopyToPoints(vtkPoints2D *points, vtkPoints2D *previous_points, A *a, B *b,
int n)
int n, int logScale)
{
points->SetNumberOfPoints(n);
for (int i = 0; i < n; ++i)
......@@ -53,13 +54,16 @@ void CopyToPoints(vtkPoints2D *points, vtkPoints2D *previous_points, A *a, B *b,
double prev[] = {0.0,0.0};
if (previous_points)
previous_points->GetPoint(i,prev);
points->SetPoint(i, a[i], b[i] + prev[1]);
points->SetPoint(i,
(logScale & 1) ? log10(a[i]) : a[i],
(logScale & 2) ? log10(b[i] + prev[1]) : (b[i] + prev[1]));
}
}
// Copy one array into the points array, use the index of that array as x
template<class A>
void CopyToPoints(vtkPoints2D *points, vtkPoints2D *previous_points, A *a, int n)
void CopyToPoints(
vtkPoints2D *points, vtkPoints2D *previous_points, A *a, int n, int logScale)
{
points->SetNumberOfPoints(n);
for (int i = 0; i < n; ++i)
......@@ -68,19 +72,22 @@ void CopyToPoints(vtkPoints2D *points, vtkPoints2D *previous_points, A *a, int n
if (previous_points)
previous_points->GetPoint(i,prev);
points->SetPoint(i, i, a[i] + prev[1]);
points->SetPoint(i,
(logScale & 1) ? log10(i + 1.0) : i,
(logScale & 2) ? log10(a[i] + prev[1]) : (a[i] + prev[1]));
}
}
// Copy the two arrays into the points array
template<class A>
void CopyToPointsSwitch(vtkPoints2D *points, vtkPoints2D *previous_points, A *a,
vtkDataArray *b, int n)
vtkDataArray *b, int n, int logScale)
{
switch(b->GetDataType())
{
vtkTemplateMacro(
CopyToPoints(points,previous_points, a,
static_cast<VTK_TT*>(b->GetVoidPointer(0)), n));
static_cast<VTK_TT*>(b->GetVoidPointer(0)), n, logScale));
}
}
......@@ -146,8 +153,9 @@ class vtkPlotBarSegment : public vtkObject {
delete this->SelectionSet;
}
void Configure(vtkPlotBar *bar, vtkDataArray *x_array,
vtkDataArray *y_array, vtkPlotBarSegment *prev)
void Configure(
vtkPlotBar* bar, vtkDataArray* x_array, vtkDataArray* y_array,
vtkAxis* x_axis, vtkAxis* y_axis, vtkPlotBarSegment* prev)
{
this->Bar = bar;
this->Previous = prev;
......@@ -159,6 +167,9 @@ class vtkPlotBarSegment : public vtkObject {
delete this->Sorted;
delete this->SelectionSet;
int logScale =
(x_axis->GetLogScaleActive() ? 1 : 0) +
(y_axis->GetLogScaleActive() ? 2 : 0);
if (x_array)
{
switch (x_array->GetDataType())
......@@ -166,7 +177,7 @@ class vtkPlotBarSegment : public vtkObject {
vtkTemplateMacro(
CopyToPointsSwitch(this->Points,this->Previous ? this->Previous->Points : 0,
static_cast<VTK_TT*>(x_array->GetVoidPointer(0)),
y_array,x_array->GetNumberOfTuples()));
y_array,x_array->GetNumberOfTuples(), logScale));
}
}
else
......@@ -176,7 +187,7 @@ class vtkPlotBarSegment : public vtkObject {
vtkTemplateMacro(
CopyToPoints(this->Points, this->Previous ? this->Previous->Points : 0,
static_cast<VTK_TT*>(y_array->GetVoidPointer(0)),
y_array->GetNumberOfTuples()));
y_array->GetNumberOfTuples(), logScale));
}
}
}
......@@ -391,12 +402,13 @@ public:
this->Segments.clear();
}
vtkPlotBarSegment *AddSegment(vtkDataArray *x_array, vtkDataArray *y_array,
vtkPlotBarSegment *prev=0)
vtkPlotBarSegment* AddSegment(
vtkDataArray *x_array, vtkDataArray *y_array,
vtkAxis* x_axis, vtkAxis* y_axis, vtkPlotBarSegment *prev=0)
{
vtkSmartPointer<vtkPlotBarSegment> segment =
vtkSmartPointer<vtkPlotBarSegment>::New();
segment->Configure(this->Bar,x_array,y_array,prev);
segment->Configure(this->Bar, x_array, y_array, x_axis, y_axis, prev);
this->Segments.push_back(segment);
return segment;
}
......@@ -525,6 +537,8 @@ bool vtkPlotBar::Paint(vtkContext2D *painter)
return false;
}
else if(this->Data->GetMTime() > this->BuildTime ||
this->GetXAxis()->GetMTime() > this->BuildTime ||
this->GetYAxis()->GetMTime() > this->BuildTime ||
table->GetMTime() > this->BuildTime ||
this->MTime > this->BuildTime)
{
......@@ -758,7 +772,7 @@ bool vtkPlotBar::UpdateTableCache(vtkTable *table)
this->Private->Update();
vtkPlotBarSegment *prev = this->Private->AddSegment(x,y);
vtkPlotBarSegment *prev = this->Private->AddSegment(x, y, this->GetXAxis(), this->GetYAxis());
std::map< int, std::string >::iterator it;
......@@ -766,7 +780,7 @@ bool vtkPlotBar::UpdateTableCache(vtkTable *table)
it != this->Private->AdditionalSeries.end(); ++it )
{
y = vtkDataArray::SafeDownCast(table->GetColumnByName((*it).second.c_str()));
prev = this->Private->AddSegment(x,y,prev);
prev = this->Private->AddSegment(x,y, this->GetXAxis(), this->GetYAxis(),prev);
}
this->TooltipDefaultLabelFormat.clear();
......
......@@ -355,11 +355,11 @@ bool vtkPlotParallelCoordinates::UpdateTableCache(vtkTable *table)
axis->SetCustomTickPositions(arr, strings);
if (strings->GetNumberOfTuples() > 1)
{
axis->SetRange(0.0, strings->GetNumberOfTuples()-1);
axis->SetUnscaledRange(0.0, strings->GetNumberOfTuples()-1);
}
else
{
axis->SetRange(-0.1, 0.1);
axis->SetUnscaledRange(-0.1, 0.1);
}
axis->Update();
}
......@@ -373,8 +373,8 @@ bool vtkPlotParallelCoordinates::UpdateTableCache(vtkTable *table)
}
// Also need the range from the appropriate axis, to normalize points
float min = axis->GetMinimum();
float max = axis->GetMaximum();
float min = axis->GetUnscaledMinimum();
float max = axis->GetUnscaledMaximum();
float scale = 1.0f / (max - min);
for (vtkIdType j = 0; j < rows; ++j)
......
......@@ -576,23 +576,43 @@ void vtkPlotPoints::CalculateLogSeries()
{
return;
}
this->LogX = this->XAxis->GetLogScale();
this->LogY = this->YAxis->GetLogScale();
this->LogX = this->XAxis->GetLogScaleActive();
this->LogY = this->YAxis->GetLogScaleActive();
float* data = static_cast<float*>(this->Points->GetVoidPointer(0));
vtkIdType n = this->Points->GetNumberOfPoints();
if (this->LogX)
{
for (vtkIdType i = 0; i < n; ++i)
if (this->XAxis->GetUnscaledMinimum() < 0.)
{
data[2*i] = log10(data[2*i]);
for (vtkIdType i = 0; i < n; ++i)
{
data[2*i] = log10(fabs(data[2*i]));
}
}
else
{
for (vtkIdType i = 0; i < n; ++i)
{
data[2*i] = log10(data[2*i]);
}
}
}
if (this->LogY)
{
for (vtkIdType i = 0; i < n; ++i)
{
data[2*i+1] = log10(data[2*i+1]);
}
if (this->YAxis->GetUnscaledMinimum() < 0.)
{
for (vtkIdType i = 0; i < n; ++i)
{
data[2*i+1] = log10(fabs(data[2*i+1]));
}
}
else
{
for (vtkIdType i = 0; i < n; ++i)
{
data[2*i+1] = log10(data[2*i+1]);
}
}
}
}
......@@ -698,6 +718,10 @@ void vtkPlotPoints::CalculateBounds(double bounds[4])
}
// Now figure out the next range
start = end + 1;
while (i < nBad && start == this->BadPoints->GetValue(i))
{
start = this->BadPoints->GetValue(i++) + 1;
}
if (++i < nBad)
{
end = this->BadPoints->GetValue(i);
......
......@@ -168,8 +168,8 @@ class vtkPlotStackedSegment : public vtkObject {
return;
}
bool logX = xAxis->GetLogScale();
bool logY = yAxis->GetLogScale();
bool logX = xAxis->GetLogScaleActive();
bool logY = yAxis->GetLogScaleActive();
float* data = static_cast<float*>(this->Points->GetVoidPointer(0));
......@@ -615,10 +615,10 @@ void vtkPlotStacked::Update()
this->UpdateTableCache(table);
}
else if ((this->XAxis && this->XAxis->GetMTime() > this->BuildTime) ||
(this->YAxis && this->YAxis->GetMaximum() > this->BuildTime))
(this->YAxis && this->YAxis->GetMTime() > this->BuildTime))
{
if (this->LogX != this->XAxis->GetLogScale() ||
this->LogY != this->YAxis->GetLogScale())
if (this->LogX != this->XAxis->GetLogScaleActive() ||
this->LogY != this->YAxis->GetLogScaleActive())
{
this->UpdateTableCache(table);
}
......@@ -781,8 +781,8 @@ bool vtkPlotStacked::UpdateTableCache(vtkTable *table)
}
// Record if this update was done with Log scale.
this->LogX = this->XAxis ? this->XAxis->GetLogScale(): false;
this->LogY = this->YAxis ? this->YAxis->GetLogScale(): false;
this->LogX = this->XAxis ? this->XAxis->GetLogScaleActive(): false;
this->LogY = this->YAxis ? this->YAxis->GetLogScaleActive(): false;
this->BuildTime.Modified();
return true;
......
......@@ -469,10 +469,11 @@ bool vtkScatterPlotMatrix::SetActivePlot(const vtkVector2i &pos)
if (xy && active)
{
vtkAxis *a = active->GetAxis(vtkAxis::BOTTOM);
xy->GetAxis(vtkAxis::TOP)->SetRange(a->GetMinimum(), a->GetMaximum());
xy->GetAxis(vtkAxis::TOP)->SetUnscaledRange(
a->GetUnscaledMinimum(), a->GetUnscaledMaximum());
a = active->GetAxis