Skip to content

MultiplePlots

vtk-examples/Cxx/Plotting/MultiplePlots


Description

Display multiple plots by using viewports in a single render window.

In this case, we display two graphs side-by-side.

The difference between setting a background in the renderer and setting the chart background is shown.

Note

This example was prompted by this discussion vtk chart background shifted towards origin.

Other languages

See (Python)

Question

If you have a question about this example, please use the VTK Discourse Forum

Code

MultiplePlots.cxx

#include <vtkAxis.h>
#include <vtkBrush.h>
#include <vtkChartXY.h>
#include <vtkContextActor.h>
#include <vtkContextScene.h>
#include <vtkFloatArray.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlotPoints.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkTable.h>
#include <vtkVersion.h>

#include <array>
#include <cmath>
#include <vector>

#if VTK_VERSION_NUMBER >= 90220220630ULL
#define VTK_HAS_SETCOLORF 1
#endif

int main(int, char*[])
{
  vtkNew<vtkNamedColors> colors;

  vtkNew<vtkRenderWindow> renWin;
  renWin->SetWindowName("MultiplePlots");
  vtkNew<vtkRenderWindowInteractor> iRen;
  iRen->SetRenderWindow(renWin);

  // Setup the viewports
  auto gridDimensionsX = 2;
  auto gridDimensionsY = 1;
  auto rendererSizeX = 320;
  auto rendererSizeY = 240;
  renWin->SetSize(rendererSizeX * gridDimensionsX,
                  rendererSizeY * gridDimensionsY);
  std::cout << rendererSizeX * gridDimensionsX << " "
            << gridDimensionsY * gridDimensionsY << std::endl;
  std::vector<std::array<double, 4>> viewPorts;
  for (auto row = 0; row < gridDimensionsY; ++row)
  {
    for (auto col = 0; col < gridDimensionsX; ++col)
    {
      // index = row * gridDimensionsX + col

      // (xmin, ymin, xmax, ymax)
      viewPorts.push_back(std::array<double, 4>{
          static_cast<double>(col) / gridDimensionsX,
          static_cast<double>(gridDimensionsY - (row + 1.0)) / gridDimensionsY,
          static_cast<double>(col + 1.0) / gridDimensionsX,
          static_cast<double>(gridDimensionsY - static_cast<double>(row)) /
              gridDimensionsY});
    }
  }

  // Link the renderers to the viewports.
  vtkNew<vtkRenderer> leftRenderer;
  leftRenderer->SetBackground(colors->GetColor3d("AliceBlue").GetData());
  leftRenderer->SetViewport(viewPorts[0].data());
  renWin->AddRenderer(leftRenderer);

  vtkNew<vtkRenderer> rightRenderer;
  rightRenderer->SetBackground(colors->GetColor3d("Lavender").GetData());
  rightRenderer->SetViewport(viewPorts[1].data());
  renWin->AddRenderer(rightRenderer);

  // Create the charts.
  vtkNew<vtkChartXY> leftChart;
  vtkNew<vtkContextScene> leftChartScene;
  vtkNew<vtkContextActor> leftChartActor;

  leftChartScene->AddItem(leftChart);
  leftChartActor->SetScene(leftChartScene);

  leftRenderer->AddActor(leftChartActor);
  leftChartScene->SetRenderer(leftRenderer);

  auto xAxis = leftChart->GetAxis(vtkAxis::BOTTOM);
  xAxis->GetGridPen()->SetColor(colors->GetColor4ub("LightGrey"));
  xAxis->SetTitle("x");
  auto yAxis = leftChart->GetAxis(vtkAxis::LEFT);
  yAxis->GetGridPen()->SetColor(colors->GetColor4ub("LightGrey"));
  yAxis->SetTitle("cos(x)");
#if VTK_HAS_SETCOLORF
  leftChart->GetBackgroundBrush()->SetColorF(
      colors->GetColor4d("MistyRose").GetData());
#else
  leftChart->GetBackgroundBrush()->SetColor(
      colors->GetColor4d("MistyRose").GetData());
#endif
  leftChart->GetBackgroundBrush()->SetOpacityF(0.4);
  leftChart->SetTitle("Cosine");

  vtkNew<vtkChartXY> rightChart;
  vtkNew<vtkContextScene> rightChartScene;
  vtkNew<vtkContextActor> rightChartActor;

  rightChartScene->AddItem(rightChart);
  rightChartActor->SetScene(rightChartScene);

  rightRenderer->AddActor(rightChartActor);
  rightChartScene->SetRenderer(rightRenderer);

  xAxis = rightChart->GetAxis(vtkAxis::BOTTOM);
  xAxis->GetGridPen()->SetColor(colors->GetColor4ub("LightCyan"));
  xAxis->SetTitle("x");
  yAxis = rightChart->GetAxis(vtkAxis::LEFT);
  yAxis->GetGridPen()->SetColor(colors->GetColor4ub("LightCyan"));
  yAxis->SetTitle("sin(x)");
#if VTK_HAS_SETCOLORF
  rightChart->GetBackgroundBrush()->SetColorF(
      colors->GetColor4d("Thistle").GetData());
#else
  rightChart->GetBackgroundBrush()->SetColor(
      colors->GetColor4d("Thistle").GetData());
#endif
  rightChart->GetBackgroundBrush()->SetOpacityF(0.4);
  rightChart->SetTitle("Sine");

  // Create a table with some points in it.
  vtkNew<vtkTable> table;

  vtkNew<vtkFloatArray> arrX;
  arrX->SetName("X Axis");
  table->AddColumn(arrX);

  vtkNew<vtkFloatArray> arrC;
  arrC->SetName("Cosine");
  table->AddColumn(arrC);

  vtkNew<vtkFloatArray> arrS;
  arrS->SetName("Sine");
  table->AddColumn(arrS);

  // Fill in the table with some example values.
  auto numPoints = 40;
  auto inc = 7.5 / (numPoints - 1.0);
  table->SetNumberOfRows(numPoints);
  for (int i = 0; i < numPoints; ++i)
  {
    table->SetValue(i, 0, i * inc);
    table->SetValue(i, 1, cos(i * inc));
    table->SetValue(i, 2, sin(i * inc));
  }

  auto ptColor = colors->GetColor4ub("Black");

  auto points = leftChart->AddPlot(vtkChart::POINTS);
  points->SetInputData(table, 0, 1);
  points->SetColor(ptColor.GetRed(), ptColor.GetGreen(), ptColor.GetBlue(),
                   ptColor.GetAlpha());
  points->SetWidth(1.0);
  dynamic_cast<vtkPlotPoints*>(points)->SetMarkerStyle(vtkPlotPoints::CROSS);

  points = rightChart->AddPlot(vtkChart::POINTS);
  points->SetInputData(table, 0, 2);
  points->SetColor(ptColor.GetRed(), ptColor.GetGreen(), ptColor.GetBlue(),
                   ptColor.GetAlpha());
  points->SetWidth(1.0);
  dynamic_cast<vtkPlotPoints*>(points)->SetMarkerStyle(vtkPlotPoints::PLUS);

  renWin->Render();
  iRen->Initialize();
  iRen->Start();

  return EXIT_SUCCESS;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.12 FATAL_ERROR)

