vtkParallelCoordinatesActor.cxx 18.5 KB
Newer Older
1 2 3 4 5
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkParallelCoordinatesActor.cxx

6
  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 8
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9

10 11
     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12
     PURPOSE.  See the above copyright notice for more information.
13 14 15

=========================================================================*/
#include "vtkParallelCoordinatesActor.h"
16

17
#include "vtkAxisActor2D.h"
18 19
#include "vtkCellArray.h"
#include "vtkFieldData.h"
20 21
#include "vtkMath.h"
#include "vtkObjectFactory.h"
22
#include "vtkPolyData.h"
23
#include "vtkPolyDataMapper2D.h"
24 25
#include "vtkTextMapper.h"
#include "vtkTextProperty.h"
26
#include "vtkTrivialProducer.h"
27
#include "vtkViewport.h"
28
#include "vtkWindow.h"
29

Brad King's avatar
Brad King committed
30
vtkStandardNewMacro(vtkParallelCoordinatesActor);
31

32 33
vtkCxxSetObjectMacro(vtkParallelCoordinatesActor,LabelTextProperty,vtkTextProperty);
vtkCxxSetObjectMacro(vtkParallelCoordinatesActor,TitleTextProperty,vtkTextProperty);
34

35 36 37 38 39 40 41 42 43 44 45 46 47 48
class vtkParallelCoordinatesActorConnection : public vtkAlgorithm
{
public:
  static vtkParallelCoordinatesActorConnection *New();
  vtkTypeMacro(vtkParallelCoordinatesActorConnection,vtkAlgorithm);

  vtkParallelCoordinatesActorConnection()
    {
      this->SetNumberOfInputPorts(1);
    }
};

vtkStandardNewMacro(vtkParallelCoordinatesActorConnection);

49
//----------------------------------------------------------------------------
50 51 52 53
// Instantiate object
vtkParallelCoordinatesActor::vtkParallelCoordinatesActor()
{
  this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport();
54
  this->PositionCoordinate->SetValue(0.1,0.1);
55

56
  this->Position2Coordinate->SetValue(0.9, 0.8);
57

58
  this->IndependentVariables = VTK_IV_COLUMN;
59
  this->N = 0;
60

61 62
  this->ConnectionHolder = vtkParallelCoordinatesActorConnection::New();

63
  this->Axes = NULL;
64 65
  this->Mins = NULL;
  this->Maxs = NULL;
66
  this->Xs = NULL;
67 68

  this->Title = NULL;
69

70
  this->TitleMapper = vtkTextMapper::New();
71

72 73 74 75
  this->TitleActor = vtkActor2D::New();
  this->TitleActor->SetMapper(this->TitleMapper);
  this->TitleActor->GetPositionCoordinate()->SetCoordinateSystemToViewport();

76
  this->PlotData = vtkPolyData::New();
77

78
  this->PlotMapper = vtkPolyDataMapper2D::New();
79
  this->PlotMapper->SetInputData(this->PlotData);
80

81 82 83
  this->PlotActor = vtkActor2D::New();
  this->PlotActor->SetMapper(this->PlotMapper);

84
  this->NumberOfLabels = 2;
85 86 87 88 89 90 91 92 93 94

  this->LabelTextProperty = vtkTextProperty::New();
  this->LabelTextProperty->SetBold(1);
  this->LabelTextProperty->SetItalic(1);
  this->LabelTextProperty->SetShadow(1);
  this->LabelTextProperty->SetFontFamilyToArial();

  this->TitleTextProperty = vtkTextProperty::New();
  this->TitleTextProperty->ShallowCopy(this->LabelTextProperty);

95
  this->LabelFormat = new char[8];
96
  sprintf(this->LabelFormat,"%s","%-#6.3g");
97

98 99 100
  this->LastPosition[0] =
    this->LastPosition[1] =
    this->LastPosition2[0] =
101
    this->LastPosition2[1] = 0;
102 103
}

