Commit 55cb7e11 authored by David Thompson's avatar David Thompson
Browse files

Use scalar annotations on interval-mode scalar bar.

This commit renders user-provided notes associated with specific
scalar values on the interval-mode scalar bar. Previously, only
the categorical mode rendered these annotations.

Also, provide the scalar bar with an optional swatch
to illustrate the color assigned to NaN values.

Add an option to color leader lines from the scalar bar to
the annotation labels by the corresponding scalar value.

This commit also breaks the process of rebuilding the scalar bar
into several virtual methods so that subclasses (particularly
ParaView's `vtkPVScalarBarActor`) can reuse more of the base class
functionality. The process is now separated into 2 phases: layout,
where bounding boxes for scalar bar components are placed; and
configuration, where actors are positioned and geometry is created.
This includes some changes to text actor to support constrained
placement and text size queries.

Add a test for the new scalar bar options.
There are now many more options controlling how the scalar bar behaves.
In particular many settings interact with the way geometry is rendered:
the lookup table may be indexed or not (thus tick marks may not be
rendered); the orientation may be horizontal or vertical; annotations
may be rendered or not; the NaN annotation may be omitted; leader lines
to annotations may be colored by the scalar they annotate or by the label
color; and the tick marks may precede or succeed the scalar bar.
Also, we must test how empty labels are handled and how even vs odd
numbers of labels affect placement (since the algorithm for placement
behaves differently in these cases).

We cannot perform a full factorial test, but do test independent
configurations.

Finally, this commit improves the performance of prominent value
detection for primitive-type arrays (e.g., int, double) by avoiding
the use of vtkVariant instances to hold the working set of distinct
values during sampling.

Change-Id: I852f9b497d5e6ab619d9d7b763f641c44e4869cf
parent 9e23a9d9
......@@ -54,6 +54,8 @@
# endif
#endif
#include <algorithm>
#include <iterator>
#include <set>
#include <cmath>
......@@ -505,7 +507,8 @@ void vtkAbstractArray::GetProminentComponentValues(
if (comp >= 0 && info)
{
vtkInformationVector* infoVec = info->Get(PER_COMPONENT());
if (!infoVec || infoVec->GetNumberOfInformationObjects() < this->NumberOfComponents)
if (!infoVec ||
infoVec->GetNumberOfInformationObjects() < this->NumberOfComponents)
{
infoVec = vtkInformationVector::New();
infoVec->SetNumberOfInformationObjects(this->NumberOfComponents);
......@@ -563,17 +566,20 @@ void vtkAbstractArray::GetProminentComponentValues(
}
}
//--------------------------------------------------------------------------
//-----------------------------------------------------------------------------
namespace
{
template<typename T>
bool AccumulateSampleValues(
T* array, int nc, vtkIdType begin, vtkIdType end, vtkIdType vtkNotUsed(minFreq),
std::vector<std::set<vtkVariant> >& uniques)
T* array, int nc, vtkIdType begin, vtkIdType end,
std::vector<std::set<T> >& uniques, std::set<std::vector<T> >& tupleUniques)
{
// number of discrete components remaining (tracked during iteration):
int ndc = nc;
std::pair<std::set<vtkVariant>::iterator,bool> result;
std::pair<typename std::set<T>::iterator,bool> result;
std::pair<typename std::set<std::vector<T> >::iterator,bool> tresult;
std::vector<T> tuple;
tuple.resize(nc);
// Here we iterate over the components and add to their respective lists
// of previously encountered values -- as long as there are not too many
// values already in the list. We also accumulate each component's value
......@@ -586,7 +592,9 @@ bool AccumulateSampleValues(
{
if (uniques[j].size() > vtkAbstractArray::MAX_DISCRETE_VALUES)
continue;
result = uniques[j].insert(array[i * nc + j]);
T& val(array[i * nc + j]);
tuple[j] = val;
result = uniques[j].insert(val);
if (result.second)
{
if (uniques[j].size() == vtkAbstractArray::MAX_DISCRETE_VALUES + 1)
......@@ -599,22 +607,86 @@ bool AccumulateSampleValues(
// values, it is worth seeing whether the tuple as a whole is unique:
if ( nc > 1 && ndc == nc )
{
vtkNew<vtkVariantArray> tuple;
tuple->SetNumberOfComponents(nc);
tuple->SetNumberOfTuples(1);
for (int j = 0; j < nc; ++j)
{
tuple->SetVariantValue(j, array[i * nc + j]);
}
vtkVariant wholeThing(tuple.GetPointer());
result = uniques[nc].insert(wholeThing);
tresult = tupleUniques.insert(tuple);
(void)tresult; // nice to have when debugging.
}
}
return ndc == 0;
}
//-----------------------------------------------------------------------------
template<typename U>
void SampleProminentValues(
std::vector<std::vector<vtkVariant> >& uniques, vtkIdType maxId,
int nc, vtkIdType nt, int blockSize, vtkIdType numberOfBlocks, U* ptr)
{
std::vector<std::set<U> > typeSpecificUniques;
std::set<std::vector<U> > typeSpecificUniqueTuples;
typeSpecificUniques.resize(nc);
// I. Accumulate samples for all components plus the tuple,
// either for the full array or a random subset.
if (numberOfBlocks * blockSize > maxId / 2)
{ // Awwww, just do the whole array already!
AccumulateSampleValues(
ptr, nc, 0, nt,
typeSpecificUniques, typeSpecificUniqueTuples);
}
else
{ // Choose random blocks
vtkNew<vtkMinimalStandardRandomSequence> seq;
// test different blocks each time we're called:
seq->SetSeed(seq->GetMTime() ^ 0xdeadbeef);
vtkIdType totalBlockCount =
nt / blockSize +
(nt % blockSize ? 1 : 0);
std::set<vtkIdType> startTuples;
// Sort the list of blocks we'll search to maintain cache coherence.
for (int i = 0; i < numberOfBlocks; ++ i, seq->Next())
{
vtkIdType startTuple =
static_cast<vtkIdType>(seq->GetValue() * totalBlockCount) * blockSize;
startTuples.insert(startTuple);
}
// Now iterate over the blocks, accumulating unique values and tuples.
std::set<vtkIdType>::iterator blkIt;
for (blkIt = startTuples.begin(); blkIt != startTuples.end(); ++blkIt)
{
vtkIdType startTuple = *blkIt;
vtkIdType endTuple = startTuple + blockSize;
endTuple = endTuple < nt ? endTuple : nt;
bool endEarly = AccumulateSampleValues(
ptr, nc, startTuple, endTuple,
typeSpecificUniques, typeSpecificUniqueTuples);
if (endEarly)
break;
}
}
// II. Convert type-specific sets of unique values into non-type-specific
// vectors of vtkVariants for storage in array information.
// Handle per-component uniques first
for (int i = 0; i < nc; ++i)
{
std::back_insert_iterator<std::vector<vtkVariant> > bi(uniques[i]);
std::copy(typeSpecificUniques[i].begin(), typeSpecificUniques[i].end(), bi);
}
// Now squash any tuple-wide uniques into
// the final entry of the outer vector.
typename std::set<std::vector<U> >::iterator si;
for (
si = typeSpecificUniqueTuples.begin();
si != typeSpecificUniqueTuples.end();
++si)
{
std::back_insert_iterator<std::vector<vtkVariant> > bi(uniques[nc]);
std::copy(si->begin(), si->end(), bi);
}
}
} // End anonymous namespace.
//--------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void vtkAbstractArray::UpdateDiscreteValueSet(
double uncertainty, double minimumProminence)
{
......@@ -623,13 +695,15 @@ void vtkAbstractArray::UpdateDiscreteValueSet(
// M*N = f(T; P, U) and f some sublinear function of T.
// If every component plus all components taken together each have more than
// MAX_DISCRETE_VALUES distinct values, then we exit early.
// M is chosen based on the number of bytes per tuple to maximize use of a cache
// line (assuming a 64-byte cache line until kwsys::SystemInformation or the like
// can provide a platform-independent way to query it).
// M is chosen based on the number of bytes per tuple to maximize use of a
// cache line (assuming a 64-byte cache line until kwsys::SystemInformation
// or the like can provide a platform-independent way to query it).
//
// N is chosen to satisfy the requested uncertainty and prominence criteria specified.
// N is chosen to satisfy the requested uncertainty and prominence criteria
// specified.
#define VTK_CACHE_LINE_SIZE 64
#define VTK_SAMPLE_FACTOR 5
// I. Determine the granularity at which the array should be sampled.
int numberOfComponentsWithProminentValues = 0;
int nc = this->NumberOfComponents;
int blockSize = VTK_CACHE_LINE_SIZE / (this->GetDataTypeSize() * nc);
......@@ -653,8 +727,13 @@ void vtkAbstractArray::UpdateDiscreteValueSet(
{
numberOfSampleTuples = VTK_SAMPLE_FACTOR * logfac;
}
/*
// Theoretically, we should discard values or tuples that recur fewer
// than minFreq times in our sample, but in practice this involves
// counting and communication that slow us down.
vtkIdType minFreq = static_cast<vtkIdType>(
numberOfSampleTuples * minimumProminence / 2);
*/
vtkIdType numberOfBlocks =
numberOfSampleTuples / blockSize +
(numberOfSampleTuples % blockSize ? 1 : 0);
......@@ -664,67 +743,30 @@ void vtkAbstractArray::UpdateDiscreteValueSet(
2 * MAX_DISCRETE_VALUES / blockSize +
(2 * MAX_DISCRETE_VALUES % blockSize ? 1 : 0);
}
std::vector<std::set<vtkVariant> > uniques(nc > 1 ? nc + 1 : nc);
if (numberOfBlocks * blockSize > this->MaxId / 2)
{ // Awwww, just do the whole array already!
switch(this->GetDataType())
{
vtkSuperExtraExtendedTemplateMacro(
AccumulateSampleValues(
static_cast<VTK_TT*>(this->GetVoidPointer(0)),
nc, 0, nt, minFreq, uniques));
default:
vtkErrorMacro("Array type " << this->GetClassName() << " not supported.");
break;
}
}
else
{ // Choose random blocks
vtkNew<vtkMinimalStandardRandomSequence> seq;
// test different blocks each time we're called:
seq->SetSeed(seq->GetMTime() ^ 0xdeadbeef);
vtkIdType totalBlockCount =
nt / blockSize +
(nt % blockSize ? 1 : 0);
for (int i = 0; i < numberOfBlocks; ++ i, seq->Next())
{
vtkIdType startTuple =
static_cast<vtkIdType>(seq->GetValue() * totalBlockCount) * blockSize;
vtkIdType endTuple = startTuple + blockSize;
endTuple = endTuple < nt ? endTuple : nt;
bool endEarly;
switch(this->GetDataType())
{
vtkSuperExtraExtendedTemplateMacro(
endEarly = AccumulateSampleValues(
static_cast<VTK_TT*>(this->GetVoidPointer(0)),
nc, startTuple, endTuple, minFreq, uniques));
default:
vtkErrorMacro(
"Array type " << this->GetClassName() << " not supported.");
endEarly = true;
break;
}
if (endEarly)
break;
}
// II. Sample the array.
std::vector<std::vector<vtkVariant> > uniques(nc > 1 ? nc + 1 : nc);
switch(this->GetDataType())
{
vtkSuperExtraExtendedTemplateMacro(
SampleProminentValues(
uniques, this->MaxId, nc, nt, blockSize, numberOfBlocks,
static_cast<VTK_TT*>(this->GetVoidPointer(0))));
default:
vtkErrorMacro("Array type " << this->GetClassName() << " not supported.");
break;
}
// III. Store the results in the array's vtkInformation.
int c;
for (c = 0; c < nc; ++c)
{
if (uniques[c].size() <= MAX_DISCRETE_VALUES)
{
++ numberOfComponentsWithProminentValues;
std::vector<vtkVariant> compUniques;
std::set<vtkVariant>::iterator sit;
for (sit = uniques[c].begin(); sit != uniques[c].end(); ++sit)
{
compUniques.push_back(*sit);
}
this->GetInformation()->Get(
PER_COMPONENT())->GetInformationObject(c)->Set(
DISCRETE_VALUES(), &compUniques[0],
static_cast<int>(compUniques.size()));
DISCRETE_VALUES(), &uniques[c][0],
static_cast<int>(uniques[c].size()));
}
else
{
......@@ -733,40 +775,24 @@ void vtkAbstractArray::UpdateDiscreteValueSet(
DISCRETE_VALUES());
}
}
if (nc > 1 && uniques[nc].size() <= MAX_DISCRETE_VALUES)
if (nc > 1 &&
static_cast<int>(uniques[nc].size()) <= MAX_DISCRETE_VALUES * nc)
{
std::vector<vtkVariant> compUniques;
std::set<vtkVariant>::iterator sit;
for (sit = uniques[nc].begin(); sit != uniques[nc].end(); ++sit)
{
vtkAbstractArray* tuple = sit->ToArray();
if (tuple)
{
for (c = 0; c <= tuple->GetMaxId(); ++c)
{
compUniques.push_back(tuple->GetVariantValue(c));
}
}
}
++ numberOfComponentsWithProminentValues;
this->GetInformation()->Set(
DISCRETE_VALUES(), &compUniques[0],
static_cast<int>(compUniques.size()));
DISCRETE_VALUES(), &uniques[nc][0],
static_cast<int>(uniques[nc].size()));
}
else
{ // Remove the key
this->GetInformation()->Remove(DISCRETE_VALUES());
}
if (numberOfComponentsWithProminentValues > 0)
{
double params[2];
params[0] = uncertainty;
params[1] = minimumProminence;
this->GetInformation()->Set(
DISCRETE_VALUE_SAMPLE_PARAMETERS(), params, 2);
}
else
{ // Remove the parameter-value key
this->GetInformation()->Remove(DISCRETE_VALUE_SAMPLE_PARAMETERS());
}
// Always store the sample parameters; this lets us know not to
// re-run the sampling algorithm.
double params[2];
params[0] = uncertainty;
params[1] = minimumProminence;
this->GetInformation()->Set(
DISCRETE_VALUE_SAMPLE_PARAMETERS(), params, 2);
}
......@@ -1211,3 +1211,15 @@ vtkIdType vtkLookupTable::GetNumberOfAvailableColors()
{
return this->Table->GetNumberOfTuples();
}
//----------------------------------------------------------------------------
void vtkLookupTable::GetIndexedColor(vtkIdType idx, double rgba[4])
{
vtkIdType n = this->GetNumberOfAvailableColors();
if (n > 0 && idx >= 0)
{
this->GetTableValue(idx % n, rgba);
return;
}
this->GetNanColor(rgba);
}
......@@ -275,6 +275,13 @@ public:
// Get the number of available colors for mapping to.
virtual vtkIdType GetNumberOfAvailableColors();
// Description:
// Return a color given an integer index.
//
// This is used to assign colors to annotations (given an offset into the list of annotations).
// If the table is empty or \a idx < 0, then NanColor is returned.
virtual void GetIndexedColor(vtkIdType idx, double rgba[4]);
protected:
vtkLookupTable(int sze=256, int ext=256);
~vtkLookupTable();
......
......@@ -1765,6 +1765,21 @@ void vtkScalarsToColors::ResetAnnotations()
this->Modified();
}
//----------------------------------------------------------------------------
void vtkScalarsToColors::GetAnnotationColor(const vtkVariant& val, double rgba[4])
{
if (this->IndexedLookup)
{
vtkIdType i = this->GetAnnotatedValueIndex(val);
this->GetIndexedColor(i, rgba);
}
else
{
this->GetColor(val.ToDouble(), rgba);
rgba[3] = 1.;
}
}
//----------------------------------------------------------------------------
vtkIdType vtkScalarsToColors::CheckForAnnotatedValue(vtkVariant value)
{
......@@ -1792,6 +1807,12 @@ vtkIdType vtkScalarsToColors::GetAnnotatedValueIndexInternal(vtkVariant& value)
return i;
}
//----------------------------------------------------------------------------
void vtkScalarsToColors::GetIndexedColor(vtkIdType, double rgba[4])
{
rgba[0] = rgba[1] = rgba[2] = rgba[3] = 0.;
}
//----------------------------------------------------------------------------
void vtkScalarsToColors::UpdateAnnotatedValueMap()
{
......
......@@ -241,39 +241,55 @@ public:
*
* Returns the index of \a value in the list of annotations.
*/
virtual vtkIdType SetAnnotation( vtkVariant value, vtkStdString annotation );
virtual vtkIdType SetAnnotation(vtkVariant value, vtkStdString annotation);
/// This variant of \a SetAnnotation accepts the value as a string so ParaView can treat annotations as string vector arrays.
virtual vtkIdType SetAnnotation( vtkStdString value, vtkStdString annotation );
virtual vtkIdType SetAnnotation(vtkStdString value, vtkStdString annotation);
/// Return the annotated value at a particular index in the list of annotations.
vtkIdType GetNumberOfAnnotatedValues();
/// Return the annotated value at a particular index in the list of annotations.
vtkVariant GetAnnotatedValue( vtkIdType idx );
vtkVariant GetAnnotatedValue(vtkIdType idx);
/// Return the annotation at a particular index in the list of annotations.
vtkStdString GetAnnotation( vtkIdType idx );
vtkStdString GetAnnotation(vtkIdType idx);
/// Obtain the color associated with a particular annotated value (or NanColor if unmatched).
virtual void GetAnnotationColor(const vtkVariant& val, double rgba[4]);
/// Return the index of the given value in the list of annotated values (or -1 if not present).
vtkIdType GetAnnotatedValueIndex( vtkVariant val );
/// Look up an index into the array of annotations given a value. Does no pointer checks. Returns -1 when \a val not present.
vtkIdType GetAnnotatedValueIndexInternal( vtkVariant& val );
vtkIdType GetAnnotatedValueIndexInternal(vtkVariant& val);
/** Get the "indexed color" assigned to an index.
*
* The index is used in \a IndexedLookup mode to assign colors to annotations (in the order
* the annotations were set).
* Subclasses must implement this and interpret how to treat the index.
* vtkLookupTable simply returns GetTableValue(\a index % \a this->GetNumberOfTableValues()).
* vtkColorTransferFunction returns the color assocated with node \a index % \a this->GetSize().
*
* Note that implementations *must* set the opacity (alpha) component of the color, even if they
* do not provide opacity values in their colormaps. In that case, alpha = 1 should be used.
*/
virtual void GetIndexedColor(vtkIdType i, double rgba[4]);
/**\brief Remove an existing entry from the list of annotated values.
*
* True is returned when the entry was actually removed (i.e., it existed before the call).
* Otherwise, false is returned.
*/
virtual bool RemoveAnnotation( vtkVariant value );
virtual bool RemoveAnnotation(vtkVariant value);
/// Remove all existing values and their annotations.
virtual void ResetAnnotations();
// Description:
// Set/get whether the lookup table is for categorical or ordinal data.
// The default is ordinal data and values not present in the lookup table
// The default is ordinal data; values not present in the lookup table
// will be assigned an interpolated color.
// When categorical data is present, only values in the lookup table will be
// considered valid; all other values will be assigned \a NanColor.
......
......@@ -84,7 +84,8 @@ public:
// Description:
// A cell traversal methods that is more efficient than vtkDataSet traversal
// methods. GetNextCell() gets the next cell in the list. If end of list
// is encountered, 0 is returned.
// is encountered, 0 is returned. A value of 1 is returned whenever
// npts and pts have been updated without error.
int GetNextCell(vtkIdType& npts, vtkIdType* &pts);
// Description:
......
......@@ -20,4 +20,14 @@ set(Module_SRCS
vtkXYPlotActor.cxx
)
set(${vtk-module}_HDRS
vtkScalarBarActorInternal.h
)
set_source_files_properties(
vtkScalarBarActorInternal.h
HEADER_FILE_ONLY
WRAP_EXCLUDE
)
vtk_module_library(vtkRenderingAnnotation ${Module_SRCS})
This diff is collapsed.
......@@ -56,11 +56,13 @@
#include "vtkRenderingAnnotationModule.h" // For export macro
#include "vtkActor2D.h"
class vtkMathTextActor;
class vtkColor3ub;
class vtkPolyData;
class vtkPolyDataMapper2D;
class vtkProperty2D;
class vtkScalarsToColors;
class vtkScalarBarActorInternal;
class vtkTextActor;
class vtkTextMapper;
class vtkTextProperty;
class vtkTexture;
......@@ -78,7 +80,7 @@ public:
// Instantiate object with 64 maximum colors; 5 labels; %%-#6.3g label
// format, no title, and vertical orientation. The initial scalar bar
// size is (0.05 x 0.8) of the viewport size.
static vtkScalarBarActor *New();
static vtkScalarBarActor* New();
// Description:
// Draw the scalar bar and annotation text to the screen.
......@@ -94,13 +96,13 @@ public:
// Release any graphics resources that are being consumed by this actor.
// The parameter window could be used to determine which graphic
// resources to release.
virtual void ReleaseGraphicsResources(vtkWindow *);
virtual void ReleaseGraphicsResources(vtkWindow*);
// Description:
// Set/Get the lookup table to use. The lookup table specifies the number
// of colors to use in the table (if not overridden), the scalar range,
// and any annotated values.
// Annotated values are rendered using vtkMathTextActor.
// Annotated values are rendered using vtkTextActor.
virtual void SetLookupTable(vtkScalarsToColors*);
vtkGetObjectMacro(LookupTable,vtkScalarsToColors);
......@@ -131,17 +133,17 @@ public:
vtkSetClampMacro(Orientation,int,VTK_ORIENT_HORIZONTAL, VTK_ORIENT_VERTICAL);
vtkGetMacro(Orientation, int);
void SetOrientationToHorizontal()
{this->SetOrientation(VTK_ORIENT_HORIZONTAL);};
void SetOrientationToVertical() {this->SetOrientation(VTK_ORIENT_VERTICAL);};
{this->SetOrientation(VTK_ORIENT_HORIZONTAL);}
void SetOrientationToVertical() {this->SetOrientation(VTK_ORIENT_VERTICAL);}
// Description:
// Set/Get the title text property.
virtual void SetTitleTextProperty(vtkTextProperty *p);
virtual void SetTitleTextProperty(vtkTextProperty* p);
vtkGetObjectMacro(TitleTextProperty,vtkTextProperty);
// Description:
// Set/Get the labels text property.
virtual void SetLabelTextProperty(vtkTextProperty *p);
virtual void SetLabelTextProperty(vtkTextProperty* p);
vtkGetObjectMacro(LabelTextProperty,vtkTextProperty);
// Description:
......@@ -162,7 +164,7 @@ public:
// Description:
// Shallow copy of a scalar bar actor. Overloads the virtual vtkProp method.
void ShallowCopy(vtkProp *prop);
void ShallowCopy(vtkProp* prop);
// Description:
// Set the width of the texture grid. Used only if UseOpacity is ON.
......@@ -178,10 +180,12 @@ public:
//ETX
// Description:
// Have the text preceding the scalar bar or succeeding it ?
// Succeed implies the that the text is Above scalar bar if orientation
// is horizontal or Right of scalar bar if orientation is vertical.
// Precede is the opposite
// Should the title and tick marks precede the scalar bar or succeed it?
// This is measured along the viewport coordinate direction perpendicular
// to the long axis of the scalar bar, not the reading direction.
// Thus, succeed implies the that the text is above scalar bar if
// the orientation is horizontal or right of scalar bar if the orientation
// is vertical. Precede is the opposite.
vtkSetClampMacro( TextPosition, int, PrecedeScalarBar, SucceedScalarBar);
vtkGetMacro( TextPosition, int );
virtual void SetTextPositionToPrecedeScalarBar()
......@@ -204,119 +208,282 @@ public:
// Set/get the padding between the scalar bar and the text annotations.
// This space is used to draw leader lines.
// The default is 8 pixels.
vtkSetMacro( AnnotationLeaderPadding, double );
vtkGetMacro( AnnotationLeaderPadding, double );
vtkSetMacro(AnnotationLeaderPadding, double);
vtkGetMacro(AnnotationLeaderPadding, double);
// Description:
// Set/get whether text annotations should be rendered or not.
// Currently, this only affects rendering when \a IndexedLookup is true.
// The default is true.
vtkSetMacro( DrawAnnotations, int );
vtkGetMacro( DrawAnnotations, int );
vtkBooleanMacro( DrawAnnotations, int );
vtkSetMacro(DrawAnnotations, int);
vtkGetMacro(DrawAnnotations, int);
vtkBooleanMacro(DrawAnnotations, int);
// Description:
// Set/get whether the NaN annotation should be rendered or not.
// This only affects rendering when \a DrawAnnotations is true.
// The default is false.
vtkSetMacro(DrawNanAnnotation, int);
vtkGetMacro(DrawNanAnnotation, int);
vtkBooleanMacro(DrawNanAnnotation, int);
// Description:
// Set/get how leader lines connecting annotations to values should be colored.
//
// When true, leader lines are all the same color (and match the LabelTextProperty color).
// When false, leader lines take on the color of the value they correspond to.
// This only affects rendering when \a DrawAnnotations is true.
// The default is false.
vtkSetMacro(FixedAnnotationLeaderLineColor, int);
vtkGetMacro(FixedAnnotationLeaderLineColor, int);
vtkBooleanMacro(FixedAnnotationLeaderLineColor, int);
// Description:
// Set/get the annotation text for "NaN" values.
vtkSetStringMacro(NanAnnotation);
vtkGetStringMacro(NanAnnotation);