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 <vtkPen.h>
#include <vtkPlot.h>
#include <vtkPlotPoints.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkTable.h>

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

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)");
  leftChart->GetBackgroundBrush()->SetColorF(
      colors->GetColor4d("MistyRose").GetData());
  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)");
  rightChart->GetBackgroundBrush()->SetColorF(
      colors->GetColor4d("Thistle").GetData());
  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.3 FATAL_ERROR)

project(MultiplePlots)

find_package(VTK COMPONENTS 
  vtkChartsCore
  vtkCommonColor
  vtkCommonCore
  vtkCommonDataModel
  vtkInteractionStyle
  vtkRenderingContext2D
  vtkRenderingContextOpenGL2
  vtkRenderingCore
  vtkRenderingFreeType
  vtkRenderingGL2PSOpenGL2
  vtkRenderingOpenGL2
  QUIET
)

if (NOT VTK_FOUND)
  message("Skipping MultiplePlots: ${VTK_NOT_FOUND_MESSAGE}")
  return ()
endif()
message (STATUS "VTK_VERSION: ${VTK_VERSION}")
if (VTK_VERSION VERSION_LESS "8.90.0")
  # old system
  include(${VTK_USE_FILE})
  add_executable(MultiplePlots MACOSX_BUNDLE MultiplePlots.cxx )
  target_link_libraries(MultiplePlots PRIVATE ${VTK_LIBRARIES})
else ()
  # include all components
  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}
    )
endif ()

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.