104
//----------------------------------------------------------------------------
105 106
vtkParallelCoordinatesActor::~vtkParallelCoordinatesActor()
{
Bill Lorensen's avatar
Bill Lorensen committed
107 108 109 110
  this->TitleMapper->Delete();
  this->TitleMapper = NULL;
  this->TitleActor->Delete();
  this->TitleActor = NULL;
111

112
  this->ConnectionHolder->Delete();
113
  this->ConnectionHolder = 0;
114

115
  this->Initialize();
116

117 118 119 120
  this->PlotData->Delete();
  this->PlotMapper->Delete();
  this->PlotActor->Delete();

121 122
  delete [] this->Title;
  this->Title = NULL;
123

124 125
  delete [] this->LabelFormat;
  this->LabelFormat = NULL;
126 127 128

  this->SetLabelTextProperty(NULL);
  this->SetTitleTextProperty(NULL);
129 130
}

131
//----------------------------------------------------------------------------
132 133 134
// Free-up axes and related stuff
void vtkParallelCoordinatesActor::Initialize()
{
135 136 137 138 139 140 141 142
  if ( this->Axes )
    {
    for (int i=0; i<this->N; i++)
      {
      this->Axes[i]->Delete();
      }
    delete [] this->Axes;
    this->Axes = NULL;
143 144 145 146
    delete [] this->Mins;
    this->Mins = NULL;
    delete [] this->Maxs;
    this->Maxs = NULL;
147 148
    delete [] this->Xs;
    this->Xs = NULL;
149
    }
150
  this->N = 0;
151 152
}

153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
//----------------------------------------------------------------------------
void vtkParallelCoordinatesActor::SetInputConnection(vtkAlgorithmOutput* ao)
{
  this->ConnectionHolder->SetInputConnection(ao);
}

//----------------------------------------------------------------------------
void vtkParallelCoordinatesActor::SetInputData(vtkDataObject* dobj)
{
  vtkTrivialProducer* tp = vtkTrivialProducer::New();
  tp->SetOutput(dobj);
  this->SetInputConnection(tp->GetOutputPort());
  tp->Delete();
}

//----------------------------------------------------------------------------
vtkDataObject* vtkParallelCoordinatesActor::GetInput()
{
171
  return this->ConnectionHolder->GetInputDataObject(0, 0);
172 173
}

174
//----------------------------------------------------------------------------
175 176 177 178 179 180
// Plot scalar data for each input dataset.
int vtkParallelCoordinatesActor::RenderOverlay(vtkViewport *viewport)
{
  int renderedSomething=0;

  // Make sure input is up to date.
181
  if ( this->GetInput() == NULL || this->N <= 0 )
182 183 184 185 186 187 188 189 190 191
    {
    vtkErrorMacro(<< "Nothing to plot!");
    return 0;
    }

  if ( this->Title != NULL )
    {
    renderedSomething += this->TitleActor->RenderOverlay(viewport);
    }

192 193 194
  this->PlotActor->SetProperty(this->GetProperty());
  renderedSomething += this->PlotActor->RenderOverlay(viewport);

195 196 197 198
  for (int i=0; i<this->N; i++)
    {
    renderedSomething += this->Axes[i]->RenderOverlay(viewport);
    }
199

200 201 202
  return renderedSomething;
}