project(MultiplePlots)

find_package(VTK COMPONENTS 
)

if (NOT VTK_FOUND)
  message(FATAL_ERROR "MultiplePlots: Unable to find the VTK build folder.")
endif()

# Prevent a "command line is too long" failure in Windows.
set(CMAKE_NINJA_FORCE_RESPONSE_FILE "ON" CACHE BOOL "Force Ninja to use response files.")
add_executable(MultiplePlots MACOSX_BUNDLE MultiplePlots.cxx )
  target_link_libraries(MultiplePlots PRIVATE ${VTK_LIBRARIES}
)
# vtk_module_autoinit is needed
vtk_module_autoinit(
  TARGETS MultiplePlots
  MODULES ${VTK_LIBRARIES}
)

Download and Build MultiplePlots

Click here to download MultiplePlots and its CMakeLists.txt file. Once the tarball MultiplePlots.tar has been downloaded and extracted,

cd MultiplePlots/build

If VTK is installed:

cmake ..

If VTK is not installed but compiled on your system, you will need to specify the path to your VTK build:

cmake -DVTK_DIR:PATH=/home/me/vtk_build ..

Build the project:

make

and run it:

./MultiplePlots

WINDOWS USERS

Be sure to add the VTK bin directory to your path. This will resolve the VTK dll's at run time.