203
//----------------------------------------------------------------------------
204 205
int vtkParallelCoordinatesActor::RenderOpaqueGeometry(vtkViewport *viewport)
{
206
  int renderedSomething = 0;
207 208 209

  // Initialize

210
  vtkDebugMacro(<<"Plotting parallel coordinates");
211

212 213
  // Make sure input is up to date, and that the data is the correct shape to
  // plot.
214

215
  if (!this->GetInput())
216 217
    {
    vtkErrorMacro(<< "Nothing to plot!");
218
    return renderedSomething;
219 220
    }

221 222 223 224 225 226 227 228 229 230 231 232
  if (!this->TitleTextProperty)
    {
    vtkErrorMacro(<<"Need title text property to render plot");
    return renderedSomething;
    }

  if (!this->LabelTextProperty)
    {
    vtkErrorMacro(<<"Need label text property to render plot");
    return renderedSomething;
    }

233 234
  // Viewport change may not require rebuild

Sebastien Barre's avatar
Sebastien Barre committed
235
  int positionsHaveChanged = 0;
236 237
  if (viewport->GetMTime() > this->BuildTime ||
      (viewport->GetVTKWindow() &&
238 239
       viewport->GetVTKWindow()->GetMTime() > this->BuildTime))
    {
240
    int *lastPosition =
241 242 243 244 245 246 247 248 249 250 251 252
      this->PositionCoordinate->GetComputedViewportValue(viewport);
    int *lastPosition2 =
      this->Position2Coordinate->GetComputedViewportValue(viewport);
    if (lastPosition[0] != this->LastPosition[0] ||
        lastPosition[1] != this->LastPosition[1] ||
        lastPosition2[0] != this->LastPosition2[0] ||
        lastPosition2[1] != this->LastPosition2[1] )
      {
      this->LastPosition[0] = lastPosition[0];
      this->LastPosition[1] = lastPosition[1];
      this->LastPosition2[0] = lastPosition2[0];
      this->LastPosition2[1] = lastPosition2[1];
Sebastien Barre's avatar
Sebastien Barre committed
253
      positionsHaveChanged = 1;
254 255
      }
    }
256

257
  // Check modified time to see whether we have to rebuild.
258

259 260
  this->ConnectionHolder->GetInputAlgorithm()->Update();

Sebastien Barre's avatar
Sebastien Barre committed
261 262
  if (positionsHaveChanged ||
      this->GetMTime() > this->BuildTime ||
263
      this->GetInput()->GetMTime() > this->BuildTime ||
264 265
      this->LabelTextProperty->GetMTime() > this->BuildTime ||
      this->TitleTextProperty->GetMTime() > this->BuildTime)
266
    {
267 268
    int *size = viewport->GetSize();
    int stringSize[2];
269 270 271

    vtkDebugMacro(<<"Rebuilding plot");

272 273 274
    // Build axes

    if (!this->PlaceAxes(viewport, size))
275
      {
276
      return renderedSomething;
277 278
      }

279 280
    // Build title

281
    this->TitleMapper->SetInput(this->Title);
282 283 284 285 286 287 288 289 290 291 292 293

    if (this->TitleTextProperty->GetMTime() > this->BuildTime)
      {
      // Shallow copy here since the justification is changed but we still
      // want to allow actors to share the same text property, and in that case
      // specifically allow the title and label text prop to be the same.
      this->TitleMapper->GetTextProperty()->ShallowCopy(
        this->TitleTextProperty);
      this->TitleMapper->GetTextProperty()->SetJustificationToCentered();
      }

    // We could do some caching here, but hey, that's just the title
294
    vtkTextMapper::SetRelativeFontSize(this->TitleMapper, viewport, size, stringSize, 0.015);
295

296
    this->TitleActor->GetPositionCoordinate()->
297
      SetValue((this->Xs[0]+this->Xs[this->N-1])/2.0,this->YMax+stringSize[1]/2.0);
298 299
    this->TitleActor->SetProperty(this->GetProperty());

300
    this->BuildTime.Modified();
301 302

    } // If need to rebuild the plot
303

304 305 306 307 308
  if ( this->Title != NULL )
    {
    renderedSomething += this->TitleActor->RenderOpaqueGeometry(viewport);
    }

309 310 311
  this->PlotActor->SetProperty(this->GetProperty());
  renderedSomething += this->PlotActor->RenderOpaqueGeometry(viewport);

312 313 314 315 316
  for (int i=0; i<this->N; i++)
    {
    renderedSomething += this->Axes[i]->RenderOpaqueGeometry(viewport);
    }

317 318 319
  return renderedSomething;
}

320 321 322 323 324 325 326 327
//-----------------------------------------------------------------------------
// Description:
// Does this prop have some translucent polygonal geometry?
int vtkParallelCoordinatesActor::HasTranslucentPolygonalGeometry()
{
  return 0;
}

Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
//----------------------------------------------------------------------------
static inline int vtkParallelCoordinatesActorGetComponent(vtkFieldData* field,
  vtkIdType tuple, int component, double* val)
{
  int array_comp;
  int array_index = field->GetArrayContainingComponent(component, array_comp);
  if (array_index < 0)
    {
    return 0;
    }
  vtkDataArray* da = field->GetArray(array_index);
  if (!da)
    {
    // non-numeric array.
    return 0;
    }
  *val = da->GetComponent(tuple, array_comp);
  return 1;
}

348
//----------------------------------------------------------------------------
Bill Lorensen's avatar
Bill Lorensen committed
349
int vtkParallelCoordinatesActor::PlaceAxes(vtkViewport *viewport, int *vtkNotUsed(size))
350
{
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
351
  vtkIdType i, j, k, ptId;
352 353
  vtkDataObject *input = this->GetInput();
  vtkFieldData *field = input->GetFieldData();
354 355
  double v = 0.0;

356 357 358 359 360 361
  this->Initialize();

  if ( ! field )
    {
    return 0;
    }
362

363
  // Determine the shape of the field
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
364 365 366 367
  int numComponents = field->GetNumberOfComponents(); //number of components
    // Note: numComponents also includes the non-numeric arrays.

  int numColumns = 0; //number of "columns" -- includes only numeric arrays.
368
  vtkIdType numRows = VTK_ID_MAX; //figure out number of rows
Amy Squillacote's avatar
Amy Squillacote committed
369
  vtkIdType numTuples;
370 371
  vtkDataArray *array;
  for (i=0; i<field->GetNumberOfArrays(); i++)
372
    {
373
    array = field->GetArray(i);
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
374 375 376 377 378 379
    if (!array)
      {
      // skip over non-numeric arrays.
      continue;
      }
    numColumns += array->GetNumberOfComponents();
380 381
    numTuples = array->GetNumberOfTuples();
    if ( numTuples < numRows )
382
      {
383
      numRows = numTuples;
384
      }
385 386 387 388 389 390
    }

  // Determine the number of independent variables
  if ( this->IndependentVariables == VTK_IV_COLUMN )
    {
    this->N = numColumns;
391 392 393
    }
  else //row
    {
394
    this->N = numRows;
395 396
    }

397
  if ( this->N <= 0 || this->N >= VTK_ID_MAX )
398 399 400 401 402
    {
    this->N = 0;
    vtkErrorMacro(<<"No field data to plot");
    return 0;
    }
403

404 405
  // We need to loop over the field to determine the range of
  // each independent variable.
406 407
  this->Mins = new double [this->N];
  this->Maxs = new double [this->N];
408 409
  for (i=0; i<this->N; i++)
    {
410 411
    this->Mins[i] =  VTK_DOUBLE_MAX;
    this->Maxs[i] = -VTK_DOUBLE_MAX;
412 413 414 415
    }

  if ( this->IndependentVariables == VTK_IV_COLUMN )
    {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
416 417
    k = 0;
    for (j=0; j<numComponents; j++)
418
      {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
419 420 421 422 423 424 425
      int array_comp, array_index;
      array_index = field->GetArrayContainingComponent(j, array_comp);
      if (array_index < 0 || !field->GetArray(array_index))
        {
        // non-numeric component, simply skip it.
        continue;
        }
426 427
      for (i=0; i<numRows; i++)
        {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
428 429 430
        //v = field->GetComponent(i,j);
        ::vtkParallelCoordinatesActorGetComponent(field, i, j, &v);
        if ( v < this->Mins[k] )
431
          {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
432
          this->Mins[k] = v;
433
          }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
434
        if ( v > this->Maxs[k] )
435
          {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
436
          this->Maxs[k] = v;
437 438
          }
        }
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
439
      k++;
440 441 442 443 444 445
      }
    }
  else //row
    {
    for (j=0; j<numRows; j++)
      {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
446
      for (i=0; i<numComponents; i++)
447
        {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
448 449 450 451 452 453 454
        //v = field->GetComponent(j,i);
        if (::vtkParallelCoordinatesActorGetComponent(field,
            j, i, &v) == 0)
          {
          // non-numeric component, simply skip.
          continue;
          }
455 456 457 458 459 460 461 462 463 464 465 466
        if ( v < this->Mins[j] )
          {
          this->Mins[j] = v;
          }
        if ( v > this->Maxs[j] )
          {
          this->Maxs[j] = v;
          }
        }
      }
    }

467
  // Allocate space and create axes
468 469 470

  // TODO: this should be optimized, maybe by keeping a list of allocated
  // objects, in order to avoid creation/destruction of axis actors
471
  // and their underlying text properties (i.e. each time an axis is
472 473
  // created, text properties are created and shallow-assigned a
  // font size which value might be "far" from the target font size).
474

475 476 477 478
  this->Axes = new vtkAxisActor2D* [this->N];
  for (i=0; i<this->N; i++)
    {
    this->Axes[i] = vtkAxisActor2D::New();
Sebastien Barre's avatar
Sebastien Barre committed
479 480
    this->Axes[i]->GetPositionCoordinate()->SetCoordinateSystemToViewport();
    this->Axes[i]->GetPosition2Coordinate()->SetCoordinateSystemToViewport();
481 482
    this->Axes[i]->SetRange(this->Mins[i],this->Maxs[i]);
    this->Axes[i]->AdjustLabelsOff();
483 484 485
    this->Axes[i]->SetNumberOfLabels(this->NumberOfLabels);
    this->Axes[i]->SetLabelFormat(this->LabelFormat);
    this->Axes[i]->SetProperty(this->GetProperty());
486 487 488 489 490
    // We do not need shallow copy here since we do not modify any attributes
    // in that class and we know that vtkAxisActor2D use ShallowCopy internally
    // so that the size of the text prop is not affected by the automatic
    // adjustment of its text mapper's size.
    this->Axes[i]->SetLabelTextProperty(this->LabelTextProperty);
491 492 493 494 495 496 497 498 499 500 501 502
    }
  this->Xs = new int [this->N];

  // Get the location of the corners of the box
  int *p1 = this->PositionCoordinate->GetComputedViewportValue(viewport);
  int *p2 = this->Position2Coordinate->GetComputedViewportValue(viewport);

  // Specify the positions for the axes
  this->YMin = p1[1];
  this->YMax = p2[1];
  for (i=0; i<this->N; i++)
    {
503 504
    this->Xs[i] = static_cast<int>(
      p1[0] + i/static_cast<double>(this->N) * (p2[0]-p1[0]));
505
    this->Axes[i]->GetPositionCoordinate()->SetValue(this->Xs[i],
506
                                                     this->YMin);
507
    this->Axes[i]->GetPosition2Coordinate()->SetValue(this->Xs[i],
508
                                                      this->YMax);
509 510
    }

511
  // Now generate the lines to plot
512 513 514 515 516 517
  this->PlotData->Initialize(); //remove old polydata, if any
  vtkPoints *pts = vtkPoints::New();
  pts->Allocate(numRows*numColumns);
  vtkCellArray *lines = vtkCellArray::New();
  this->PlotData->SetPoints(pts);
  this->PlotData->SetLines(lines);
518

519
  double x[3]; x[2] = 0.0;
520 521
  if ( this->IndependentVariables == VTK_IV_COLUMN )
    {
522 523 524 525
    lines->Allocate(lines->EstimateSize(numRows,numColumns));
    for (j=0; j<numRows; j++)
      {
      lines->InsertNextCell(numColumns);
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
526
      for (i=0,k=0; i<numColumns && k < numComponents; k++)
527
        {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
528 529 530 531 532 533
        // v = field->GetComponent(j,i);
        if (::vtkParallelCoordinatesActorGetComponent(field, j, k, &v) == 0)
          {
          // skip non-numeric components.
          continue;
          }
534 535 536 537 538 539 540
        x[0] = this->Xs[i];
        if ( (this->Maxs[i]-this->Mins[i]) == 0.0 )
          {
          x[1] = 0.5 * (this->YMax - this->YMin);
          }
        else
          {
541
          x[1] = this->YMin +
542 543 544
            ((v - this->Mins[i]) / (this->Maxs[i] - this->Mins[i])) *
            (this->YMax - this->YMin);
          }
545 546
        ptId = pts->InsertNextPoint(x);
        lines->InsertCellPoint(ptId);
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
547
        i++;
548 549
        }
      }
550 551 552
    }
  else //row
    {
553
    lines->Allocate(lines->EstimateSize(numColumns,numRows));
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
554
    for (j=0; j<numComponents; j++)
555
      {
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
556 557 558 559 560 561 562
      int array_comp;
      int array_index = field->GetArrayContainingComponent(j, array_comp);
      if (!field->GetArray(array_index))
        {
        // non-numeric component, skip it.
        continue;
        }
563 564 565 566
      lines->InsertNextCell(numColumns);
      for (i=0; i<numRows; i++)
        {
        x[0] = this->Xs[i];
Utkarsh Ayachit's avatar
Utkarsh Ayachit committed
567 568
        // v = field->GetComponent(i,j);
        vtkParallelCoordinatesActorGetComponent(field, i, j, &v);
569 570 571 572 573 574
        if ( (this->Maxs[i]-this->Mins[i]) == 0.0 )
          {
          x[1] = 0.5 * (this->YMax - this->YMin);
          }
        else
          {
575
          x[1] = this->YMin +
576 577 578
            ((v - this->Mins[i]) / (this->Maxs[i] - this->Mins[i])) *
            (this->YMax - this->YMin);
          }
579 580
        ptId = pts->InsertNextPoint(x);
        lines->InsertCellPoint(ptId);
581 582
        }
      }
583 584
    }

585 586 587
  pts->Delete();
  lines->Delete();

588
  return 1;
589 590
}

591
//----------------------------------------------------------------------------
592 593 594 595 596 597 598 599 600 601 602 603
// Release any graphics resources that are being consumed by this actor.
// The parameter window could be used to determine which graphic
// resources to release.
void vtkParallelCoordinatesActor::ReleaseGraphicsResources(vtkWindow *win)
{
  this->TitleActor->ReleaseGraphicsResources(win);
  for (int i=0; this->Axes && i<this->N; i++)
    {
    this->Axes[i]->ReleaseGraphicsResources(win);
    }
}

604
//----------------------------------------------------------------------------
605 606
void vtkParallelCoordinatesActor::PrintSelf(ostream& os, vtkIndent indent)
{
Brad King's avatar
Brad King committed
607
  this->Superclass::PrintSelf(os,indent);
608

609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628
  if (this->TitleTextProperty)
    {
    os << indent << "Title Text Property:\n";
    this->TitleTextProperty->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Title Text Property: (none)\n";
    }

  if (this->LabelTextProperty)
    {
    os << indent << "Label Text Property:\n";
    this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Label Text Property: (none)\n";
    }

629
  os << indent << "Position2 Coordinate: "
630 631
     << this->Position2Coordinate << "\n";
  this->Position2Coordinate->PrintSelf(os, indent.GetNextIndent());
632

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647
  os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n";
  os << indent << "Number Of Independent Variables: " << this->N << "\n";
  os << indent << "Independent Variables: ";
  if ( this->IndependentVariables == VTK_IV_COLUMN )
    {
    os << "Columns\n";
    }
  else
    {
    os << "Rows\n";
    }

  os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n";

  os << indent << "Label Format: " << this->LabelFormat << "\n";
648
}