diff --git a/src/Cxx.md b/src/Cxx.md
index 932d170fa1d5a4b042e0681b6686c92dee7bbeab..7af31cf2f075072f9e66212d876b1d09cb796bde 100644
--- a/src/Cxx.md
+++ b/src/Cxx.md
@@ -1034,6 +1034,8 @@ See [this tutorial](http://www.vtk.org/Wiki/VTK/Tutorials/3DDataTypes) for a bri
 [Follower](/Cxx/Visualization/Follower) | Draw text that stays right side up.
 [FontFile](/Cxx/Visualization/FontFile) | Use an external font.
 [FrogBrain](/Cxx/Visualization/FrogBrain) | The frog’s brain. Model extracted without smoothing (left) and with smoothing (right).
+[FroggieSurface](/Cxx/Visualization/FroggieSurface) | All or some frog tissues are reconstructed from the original segmented data.
+[FroggieView](/Cxx/Visualization/FroggieView) | View all or some frog tissues and adjust the translucency of the tissues.
 [FrogSlice](/Cxx/Visualization/FrogSlice) | Photographic slice of frog (upper left), segmented frog (upper right) and composite of photo and segmentation (bottom). The purple color represents the stomach and the kidneys are yellow.
 [Glyph2D](/Cxx/Filtering/Glyph2D) |
 [Glyph3D](/Cxx/Filtering/Glyph3D) |
diff --git a/src/Cxx/Visualization/CMakeLists.txt b/src/Cxx/Visualization/CMakeLists.txt
index 500eafcb86d01bd8d15166c3c3ffed486bbcea52..4ae4ad8e7af9939c0df9d4da1de06d317b7da9d9 100644
--- a/src/Cxx/Visualization/CMakeLists.txt
+++ b/src/Cxx/Visualization/CMakeLists.txt
@@ -48,8 +48,10 @@ if(NOT VTK_BINARY_DIR)
   RenderingLOD
   RenderingLabel
   RenderingOpenGL2
+  OPTIONAL_COMPONENTS
+  cli11
+  jsoncpp
   TestingRendering
-  ${optional}
   QUIET
 )
 endif()
@@ -61,6 +63,18 @@ set(KIT_LIBS ${VTK_LIBRARIES})
 
 file(GLOB ALL_FILES *.cxx)
 
+include(${WikiExamples_SOURCE_DIR}/CMake/RequiresCxxVersion.cmake)
+set(CXX_VERSION_MIN "17")
+Requires_Cxx_Version(FroggieSurface ${CXX_VERSION_MIN} ALL_FILES)
+Requires_Cxx_Version(FroggieView ${CXX_VERSION_MIN} ALL_FILES)
+
+include(${WikiExamples_SOURCE_DIR}/CMake/RequiresModule.cmake)
+Requires_Module(FroggieSurface cli11)
+Requires_Module(FroggieView cli11)
+Requires_Module(FroggieSurface jsoncpp)
+Requires_Module(FroggieView jsoncpp)
+
+
 Requires_Module(ExtrudePolyDataAlongLine SplineDrivenImageSlicer)
 #Requires_Module(ShadowsOpenGL RenderingOpenGL)
 #Requires_Setting_Off(StreamLines VTK_LEGACY_REMOVE)
@@ -102,6 +116,8 @@ if (BUILD_TESTING)
     ExtrudePolyDataAlongLine
     FontFile
     FrogBrain
+    FroggieSurface
+    FroggieView
     FrogSlice
     Glyph3DImage
     Glyph3DMapper
@@ -182,6 +198,15 @@ if (BUILD_TESTING)
   add_test(${KIT}-FontFile ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
     TestFontFile ${DATA}/CopyPaste.ttf)
 
+    if(TARGET FroggieSurface)
+    add_test(${KIT}-FroggieSurface ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
+    TestFroggieSurface ${DATA}/Frog_mhd.json)
+  endif()
+  if(TARGET FroggieView)
+    add_test(${KIT}-FroggieView ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
+      TestFroggieView ${DATA}/Frog_vtk.json)
+  endif()
+
   add_test(${KIT}-Glyph3DImage ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${KIT}CxxTests
     TestGlyph3DImage ${DATA}/emote.jpg)
 
diff --git a/src/Cxx/Visualization/FroggieSurface.cxx b/src/Cxx/Visualization/FroggieSurface.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..52e2736398446785c605c13a5d4ca25ccea375e6
--- /dev/null
+++ b/src/Cxx/Visualization/FroggieSurface.cxx
@@ -0,0 +1,1182 @@
+#include <vtkActor.h>
+#include <vtkAnnotatedCubeActor.h>
+#include <vtkAxesActor.h>
+#include <vtkCamera.h>
+#include <vtkCameraOrientationWidget.h>
+#include <vtkCaptionActor2D.h>
+#include <vtkDecimatePro.h>
+#include <vtkFlyingEdges3D.h>
+#include <vtkImageGaussianSmooth.h>
+#include <vtkImageIslandRemoval2D.h>
+#include <vtkImageShrink3D.h>
+#include <vtkImageThreshold.h>
+#include <vtkInteractorStyleTrackballCamera.h>
+#include <vtkLookupTable.h>
+#include <vtkMarchingCubes.h>
+#include <vtkMatrix4x4.h>
+#include <vtkMetaImageReader.h>
+#include <vtkNamedColors.h>
+#include <vtkNew.h>
+#include <vtkOrientationMarkerWidget.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkPolyDataNormals.h>
+#include <vtkProp3D.h>
+#include <vtkPropAssembly.h>
+#include <vtkProperty.h>
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+#include <vtkRenderer.h>
+#include <vtkSmartPointer.h>
+#include <vtkStripper.h>
+#include <vtkTextProperty.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
+#include <vtkWindowedSincPolyDataFilter.h>
+
+#include <vtk_cli11.h>
+#include <vtk_jsoncpp.h>
+
+#include <array>
+#include <cstdlib>
+#include <filesystem>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+#include <variant>
+
+namespace fs = std::filesystem;
+
+namespace {
+struct Parameters
+{
+  std::vector<std::string> names;
+  std::map<std::string, std::string> colors;
+  std::map<std::string, std::string> mhdFiles;
+  std::vector<std::string> fig_129b;
+  std::vector<std::string> fig_129cd;
+  std::map<std::string,
+           std::map<std::string, std::variant<int, double, std::string>>>
+      tissues;
+
+  bool parsedOk{false};
+};
+
+/**
+ * Take a string and convert it to lowercase.
+ *
+ * See: https://en.cppreference.com/w/cpp/string/byte/tolower
+ * Only works with ASCII characters.
+ *
+ * @param s: The string to be converted to lowercase.
+ *
+ * @return The lowercase version of the string.
+ */
+std::string ToLowerCase(std::string s);
+
+/**
+ * Read the parameters from a json file and check that the file paths exist.
+ *
+ * @param fnPath: The path to the json file.
+ * @param parameters:  The parameters.
+ */
+void ParseJSON(const fs::path fnPath, Parameters& parameters);
+
+/**
+ * Create the lookup table for the frog tissues.
+ *
+ * Each table value corresponds the color of one of the frog tissues.
+ *
+ * @param indices: The tissue name and index.
+ * @param colors: The tissue name and color.
+ * @return: The lookup table.
+ */
+vtkNew<vtkLookupTable>
+CreateTissueLUT(std::map<std::string, int> const& indices,
+                std::map<std::string, std::string>& colors);
+
+class SliceOrder
+{
+  // clang-format off
+  /*
+    These transformations permute image and other geometric data to maintain
+      proper orientation regardless of the acquisition order. After applying
+      these transforms with vtkTransformFilter, a view up of 0, -1, 0 will
+      result in the body part facing the viewer.
+     
+    NOTE: Some transformations have a -1 scale factor for one of the components.
+          To ensure proper polygon orientation and normal direction,
+            you must apply the vtkPolyDataNormals filter.
+
+    Naming (the nomenclature is medical):
+      si - superior to inferior (top to bottom)
+      is - inferior to superior (bottom to top)
+      ap - anterior to posterior (front to back)
+      pa - posterior to anterior (back to front)
+      lr - left to right
+      rl - right to left
+
+    */
+  // clang-format on
+
+public:
+  /**
+   * Generate the transforms corresponding to the slice order.
+   */
+  SliceOrder();
+
+  virtual ~SliceOrder() = default;
+
+public:
+  /**
+   * Returns the vtkTransform corresponding to the slice order.
+   *
+   * @param sliceOrder: The slice order.
+   * @return The vtkTransform corresponding to the slice order.
+   */
+  vtkSmartPointer<vtkTransform> Get(std::string const& sliceOrder);
+
+  /**
+   * Print the homogenous matrix corresponding to the slice order.
+   *
+   * @param order: The slice order.
+   */
+  void PrintTransform(std::string const& order);
+
+  /**
+   * Print all the homogenous matrices corresponding to the slice orders.
+   *
+   */
+  void PrintAlltransforms();
+
+private:
+  std::map<std::string, vtkSmartPointer<vtkTransform>> transform;
+};
+
+/**
+ * Create the actor for a specific tissue.
+ *
+ * @param name: The tissue name.
+ * @param tissue: The tissue parameters.
+ * @param files: The path to the tissue files.
+ * @param flying_edges: If true use flying edges.
+ * @param decimate: If true decimate.
+ * @param lut: The color lookup table for the tissues.
+ * @param so: The transforms corresponding to the slice order.
+ * @param actor: The actor.
+ */
+void CreateTissueActor(
+    std::string const& name,
+    std::map<std::string, std::variant<int, double, std::string>>& tissue,
+    std::map<std::string, std::string>& files, bool const& flying_edges,
+    bool const& decimate, vtkLookupTable& color_lut, SliceOrder& so,
+    vtkActor* actor);
+
+/**
+ * @param scale: Sets the scale and direction of the axes.
+ * @param xyzLabels: Labels for the axes.
+ * @return The axes actor.
+ */
+vtkNew<vtkAxesActor> MakeAxesActor(std::array<double, 3>& scale,
+                                   std::array<std::string, 3> const& xyzLabels);
+
+/**
+ * @param cubeLabels: The labels for the cube faces.
+ * @param colors: Used to set the colors of the cube faces.
+ * @return The annotated cube actor.
+ */
+vtkNew<vtkAnnotatedCubeActor>
+MakeAnnotatedCubeActor(std::array<std::string, 6> const& cubeLabels,
+                       vtkNamedColors* colors);
+
+/**
+ * @param labelSelector: The selector used to define labels for the axes and
+ * cube.
+ * @param colors: Used to set the colors of the cube faces.
+ * @return The combined axes and annotated cube prop.
+ */
+vtkNew<vtkPropAssembly> MakeCubeActor(std::string const& labelSelector,
+                                      vtkNamedColors* colors);
+} // namespace
+
+int main(int argc, char* argv[])
+{
+  CLI::App app{"Display all frog parts and translucent skin."};
+
+  // Define options
+  std::string fileName;
+  app.add_option("fileName", fileName,
+                 "The path to the JSON file e.g. Frog_mhd.json.")
+      ->required()
+      ->check(CLI::ExistingFile);
+  bool flyingEdges{true};
+  app.add_flag("-m{false},!-n", flyingEdges,
+               "Use flying edges by default, marching cubes if set.");
+  bool decimation{false};
+  // -o: obliterate a synonym for decimation.
+  app.add_flag("-o", decimation, "Decimate if set.");
+  std::vector<std::string> chosenTissues;
+  app.add_option("-t", chosenTissues, "Select one or more tissues.");
+
+  std::array<bool, 4> view{false, false, false, false};
+  auto* ogroup = app.add_option_group(
+      "view",
+      "Select a view corresponding to Fig 12-9 in the VTK Textbook. Only none "
+      "or one of these can be selected.");
+  ogroup->add_flag("-a", view[0],
+                   "The view corresponds to Fig 12-9a in the VTK Textbook");
+  ogroup->add_flag("-b", view[1],
+                   "The view corresponds to Fig 12-9b in the VTK Textbook");
+  ogroup->add_flag("-c", view[2],
+                   "The view corresponds to Fig 12-9c in the VTK Textbook");
+  ogroup->add_flag("-d", view[3],
+                   "The view corresponds to Fig 12-9d in the VTK Textbook");
+
+  CLI11_PARSE(app, argc, argv);
+
+  auto selectCount = std::count_if(view.begin(), view.end(),
+                                   [=](const bool& e) { return e == true; });
+  if (selectCount > 1)
+  {
+    std::cerr
+        << "Only one or none of the options -a, -b, -c, -d can be selected;"
+        << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  auto fnPath = fs::path(fileName);
+  if (!fnPath.has_extension())
+  {
+    fnPath.replace_extension(".json");
+  }
+  if (!fs::is_regular_file(fnPath))
+  {
+    std::cerr << "Unable to find: " << fnPath << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  Parameters parameters;
+  ParseJSON(fnPath, parameters);
+  if (!parameters.parsedOk)
+  {
+    return EXIT_FAILURE;
+  }
+
+  std::vector<std::string> tissues;
+  std::map<std::string, int> indices;
+
+  for (auto const& n : parameters.names)
+  {
+    if (n != "brainbin")
+    {
+      tissues.push_back(n);
+      indices[n] = *std::get_if<int>(&parameters.tissues[n]["tissue"]);
+    }
+  }
+  auto lut = CreateTissueLUT(indices, parameters.colors);
+
+  char selectFigure{'\0'};
+  if (selectCount == 1)
+  {
+    if (view[0])
+    {
+      selectFigure = 'a';
+    }
+    else if (view[1])
+    {
+      // No skin.
+      tissues = parameters.fig_129b;
+      selectFigure = 'b';
+    }
+    else if (view[2])
+    {
+      // No skin, blood and skeleton.
+      tissues = parameters.fig_129cd;
+      selectFigure = 'c';
+    }
+    else
+    {
+      // No skin, blood and skeleton.
+      tissues = parameters.fig_129cd;
+      selectFigure = 'd';
+    }
+  }
+
+  if (!chosenTissues.empty())
+  {
+    for (auto i = 0; i < chosenTissues.size(); ++i)
+    {
+      chosenTissues[i] = ToLowerCase(chosenTissues[i]);
+    }
+    std::vector<std::string> res;
+    auto has_brainbin{false};
+    if (std::find(chosenTissues.begin(), chosenTissues.end(), "brainbin") !=
+        chosenTissues.end())
+    {
+      std::cout << "Using brainbin instead of brain." << std::endl;
+      res.push_back("brainbin");
+      indices.erase("brain");
+      indices["brainbin"] = 2;
+      parameters.colors.erase("brain");
+      parameters.colors["brainbin"] = "beige";
+      has_brainbin = true;
+    }
+    for (auto const& ct : chosenTissues)
+    {
+      if (has_brainbin && (ct == "brain" || ct == "brainbin"))
+      {
+        continue;
+      }
+      if (std::find(tissues.begin(), tissues.end(), ct) != tissues.end())
+      {
+        res.push_back(ct);
+      }
+      else
+      {
+        std::cout << "Tissue: " << ct << " is not available." << std::endl;
+        return EXIT_FAILURE;
+      }
+    }
+    if (res.size() == 1 && res[0] == "skin")
+    {
+      parameters.tissues["skin"]["opacity"] = 1.0;
+    }
+    tissues = res;
+  }
+
+  vtkNew<vtkNamedColors> colors;
+  colors->SetColor("ParaViewBkg",
+                   std::array<unsigned char, 4>{82, 87, 110, 255}.data());
+
+  // Setup render window, renderer, and interactor.
+  vtkNew<vtkRenderer> ren;
+  vtkNew<vtkRenderWindow> renWin;
+  renWin->AddRenderer(ren);
+  vtkNew<vtkRenderWindowInteractor> iRen;
+  iRen->SetRenderWindow(renWin);
+  vtkNew<vtkInteractorStyleTrackballCamera> style;
+  iRen->SetInteractorStyle(style);
+
+  SliceOrder so;
+  // so.PrintAlltransforms();
+
+  size_t colorSize{0};
+  for (auto const& p : parameters.colors)
+  {
+    colorSize = std::max(colorSize, p.second.size());
+  }
+  size_t nameSize{0};
+  for (auto const& p : parameters.names)
+  {
+    nameSize = std::max(nameSize, p.size());
+  }
+
+  std::string line(7 + nameSize + colorSize, '-');
+
+  std::cout << line << '\n'
+            << std::setw(nameSize) << std::left << "Tissue"
+            << " Label "
+            << "Color" << '\n'
+            << line << std::endl;
+  auto intSize = 2;
+
+  for (auto const& name : tissues)
+  {
+    vtkNew<vtkActor> actor;
+    CreateTissueActor(name, parameters.tissues[name], parameters.mhdFiles,
+                      flyingEdges, decimation, *lut, so, actor);
+    ren->AddActor(actor);
+    std::cout << std::setw(nameSize) << std::left << name << " "
+              << std::setw(intSize + 3) << std::right << indices[name] << " "
+              << std::setw(colorSize) << std::left << parameters.colors[name]
+              << std::endl;
+  }
+  std::cout << line << std::endl;
+
+  renWin->SetSize(1024, 1024);
+  renWin->SetWindowName("FroggieSurface");
+
+  ren->SetBackground(colors->GetColor3d("ParaViewBkg").GetData());
+
+  auto camera = ren->GetActiveCamera();
+  if (selectFigure == '\0')
+  {
+    // Orient so that we look down on the dorsal surface and
+    //  the superior surface faces the top of the screen.
+    vtkNew<vtkTransform> transform;
+    transform->SetMatrix(camera->GetModelTransformMatrix());
+    transform->RotateY(-90);
+    transform->RotateZ(90);
+    camera->SetModelTransformMatrix(transform->GetMatrix());
+    ren->ResetCamera();
+  }
+  else
+  {
+    if (selectFigure == 'a')
+    {
+      // Fig 12-9a in the VTK Textbook
+      camera->SetPosition(742.731237, -441.329635, -877.192015);
+      camera->SetFocalPoint(247.637687, 120.680880, -253.487473);
+      camera->SetViewUp(-0.323882, -0.816232, 0.478398);
+      camera->SetDistance(974.669585);
+      camera->SetClippingRange(311.646383, 1803.630763);
+    }
+    else if (selectFigure == 'b')
+    {
+      // Fig 12-9b in the VTK Textbook
+      camera->SetPosition(717.356065, -429.889054, -845.381584);
+      camera->SetFocalPoint(243.071719, 100.996487, -247.446340);
+      camera->SetViewUp(-0.320495, -0.820148, 0.473962);
+      camera->SetDistance(929.683631);
+      camera->SetClippingRange(293.464446, 1732.794957);
+    }
+    else if (selectFigure == 'c')
+    {
+      // Fig 12-9c in the VTK Textbook
+      camera->SetPosition(447.560023, -136.611491, -454.753689);
+      camera->SetFocalPoint(253.142277, 91.949451, -238.583973);
+      camera->SetViewUp(-0.425438, -0.786048, 0.448477);
+      camera->SetDistance(369.821187);
+      camera->SetClippingRange(0.829116, 829.115939);
+    }
+    else if (selectFigure == 'd')
+    {
+      // Fig 12-9d in the VTK Textbook
+      camera->SetPosition(347.826249, -469.633647, -236.234262);
+      camera->SetFocalPoint(296.893207, 89.307704, -225.156581);
+      camera->SetViewUp(-0.687345, -0.076948, 0.722244);
+      camera->SetDistance(561.366478);
+      camera->SetClippingRange(347.962064, 839.649856);
+    }
+  }
+
+  vtkNew<vtkCameraOrientationWidget> cow;
+  cow->SetParentRenderer(ren);
+  // Turn off if you do not want it.
+  cow->On();
+  cow->EnabledOn();
+
+  vtkNew<vtkOrientationMarkerWidget> om;
+  std::string labels;
+  if (selectFigure != '\0')
+  {
+    // Superior Anterior Left
+    labels = "sal";
+  }
+  else
+  {
+    // Right Superior Posterior
+    labels = "rsp";
+  }
+
+  auto axes = MakeCubeActor(labels, colors);
+  om->SetOrientationMarker(axes);
+  // Position upper left in the viewport.
+  // om->SetViewport(0.0, 0.8, 0.2, 1.0);
+  // Position lower left in the viewport.
+  om->SetViewport(0, 0, 0.2, 0.2);
+  om->SetInteractor(iRen);
+  om->EnabledOn();
+  om->InteractiveOn();
+
+  renWin->Render();
+
+  iRen->Start();
+  return EXIT_SUCCESS;
+}
+
+namespace {
+
+std::string ToLowerCase(std::string s)
+{
+  std::transform(s.begin(), s.end(), s.begin(),
+                 [](unsigned char c) { return std::tolower(c); } // correct
+  );
+  return s;
+}
+
+void ParseJSON(const fs::path fnPath, Parameters& parameters)
+{
+  std::ifstream ifs(fnPath);
+  Json::Value root;
+
+  if (ifs)
+  {
+    std::string str;
+    std::string errors;
+    Json::CharReaderBuilder builder{};
+    auto reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
+
+    std::ostringstream ss;
+    ss << ifs.rdbuf(); // Read in the file comtents
+    str = ss.str();
+    auto parsingSuccessful =
+        reader->parse(str.c_str(), str.c_str() + str.size(), &root, &errors);
+    ifs.close();
+    if (!parsingSuccessful)
+    {
+      std::cout << errors << std::endl;
+      parameters.parsedOk = false;
+      return;
+    }
+    parameters.parsedOk = true;
+  }
+  else
+  {
+    std::cerr << "Unable to open: " << fnPath << std::endl;
+    parameters.parsedOk = false;
+  }
+
+  // Get the parameters that we need.
+  fs::path mhdPath;
+  std::vector<std::string> fileNames;
+  for (Json::Value::const_iterator outer = root.begin(); outer != root.end();
+       ++outer)
+  {
+    if (outer.name() == "files")
+    {
+      std::string path;
+      for (Json::Value::const_iterator pth = root["files"].begin();
+           pth != root["files"].end(); ++pth)
+      {
+        if (pth.name() == "root")
+        {
+          mhdPath = fs::path(pth->asString());
+        }
+        if (pth.name() == "mhd_files")
+        {
+          for (Json::Value::const_iterator fls =
+                   root["files"]["mhd_files"].begin();
+               fls != root["files"]["mhd_files"].end(); ++fls)
+          {
+            fileNames.push_back(fls->asString());
+          }
+        }
+      }
+    }
+    if (outer.name() == "tissues")
+    {
+      for (Json::Value::const_iterator tc = root["tissues"]["colors"].begin();
+           tc != root["tissues"]["colors"].end(); ++tc)
+      {
+        parameters.colors[tc.name()] = tc->asString();
+      }
+    }
+    if (outer.name() == "figures")
+    {
+      for (Json::Value::const_iterator c = root["figures"]["fig12-9b"].begin();
+           c != root["figures"]["fig12-9b"].end(); ++c)
+      {
+        parameters.fig_129b.push_back(c->asString());
+      }
+      for (Json::Value::const_iterator c = root["figures"]["fig12-9cd"].begin();
+           c != root["figures"]["fig12-9cd"].end(); ++c)
+      {
+        parameters.fig_129cd.push_back(c->asString());
+      }
+    }
+    if (outer.name() == "tissue_parameters")
+    {
+      // A map of the parameters and the type of the parameter.
+      std::map<std::string, std::string> parameterTypes;
+      for (Json::Value::const_iterator p =
+               root["tissue_parameters"]["parameter types"].begin();
+           p != root["tissue_parameters"]["parameter types"].end(); ++p)
+      {
+        parameterTypes[p.name()] = p->asString();
+      }
+
+      // Map a variant of the correct type to the parameter name.
+      // parameterTypes: A map of the parameters and the type of the parameter.
+      // p: The Json iterator
+      // kv: The map of the parameter name (ket) and
+      //     the vatiant of the correct type (value).
+      auto populate =
+          [&parameterTypes](
+              Json::Value::const_iterator& p,
+              std::map<std::string, std::variant<int, double, std::string>>&
+                  kv) {
+            std::string n = p.name();
+            if (parameterTypes.find(n) == parameterTypes.end())
+            {
+              std::cout << "We cannot determine the type for " << n
+                        << std::endl;
+              return;
+            }
+            if (parameterTypes[p.name()] == "int")
+            {
+              kv[ToLowerCase(p.name())] = p->asInt();
+            }
+            if (parameterTypes[p.name()] == "dbl")
+            {
+              kv[ToLowerCase(p.name())] = p->asDouble();
+            }
+            if (parameterTypes[p.name()] == "str")
+            {
+              kv[ToLowerCase(p.name())] = p->asString();
+            }
+          };
+
+      std::map<std::string, std::variant<int, double, std::string>> bp;
+      for (Json::Value::const_iterator p =
+               root["tissue_parameters"]["default"].begin();
+           p != root["tissue_parameters"]["default"].end(); ++p)
+      {
+        populate(p, bp);
+      }
+      for (Json::Value::const_iterator p =
+               root["tissue_parameters"]["frog"].begin();
+           p != root["tissue_parameters"]["frog"].end(); ++p)
+      {
+        populate(p, bp);
+      }
+      std::set<std::string> exclude{"default", "frog", "parameter types"};
+      for (Json::Value::const_iterator p = root["tissue_parameters"].begin();
+           p != root["tissue_parameters"].end(); ++p)
+      {
+        if (exclude.find(p.name()) != exclude.end())
+        {
+          continue;
+        }
+        std::map<std::string, std::variant<int, double, std::string>> tmp;
+        std::copy(bp.begin(), bp.end(), std::inserter(tmp, tmp.end()));
+        for (Json::Value::const_iterator q =
+                 root["tissue_parameters"][p.name()].begin();
+             q != root["tissue_parameters"][p.name()].end(); ++q)
+        {
+          populate(q, tmp);
+        }
+        parameters.tissues[p.name()] = tmp;
+        parameters.names.push_back(p.name());
+      }
+    }
+  }
+
+  //  Build and check the paths.
+  if (!fileNames.empty())
+  {
+    if (fileNames.size() != 2)
+    {
+      std::cerr << "Expected two file names.";
+      parameters.parsedOk = false;
+    }
+    else
+    {
+      for (size_t i = 0; i < fileNames.size(); i++)
+      {
+        auto pth = fnPath.parent_path() / mhdPath / fs::path(fileNames[i]);
+        fileNames[i] = pth.make_preferred().string();
+        if (!(fs::is_regular_file(pth) && fs::exists(pth)))
+        {
+          std::cerr << "Not a file or path does not exist: " << fileNames[i]
+                    << std::endl;
+          parameters.parsedOk = false;
+        }
+        else
+        {
+          parameters.mhdFiles[pth.stem().string()] =
+              pth.make_preferred().string();
+        }
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "Expected .mhd file names in the JSON file.";
+    parameters.parsedOk = false;
+  }
+}
+
+vtkNew<vtkLookupTable>
+CreateTissueLUT(std::map<std::string, int> const& indices,
+                std::map<std::string, std::string>& colors)
+{
+  vtkNew<vtkLookupTable> lut;
+  lut->SetNumberOfColors(colors.size());
+  lut->SetTableRange(0, colors.size() - 1);
+  lut->Build();
+
+  vtkNew<vtkNamedColors> nc;
+
+  for (auto const& p : indices)
+  {
+    lut->SetTableValue(p.second, nc->GetColor4d(colors[p.first]).GetData());
+  }
+
+  return lut;
+}
+
+SliceOrder::SliceOrder()
+{
+  vtkNew<vtkMatrix4x4> si_mat;
+  si_mat->Zero();
+  si_mat->SetElement(0, 0, 1);
+  si_mat->SetElement(1, 2, 1);
+  si_mat->SetElement(2, 1, -1);
+  si_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkMatrix4x4> is_mat;
+  is_mat->Zero();
+  is_mat->SetElement(0, 0, 1);
+  is_mat->SetElement(1, 2, -1);
+  is_mat->SetElement(2, 1, -1);
+  is_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkMatrix4x4> lr_mat;
+  lr_mat->Zero();
+  lr_mat->SetElement(0, 2, -1);
+  lr_mat->SetElement(1, 1, -1);
+  lr_mat->SetElement(2, 0, 1);
+  lr_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkMatrix4x4> rl_mat;
+  rl_mat->Zero();
+  rl_mat->SetElement(0, 2, 1);
+  rl_mat->SetElement(1, 1, -1);
+  rl_mat->SetElement(2, 0, 1);
+  rl_mat->SetElement(3, 3, 1);
+
+  // The previous transforms assume radiological views of the slices
+  //  (viewed from the feet).
+  // Other modalities such as physical sectioning may view from the head.
+  // The following transforms modify the original with a 180° rotation about y
+
+  vtkNew<vtkMatrix4x4> hf_mat;
+  hf_mat->Zero();
+  hf_mat->SetElement(0, 0, -1);
+  hf_mat->SetElement(1, 1, 1);
+  hf_mat->SetElement(2, 2, -1);
+  hf_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkTransform> si_trans;
+  si_trans->SetMatrix(si_mat);
+  this->transform["si"] = si_trans;
+
+  vtkNew<vtkTransform> is_trans;
+  is_trans->SetMatrix(is_mat);
+  this->transform["is"] = is_trans;
+
+  vtkNew<vtkTransform> ap_trans;
+  ap_trans->Scale(1, -1, 1);
+  this->transform["ap"] = ap_trans;
+
+  vtkNew<vtkTransform> pa_trans;
+  pa_trans->Scale(1, -1, -1);
+  this->transform["pa"] = pa_trans;
+
+  vtkNew<vtkTransform> lr_trans;
+  lr_trans->SetMatrix(lr_mat);
+  this->transform["lr"] = lr_trans;
+
+  vtkNew<vtkTransform> rl_trans;
+  lr_trans->SetMatrix(rl_mat);
+  this->transform["rl"] = rl_trans;
+
+  vtkNew<vtkTransform> hf_trans;
+  hf_trans->SetMatrix(hf_mat);
+  this->transform["hf"] = hf_trans;
+
+  vtkNew<vtkTransform> hf_si_trans;
+  hf_si_trans->SetMatrix(hf_mat);
+  hf_si_trans->Concatenate(si_mat);
+  this->transform["hfsi"] = hf_si_trans;
+
+  vtkNew<vtkTransform> hf_is_trans;
+  hf_is_trans->SetMatrix(hf_mat);
+  hf_is_trans->Concatenate(is_mat);
+  this->transform["hfis"] = hf_is_trans;
+
+  vtkNew<vtkTransform> hf_ap_trans;
+  hf_ap_trans->SetMatrix(hf_mat);
+  hf_ap_trans->Scale(1, -1, 1);
+  this->transform["hfap"] = hf_ap_trans;
+
+  vtkNew<vtkTransform> hf_pa_trans;
+  hf_pa_trans->SetMatrix(hf_mat);
+  hf_pa_trans->Scale(1, -1, -1);
+  this->transform["hfpa"] = hf_pa_trans;
+
+  vtkNew<vtkTransform> hf_lr_trans;
+  hf_lr_trans->SetMatrix(hf_mat);
+  hf_lr_trans->Concatenate(lr_mat);
+  this->transform["hflr"] = hf_lr_trans;
+
+  vtkNew<vtkTransform> hf_rl_trans;
+  hf_rl_trans->SetMatrix(hf_mat);
+  hf_rl_trans->Concatenate(rl_mat);
+  this->transform["hfrl"] = hf_rl_trans;
+
+  // Identity
+  this->transform["I"] = vtkNew<vtkTransform>();
+
+  // Zero
+  vtkNew<vtkTransform> z_trans;
+  z_trans->Scale(0, 0, 0);
+  this->transform["Z"] = z_trans;
+}
+
+void SliceOrder::PrintTransform(std::string const& order)
+{
+  auto m = this->transform[order]->GetMatrix();
+  std::ostringstream os;
+  os.setf(std::ios_base::fmtflags(), std::ios_base::floatfield);
+  os << order << '\n';
+  for (int i = 0; i < 4; ++i)
+  {
+    for (int j = 0; j < 4; ++j)
+    {
+      if (j < 3)
+      {
+        os << std::setw(6) << std::right << std::setprecision(2)
+           << m->GetElement(i, j) << " ";
+      }
+      else
+      {
+        os << std::setw(6) << std::right << m->GetElement(i, j) << '\n';
+      }
+    }
+  }
+  std::cout << os.str() << '\n';
+  os.str("");
+}
+
+void SliceOrder::PrintAlltransforms()
+{
+  for (auto const p : this->transform)
+  {
+    PrintTransform(p.first);
+  }
+}
+
+vtkSmartPointer<vtkTransform> SliceOrder::Get(std::string const& sliceOrder)
+{
+  return this->transform[sliceOrder];
+}
+
+void CreateTissueActor(
+    std::string const& name,
+    std::map<std::string, std::variant<int, double, std::string>>& tissue,
+    std::map<std::string, std::string>& files, bool const& flying_edges,
+    bool const& decimate, vtkLookupTable& color_lut, SliceOrder& so,
+    vtkActor* actor)
+{
+
+  auto pixelSize = *std::get_if<int>(&tissue["pixel_size"]);
+  auto spacing = *std::get_if<double>(&tissue["spacing"]);
+  auto startSlice = *std::get_if<int>(&tissue["start_slice"]);
+  std::array<double, 3> dataSpacing{static_cast<double>(pixelSize),
+                                     static_cast<double>(pixelSize), spacing};
+  auto columns = *std::get_if<int>(&tissue["columns"]);
+  auto rows = *std::get_if<int>(&tissue["rows"]);
+  std::array<double, 3> dataOrigin = {-(columns / 2.0) * pixelSize,
+                                       -(rows / 2.0) * pixelSize,
+                                       startSlice * spacing};
+  std::array<int, 6> voi;
+  voi[0] = *std::get_if<int>(&tissue["start_column"]);
+  voi[1] = *std::get_if<int>(&tissue["end_column"]);
+  voi[2] = *std::get_if<int>(&tissue["start_row"]);
+  voi[3] = *std::get_if<int>(&tissue["end_row"]);
+  voi[4] = *std::get_if<int>(&tissue["start_slice"]);
+  voi[5] = *std::get_if<int>(&tissue["end_slice"]);
+  // Adjust y bounds for PNM coordinate system.
+  auto tmp = voi[2];
+  voi[2] = rows - voi[3] - 1;
+  voi[3] = rows - tmp - 1;
+
+  std::string fn;
+  if (name == "skin")
+  {
+    fn = files["frog"];
+  }
+  else
+  {
+    fn = files["frogtissue"];
+  }
+
+  vtkNew<vtkMetaImageReader> reader;
+  reader->SetFileName(fn.c_str());
+  reader->SetDataSpacing(dataSpacing.data());
+  reader->SetDataOrigin(dataOrigin.data());
+  reader->SetDataExtent(voi.data());
+  reader->Update();
+
+  // These are used to determine what filters
+  // to use based on the options chosen.
+  auto islandRemoverFlag{false};
+  auto selectTissueFlag{false};
+  auto gaussianFlag{false};
+
+  vtkNew<vtkImageIslandRemoval2D> islandRemover;
+  vtkNew<vtkImageThreshold> selectTissue;
+  if (name != "skin")
+  {
+    auto ir = *std::get_if<double>(&tissue["island_replace"]);
+    auto ia = *std::get_if<double>(&tissue["island_area"]);
+    auto idx = *std::get_if<int>(&tissue["tissue"]);
+    if (ir > 0)
+    {
+      islandRemover->SetAreaThreshold(ia);
+      islandRemover->SetIslandValue(ir);
+      islandRemover->SetReplaceValue(idx);
+      islandRemover->SetInputConnection(reader->GetOutputPort());
+      islandRemover->Update();
+      islandRemoverFlag = true;
+    }
+    selectTissue->ThresholdBetween(idx, idx);
+    selectTissue->SetInValue(255);
+    selectTissue->SetOutValue(0);
+    if (islandRemoverFlag)
+    {
+      selectTissue->SetInputConnection(islandRemover->GetOutputPort());
+    }
+    else
+    {
+      selectTissue->SetInputConnection(reader->GetOutputPort());
+    }
+    selectTissue->Update();
+    selectTissueFlag = true;
+  }
+
+  std::array<int, 3> sampleRate;
+  sampleRate[0] = *std::get_if<int>(&tissue["sample_rate_column"]);
+  sampleRate[1] = *std::get_if<int>(&tissue["sample_rate_row"]);
+  sampleRate[2] = *std::get_if<int>(&tissue["sample_rate_slice"]);
+  vtkNew<vtkImageShrink3D> shrinker;
+  if (selectTissueFlag)
+  {
+    shrinker->SetInputConnection(selectTissue->GetOutputPort());
+  }
+  else
+  {
+    shrinker->SetInputConnection(reader->GetOutputPort());
+  }
+  shrinker->SetShrinkFactors(sampleRate.data());
+  shrinker->AveragingOn();
+  shrinker->Update();
+
+  std::array<double, 3> gsd;
+  gsd[0] = *std::get_if<double>(&tissue["gaussian_standard_deviation_column"]);
+  gsd[1] = *std::get_if<double>(&tissue["gaussian_standard_deviation_row"]);
+  gsd[2] = *std::get_if<double>(&tissue["gaussian_standard_deviation_slice"]);
+
+  vtkNew<vtkImageGaussianSmooth> gaussian;
+
+  bool allZero =
+      std::all_of(gsd.begin(), gsd.end(), [](double i) { return i == 0; });
+  if (!allZero)
+  {
+    std::array<double, 3> grf;
+    grf[0] = *std::get_if<double>(&tissue["gaussian_radius_factor_column"]);
+    grf[1] = *std::get_if<double>(&tissue["gaussian_radius_factor_row"]);
+    grf[2] = *std::get_if<double>(&tissue["gaussian_radius_factor_slice"]);
+
+    gaussian->SetStandardDeviations(gsd.data());
+    gaussian->SetRadiusFactors(grf.data());
+    gaussian->SetInputConnection(shrinker->GetOutputPort());
+    gaussian->Update();
+    gaussianFlag = true;
+  }
+
+  auto iso_value = *std::get_if<double>(&tissue["value"]);
+  vtkNew<vtkFlyingEdges3D> flyingIsoSurface;
+  vtkNew<vtkMarchingCubes> marchingIsoSurface;
+  if (flying_edges)
+  {
+    if (gaussianFlag)
+    {
+      flyingIsoSurface->SetInputConnection(gaussian->GetOutputPort());
+    }
+    else
+    {
+      flyingIsoSurface->SetInputConnection(shrinker->GetOutputPort());
+    }
+    flyingIsoSurface->ComputeScalarsOff();
+    flyingIsoSurface->ComputeGradientsOff();
+    flyingIsoSurface->ComputeNormalsOff();
+    flyingIsoSurface->SetValue(0, iso_value);
+    flyingIsoSurface->Update();
+  }
+  else
+  {
+    if (gaussianFlag)
+    {
+      marchingIsoSurface->SetInputConnection(gaussian->GetOutputPort());
+    }
+    else
+    {
+      marchingIsoSurface->SetInputConnection(shrinker->GetOutputPort());
+    }
+    marchingIsoSurface->ComputeScalarsOff();
+    marchingIsoSurface->ComputeGradientsOff();
+    marchingIsoSurface->ComputeNormalsOff();
+    marchingIsoSurface->SetValue(0, iso_value);
+    marchingIsoSurface->Update();
+  }
+
+  auto sliceOrder = *std::get_if<std::string>(&tissue["slice_order"]);
+  auto transform = vtkSmartPointer<vtkTransform>::New();
+  transform = so.Get(sliceOrder);
+  vtkNew<vtkTransformPolyDataFilter> tf;
+  tf->SetTransform(transform);
+  if (flying_edges)
+  {
+    tf->SetInputConnection(flyingIsoSurface->GetOutputPort());
+  }
+  else
+  {
+    tf->SetInputConnection(marchingIsoSurface->GetOutputPort());
+  }
+
+  vtkNew<vtkDecimatePro> decimator;
+  if (decimate)
+  {
+    auto decimateAngle = *std::get_if<double>(&tissue["decimate_angle"]);
+    auto decimateError = *std::get_if<double>(&tissue["decimate_error"]);
+    auto decimateReduction =
+        *std::get_if<double>(&tissue["decimate_reduction"]);
+    decimator->SetInputConnection(tf->GetOutputPort());
+    decimator->SetFeatureAngle(decimateAngle);
+    decimator->PreserveTopologyOn();
+    decimator->SetErrorIsAbsolute(1);
+    decimator->SetAbsoluteError(decimateError);
+    decimator->SetTargetReduction(decimateReduction);
+  }
+
+  auto smoothIterations = *std::get_if<int>(&tissue["smooth_iterations"]);
+  auto smoothAngle = *std::get_if<double>(&tissue["smooth_angle"]);
+  auto smoothFactor = *std::get_if<double>(&tissue["smooth_factor"]);
+  vtkNew<vtkWindowedSincPolyDataFilter> smoother;
+  if (decimate)
+  {
+    smoother->SetInputConnection(decimator->GetOutputPort());
+  }
+  else
+  {
+    smoother->SetInputConnection(tf->GetOutputPort());
+  }
+  smoother->SetNumberOfIterations(smoothIterations);
+  smoother->BoundarySmoothingOff();
+  smoother->FeatureEdgeSmoothingOff();
+  smoother->SetFeatureAngle(smoothAngle);
+  smoother->SetPassBand(smoothFactor);
+  smoother->NonManifoldSmoothingOn();
+  smoother->NormalizeCoordinatesOff();
+  smoother->Update();
+
+  auto featureAngle = *std::get_if<double>(&tissue["feature_angle"]);
+  vtkNew<vtkPolyDataNormals> normals;
+  normals->SetInputConnection(smoother->GetOutputPort());
+  normals->SetFeatureAngle(featureAngle);
+
+  vtkNew<vtkStripper> stripper;
+  stripper->SetInputConnection(normals->GetOutputPort());
+
+  vtkNew<vtkPolyDataMapper> mapper;
+  mapper->SetInputConnection(stripper->GetOutputPort());
+
+  auto opacity = *std::get_if<double>(&tissue["opacity"]);
+  auto tissue_color =
+      color_lut.GetTableValue(*std::get_if<int>(&tissue["tissue"]));
+  actor->SetMapper(mapper);
+  actor->GetProperty()->SetOpacity(opacity);
+  actor->GetProperty()->SetDiffuseColor(tissue_color);
+  actor->GetProperty()->SetSpecular(0.5);
+  actor->GetProperty()->SetSpecularPower(10);
+}
+
+vtkNew<vtkAxesActor> MakeAxesActor(std::array<double, 3>& scale,
+                                   std::array<std::string, 3> const& xyzLabels)
+{
+  vtkNew<vtkAxesActor> axes;
+  axes->SetScale(scale.data());
+  axes->SetShaftTypeToCylinder();
+  axes->SetXAxisLabelText(xyzLabels[0].c_str());
+  axes->SetYAxisLabelText(xyzLabels[1].c_str());
+  axes->SetZAxisLabelText(xyzLabels[2].c_str());
+  axes->SetCylinderRadius(0.5 * axes->GetCylinderRadius());
+  axes->SetConeRadius(1.025 * axes->GetConeRadius());
+  axes->SetSphereRadius(1.5 * axes->GetSphereRadius());
+  auto tprop = axes->GetXAxisCaptionActor2D()->GetCaptionTextProperty();
+  tprop->ItalicOn();
+  tprop->ShadowOn();
+  tprop->SetFontFamilyToTimes();
+  // Use the same text properties on the other two axes.
+  axes->GetYAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy(tprop);
+  axes->GetZAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy(tprop);
+  return axes;
+}
+
+vtkNew<vtkAnnotatedCubeActor>
+MakeAnnotatedCubeActor(std::array<std::string, 6> const& cubeLabels,
+                       vtkNamedColors* colors)
+{
+  // A cube with labeled faces.
+  vtkNew<vtkAnnotatedCubeActor> cube;
+  cube->SetXPlusFaceText(cubeLabels[0].c_str());
+  cube->SetXMinusFaceText(cubeLabels[1].c_str());
+  cube->SetYPlusFaceText(cubeLabels[2].c_str());
+  cube->SetYMinusFaceText(cubeLabels[3].c_str());
+  cube->SetZPlusFaceText(cubeLabels[4].c_str());
+  cube->SetZMinusFaceText(cubeLabels[5].c_str());
+  cube->SetFaceTextScale(0.5);
+  cube->GetCubeProperty()->SetColor(colors->GetColor3d("Gainsboro").GetData());
+
+  cube->GetTextEdgesProperty()->SetColor(
+      colors->GetColor3d("LightSlateGray").GetData());
+
+  // Change the vector text colors.
+  cube->GetXPlusFaceProperty()->SetColor(
+      colors->GetColor3d("Tomato").GetData());
+  cube->GetXMinusFaceProperty()->SetColor(
+      colors->GetColor3d("Tomato").GetData());
+  cube->GetYPlusFaceProperty()->SetColor(
+      colors->GetColor3d("DeepSkyBlue").GetData());
+  cube->GetYMinusFaceProperty()->SetColor(
+      colors->GetColor3d("DeepSkyBlue").GetData());
+  cube->GetZPlusFaceProperty()->SetColor(
+      colors->GetColor3d("SeaGreen").GetData());
+  cube->GetZMinusFaceProperty()->SetColor(
+      colors->GetColor3d("SeaGreen").GetData());
+  return cube;
+}
+
+vtkNew<vtkPropAssembly> MakeCubeActor(std::string const& labelSelector,
+                                      vtkNamedColors* colors)
+{
+  std::array<std::string, 3> xyzLabels;
+  std::array<std::string, 6> cubeLabels;
+  std::array<double, 3> scale;
+  if (labelSelector == "sal")
+  {
+    // xyzLabels = std::array<std::string,3>{"S", "A", "L"};
+    xyzLabels = std::array<std::string, 3>{"+X", "+Y", "+Z"};
+    cubeLabels = std::array<std::string, 6>{"S", "I", "A", "P", "L", "R"};
+    scale = std::array<double, 3>{1.5, 1.5, 1.5};
+  }
+  else if (labelSelector == "rsp")
+  {
+    // xyzLabels = std::array<std::string, 3>{"R", "S", "P"};
+    xyzLabels = std::array<std::string, 3>{"+X", "+Y", "+Z"};
+    cubeLabels = std::array<std::string, 6>{"R", "L", "S", "I", "P", "A"};
+    scale = std::array<double, 3>{1.5, 1.5, 1.5};
+  }
+  else
+  {
+    xyzLabels = std::array<std::string, 3>{"+X", "+Y", "+Z"};
+    cubeLabels = std::array<std::string, 6>{"+X", "-X", "+Y", "-Y", "+Z", "-Z"};
+    scale = std::array<double, 3>{1.5, 1.5, 1.5};
+  }
+
+  // We are combining a vtkAxesActor and a vtkAnnotatedCubeActor
+  // into a vtkPropAssembly
+  auto cube = MakeAnnotatedCubeActor(cubeLabels, colors);
+  auto axes = MakeAxesActor(scale, xyzLabels);
+
+  // Combine orientation markers into one with an assembly.
+  vtkNew<vtkPropAssembly> assembly;
+  assembly->AddPart(axes);
+  assembly->AddPart(cube);
+  return assembly;
+}
+
+} // namespace
diff --git a/src/Cxx/Visualization/FroggieSurface.md b/src/Cxx/Visualization/FroggieSurface.md
new file mode 100644
index 0000000000000000000000000000000000000000..fb9b119a9d89565ee1b0e8ce7c79e3dc90c29c47
--- /dev/null
+++ b/src/Cxx/Visualization/FroggieSurface.md
@@ -0,0 +1,43 @@
+### Description
+
+Frog organs along with a translucent skin are reconstructed from the original segmented data.
+
+By default the frog is oriented so that we look down on the dorsal (posterior) surface and the superior surface faces the top of the screen. The frog is rendered with the skin being translucent so that you can see the internal organs.
+
+In the lower left of the image there is a prop assembly with labelled XYZ axes and a cube labelled with anatomical orientations:
+
+- **Sagittal plane**
+  - L - left
+  - R - right
+- **Coronal plane**
+  - A - anterior
+  - P - posterior
+- **Transverse plane**
+  - S - superior  
+  - I - inferior
+
+This prop assembly can be moved and resized.
+
+Individual tissues can be specified by using the "**-t**" option e.g. "**-t skin skeleton**".
+
+We use vtkFlyingEdges3D to take the 3D structured point set and generate the iso-surfaces. However, if desired, you can specify vtkMarchingCubes instead, use the option "**-m**".
+
+The parameters used to generate the example image are loaded from a JSON file containing the data needed to access and generate the actors for each tissue along with other supplementary data such as the data file names. This means that the user need only load this one file in order to generate the data for rendering. This file is called:
+
+``` text
+<DATA>/Frog_mhd.json
+```
+
+Where `<DATA>` is the path to `?vtk-?examples/src/Testing/Data`.
+
+For information about the parameters in the JSON file, please see [Frog_mhd_format](../../Documentation/Frog_mhd_format.md).
+
+The code uses a general way of specifying transformations that can permute image and other geometric data in order to maintain proper orientation regardless of the acquisition order. See the class **SliceOrder**.
+
+The dataset was prepared at the Lawrence Berkeley National Laboratories and is included with their permission. The data was acquired by physically slicing the frog and photographing the slices. The original segmented data is in the form of tissue masks with one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500 pixels.
+
+To accommodate the volume readers in VTK, the mask files were processed and combined into one vtkMetaImageReader file, called 'frogtissue.mhd'. Integer numbers 1-15 are used to represent the 15 tissues. A similar process was done for the frog skin with the result being stored in a file called 'frog.mhd'.
+
+
+!!! info
+    Mutually exclusive options "***-a, -b, -c, -d**" are provided to let you generate approximations to the following figures: [Figure 12-9a](../../../VTKBook/12Chapter12/#Figure%2012-9a), [Figure 12-9b](../../../VTKBook/12Chapter12/#Figure%2012-9b), [Figure 12-9c](../../../VTKBook/12Chapter12/#Figure%2012-9c), and [Figure 12-9d](../../../VTKBook/12Chapter12/#Figure%2012-9d) in [Chapter 12](../../../VTKBook/12Chapter12) of the [VTK Textbook](../../../VTKBook/01Chapter1).
diff --git a/src/Cxx/Visualization/FroggieView.cxx b/src/Cxx/Visualization/FroggieView.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..363adee6092bc65330d1606317eaea240ccd4bcb
--- /dev/null
+++ b/src/Cxx/Visualization/FroggieView.cxx
@@ -0,0 +1,1133 @@
+#include <vtkActor.h>
+#include <vtkAnnotatedCubeActor.h>
+#include <vtkAxesActor.h>
+#include <vtkCallbackCommand.h>
+#include <vtkCamera.h>
+#include <vtkCameraOrientationWidget.h>
+#include <vtkCaptionActor2D.h>
+#include <vtkInteractorStyleTrackballCamera.h>
+#include <vtkLookupTable.h>
+#include <vtkMatrix4x4.h>
+#include <vtkNamedColors.h>
+#include <vtkNew.h>
+#include <vtkOrientationMarkerWidget.h>
+#include <vtkPolyDataMapper.h>
+#include <vtkPolyDataNormals.h>
+#include <vtkPolyDataReader.h>
+#include <vtkProp3D.h>
+#include <vtkPropAssembly.h>
+#include <vtkProperty.h>
+#include <vtkProperty2D.h>
+#include <vtkRenderWindow.h>
+#include <vtkRenderWindowInteractor.h>
+#include <vtkRenderer.h>
+#include <vtkSliderRepresentation2D.h>
+#include <vtkSliderWidget.h>
+#include <vtkSmartPointer.h>
+#include <vtkTextProperty.h>
+#include <vtkTransform.h>
+#include <vtkTransformPolyDataFilter.h>
+
+#include <vtk_cli11.h>
+#include <vtk_jsoncpp.h>
+
+#include <array>
+#include <cstdlib>
+#include <filesystem>
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+#include <string>
+
+namespace fs = std::filesystem;
+
+namespace {
+struct Parameters
+{
+  std::vector<std::string> names;
+  std::map<std::string, std::string> colors;
+  std::map<std::string, int> indices;
+  std::map<std::string, std::string> orientation;
+  std::map<std::string, double> opacity;
+  std::map<std::string, std::string> vtkFiles;
+  std::vector<std::string> fig_129b;
+  std::vector<std::string> fig_129cd;
+
+  bool parsedOk{false};
+};
+
+/**
+ * Take a string and convert it to lowercase.
+ *
+ * See: https://en.cppreference.com/w/cpp/string/byte/tolower
+ * Only works with ASCII characters.
+ *
+ * @param s: The string to be converted to lowercase.
+ *
+ * @return The lowercase version of the string.
+ */
+std::string ToLowerCase(std::string s);
+
+/**
+ * Read the parameters from a json file and check that the file paths exist.
+ *
+ * @param fnPath: The path to the json file.
+ * @param parameters:  The parameters.
+ */
+void ParseJSON(const fs::path fnPath, Parameters& parameters);
+
+/**
+ * Create the lookup table for the frog tissues.
+ *
+ * Each table value corresponds the color of one of the frog tissues.
+ *
+ * @param indices: The tissue name and index.
+ * @param colors: The tissue name and color.
+ * @return: The lookup table.
+ */
+vtkNew<vtkLookupTable>
+CreateTissueLUT(std::map<std::string, int> const& indices,
+                std::map<std::string, std::string>& colors);
+
+class SliceOrder
+{
+  // clang-format off
+  /*
+    These transformations permute image and other geometric data to maintain
+      proper orientation regardless of the acquisition order. After applying
+      these transforms with vtkTransformFilter, a view up of 0, -1, 0 will
+      result in the body part facing the viewer.
+     
+    NOTE: Some transformations have a -1 scale factor for one of the components.
+          To ensure proper polygon orientation and normal direction,
+            you must apply the vtkPolyDataNormals filter.
+
+    Naming (the nomenclature is medical):
+      si - superior to inferior (top to bottom)
+      is - inferior to superior (bottom to top)
+      ap - anterior to posterior (front to back)
+      pa - posterior to anterior (back to front)
+      lr - left to right
+      rl - right to left
+
+    */
+  // clang-format on
+
+public:
+  /**
+   * Generate the transforms corresponding to the slice order.
+   */
+  SliceOrder();
+
+  virtual ~SliceOrder() = default;
+
+public:
+  /**
+   * Returns the vtkTransform corresponding to the slice order.
+   *
+   * @param sliceOrder: The slice order.
+   * @return The vtkTransform corresponding to the slice order.
+   */
+  vtkSmartPointer<vtkTransform> Get(std::string const& sliceOrder);
+
+  /**
+   * Print the homogenous matrix corresponding to the slice order.
+   *
+   * @param order: The slice order.
+   */
+  void PrintTransform(std::string const& order);
+
+  /**
+   * Print all the homogenous matrices corresponding to the slice orders.
+   *
+   */
+  void PrintAlltransforms();
+
+private:
+  std::map<std::string, vtkSmartPointer<vtkTransform>> transform;
+};
+
+/**
+ * @param scale: Sets the scale and direction of the axes.
+ * @param xyzLabels: Labels for the axes.
+ * @return The axes actor.
+ */
+vtkNew<vtkAxesActor> MakeAxesActor(std::array<double, 3>& scale,
+                                   std::array<std::string, 3> const& xyzLabels);
+
+/**
+ * @param cubeLabels: The labels for the cube faces.
+ * @param colors: Used to set the colors of the cube faces.
+ * @return The annotated cube actor.
+ */
+vtkNew<vtkAnnotatedCubeActor>
+MakeAnnotatedCubeActor(std::array<std::string, 6> const& cubeLabels,
+                       vtkNamedColors* colors);
+
+/**
+ * @param labelSelector: The selector used to define labels for the axes and
+ * cube.
+ * @param colors: Used to set the colors of the cube faces.
+ * @return The combined axes and annotated cube prop.
+ */
+vtkNew<vtkPropAssembly> MakeCubeActor(std::string const& labelSelector,
+                                      vtkNamedColors* colors);
+
+class SliderCallbackOpacity : public vtkCommand
+{
+public:
+  static SliderCallbackOpacity* New()
+  {
+    return new SliderCallbackOpacity;
+  }
+  virtual void Execute(vtkObject* caller, unsigned long, void*)
+  {
+    vtkSliderWidget* sliderWidget = reinterpret_cast<vtkSliderWidget*>(caller);
+    double value = static_cast<vtkSliderRepresentation2D*>(
+                       sliderWidget->GetRepresentation())
+                       ->GetValue();
+    this->property->SetOpacity(value);
+  }
+  SliderCallbackOpacity() : property(nullptr)
+  {
+  }
+  vtkProperty* property;
+};
+struct SliderProperties
+{
+  double tubeWidth{0.004};
+  double sliderLength{0.015};
+  double sliderWidth{0.008};
+  double endCapLength{0.008};
+  double endCapWidth{0.02};
+  double titleHeight{0.02};
+  double labelHeight{0.02};
+
+  double valueMinimum{0.0};
+  double valueMaximum{1.0};
+  double valueInitial{1.0};
+
+  std::array<double, 2> p1{0.02, 0.1};
+  std::array<double, 2> p2{0.18, 0.1};
+
+  std::string title;
+
+  std::string titleColor{"Black"};
+  std::string labelColor{"Black"};
+  std::string valueColor{"DarkSlateGray"};
+  std::string sliderColor{"BurlyWood"};
+  std::string selectedColor{"Lime"};
+  std::string barColor{"Black"};
+  std::string barEndsColor{"Indigo"};
+};
+
+/**
+ * @param properties: The slider properties.
+ * @param lut: The color lookup table.
+ * @param idx: The tissue index.
+ * @return The slider widget.
+ */
+vtkNew<vtkSliderWidget> MakeSliderWidget(SliderProperties const& sp,
+                                         vtkLookupTable* lut, int const& idx);
+
+class SliderToggleCallback : public vtkCallbackCommand
+{
+public:
+  SliderToggleCallback() = default;
+
+  static SliderToggleCallback* New()
+  {
+    return new SliderToggleCallback;
+  }
+
+  /*
+   * Create a vtkCallbackCommand and reimplement it.
+   *
+   */
+  void Execute(vtkObject* caller, unsigned long /*evId*/, void*) override
+  {
+    // Note the use of reinterpret_cast to cast the caller to the expected type.
+    auto rwi = reinterpret_cast<vtkRenderWindowInteractor*>(caller);
+
+    // Get the keypress
+    std::string key = rwi->GetKeySym();
+    if (key == "n")
+    {
+      for (auto const& p : *this->sliders)
+      {
+        if (p.second->GetEnabled())
+        {
+          p.second->Off();
+        }
+        else
+        {
+          p.second->On();
+        }
+      }
+    }
+  }
+
+  /**
+   * For handling the sliders.
+   *
+   * @param sliders The sliders.
+   *
+   */
+  void SetParameters(
+      std::map<std::string, vtkSmartPointer<vtkSliderWidget>>* sliders)
+  {
+    this->sliders = sliders;
+  }
+
+private:
+  SliderToggleCallback(const SliderToggleCallback&) = delete;
+  void operator=(const SliderToggleCallback&) = delete;
+
+  std::map<std::string, vtkSmartPointer<vtkSliderWidget>>* sliders{nullptr};
+};
+
+} // namespace
+
+int main(int argc, char* argv[])
+{
+  CLI::App app{"Display all frog parts and translucent skin."};
+
+  // Define options
+  std::string fileName;
+  app.add_option("fileName", fileName,
+                 "The path to the JSON file e.g. Frog_vtk.json.")
+      ->required()
+      ->check(CLI::ExistingFile);
+
+  std::vector<std::string> chosenTissues;
+  app.add_option("-t", chosenTissues, "Select one or more tissues.");
+  auto noSliders = false;
+  app.add_flag("-n", noSliders, "No sliders");
+
+  std::array<bool, 4> view{false, false, false, false};
+  auto* ogroup = app.add_option_group(
+      "view",
+      "Select a view corresponding to Fig 12-9 in the VTK Textbook. Only none "
+      "or one of these can be selected.");
+  ogroup->add_flag("-a", view[0],
+                   "The view corresponds to Fig 12-9a in the VTK Textbook");
+  ogroup->add_flag("-b", view[1],
+                   "The view corresponds to Fig 12-9b in the VTK Textbook");
+  ogroup->add_flag("-c", view[2],
+                   "The view corresponds to Fig 12-9c in the VTK Textbook");
+  ogroup->add_flag("-d", view[3],
+                   "The view corresponds to Fig 12-9d in the VTK Textbook");
+
+  CLI11_PARSE(app, argc, argv);
+
+  auto selectCount = std::count_if(view.begin(), view.end(),
+                                   [=](const bool& e) { return e == true; });
+  if (selectCount > 1)
+  {
+    std::cerr
+        << "Only one or none of the options -a, -b, -c, -d can be selected;"
+        << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  auto fnPath = fs::path(fileName);
+  if (!fnPath.has_extension())
+  {
+    fnPath.replace_extension(".json");
+  }
+  if (!fs::is_regular_file(fnPath))
+  {
+    std::cerr << "Unable to find: " << fnPath << std::endl;
+    return EXIT_FAILURE;
+  }
+
+  Parameters parameters;
+  ParseJSON(fnPath, parameters);
+  if (!parameters.parsedOk)
+  {
+    return EXIT_FAILURE;
+  }
+
+  auto tissues = parameters.names;
+  auto indices = parameters.indices;
+
+  auto lut = CreateTissueLUT(parameters.indices, parameters.colors);
+
+  char selectFigure{'\0'};
+  if (selectCount == 1)
+  {
+    if (view[0])
+    {
+      selectFigure = 'a';
+    }
+    else if (view[1])
+    {
+      // No skin.
+      tissues = parameters.fig_129b;
+      selectFigure = 'b';
+    }
+    else if (view[2])
+    {
+      // No skin, blood and skeleton.
+      tissues = parameters.fig_129cd;
+      selectFigure = 'c';
+    }
+    else
+    {
+      // No skin, blood and skeleton.
+      tissues = parameters.fig_129cd;
+      selectFigure = 'd';
+    }
+  }
+
+  if (!chosenTissues.empty())
+  {
+    for (auto i = 0; i < chosenTissues.size(); ++i)
+    {
+      chosenTissues[i] = ToLowerCase(chosenTissues[i]);
+    }
+    std::vector<std::string> res;
+    auto has_brainbin{false};
+    if (std::find(chosenTissues.begin(), chosenTissues.end(), "brainbin") !=
+        chosenTissues.end())
+    {
+      std::cout << "Using brainbin instead of brain." << std::endl;
+      res.push_back("brainbin");
+      indices.erase("brain");
+      indices["brainbin"] = 2;
+      parameters.colors.erase("brain");
+      parameters.colors["brainbin"] = "beige";
+      has_brainbin = true;
+    }
+    for (auto const& ct : chosenTissues)
+    {
+      if (has_brainbin && (ct == "brain" || ct == "brainbin"))
+      {
+        continue;
+      }
+      if (std::find(tissues.begin(), tissues.end(), ct) != tissues.end())
+      {
+        res.push_back(ct);
+      }
+      else
+      {
+        std::cout << "Tissue: " << ct << " is not available." << std::endl;
+        return EXIT_FAILURE;
+      }
+    }
+    if (res.size() == 1 && res[0] == "skin")
+    {
+      parameters.opacity["skin"] = 1.0;
+    }
+    tissues = res;
+  }
+
+  vtkNew<vtkNamedColors> colors;
+  colors->SetColor("ParaViewBkg",
+                   std::array<unsigned char, 4>{82, 87, 110, 255}.data());
+
+  // Setup render window, renderer, and interactor.
+  vtkNew<vtkRenderer> ren;
+  vtkNew<vtkRenderWindow> renWin;
+  renWin->AddRenderer(ren);
+  vtkNew<vtkRenderWindowInteractor> iRen;
+  iRen->SetRenderWindow(renWin);
+  vtkNew<vtkInteractorStyleTrackballCamera> style;
+  iRen->SetInteractorStyle(style);
+
+  SliceOrder so;
+  // so.PrintAlltransforms();
+
+  size_t colorSize{0};
+  for (auto const& p : parameters.colors)
+  {
+    colorSize = std::max(colorSize, p.second.size());
+  }
+  size_t nameSize{0};
+  for (auto const& p : parameters.names)
+  {
+    nameSize = std::max(nameSize, p.size());
+  }
+
+  std::map<std::string, vtkSmartPointer<vtkSliderWidget>> sliders;
+  auto leftStepSize = 1.0 / 9;
+  auto leftPosY = 0.275;
+  auto leftPosX0 = 0.02;
+  auto leftPosX1 = 0.18;
+  auto rightStepSize = 1.0 / 9;
+  auto rightPosY = 0.05;
+  auto rightPosX0 = 0.8 + 0.02;
+  auto rightPosX1 = 0.8 + 0.18;
+
+  auto sliderCount = 0;
+
+  std::string line(7 + nameSize + colorSize, '-');
+
+  std::cout << line << '\n'
+            << std::setw(nameSize) << std::left << "Tissue"
+            << " Label "
+            << "Color" << '\n'
+            << line << std::endl;
+  auto intSize = 2;
+
+  for (auto const& tissue : tissues)
+  {
+    vtkNew<vtkPolyDataReader> reader;
+    reader->SetFileName(parameters.vtkFiles[tissue].c_str());
+    reader->Update();
+
+    auto trans = so.Get(parameters.orientation[tissue]);
+    trans->Scale(1, -1, -1);
+
+    vtkNew<vtkTransformPolyDataFilter> tf;
+    tf->SetInputConnection(reader->GetOutputPort());
+    tf->SetTransform(trans);
+    tf->SetInputConnection(reader->GetOutputPort());
+
+    vtkNew<vtkPolyDataNormals> normals;
+    normals->SetInputConnection(tf->GetOutputPort());
+    normals->SetFeatureAngle(60.0);
+
+    vtkNew<vtkPolyDataMapper> mapper;
+    mapper->SetInputConnection(normals->GetOutputPort());
+
+    vtkNew<vtkActor> actor;
+    actor->SetMapper(mapper);
+    actor->GetProperty()->SetOpacity(parameters.opacity[tissue]);
+    actor->GetProperty()->SetDiffuseColor(lut->GetTableValue(indices[tissue]));
+    actor->GetProperty()->SetSpecular(0.2);
+    actor->GetProperty()->SetSpecularPower(10);
+
+    ren->AddActor(actor);
+
+    if (!noSliders)
+    {
+      auto sp = SliderProperties();
+
+      sp.valueInitial = parameters.opacity[tissue];
+      sp.title = tissue;
+
+      // Screen coordinates.
+      if (sliderCount < 7)
+      {
+        sp.p1[0] = leftPosX0;
+        sp.p1[1] = leftPosY;
+        sp.p2[0] = leftPosX1;
+        sp.p2[1] = leftPosY;
+        leftPosY += leftStepSize;
+      }
+      else
+      {
+        sp.p1[0] = rightPosX0;
+        sp.p1[1] = rightPosY;
+        sp.p2[0] = rightPosX1;
+        sp.p2[1] = rightPosY;
+        rightPosY += rightStepSize;
+      }
+
+      auto sliderWidget = MakeSliderWidget(sp, lut, parameters.indices[tissue]);
+
+      sliderWidget->SetInteractor(iRen);
+      sliderWidget->SetAnimationModeToAnimate();
+      sliderWidget->EnabledOn();
+
+      vtkNew<SliderCallbackOpacity> cb;
+      cb->property = actor->GetProperty();
+      sliderWidget->AddObserver(vtkCommand::InteractionEvent, cb);
+      sliders[tissue] = sliderWidget;
+      sliderCount += 1;
+    }
+    std::cout << std::setw(nameSize) << std::left << tissue << " "
+              << std::setw(intSize + 3) << std::right << indices[tissue] << " "
+              << std::setw(colorSize) << std::left << parameters.colors[tissue]
+              << std::endl;
+  }
+  std::cout << line << std::endl;
+
+  if (noSliders)
+  {
+    renWin->SetSize(1024, 1024);
+  }
+  else
+  {
+    renWin->SetSize(1024 + 400, 1024);
+  }
+  renWin->SetWindowName("FroggieView");
+
+  ren->SetBackground(colors->GetColor3d("ParaViewBkg").GetData());
+
+  auto camera = ren->GetActiveCamera();
+  if (selectFigure == '\0')
+  {
+    // Orient so that we look down on the dorsal surface and
+    //  the superior surface faces the top of the screen.
+    vtkNew<vtkTransform> transform;
+    transform->SetMatrix(camera->GetModelTransformMatrix());
+    transform->RotateY(-90);
+    transform->RotateZ(90);
+    camera->SetModelTransformMatrix(transform->GetMatrix());
+    ren->ResetCamera();
+  }
+  else
+  {
+    if (selectFigure == 'a')
+    {
+      // Fig 12-9a in the VTK Textbook
+      camera->SetPosition(495.722368, -447.474954, -646.308030);
+      camera->SetFocalPoint(137.612066, -40.962376, -195.171023);
+      camera->SetViewUp(-0.323882, -0.816232, 0.478398);
+      camera->SetDistance(704.996499);
+      camera->SetClippingRange(319.797039, 1809.449285);
+    }
+    else if (selectFigure == 'b')
+    {
+      // Fig 12-9b in the VTK Textbook
+      camera->SetPosition(478.683494, -420.477744, -643.112038);
+      camera->SetFocalPoint(135.624874, -36.478435, -210.614440);
+      camera->SetViewUp(-0.320495, -0.820148, 0.473962);
+      camera->SetDistance(672.457328);
+      camera->SetClippingRange(307.326771, 1765.990822);
+    }
+    else if (selectFigure == 'c')
+    {
+      // Fig 12-9c in the VTK Textbook
+      camera->SetPosition(201.363313, -147.260834, -229.885066);
+      camera->SetFocalPoint(140.626206, -75.857216, -162.352531);
+      camera->SetViewUp(-0.425438, -0.786048, 0.448477);
+      camera->SetDistance(115.534047);
+      camera->SetClippingRange(7.109870, 854.091718);
+    }
+    else if (selectFigure == 'd')
+    {
+      // Fig 12-9d in the VTK Textbook
+      camera->SetPosition(115.361727, -484.656410, -6.193827);
+      camera->SetFocalPoint(49.126343, 98.501094, 1.323317);
+      camera->SetViewUp(-0.649127, -0.083475, 0.756086);
+      camera->SetDistance(586.955116);
+      camera->SetClippingRange(360.549218, 866.876230);
+    }
+  }
+
+  std::string labels;
+  if (selectFigure != '\0')
+  {
+    // Superior Anterior Left
+    labels = "sal";
+  }
+  else
+  {
+    // Right Superior Posterior
+    labels = "rsp";
+  }
+
+  vtkNew<vtkCameraOrientationWidget> cow;
+  cow->SetParentRenderer(ren);
+  if (noSliders)
+  {
+    // Turn off if you do not want it.
+    cow->On();
+    cow->EnabledOn();
+  }
+  else
+  {
+    cow->Off();
+    cow->EnabledOff();
+  }
+
+  auto axes = MakeCubeActor(labels, colors);
+  vtkNew<vtkOrientationMarkerWidget> om;
+  om->SetOrientationMarker(axes);
+  // Position upper left in the viewport.
+  // om->SetViewport(0.0, 0.8, 0.2, 1.0);
+  // Position lower left in the viewport.
+  om->SetViewport(0, 0, 0.2, 0.2);
+  om->SetInteractor(iRen);
+  om->EnabledOn();
+  om->InteractiveOn();
+
+  renWin->Render();
+
+  vtkNew<SliderToggleCallback> sliderToggle;
+  sliderToggle->SetParameters(&sliders);
+  iRen->AddObserver(vtkCommand::KeyPressEvent, sliderToggle);
+
+  iRen->Start();
+
+  return EXIT_SUCCESS;
+}
+
+namespace {
+
+std::string ToLowerCase(std::string s)
+{
+  std::transform(s.begin(), s.end(), s.begin(),
+                 [](unsigned char c) { return std::tolower(c); } // correct
+  );
+  return s;
+}
+
+void ParseJSON(const fs::path fnPath, Parameters& parameters)
+{
+  std::ifstream ifs(fnPath);
+  Json::Value root;
+
+  if (ifs)
+  {
+    std::string str;
+    std::string errors;
+    Json::CharReaderBuilder builder{};
+    auto reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
+
+    std::ostringstream ss;
+    ss << ifs.rdbuf(); // Read in the file comtents
+    str = ss.str();
+    auto parsingSuccessful =
+        reader->parse(str.c_str(), str.c_str() + str.size(), &root, &errors);
+    ifs.close();
+    if (!parsingSuccessful)
+    {
+      std::cout << errors << std::endl;
+      parameters.parsedOk = false;
+      return;
+    }
+    parameters.parsedOk = true;
+  }
+  else
+  {
+    std::cerr << "Unable to open: " << fnPath << std::endl;
+    parameters.parsedOk = false;
+  }
+
+  // Get the parameters that we need.
+  fs::path vtkPath;
+  std::vector<std::string> fileNames;
+  for (Json::Value::const_iterator outer = root.begin(); outer != root.end();
+       ++outer)
+  {
+    if (outer.name() == "files")
+    {
+      std::string path;
+      for (Json::Value::const_iterator pth = root["files"].begin();
+           pth != root["files"].end(); ++pth)
+      {
+        if (pth.name() == "root")
+        {
+          vtkPath = fs::path(pth->asString());
+        }
+        if (pth.name() == "vtk_files")
+        {
+          for (Json::Value::const_iterator fls =
+                   root["files"]["vtk_files"].begin();
+               fls != root["files"]["vtk_files"].end(); ++fls)
+          {
+            fileNames.push_back(fls->asString());
+          }
+        }
+      }
+    }
+    if (outer.name() == "tissues")
+    {
+      for (Json::Value::const_iterator tc = root["tissues"]["names"].begin();
+           tc != root["tissues"]["names"].end(); ++tc)
+      {
+        parameters.names.push_back(tc->asString());
+      }
+      for (Json::Value::const_iterator tc = root["tissues"]["indices"].begin();
+           tc != root["tissues"]["indices"].end(); ++tc)
+      {
+        parameters.indices[tc.name()] = tc->asInt();
+      }
+      for (Json::Value::const_iterator tc = root["tissues"]["colors"].begin();
+           tc != root["tissues"]["colors"].end(); ++tc)
+      {
+        parameters.colors[tc.name()] = tc->asString();
+      }
+      for (Json::Value::const_iterator tc = root["tissues"]["indices"].begin();
+           tc != root["tissues"]["indices"].end(); ++tc)
+      {
+        parameters.indices[tc.name()] = tc->asInt();
+      }
+      for (Json::Value::const_iterator tc =
+               root["tissues"]["orientation"].begin();
+           tc != root["tissues"]["orientation"].end(); ++tc)
+      {
+        parameters.orientation[tc.name()] = tc->asString();
+      }
+      for (Json::Value::const_iterator tc = root["tissues"]["opacity"].begin();
+           tc != root["tissues"]["opacity"].end(); ++tc)
+      {
+        parameters.opacity[tc.name()] = tc->asDouble();
+      }
+    }
+    if (outer.name() == "figures")
+    {
+      for (Json::Value::const_iterator c = root["figures"]["fig12-9b"].begin();
+           c != root["figures"]["fig12-9b"].end(); ++c)
+      {
+        parameters.fig_129b.push_back(c->asString());
+      }
+      for (Json::Value::const_iterator c = root["figures"]["fig12-9cd"].begin();
+           c != root["figures"]["fig12-9cd"].end(); ++c)
+      {
+        parameters.fig_129cd.push_back(c->asString());
+      }
+    }
+  }
+
+  //  Build and check the paths.
+  if (!fileNames.empty())
+  {
+    if (fileNames.size() != 17)
+    {
+      std::cerr << "Expected seventeen file names.";
+      parameters.parsedOk = false;
+    }
+    else
+    {
+      for (size_t i = 0; i < fileNames.size(); i++)
+      {
+        auto pth = fnPath.parent_path() / vtkPath / fs::path(fileNames[i]);
+        fileNames[i] = pth.make_preferred().string();
+        if (!(fs::is_regular_file(pth) && fs::exists(pth)))
+        {
+          std::cerr << "Not a file or path does not exist: " << fileNames[i]
+                    << std::endl;
+          parameters.parsedOk = false;
+        }
+        else
+        {
+          parameters.vtkFiles[pth.stem().string()] =
+              pth.make_preferred().string();
+        }
+      }
+    }
+  }
+  else
+  {
+    std::cerr << "Expected .vtk file names in the JSON file.";
+    parameters.parsedOk = false;
+  }
+}
+
+vtkNew<vtkLookupTable>
+CreateTissueLUT(std::map<std::string, int> const& indices,
+                std::map<std::string, std::string>& colors)
+{
+  vtkNew<vtkLookupTable> lut;
+  lut->SetNumberOfColors(colors.size());
+  lut->SetTableRange(0, colors.size() - 1);
+  lut->Build();
+
+  vtkNew<vtkNamedColors> nc;
+
+  for (auto const& p : indices)
+  {
+    lut->SetTableValue(p.second, nc->GetColor4d(colors[p.first]).GetData());
+  }
+
+  return lut;
+}
+
+SliceOrder::SliceOrder()
+{
+  vtkNew<vtkMatrix4x4> si_mat;
+  si_mat->Zero();
+  si_mat->SetElement(0, 0, 1);
+  si_mat->SetElement(1, 2, 1);
+  si_mat->SetElement(2, 1, -1);
+  si_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkMatrix4x4> is_mat;
+  is_mat->Zero();
+  is_mat->SetElement(0, 0, 1);
+  is_mat->SetElement(1, 2, -1);
+  is_mat->SetElement(2, 1, -1);
+  is_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkMatrix4x4> lr_mat;
+  lr_mat->Zero();
+  lr_mat->SetElement(0, 2, -1);
+  lr_mat->SetElement(1, 1, -1);
+  lr_mat->SetElement(2, 0, 1);
+  lr_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkMatrix4x4> rl_mat;
+  rl_mat->Zero();
+  rl_mat->SetElement(0, 2, 1);
+  rl_mat->SetElement(1, 1, -1);
+  rl_mat->SetElement(2, 0, 1);
+  rl_mat->SetElement(3, 3, 1);
+
+  // The previous transforms assume radiological views of the slices
+  //  (viewed from the feet).
+  // Other modalities such as physical sectioning may view from the head.
+  // The following transforms modify the original with a 180° rotation about y
+
+  vtkNew<vtkMatrix4x4> hf_mat;
+  hf_mat->Zero();
+  hf_mat->SetElement(0, 0, -1);
+  hf_mat->SetElement(1, 1, 1);
+  hf_mat->SetElement(2, 2, -1);
+  hf_mat->SetElement(3, 3, 1);
+
+  vtkNew<vtkTransform> si_trans;
+  si_trans->SetMatrix(si_mat);
+  this->transform["si"] = si_trans;
+
+  vtkNew<vtkTransform> is_trans;
+  is_trans->SetMatrix(is_mat);
+  this->transform["is"] = is_trans;
+
+  vtkNew<vtkTransform> ap_trans;
+  ap_trans->Scale(1, -1, 1);
+  this->transform["ap"] = ap_trans;
+
+  vtkNew<vtkTransform> pa_trans;
+  pa_trans->Scale(1, -1, -1);
+  this->transform["pa"] = pa_trans;
+
+  vtkNew<vtkTransform> lr_trans;
+  lr_trans->SetMatrix(lr_mat);
+  this->transform["lr"] = lr_trans;
+
+  vtkNew<vtkTransform> rl_trans;
+  lr_trans->SetMatrix(rl_mat);
+  this->transform["rl"] = rl_trans;
+
+  vtkNew<vtkTransform> hf_trans;
+  hf_trans->SetMatrix(hf_mat);
+  this->transform["hf"] = hf_trans;
+
+  vtkNew<vtkTransform> hf_si_trans;
+  hf_si_trans->SetMatrix(hf_mat);
+  hf_si_trans->Concatenate(si_mat);
+  this->transform["hfsi"] = hf_si_trans;
+
+  vtkNew<vtkTransform> hf_is_trans;
+  hf_is_trans->SetMatrix(hf_mat);
+  hf_is_trans->Concatenate(is_mat);
+  this->transform["hfis"] = hf_is_trans;
+
+  vtkNew<vtkTransform> hf_ap_trans;
+  hf_ap_trans->SetMatrix(hf_mat);
+  hf_ap_trans->Scale(1, -1, 1);
+  this->transform["hfap"] = hf_ap_trans;
+
+  vtkNew<vtkTransform> hf_pa_trans;
+  hf_pa_trans->SetMatrix(hf_mat);
+  hf_pa_trans->Scale(1, -1, -1);
+  this->transform["hfpa"] = hf_pa_trans;
+
+  vtkNew<vtkTransform> hf_lr_trans;
+  hf_lr_trans->SetMatrix(hf_mat);
+  hf_lr_trans->Concatenate(lr_mat);
+  this->transform["hflr"] = hf_lr_trans;
+
+  vtkNew<vtkTransform> hf_rl_trans;
+  hf_rl_trans->SetMatrix(hf_mat);
+  hf_rl_trans->Concatenate(rl_mat);
+  this->transform["hfrl"] = hf_rl_trans;
+
+  // Identity
+  this->transform["I"] = vtkNew<vtkTransform>();
+
+  // Zero
+  vtkNew<vtkTransform> z_trans;
+  z_trans->Scale(0, 0, 0);
+  this->transform["Z"] = z_trans;
+}
+
+void SliceOrder::PrintTransform(std::string const& order)
+{
+  auto m = this->transform[order]->GetMatrix();
+  std::ostringstream os;
+  os.setf(std::ios_base::fmtflags(), std::ios_base::floatfield);
+  os << order << '\n';
+  for (int i = 0; i < 4; ++i)
+  {
+    for (int j = 0; j < 4; ++j)
+    {
+      if (j < 3)
+      {
+        os << std::setw(6) << std::right << std::setprecision(2)
+           << m->GetElement(i, j) << " ";
+      }
+      else
+      {
+        os << std::setw(6) << std::right << m->GetElement(i, j) << '\n';
+      }
+    }
+  }
+  std::cout << os.str() << '\n';
+  os.str("");
+}
+
+void SliceOrder::PrintAlltransforms()
+{
+  for (auto const &p : this->transform)
+  {
+    PrintTransform(p.first);
+  }
+}
+
+vtkSmartPointer<vtkTransform> SliceOrder::Get(std::string const& sliceOrder)
+{
+  return this->transform[sliceOrder];
+}
+
+vtkNew<vtkAxesActor> MakeAxesActor(std::array<double, 3>& scale,
+                                   std::array<std::string, 3> const& xyzLabels)
+{
+  vtkNew<vtkAxesActor> axes;
+  axes->SetScale(scale.data());
+  axes->SetShaftTypeToCylinder();
+  axes->SetXAxisLabelText(xyzLabels[0].c_str());
+  axes->SetYAxisLabelText(xyzLabels[1].c_str());
+  axes->SetZAxisLabelText(xyzLabels[2].c_str());
+  axes->SetCylinderRadius(0.5 * axes->GetCylinderRadius());
+  axes->SetConeRadius(1.025 * axes->GetConeRadius());
+  axes->SetSphereRadius(1.5 * axes->GetSphereRadius());
+  auto tprop = axes->GetXAxisCaptionActor2D()->GetCaptionTextProperty();
+  tprop->ItalicOn();
+  tprop->ShadowOn();
+  tprop->SetFontFamilyToTimes();
+  // Use the same text properties on the other two axes.
+  axes->GetYAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy(tprop);
+  axes->GetZAxisCaptionActor2D()->GetCaptionTextProperty()->ShallowCopy(tprop);
+  return axes;
+}
+
+vtkNew<vtkAnnotatedCubeActor>
+MakeAnnotatedCubeActor(std::array<std::string, 6> const& cubeLabels,
+                       vtkNamedColors* colors)
+{
+  // A cube with labeled faces.
+  vtkNew<vtkAnnotatedCubeActor> cube;
+  cube->SetXPlusFaceText(cubeLabels[0].c_str());
+  cube->SetXMinusFaceText(cubeLabels[1].c_str());
+  cube->SetYPlusFaceText(cubeLabels[2].c_str());
+  cube->SetYMinusFaceText(cubeLabels[3].c_str());
+  cube->SetZPlusFaceText(cubeLabels[4].c_str());
+  cube->SetZMinusFaceText(cubeLabels[5].c_str());
+  cube->SetFaceTextScale(0.5);
+  cube->GetCubeProperty()->SetColor(colors->GetColor3d("Gainsboro").GetData());
+
+  cube->GetTextEdgesProperty()->SetColor(
+      colors->GetColor3d("LightSlateGray").GetData());
+
+  // Change the vector text colors.
+  cube->GetXPlusFaceProperty()->SetColor(
+      colors->GetColor3d("Tomato").GetData());
+  cube->GetXMinusFaceProperty()->SetColor(
+      colors->GetColor3d("Tomato").GetData());
+  cube->GetYPlusFaceProperty()->SetColor(
+      colors->GetColor3d("DeepSkyBlue").GetData());
+  cube->GetYMinusFaceProperty()->SetColor(
+      colors->GetColor3d("DeepSkyBlue").GetData());
+  cube->GetZPlusFaceProperty()->SetColor(
+      colors->GetColor3d("SeaGreen").GetData());
+  cube->GetZMinusFaceProperty()->SetColor(
+      colors->GetColor3d("SeaGreen").GetData());
+  return cube;
+}
+
+vtkNew<vtkPropAssembly> MakeCubeActor(std::string const& labelSelector,
+                                      vtkNamedColors* colors)
+{
+  std::array<std::string, 3> xyzLabels;
+  std::array<std::string, 6> cubeLabels;
+  std::array<double, 3> scale;
+  if (labelSelector == "sal")
+  {
+    // xyzLabels = std::array<std::string,3>{"S", "A", "L"};
+    xyzLabels = std::array<std::string, 3>{"+X", "+Y", "+Z"};
+    cubeLabels = std::array<std::string, 6>{"S", "I", "A", "P", "L", "R"};
+    scale = std::array<double, 3>{1.5, 1.5, 1.5};
+  }
+  else if (labelSelector == "rsp")
+  {
+    // xyzLabels = std::array<std::string, 3>{"R", "S", "P"};
+    xyzLabels = std::array<std::string, 3>{"+X", "+Y", "+Z"};
+    cubeLabels = std::array<std::string, 6>{"R", "L", "S", "I", "P", "A"};
+    scale = std::array<double, 3>{1.5, 1.5, 1.5};
+  }
+  else
+  {
+    xyzLabels = std::array<std::string, 3>{"+X", "+Y", "+Z"};
+    cubeLabels = std::array<std::string, 6>{"+X", "-X", "+Y", "-Y", "+Z", "-Z"};
+    scale = std::array<double, 3>{1.5, 1.5, 1.5};
+  }
+
+  // We are combining a vtkAxesActor and a vtkAnnotatedCubeActor
+  // into a vtkPropAssembly
+  auto cube = MakeAnnotatedCubeActor(cubeLabels, colors);
+  auto axes = MakeAxesActor(scale, xyzLabels);
+
+  // Combine orientation markers into one with an assembly.
+  vtkNew<vtkPropAssembly> assembly;
+  assembly->AddPart(axes);
+  assembly->AddPart(cube);
+  return assembly;
+}
+
+vtkNew<vtkSliderWidget> MakeSliderWidget(SliderProperties const& sp,
+                                         vtkLookupTable* lut, int const& idx)
+{
+  vtkNew<vtkSliderRepresentation2D> slider;
+
+  slider->SetMinimumValue(sp.valueMinimum);
+  slider->SetMaximumValue(sp.valueMaximum);
+  slider->SetValue(sp.valueInitial);
+  slider->SetTitleText(sp.title.c_str());
+
+  slider->GetPoint1Coordinate()->SetCoordinateSystemToNormalizedDisplay();
+  slider->GetPoint1Coordinate()->SetValue(sp.p1[0], sp.p1[1]);
+  slider->GetPoint2Coordinate()->SetCoordinateSystemToNormalizedDisplay();
+  slider->GetPoint2Coordinate()->SetValue(sp.p2[0], sp.p2[1]);
+
+  slider->SetTubeWidth(sp.tubeWidth);
+  slider->SetSliderLength(sp.sliderLength);
+  slider->SetSliderWidth(sp.sliderWidth);
+  slider->SetEndCapLength(sp.endCapLength);
+  slider->SetEndCapWidth(sp.endCapWidth);
+  slider->SetTitleHeight(sp.titleHeight);
+  slider->SetLabelHeight(sp.labelHeight);
+
+  vtkNew<vtkNamedColors> colors;
+  // Set the colors of the slider components.
+  // Change the color of the bar.
+  slider->GetTubeProperty()->SetColor(
+      colors->GetColor3d(sp.barColor).GetData());
+  // Change the color of the ends of the bar.
+  slider->GetCapProperty()->SetColor(
+      colors->GetColor3d(sp.barEndsColor).GetData());
+  // Change the color of the knob that slides.
+  slider->GetSliderProperty()->SetColor(
+      colors->GetColor3d(sp.sliderColor).GetData());
+  // Change the color of the knob when the mouse is held on it.
+  slider->GetSelectedProperty()->SetColor(
+      colors->GetColor3d(sp.selectedColor).GetData());
+  // Change the color of the text displaying the value.
+  slider->GetLabelProperty()->SetColor(
+      colors->GetColor3d(sp.valueColor).GetData());
+  //  Use the one color for the labels.
+  // slider->GetTitleProperty()->SetColor(colors->GetColor3d(sp.labelColor));
+  // Change the color of the text indicating what the slider controls.
+  if (idx >= 0 && idx < 16)
+  {
+    slider->GetTitleProperty()->SetColor(lut->GetTableValue(idx));
+    slider->GetTitleProperty()->ShadowOff();
+  }
+  else
+  {
+    slider->GetTitleProperty()->SetColor(
+        colors->GetColor3d(sp.titleColor).GetData());
+  }
+
+  vtkNew<vtkSliderWidget> sliderWidget;
+  sliderWidget->SetRepresentation(slider);
+
+  return sliderWidget;
+}
+
+} // namespace
diff --git a/src/Cxx/Visualization/FroggieView.md b/src/Cxx/Visualization/FroggieView.md
new file mode 100644
index 0000000000000000000000000000000000000000..b7509f18fa321ea8b07246f0c21c3c0f491c1195
--- /dev/null
+++ b/src/Cxx/Visualization/FroggieView.md
@@ -0,0 +1,44 @@
+### Description
+
+Frog organs along with a translucent skin are reconstructed from the original segmented data.
+
+By default the frog is oriented so that we look down on the dorsal (posterior) surface and the superior surface faces the top of the screen. The frog is rendered with the skin being translucent so that you can see the internal organs.
+
+In the lower left of the image there is a prop assembly with labelled XYZ axes and a cube labelled with anatomical orientations:
+
+- **Sagittal plane**
+  - L - left
+  - R - right
+- **Coronal plane**
+  - A - anterior
+  - P - posterior
+- **Transverse plane**
+  - S - superior  
+  - I - inferior
+
+This prop assembly can be moved and resized.
+
+The opacity of eaxh tissue is controlled by a slider, additionally you can turn all the sliders on or off by pressing the "**n**" key.
+
+If the option "**-n**" is selected, no sliders will displayed.
+
+Individual tissues can be specified by using the "**-t**" option e.g. "**-t skin skeleton**".
+
+The parameters used to generate the example image are loaded from a JSON file containing the data needed to access and generate the actors for each tissue along with other supplementary data such as the data file names. This means that the user need only load this one file in order to generate the data for rendering. This file is called:
+
+``` text
+<DATA>/Frog_vtk.json
+```
+
+Where `<DATA>` is the path to `?vtk-?examples/src/Testing/Data`.
+
+For information about the parameters in the JSON file, please see [Frog_vtk_format](../../Documentation/Frog_vtk_format.md).
+
+The code uses a general way of specifying transformations that can permute image and other geometric data in order to maintain proper orientation regardless of the acquisition order. See the class **SliceOrder**.
+
+The dataset was prepared at the Lawrence Berkeley National Laboratories. It is included with their permission. The data was acquired by physically slicing the frog and photographing the slices. The original segmented data is in the form of tissue masks with one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500 pixels.
+
+This example uses the `*.vtk` tissue files. These were pre-processed using the original data so that loading is much faster.
+
+!!! info
+    Mutually exclusive options "***-a -b -c -d**" are provided to let you generate approximations to the following figures: [Figure 12-9a](../../../VTKBook/12Chapter12/#Figure%2012-9a), [Figure 12-9b](../../../VTKBook/12Chapter12/#Figure%2012-9b), [Figure 12-9c](../../../VTKBook/12Chapter12/#Figure%2012-9c), and [Figure 12-9d](../../../VTKBook/12Chapter12/#Figure%2012-9d) in [Chapter 12](../../../VTKBook/12Chapter12) of the [VTK Textbook](../../../VTKBook/01Chapter1).
diff --git a/src/Documentation/Frog_mhd_format.md b/src/Documentation/Frog_mhd_format.md
new file mode 100644
index 0000000000000000000000000000000000000000..760f4f3658e9f1ce54b471c43ace7dbcffc3f5ae
--- /dev/null
+++ b/src/Documentation/Frog_mhd_format.md
@@ -0,0 +1,17 @@
+# Frog MHD Format
+
+The following keys are recognised:
+
+## Keys
+
+- **title**: A title.
+- **files**: A vector/list of paths to the *.mhd files needed.
+- **tissues**
+  - **colors**: A map/dict of tissue names and colors.
+- **figures**
+  - **fig12-9b**: The vector/list of tissues needed for figure 12-9b.
+  - **fig12-9cd**: The vector/list of tissues needed for figure 12-9c and 12-9d.
+- **tissue_parameters**: The required parameters for each tissue are specified here.
+  - **parameter types**: A map/dict of tissue parameters of each tissue parameter and its type. Essential for C++ code.
+  - **default**>: The default tissue parameters, a map/dict of tissue parameters and values.
+  - <**tissue name**>: The map/dict of tissue parameters and values for each tissue.
diff --git a/src/Documentation/Frog_vtk_format.md b/src/Documentation/Frog_vtk_format.md
new file mode 100644
index 0000000000000000000000000000000000000000..5cd7be157838d37ee1df68b9d69d448430fbc97c
--- /dev/null
+++ b/src/Documentation/Frog_vtk_format.md
@@ -0,0 +1,17 @@
+# Frog VTK Format
+
+The following keys are recognised:
+
+## Keys
+
+- **title**: A title.
+- **files**: A vector/list of paths to the *.vtk files needed.
+- **tissues**
+  - **names**: A vector/list of the tissue names.
+  - **indices**: A map/dict of tissue names and index.
+  - **colors**: A map/dict of tissue names and colors.
+  - **orientation**: A map/dict of tissue names and orientation.
+  - **opacity**: A map/dict of tissue names and opacity.
+- **figures**
+  - **fig12-9b**: The vector/list of tissues needed for figure 12-9b.
+  - **fig12-9cd**: The vector/list of tissues needed for figure 12-9c and 12-9d.
diff --git a/src/Python.md b/src/Python.md
index f45e3159cac7823215ceb0e13a80df3c07fe2b4f..35d996a567aef785c09ff3e61d7785f12f13e534 100644
--- a/src/Python.md
+++ b/src/Python.md
@@ -548,10 +548,9 @@ See [this tutorial](http://www.vtk.org/Wiki/VTK/Tutorials/3DDataTypes) for a bri
 [ElevationBandsWithGlyphs](/Python/Visualization/ElevationBandsWithGlyphs) | Demonstrates the coloring of a surface by partitioning the elevation into bands and using arrows to display the normals on the surface.
 [ExponentialCosine](/Python/VisualizationAlgorithms/ExponentialCosine) | Carpet plots. Visualization of an exponential cosine function. Function values are indicated by surface displacement. Colors indicate derivative values.
 [FlyingHeadSlice](/Python/VisualizationAlgorithms/FlyingHeadSlice) | Flying edges used to generate contour lines.
-[Frog](/Python/Visualization/Frog) | View frog organs through a translucent skin. Used to generate the illustrations in the VTK TextBook.
-[FrogBrain](/Python/Visualization/FrogBrain) | The frog’s brain. Model extracted without smoothing (left) and with smoothing (right).
-[FrogDemo](/Python/Visualization/FrogDemo) | View all or some frog tissues and adjust the translucency of the tissues.
-[FrogReconstruction](/Python/Visualization/FrogReconstruction) | Frog organs along with a translucent skin are reconstructed from the original segmented data.
+[FrogBrain](/Python/Visualization/FrogBrain) | The frog's brain. Model extracted without smoothing (left) and with smoothing (right).
+[FroggieSurface](/Python/Visualization/FroggieSurface) | All or some frog tissues are reconstructed from the original segmented data.
+[FroggieView](/Python/Visualization/FroggieView) | View all or some frog tissues and adjust the translucency of the tissues.
 [FrogSlice](/Python/Visualization/FrogSlice) | Photographic slice of frog (upper left), segmented frog (upper right) and composite of photo and segmentation (bottom). The purple color represents the stomach and the kidneys are yellow.
 [GlyphTable](/Python/Visualization/GlyphTable) | Vary the shapes of glyphed points using a glyph table
 [Hanoi](/Python/Visualization/Hanoi) | Towers of Hanoi.
diff --git a/src/Python/Visualization/Frog.md b/src/Python/Visualization/Frog.md
deleted file mode 100644
index b0bb3d30aace2df89e7a3bfe2798480f1e7ff98e..0000000000000000000000000000000000000000
--- a/src/Python/Visualization/Frog.md
+++ /dev/null
@@ -1,15 +0,0 @@
-### Description
-
-Frog organs along with a translucent skin can be viewed.
-
-The dataset is derived from a frog. This data was prepared at Lawrence Berkeley National Laboratories and is included with their permission. The data was acquired by physically slicing the frog and photographing the slices. The original segmented data is in the form of tissue masks with one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500 pixels.
-
-This example uses the vtkPolyData file for the skin and files that are generated from the tissue masks. You add tissues by specifying a list of tissue names. Note that the skin is rendered as being translucent so that you can see the internal organs.
-
-The code uses a general way of specifying transformations that can permute image and other geometric data in order to maintain proper orientation regardless of the acquisition order. See the class **SliceOrder**.
-
-!!! info
-    [FrogReconstruction](../FrogReconstruction) for an example detailing a general method for reconstructing from the original data.
-
-!!! info
-    By specifying the tissues and other parameters, as outlined in the code, you can generate the following figures: [Figure 12-9a](../../../VTKBook/12Chapter12/#Figure%2012-9a), [Figure 12-9b](../../../VTKBook/12Chapter12/#Figure%2012-9b), [Figure 12-9c](../../../VTKBook/12Chapter12/#Figure%2012-9c), and [Figure 12-9d](../../../VTKBook/12Chapter12/#Figure%2012-9d) in [Chapter 12](../../../VTKBook/12Chapter12) of the [VTK Textbook](../../../VTKBook/01Chapter1).
diff --git a/src/Python/Visualization/Frog.py b/src/Python/Visualization/Frog.py
deleted file mode 100755
index 3dba22cd015c99019583c99747482c44d25ca5c7..0000000000000000000000000000000000000000
--- a/src/Python/Visualization/Frog.py
+++ /dev/null
@@ -1,404 +0,0 @@
-#!/usr/bin/env python
-
-from pathlib import Path
-
-# noinspection PyUnresolvedReferences
-import vtkmodules.vtkInteractionStyle
-# noinspection PyUnresolvedReferences
-import vtkmodules.vtkRenderingOpenGL2
-from vtkmodules.vtkCommonColor import vtkNamedColors
-from vtkmodules.vtkCommonCore import vtkLookupTable
-from vtkmodules.vtkCommonMath import vtkMatrix4x4
-from vtkmodules.vtkCommonTransforms import vtkTransform
-from vtkmodules.vtkFiltersCore import vtkPolyDataNormals
-from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter
-from vtkmodules.vtkIOLegacy import vtkPolyDataReader
-from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
-from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
-from vtkmodules.vtkRenderingCore import (
-    vtkActor,
-    vtkPolyDataMapper,
-    vtkRenderWindow,
-    vtkRenderWindowInteractor,
-    vtkRenderer
-)
-
-
-def get_program_parameters(argv):
-    import argparse
-    description = 'Display the frog organs along with a translucent skin.'
-    epilogue = '''
-To specify all the tissues at once:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach skin
-
-You can leave out brainbin, it is the brain with no gaussian smoothing.
-
-Here are the parameters used to get the views in the VTK Textbook:
-Fig12-9a:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach skin -a
-Fig12-9b:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach -a
-Fig12-9c:
- brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve spleen stomach -c
-Fig12-9c:
- brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve spleen stomach -d
-    '''
-    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
-                                     formatter_class=argparse.RawDescriptionHelpFormatter)
-
-    group = parser.add_mutually_exclusive_group()
-    group.add_argument('-a', action='store_const', dest='view', const='a',
-                       help='The view corresponds to Figs 12-9a and 12-9b in the VTK Textbook')
-    group.add_argument('-c', action='store_const', dest='view', const='c',
-                       help='The view corresponds to Figs 12-9c in the VTK Textbook')
-    group.add_argument('-d', action='store_const', dest='view', const='d',
-                       help='The view corresponds to Figs 12-9d in the VTK Textbook')
-    parser.set_defaults(type=None)
-
-    parser.add_argument('data_folder', help='The path to the files: frog.mhd and frogtissue.mhd.')
-    parser.add_argument('tissues', nargs='+', help='List of one or more tissues.')
-    args = parser.parse_args()
-    return args.data_folder, args.tissues, args.view
-
-
-def main(data_folder, tissues, view):
-    colors = vtkNamedColors()
-
-    # Setup render window, renderer, and interactor.
-    renderer = vtkRenderer()
-    render_window = vtkRenderWindow()
-    render_window.AddRenderer(renderer)
-    render_window_interactor = vtkRenderWindowInteractor()
-    render_window_interactor.SetRenderWindow(render_window)
-
-    tm = create_tissue_map()
-    path = Path(data_folder)
-    color_lut = create_frog_lut(colors)
-    res = ['Using the following tissues:']
-    for tissue in tissues:
-        source = None
-        if path.is_dir():
-            source = path.joinpath(tissue).with_suffix('.vtk')
-            if not source.is_file():
-                s = 'The file: {:s} does not exist.'.format(str(source))
-                print(s)
-                continue
-        actor = create_frog_actor(str(source), tissue, tm[tissue][1])
-        actor.GetProperty().SetOpacity(tm[tissue][2])
-        actor.GetProperty().SetDiffuseColor(color_lut.GetTableValue(tm[tissue][0])[:3])
-        actor.GetProperty().SetSpecular(0.2)
-        actor.GetProperty().SetSpecularPower(10)
-        renderer.AddActor(actor)
-        res.append('{:>11s}, label: {:2d}'.format(tissue, tm[tissue][0]))
-
-    if len(res) > 1:
-        print('\n'.join(res))
-
-    render_window.SetSize(640, 640)
-    render_window.SetWindowName('Frog')
-
-    renderer.SetBackground(colors.GetColor3d('LightSteelBlue'))
-
-    # Initial view (looking down on the dorsal surface).
-    renderer.GetActiveCamera().Roll(-90)
-    renderer.ResetCamera()
-
-    #  Final view
-    if view:
-        if view == 'a':
-            # Figs 12-9a and 12-9b in the VTK Textbook
-            camera = renderer.GetActiveCamera()
-            camera.SetPosition(-599.880035, 548.906952, 313.670289)
-            camera.SetFocalPoint(-8.376500, 40.691664, -156.007163)
-            camera.SetViewUp(0.294699, -0.440638, 0.847933)
-            camera.SetDistance(910.360434)
-            camera.SetClippingRange(231.699387, 1758.550290)
-        elif view == 'c':
-            # Figs 12-9c in the VTK Textbook
-            camera = renderer.GetActiveCamera()
-            camera.SetPosition(-206.616664, 182.524078, 87.589931)
-            camera.SetFocalPoint(-5.721571, -0.074326, -97.940837)
-            camera.SetViewUp(0.300335, -0.496855, 0.814208)
-            camera.SetDistance(328.820135)
-            camera.SetClippingRange(0.810268, 810.268454)
-        elif view == 'd':
-            # Fig 12-9d in the VTK Textbook
-            camera = renderer.GetActiveCamera()
-            camera.SetPosition(-40.912047, -65.274764, 588.508700)
-            camera.SetFocalPoint(-10.418979, 17.700133, -158.643842)
-            camera.SetViewUp(0.741687, -0.669297, -0.044059)
-            camera.SetDistance(752.363995)
-            camera.SetClippingRange(444.653021, 997.508259)
-
-    render_window.Render()
-
-    axes = vtkAxesActor()
-
-    widget = vtkOrientationMarkerWidget()
-    rgba = [0.0, 0.0, 0.0, 0.0]
-    colors.GetColor("Carrot", rgba)
-    widget.SetOutlineColor(rgba[0], rgba[1], rgba[2])
-    widget.SetOrientationMarker(axes)
-    widget.SetInteractor(render_window_interactor)
-    widget.SetViewport(0.0, 0.0, 0.2, 0.2)
-    widget.SetEnabled(1)
-    widget.InteractiveOn()
-
-    render_window_interactor.Start()
-
-
-def create_frog_actor(file_name, tissue, transform):
-    so = SliceOrder()
-
-    reader = vtkPolyDataReader()
-    reader.SetFileName(file_name)
-    reader.Update()
-
-    trans = so.get(transform)
-    if tissue == 'brainbin':
-        trans.Scale(1, -1, 1)
-        trans.RotateZ(180)
-    tf = vtkTransformPolyDataFilter()
-    tf.SetInputConnection(reader.GetOutputPort())
-    tf.SetTransform(trans)
-    tf.SetInputConnection(reader.GetOutputPort())
-
-    normals = vtkPolyDataNormals()
-    normals.SetInputConnection(tf.GetOutputPort())
-    normals.SetFeatureAngle(60.0)
-
-    mapper = vtkPolyDataMapper()
-    mapper.SetInputConnection(normals.GetOutputPort())
-
-    actor = vtkActor()
-    actor.SetMapper(mapper)
-
-    return actor
-
-
-class SliceOrder:
-    """
-    These transformations permute image and other geometric data to maintain proper
-     orientation regardless of the acquisition order. After applying these transforms with
-    vtkTransformFilter, a view up of 0,-1,0 will result in the body part
-    facing the viewer.
-    NOTE: some transformations have a -1 scale factor for one of the components.
-          To ensure proper polygon orientation and normal direction, you must
-          apply the vtkPolyDataNormals filter.
-
-    Naming (the nomenclature is medical):
-    si - superior to inferior (top to bottom)
-    is - inferior to superior (bottom to top)
-    ap - anterior to posterior (front to back)
-    pa - posterior to anterior (back to front)
-    lr - left to right
-    rl - right to left
-    """
-
-    def __init__(self):
-        self.si_mat = vtkMatrix4x4()
-        self.si_mat.Zero()
-        self.si_mat.SetElement(0, 0, 1)
-        self.si_mat.SetElement(1, 2, 1)
-        self.si_mat.SetElement(2, 1, -1)
-        self.si_mat.SetElement(3, 3, 1)
-
-        self.is_mat = vtkMatrix4x4()
-        self.is_mat.Zero()
-        self.is_mat.SetElement(0, 0, 1)
-        self.is_mat.SetElement(1, 2, -1)
-        self.is_mat.SetElement(2, 1, -1)
-        self.is_mat.SetElement(3, 3, 1)
-
-        self.lr_mat = vtkMatrix4x4()
-        self.lr_mat.Zero()
-        self.lr_mat.SetElement(0, 2, -1)
-        self.lr_mat.SetElement(1, 1, -1)
-        self.lr_mat.SetElement(2, 0, 1)
-        self.lr_mat.SetElement(3, 3, 1)
-
-        self.rl_mat = vtkMatrix4x4()
-        self.rl_mat.Zero()
-        self.rl_mat.SetElement(0, 2, 1)
-        self.rl_mat.SetElement(1, 1, -1)
-        self.rl_mat.SetElement(2, 0, 1)
-        self.rl_mat.SetElement(3, 3, 1)
-
-        """
-        The previous transforms assume radiological views of the slices (viewed from the feet). other
-        modalities such as physical sectioning may view from the head. These transforms modify the original
-        with a 180° rotation about y
-        """
-
-        self.hf_mat = vtkMatrix4x4()
-        self.hf_mat.Zero()
-        self.hf_mat.SetElement(0, 0, -1)
-        self.hf_mat.SetElement(1, 1, 1)
-        self.hf_mat.SetElement(2, 2, -1)
-        self.hf_mat.SetElement(3, 3, 1)
-
-    def s_i(self):
-        t = vtkTransform()
-        t.SetMatrix(self.si_mat)
-        return t
-
-    def i_s(self):
-        t = vtkTransform()
-        t.SetMatrix(self.is_mat)
-        return t
-
-    @staticmethod
-    def a_p():
-        t = vtkTransform()
-        return t.Scale(1, -1, 1)
-
-    @staticmethod
-    def p_a():
-        t = vtkTransform()
-        return t.Scale(1, -1, -1)
-
-    def l_r(self):
-        t = vtkTransform()
-        t.SetMatrix(self.lr_mat)
-        t.Update()
-        return t
-
-    def r_l(self):
-        t = vtkTransform()
-        t.SetMatrix(self.lr_mat)
-        return t
-
-    def h_f(self):
-        t = vtkTransform()
-        t.SetMatrix(self.hf_mat)
-        return t
-
-    def hf_si(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.si_mat)
-        return t
-
-    def hf_is(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.is_mat)
-        return t
-
-    def hf_ap(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Scale(1, -1, 1)
-        return t
-
-    def hf_pa(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Scale(1, -1, -1)
-        return t
-
-    def hf_lr(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.lr_mat)
-        return t
-
-    def hf_rl(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.rl_mat)
-        return t
-
-    def get(self, order):
-        """
-        Returns the vtkTransform corresponding to the slice order.
-        
-        :param order: The slice order
-        :return: The vtkTransform to use
-        """
-        if order == 'si':
-            return self.s_i()
-        elif order == 'is':
-            return self.i_s()
-        elif order == 'ap':
-            return self.a_p()
-        elif order == 'pa':
-            return self.p_a()
-        elif order == 'lr':
-            return self.l_r()
-        elif order == 'rl':
-            return self.r_l()
-        elif order == 'hf':
-            return self.h_f()
-        elif order == 'hfsi':
-            return self.hf_si()
-        elif order == 'hfis':
-            return self.hf_is()
-        elif order == 'hfap':
-            return self.hf_ap()
-        elif order == 'hfpa':
-            return self.hf_pa()
-        elif order == 'hflr':
-            return self.hf_lr()
-        elif order == 'hfrl':
-            return self.hf_rl()
-        else:
-            s = 'No such transform "{:s}" exists.'.format(order)
-            raise Exception(s)
-
-
-def create_frog_lut(colors):
-    lut = vtkLookupTable()
-    lut.SetNumberOfColors(16)
-    lut.SetTableRange(0, 15)
-    lut.Build()
-
-    lut.SetTableValue(0, colors.GetColor4d('LimeGreen'))  # skin
-    lut.SetTableValue(1, colors.GetColor4d('salmon'))  # blood
-    lut.SetTableValue(2, colors.GetColor4d('beige'))  # brain
-    lut.SetTableValue(3, colors.GetColor4d('orange'))  # duodenum
-    lut.SetTableValue(4, colors.GetColor4d('misty_rose'))  # eye_retina
-    lut.SetTableValue(5, colors.GetColor4d('white'))  # eye_white
-    lut.SetTableValue(6, colors.GetColor4d('tomato'))  # heart
-    lut.SetTableValue(7, colors.GetColor4d('raspberry'))  # ileum
-    lut.SetTableValue(8, colors.GetColor4d('banana'))  # kidney
-    lut.SetTableValue(9, colors.GetColor4d('peru'))  # l_intestine
-    lut.SetTableValue(10, colors.GetColor4d('pink'))  # liver
-    lut.SetTableValue(11, colors.GetColor4d('powder_blue'))  # lung
-    lut.SetTableValue(12, colors.GetColor4d('carrot'))  # nerve
-    lut.SetTableValue(13, colors.GetColor4d('wheat'))  # skeleton
-    lut.SetTableValue(14, colors.GetColor4d('violet'))  # spleen
-    lut.SetTableValue(15, colors.GetColor4d('plum'))  # stomach
-
-    return lut
-
-
-def create_tissue_map():
-    tiss = dict()
-    # key: name of the tissue
-    # value: [lut_index, transform, opacity]
-    tiss['skin'] = [0, 'hfsi', 0.4]
-    tiss['blood'] = [1, 'is', 1.0]
-    tiss['brain'] = [2, 'is', 1.0]
-    tiss['brainbin'] = [2, 'is', 1.0]
-    tiss['duodenum'] = [3, 'is', 1.0]
-    tiss['eye_retna'] = [4, 'is', 1.0]
-    tiss['eye_white'] = [5, 'is', 1.0]
-    tiss['heart'] = [6, 'is', 1.0]
-    tiss['ileum'] = [7, 'is', 1.0]
-    tiss['kidney'] = [8, 'is', 1.0]
-    tiss['l_intestine'] = [9, 'is', 1.0]
-    tiss['liver'] = [10, 'is', 1.0]
-    tiss['lung'] = [11, 'is', 1.0]
-    tiss['nerve'] = [12, 'is', 1.0]
-    tiss['skeleton'] = [13, 'is', 1.0]
-    tiss['spleen'] = [14, 'is', 1.0]
-    tiss['stomach'] = [15, 'is', 1.0]
-    return tiss
-
-
-if __name__ == '__main__':
-    import sys
-
-    data_folder, tissues, view = get_program_parameters(sys.argv)
-    main(data_folder, tissues, view)
diff --git a/src/Python/Visualization/FrogDemo.md b/src/Python/Visualization/FrogDemo.md
deleted file mode 100644
index 7b14a1282990e1d65c6ac60c1eb0ff890bd4ad58..0000000000000000000000000000000000000000
--- a/src/Python/Visualization/FrogDemo.md
+++ /dev/null
@@ -1,7 +0,0 @@
-### Description
-
-View all or some frog tissues and adjust the translucency of the tissues.
-
-Sliders are provided in the right-hand window to to control the opacity of the individual tissues.
-
-This example extends [Frog](../Frog) by providing user control over opacity.
diff --git a/src/Python/Visualization/FrogDemo.py b/src/Python/Visualization/FrogDemo.py
deleted file mode 100755
index 5c07816f10083e481db9978219e5983ad41555c0..0000000000000000000000000000000000000000
--- a/src/Python/Visualization/FrogDemo.py
+++ /dev/null
@@ -1,513 +0,0 @@
-#!/usr/bin/env python
-
-from pathlib import Path
-
-# noinspection PyUnresolvedReferences
-import vtkmodules.vtkInteractionStyle
-# noinspection PyUnresolvedReferences
-import vtkmodules.vtkRenderingOpenGL2
-from vtkmodules.vtkCommonColor import vtkNamedColors
-from vtkmodules.vtkCommonCore import (
-    vtkCommand,
-    vtkLookupTable
-)
-from vtkmodules.vtkCommonMath import vtkMatrix4x4
-from vtkmodules.vtkCommonTransforms import vtkTransform
-from vtkmodules.vtkFiltersCore import vtkPolyDataNormals
-from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter
-from vtkmodules.vtkIOLegacy import vtkPolyDataReader
-from vtkmodules.vtkInteractionWidgets import (
-    vtkOrientationMarkerWidget,
-    vtkSliderRepresentation2D,
-    vtkSliderWidget
-)
-from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
-from vtkmodules.vtkRenderingCore import (
-    vtkActor,
-    vtkPolyDataMapper,
-    vtkRenderWindow,
-    vtkRenderWindowInteractor,
-    vtkRenderer
-)
-
-
-def get_program_parameters(argv):
-    import argparse
-    description = 'Display the frog organs along with a translucent skin.'
-    epilogue = '''
-To specify all the tissues at once:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach skin
-
-You can leave out brainbin, it is the brain with no gaussian smoothing.
-
-Here are the parameters used to get the views in the VTK Textbook:
-Fig12-9a:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach skin -a
-Fig12-9b:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach -a
-Fig12-9c:
- brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve spleen stomach -c
-Fig12-9c:
- brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve spleen stomach -d
-    '''
-    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
-                                     formatter_class=argparse.RawDescriptionHelpFormatter)
-
-    group = parser.add_mutually_exclusive_group()
-    group.add_argument('-a', action='store_const', dest='view', const='a',
-                       help='The view corresponds to Figs 12-9a and 12-9b in the VTK Textbook')
-    group.add_argument('-c', action='store_const', dest='view', const='c',
-                       help='The view corresponds to Figs 12-9c in the VTK Textbook')
-    group.add_argument('-d', action='store_const', dest='view', const='d',
-                       help='The view corresponds to Figs 12-9d in the VTK Textbook')
-    parser.set_defaults(type=None)
-
-    parser.add_argument('data_folder', help='The path to the files: frog.mhd and frogtissue.mhd.')
-    parser.add_argument('tissues', nargs='+', help='List of one or more tissues.')
-    args = parser.parse_args()
-    return args.data_folder, args.tissues, args.view
-
-
-def main(data_folder, tissues, view):
-    colors = vtkNamedColors()
-
-    # Setup render window, renderers, and interactor.
-    # ren_1 is for the frog rendering, ren_2 is for the slider rendering.
-    ren_1 = vtkRenderer()
-    ren_2 = vtkRenderer()
-    render_window = vtkRenderWindow()
-    render_window.AddRenderer(ren_1)
-    render_window.AddRenderer(ren_2)
-    ren_1.SetViewport(0.0, 0.0, 0.7, 1.0)
-    ren_2.SetViewport(0.7, 0.0, 1, 1)
-    render_window_interactor = vtkRenderWindowInteractor()
-    render_window_interactor.SetRenderWindow(render_window)
-
-    tm = create_tissue_map()
-    path = Path(data_folder)
-    lut = create_frog_lut(colors)
-    sliders = dict()
-    step_size = 1.0 / 17
-    pos_y = 0.05
-
-    res = ['Using the following tissues:']
-    for tissue in tissues:
-        source = None
-        if path.is_dir():
-            source = path.joinpath(tissue).with_suffix('.vtk')
-            if not source.is_file():
-                s = 'The file: {:s} does not exist.'.format(str(source))
-                print(s)
-                continue
-        actor = create_frog_actor(str(source), tissue, tm[tissue][1])
-        actor.GetProperty().SetOpacity(tm[tissue][2])
-        actor.GetProperty().SetDiffuseColor(lut.GetTableValue(tm[tissue][0])[:3])
-        actor.GetProperty().SetSpecular(0.2)
-        actor.GetProperty().SetSpecularPower(10)
-        ren_1.AddActor(actor)
-        res.append('{:>11s}, label: {:2d}'.format(tissue, tm[tissue][0]))
-
-        slider_properties = SliderProperties()
-        slider_properties.value_initial = tm[tissue][2]
-        slider_properties.title = tissue
-        # Screen coordinates
-        slider_properties.p1 = [0.05, pos_y]
-        slider_properties.p2 = [0.25, pos_y]
-        pos_y += step_size
-        cb = SliderCB(actor.GetProperty())
-
-        slider_widget = make_slider_widget(slider_properties, colors, lut, tm[tissue][0])
-        slider_widget.SetInteractor(render_window_interactor)
-        slider_widget.SetAnimationModeToAnimate()
-        slider_widget.EnabledOn()
-        slider_widget.SetCurrentRenderer(ren_2)
-        slider_widget.AddObserver(vtkCommand.InteractionEvent, cb)
-        sliders[tissue] = slider_widget
-
-    if len(res) > 1:
-        print('\n'.join(res))
-
-    render_window.SetSize(800, 600)
-    render_window.SetWindowName('FrogDemo')
-
-    ren_1.SetBackground(colors.GetColor3d('LightSteelBlue'))
-    ren_2.SetBackground(colors.GetColor3d('MidnightBlue'))
-
-    # Initial view (looking down on the dorsal surface).
-    ren_1.GetActiveCamera().Roll(-90)
-    ren_1.ResetCamera()
-
-    #  Final view
-    if view:
-        if view == 'a':
-            # Figs 12-9a and 12-9b in the VTK Textbook
-            camera = ren_1.GetActiveCamera()
-            camera.SetPosition(-599.880035, 548.906952, 313.670289)
-            camera.SetFocalPoint(-8.376500, 40.691664, -156.007163)
-            camera.SetViewUp(0.294699, -0.440638, 0.847933)
-            camera.SetDistance(910.360434)
-            camera.SetClippingRange(231.699387, 1758.550290)
-        elif view == 'c':
-            # Figs 12-9c in the VTK Textbook
-            camera = ren_1.GetActiveCamera()
-            camera.SetPosition(-206.616664, 182.524078, 87.589931)
-            camera.SetFocalPoint(-5.721571, -0.074326, -97.940837)
-            camera.SetViewUp(0.300335, -0.496855, 0.814208)
-            camera.SetDistance(328.820135)
-            camera.SetClippingRange(0.810268, 810.268454)
-        elif view == 'd':
-            # Fig 12-9d in the VTK Textbook
-            camera = ren_1.GetActiveCamera()
-            camera.SetPosition(-40.912047, -65.274764, 588.508700)
-            camera.SetFocalPoint(-10.418979, 17.700133, -158.643842)
-            camera.SetViewUp(0.741687, -0.669297, -0.044059)
-            camera.SetDistance(752.363995)
-            camera.SetClippingRange(444.653021, 997.508259)
-
-    render_window.Render()
-
-    axes = vtkAxesActor()
-
-    widget = vtkOrientationMarkerWidget()
-    rgba = [0.0, 0.0, 0.0, 0.0]
-    colors.GetColor("Carrot", rgba)
-    widget.SetOutlineColor(rgba[0], rgba[1], rgba[2])
-    widget.SetOrientationMarker(axes)
-    widget.SetInteractor(render_window_interactor)
-    widget.SetViewport(0.0, 0.0, 0.2, 0.2)
-    widget.SetEnabled(1)
-    widget.InteractiveOn()
-
-    render_window_interactor.Start()
-
-
-def create_frog_actor(file_name, tissue, transform):
-    so = SliceOrder()
-
-    reader = vtkPolyDataReader()
-    reader.SetFileName(file_name)
-    reader.Update()
-
-    trans = so.get(transform)
-    if tissue == 'brainbin':
-        trans.Scale(1, -1, 1)
-        trans.RotateZ(180)
-    tf = vtkTransformPolyDataFilter()
-    tf.SetInputConnection(reader.GetOutputPort())
-    tf.SetTransform(trans)
-    tf.SetInputConnection(reader.GetOutputPort())
-
-    normals = vtkPolyDataNormals()
-    normals.SetInputConnection(tf.GetOutputPort())
-    normals.SetFeatureAngle(60.0)
-
-    mapper = vtkPolyDataMapper()
-    mapper.SetInputConnection(normals.GetOutputPort())
-
-    actor = vtkActor()
-    actor.SetMapper(mapper)
-
-    return actor
-
-
-class SliceOrder:
-    """
-    These transformations permute image and other geometric data to maintain proper
-     orientation regardless of the acquisition order. After applying these transforms with
-    vtkTransformFilter, a view up of 0,-1,0 will result in the body part
-    facing the viewer.
-    NOTE: some transformations have a -1 scale factor for one of the components.
-          To ensure proper polygon orientation and normal direction, you must
-          apply the vtkPolyDataNormals filter.
-
-    Naming (the nomenclature is medical):
-    si - superior to inferior (top to bottom)
-    is - inferior to superior (bottom to top)
-    ap - anterior to posterior (front to back)
-    pa - posterior to anterior (back to front)
-    lr - left to right
-    rl - right to left
-    """
-
-    def __init__(self):
-        self.si_mat = vtkMatrix4x4()
-        self.si_mat.Zero()
-        self.si_mat.SetElement(0, 0, 1)
-        self.si_mat.SetElement(1, 2, 1)
-        self.si_mat.SetElement(2, 1, -1)
-        self.si_mat.SetElement(3, 3, 1)
-
-        self.is_mat = vtkMatrix4x4()
-        self.is_mat.Zero()
-        self.is_mat.SetElement(0, 0, 1)
-        self.is_mat.SetElement(1, 2, -1)
-        self.is_mat.SetElement(2, 1, -1)
-        self.is_mat.SetElement(3, 3, 1)
-
-        self.lr_mat = vtkMatrix4x4()
-        self.lr_mat.Zero()
-        self.lr_mat.SetElement(0, 2, -1)
-        self.lr_mat.SetElement(1, 1, -1)
-        self.lr_mat.SetElement(2, 0, 1)
-        self.lr_mat.SetElement(3, 3, 1)
-
-        self.rl_mat = vtkMatrix4x4()
-        self.rl_mat.Zero()
-        self.rl_mat.SetElement(0, 2, 1)
-        self.rl_mat.SetElement(1, 1, -1)
-        self.rl_mat.SetElement(2, 0, 1)
-        self.rl_mat.SetElement(3, 3, 1)
-
-        """
-        The previous transforms assume radiological views of the slices (viewed from the feet). other
-        modalities such as physical sectioning may view from the head. These transforms modify the original
-        with a 180° rotation about y
-        """
-
-        self.hf_mat = vtkMatrix4x4()
-        self.hf_mat.Zero()
-        self.hf_mat.SetElement(0, 0, -1)
-        self.hf_mat.SetElement(1, 1, 1)
-        self.hf_mat.SetElement(2, 2, -1)
-        self.hf_mat.SetElement(3, 3, 1)
-
-    def s_i(self):
-        t = vtkTransform()
-        t.SetMatrix(self.si_mat)
-        return t
-
-    def i_s(self):
-        t = vtkTransform()
-        t.SetMatrix(self.is_mat)
-        return t
-
-    @staticmethod
-    def a_p():
-        t = vtkTransform()
-        return t.Scale(1, -1, 1)
-
-    @staticmethod
-    def p_a():
-        t = vtkTransform()
-        return t.Scale(1, -1, -1)
-
-    def l_r(self):
-        t = vtkTransform()
-        t.SetMatrix(self.lr_mat)
-        t.Update()
-        return t
-
-    def r_l(self):
-        t = vtkTransform()
-        t.SetMatrix(self.lr_mat)
-        return t
-
-    def h_f(self):
-        t = vtkTransform()
-        t.SetMatrix(self.hf_mat)
-        return t
-
-    def hf_si(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.si_mat)
-        return t
-
-    def hf_is(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.is_mat)
-        return t
-
-    def hf_ap(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Scale(1, -1, 1)
-        return t
-
-    def hf_pa(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Scale(1, -1, -1)
-        return t
-
-    def hf_lr(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.lr_mat)
-        return t
-
-    def hf_rl(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.rl_mat)
-        return t
-
-    def get(self, order):
-        """
-        Returns the vtkTransform corresponding to the slice order.
-        
-        :param order: The slice order
-        :return: The vtkTransform to use
-        """
-        if order == 'si':
-            return self.s_i()
-        elif order == 'is':
-            return self.i_s()
-        elif order == 'ap':
-            return self.a_p()
-        elif order == 'pa':
-            return self.p_a()
-        elif order == 'lr':
-            return self.l_r()
-        elif order == 'rl':
-            return self.r_l()
-        elif order == 'hf':
-            return self.h_f()
-        elif order == 'hfsi':
-            return self.hf_si()
-        elif order == 'hfis':
-            return self.hf_is()
-        elif order == 'hfap':
-            return self.hf_ap()
-        elif order == 'hfpa':
-            return self.hf_pa()
-        elif order == 'hflr':
-            return self.hf_lr()
-        elif order == 'hfrl':
-            return self.hf_rl()
-        else:
-            s = 'No such transform "{:s}" exists.'.format(order)
-            raise Exception(s)
-
-
-def create_frog_lut(colors):
-    lut = vtkLookupTable()
-    lut.SetNumberOfColors(16)
-    lut.SetTableRange(0, 15)
-    lut.Build()
-
-    lut.SetTableValue(0, colors.GetColor4d('LimeGreen'))  # skin
-    lut.SetTableValue(1, colors.GetColor4d('salmon'))  # blood
-    lut.SetTableValue(2, colors.GetColor4d('beige'))  # brain
-    lut.SetTableValue(3, colors.GetColor4d('orange'))  # duodenum
-    lut.SetTableValue(4, colors.GetColor4d('misty_rose'))  # eye_retina
-    lut.SetTableValue(5, colors.GetColor4d('white'))  # eye_white
-    lut.SetTableValue(6, colors.GetColor4d('tomato'))  # heart
-    lut.SetTableValue(7, colors.GetColor4d('raspberry'))  # ileum
-    lut.SetTableValue(8, colors.GetColor4d('banana'))  # kidney
-    lut.SetTableValue(9, colors.GetColor4d('peru'))  # l_intestine
-    lut.SetTableValue(10, colors.GetColor4d('pink'))  # liver
-    lut.SetTableValue(11, colors.GetColor4d('powder_blue'))  # lung
-    lut.SetTableValue(12, colors.GetColor4d('carrot'))  # nerve
-    lut.SetTableValue(13, colors.GetColor4d('wheat'))  # skeleton
-    lut.SetTableValue(14, colors.GetColor4d('violet'))  # spleen
-    lut.SetTableValue(15, colors.GetColor4d('plum'))  # stomach
-
-    return lut
-
-
-def create_tissue_map():
-    tiss = dict()
-    # key: name of the tissue
-    # value: [lut_index, transform, opacity]
-    tiss['skin'] = [0, 'hfsi', 0.4]
-    tiss['blood'] = [1, 'is', 1.0]
-    tiss['brain'] = [2, 'is', 1.0]
-    tiss['brainbin'] = [2, 'is', 1.0]
-    tiss['duodenum'] = [3, 'is', 1.0]
-    tiss['eye_retna'] = [4, 'is', 1.0]
-    tiss['eye_white'] = [5, 'is', 1.0]
-    tiss['heart'] = [6, 'is', 1.0]
-    tiss['ileum'] = [7, 'is', 1.0]
-    tiss['kidney'] = [8, 'is', 1.0]
-    tiss['l_intestine'] = [9, 'is', 1.0]
-    tiss['liver'] = [10, 'is', 1.0]
-    tiss['lung'] = [11, 'is', 1.0]
-    tiss['nerve'] = [12, 'is', 1.0]
-    tiss['skeleton'] = [13, 'is', 1.0]
-    tiss['spleen'] = [14, 'is', 1.0]
-    tiss['stomach'] = [15, 'is', 1.0]
-    return tiss
-
-
-class SliderProperties:
-    tube_width = 0.008
-    slider_length = 0.008
-    title_height = 0.01
-    label_height = 0.01
-
-    value_minimum = 0.0
-    value_maximum = 1.0
-    value_initial = 1.0
-
-    p1 = [0.1, 0.1]
-    p2 = [0.3, 0.1]
-
-    title = None
-
-    title_color = 'MistyRose'
-    value_color = 'Cyan'
-    slider_color = 'Coral'
-    selected_color = 'Lime'
-    bar_color = 'Yellow'
-    bar_ends_color = 'Gold'
-
-
-def make_slider_widget(properties, colors, lut, idx):
-    slider = vtkSliderRepresentation2D()
-
-    slider.SetMinimumValue(properties.value_minimum)
-    slider.SetMaximumValue(properties.value_maximum)
-    slider.SetValue(properties.value_initial)
-    slider.SetTitleText(properties.title)
-
-    slider.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay()
-    slider.GetPoint1Coordinate().SetValue(properties.p1[0], properties.p1[1])
-    slider.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay()
-    slider.GetPoint2Coordinate().SetValue(properties.p2[0], properties.p2[1])
-
-    slider.SetTubeWidth(properties.tube_width)
-    slider.SetSliderLength(properties.slider_length)
-    slider.SetTitleHeight(properties.title_height)
-    slider.SetLabelHeight(properties.label_height)
-
-    # Set the color properties
-    # Change the color of the bar.
-    slider.GetTubeProperty().SetColor(colors.GetColor3d(properties.bar_color))
-    # Change the color of the ends of the bar.
-    slider.GetCapProperty().SetColor(colors.GetColor3d(properties.bar_ends_color))
-    # Change the color of the knob that slides.
-    slider.GetSliderProperty().SetColor(colors.GetColor3d(properties.slider_color))
-    # Change the color of the knob when the mouse is held on it.
-    slider.GetSelectedProperty().SetColor(colors.GetColor3d(properties.selected_color))
-    # Change the color of the text displaying the value.
-    slider.GetLabelProperty().SetColor(colors.GetColor3d(properties.value_color))
-    # Change the color of the text indicating what the slider controls
-    if idx in range(0, 16):
-        slider.GetTitleProperty().SetColor(lut.GetTableValue(idx)[:3])
-        slider.GetTitleProperty().ShadowOff()
-    else:
-        slider.GetTitleProperty().SetColor(colors.GetColor3d(properties.title_color))
-
-    slider_widget = vtkSliderWidget()
-    slider_widget.SetRepresentation(slider)
-
-    return slider_widget
-
-
-class SliderCB:
-    def __init__(self, actor_property):
-        self.actorProperty = actor_property
-
-    def __call__(self, caller, ev):
-        slider_widget = caller
-        value = slider_widget.GetRepresentation().GetValue()
-        self.actorProperty.SetOpacity(value)
-
-
-if __name__ == '__main__':
-    import sys
-
-    data_folder, tissues, view = get_program_parameters(sys.argv)
-    main(data_folder, tissues, view)
diff --git a/src/Python/Visualization/FrogReconstruction.md b/src/Python/Visualization/FrogReconstruction.md
deleted file mode 100644
index 082b820953f001196d4dee0be6c9a0c4435f308c..0000000000000000000000000000000000000000
--- a/src/Python/Visualization/FrogReconstruction.md
+++ /dev/null
@@ -1,14 +0,0 @@
-### Description
-
-Frog organs along with a translucent skin are reconstructed from the original segmented data.
-
-vtkFlyingEdges3D is used by default to take the 3D structured point set and generate the iso-surface. However if desired, you can specify vtkMarchingCubes instead.
-
-The dataset is derived from a frog. This data was prepared at Lawrence Berkeley National Laboratories and is included with their permission. The data was acquired by physically slicing the frog and photographing the slices. The original segmented data is in the form of tissue masks with one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500 pixels.
-
-To accommodate the volume readers we have in VTK, we processed the mask files and combined them all into one vtkMetaImageReader *.mhd* file. Integer numbers 1–15 to represent the 15 tissues. A similar process was done for the frog skin.
-
-The code uses a general way of specifying transformations that can permute image and other geometric data in order to maintain proper orientation regardless of the acquisition order. See the class **SliceOrder**.
-
-!!! info
-    By specifying the tissues and other parameters, as outlined in the code, you can generate approximations to the following figures: [Figure 12-9a](../../../VTKBook/12Chapter12/#Figure%2012-9a), [Figure 12-9b](../../../VTKBook/12Chapter12/#Figure%2012-9b), [Figure 12-9c](../../../VTKBook/12Chapter12/#Figure%2012-9c), and [Figure 12-9d](../../../VTKBook/12Chapter12/#Figure%2012-9d) in [Chapter 12](../../../VTKBook/12Chapter12) of the [VTK Textbook](../../../VTKBook/01Chapter1).
diff --git a/src/Python/Visualization/FrogReconstruction.py b/src/Python/Visualization/FrogReconstruction.py
deleted file mode 100755
index 3d36068bd29dc63f314be2d8a4d427fb6770b25d..0000000000000000000000000000000000000000
--- a/src/Python/Visualization/FrogReconstruction.py
+++ /dev/null
@@ -1,843 +0,0 @@
-#!/usr/bin/env python
-
-import collections
-from pathlib import Path
-
-# noinspection PyUnresolvedReferences
-import vtkmodules.vtkInteractionStyle
-# noinspection PyUnresolvedReferences
-import vtkmodules.vtkRenderingOpenGL2
-from vtkmodules.vtkCommonColor import vtkNamedColors
-from vtkmodules.vtkCommonCore import vtkLookupTable
-from vtkmodules.vtkCommonMath import vtkMatrix4x4
-from vtkmodules.vtkCommonTransforms import vtkTransform
-from vtkmodules.vtkFiltersCore import (
-    vtkContourFilter,
-    vtkDecimatePro,
-    vtkExecutionTimer,
-    vtkFlyingEdges3D,
-    vtkMarchingCubes,
-    vtkPolyDataNormals,
-    vtkStripper,
-    vtkWindowedSincPolyDataFilter
-)
-from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter
-from vtkmodules.vtkIOImage import vtkMetaImageReader
-from vtkmodules.vtkImagingCore import (
-    vtkImageShrink3D,
-    vtkImageThreshold
-)
-from vtkmodules.vtkImagingGeneral import vtkImageGaussianSmooth
-from vtkmodules.vtkImagingMorphological import vtkImageIslandRemoval2D
-from vtkmodules.vtkInteractionWidgets import vtkOrientationMarkerWidget
-from vtkmodules.vtkRenderingAnnotation import vtkAxesActor
-from vtkmodules.vtkRenderingCore import (
-    vtkActor,
-    vtkPolyDataMapper,
-    vtkRenderWindow,
-    vtkRenderWindowInteractor,
-    vtkRenderer
-)
-
-
-def get_program_parameters(argv):
-    import argparse
-    description = 'Display all frog parts and translucent skin.'
-    epilogue = '''
-To specify all the tissues at once:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach skin
-
-You can leave out brainbin, it is the brain with no gaussian smoothing.
-
-Here are the parameters used to get the views in the VTK Textbook:
-Fig12-9a:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach skin -a
-Fig12-9b:
- blood brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve skeleton spleen stomach -a
-Fig12-9c:
- brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve spleen stomach -c
-Fig12-9c:
- brain duodenum eye_retna eye_white heart ileum kidney l_intestine liver lung nerve spleen stomach -d
-    '''
-    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
-                                     formatter_class=argparse.RawDescriptionHelpFormatter)
-
-    group = parser.add_mutually_exclusive_group()
-    group.add_argument('-a', action='store_const', dest='view', const='a',
-                       help='The view corresponds to Figs 12-9a and 12-9b in the VTK Textbook')
-    group.add_argument('-c', action='store_const', dest='view', const='c',
-                       help='The view corresponds to Figs 12-9c in the VTK Textbook')
-    group.add_argument('-d', action='store_const', dest='view', const='d',
-                       help='The view corresponds to Figs 12-9d in the VTK Textbook')
-    parser.set_defaults(type=None)
-
-    parser.add_argument('-m', action='store_false', dest='flying_edges',
-                        help='Use flying edges by default, marching cubes if set.')
-    parser.add_argument('-t', action='store_true', dest='decimation',
-                        help='Decimate if set.')
-    parser.add_argument('data_folder', help='The path to the files: frog.mhd and frogtissue.mhd.')
-    parser.add_argument('tissues', nargs='+', help='List of one or more tissues.')
-    args = parser.parse_args()
-    return args.data_folder, args.tissues, args.view, args.flying_edges, args.decimation
-
-
-def main(data_folder, tissues, view, flying_edges, decimate):
-    colors = vtkNamedColors()
-
-    path = Path(data_folder)
-    if path.is_dir():
-        s = ''
-        frog_fn = path.joinpath('frog').with_suffix('.mhd')
-        if not frog_fn.is_file():
-            s += 'The file: {:s} does not exist.\n'.format(str(frog_fn))
-            print(s)
-        frog_tissue_fn = path.joinpath('frogtissue').with_suffix('.mhd')
-        if not frog_tissue_fn.is_file():
-            s += 'The file: {:s} does not exist.'.format(str(frog_tissue_fn))
-        if s:
-            print(s)
-            return
-    else:
-        print('Expected a path to frog.mhs and frogtissue.mhd')
-        return
-
-    # Tissue parameters
-    available_tissues = tissue_parameters()
-    selected_tissues = {key: available_tissues[key] for key in tissues}
-    if not selected_tissues:
-        print('No tissues!')
-        return
-
-    missing_parameters = False
-    for k, v in selected_tissues.items():
-        res = check_for_required_parameters(k, v)
-        if res:
-            print(res)
-            missing_parameters = True
-    if missing_parameters:
-        print('Some required parameters are missing!')
-        return
-
-    # Setup render window, renderer, and interactor.
-    renderer = vtkRenderer()
-    render_window = vtkRenderWindow()
-    render_window.AddRenderer(renderer)
-    render_window_interactor = vtkRenderWindowInteractor()
-    render_window_interactor.SetRenderWindow(render_window)
-
-    lut = create_frog_lut(colors)
-
-    #  Time some filters
-    ict = collections.defaultdict(dict)
-
-    for name, tissue in selected_tissues.items():
-        print('Tissue: {:>9s}, label: {:2d}'.format(name, tissue['TISSUE']))
-        t, actor = create_frog_actor(frog_fn, frog_tissue_fn, tissue, flying_edges, decimate, lut)
-        ict[name] = t
-        renderer.AddActor(actor)
-
-    # Initial view (looking down on the dorsal surface).
-    renderer.GetActiveCamera().Roll(-90)
-    renderer.ResetCamera()
-
-    #  Final view
-    if view:
-        if view == 'a':
-            # Figs 12-9a and 12-9b in the VTK Textbook
-            camera = renderer.GetActiveCamera()
-            camera.SetPosition(-850.073854, 834.142692, 266.017598)
-            camera.SetFocalPoint(-72.387897, 109.637349, -306.343185)
-            camera.SetViewUp(0.284585, -0.387303, 0.876931)
-            camera.SetDistance(1207.186939)
-            camera.SetClippingRange(247.737449, 1758.922849)
-        elif view == 'c':
-            # Figs 12-9c in the VTK Textbook
-            camera = renderer.GetActiveCamera()
-            camera.SetPosition(-438.993734, 404.715262, 105.797836)
-            camera.SetFocalPoint(-254.193794, 245.672169, -95.535892)
-            camera.SetViewUp(0.256893, -0.629643, 0.733182)
-            camera.SetDistance(316.197712)
-            camera.SetClippingRange(0.789810, 789.809963)
-        elif view == 'd':
-            # Fig 12-9d in the VTK Textbook
-            camera = renderer.GetActiveCamera()
-            camera.SetPosition(-262.252604, 229.863144, 562.084505)
-            camera.SetFocalPoint(-288.693092, 228.870041, -91.185421)
-            camera.SetViewUp(0.729526, -0.683360, -0.028488)
-            camera.SetDistance(653.805539)
-            camera.SetClippingRange(452.459105, 905.003135)
-
-    print('Timings:')
-    print('\n'.join(format_timings(ict)))
-
-    renderer.SetBackground(colors.GetColor3d('LightSteelBlue'))
-
-    render_window.SetSize(640, 640)
-    render_window.SetWindowName('FrogReconstruction')
-    render_window.Render()
-
-    axes = vtkAxesActor()
-
-    widget = vtkOrientationMarkerWidget()
-    rgba = [0.0, 0.0, 0.0, 0.0]
-    colors.GetColor("Carrot", rgba)
-    widget.SetOutlineColor(rgba[0], rgba[1], rgba[2])
-    widget.SetOrientationMarker(axes)
-    widget.SetInteractor(render_window_interactor)
-    widget.SetViewport(0.0, 0.0, 0.2, 0.2)
-    widget.SetEnabled(1)
-    widget.InteractiveOn()
-
-    render_window.Render()
-
-    render_window_interactor.Start()
-
-
-def create_frog_actor(frog_fn, frog_tissue_fn, tissue, flying_edges, decimate, lut):
-    # Get the tissue parameters
-    pixel_size = tissue['PIXEL_SIZE']
-    columns = tissue['COLUMNS']
-    rows = tissue['ROWS']
-
-    voi = tissue['VOI']
-    spacing = float(tissue['SPACING'])
-    start_slice = float(tissue['START_SLICE'])
-    data_spacing = [pixel_size, pixel_size, spacing]
-    data_origin = [-(columns / 2.0) * pixel_size, -(rows / 2.0) * pixel_size, start_slice * spacing]
-
-    #
-    # adjust y bounds for PNM coordinate system
-    #
-    tmp = voi[2]
-    voi[2] = rows - voi[3] - 1
-    voi[3] = rows - tmp - 1
-
-    if tissue['NAME'] == 'skin':
-        fn = frog_fn
-    else:
-        fn = frog_tissue_fn
-
-    reader = vtkMetaImageReader()
-    reader.SetFileName(str(fn))
-    reader.SetDataSpacing(data_spacing)
-    reader.SetDataOrigin(data_origin)
-    reader.SetDataExtent(voi)
-    reader.Update()
-
-    last_connection = reader
-
-    if not tissue['NAME'] == 'skin':
-        if tissue['ISLAND_REPLACE'] >= 0:
-            island_remover = vtkImageIslandRemoval2D()
-            island_remover.SetAreaThreshold(tissue['ISLAND_AREA'])
-            island_remover.SetIslandValue(tissue['ISLAND_REPLACE'])
-            island_remover.SetReplaceValue(tissue['TISSUE'])
-            island_remover.SetInput(last_connection.GetOutput())
-            island_remover.Update()
-            last_connection = island_remover
-
-        select_tissue = vtkImageThreshold()
-        select_tissue.ThresholdBetween(tissue['TISSUE'], tissue['TISSUE'])
-        select_tissue.SetInValue(255)
-        select_tissue.SetOutValue(0)
-        select_tissue.SetInputConnection(last_connection.GetOutputPort())
-        last_connection = select_tissue
-
-    shrinker = vtkImageShrink3D()
-    shrinker.SetInputConnection(last_connection.GetOutputPort())
-    shrinker.SetShrinkFactors(tissue['SAMPLE_RATE'])
-    shrinker.AveragingOn()
-    last_connection = shrinker
-
-    if not all(v == 0 for v in tissue['GAUSSIAN_STANDARD_DEVIATION']):
-        gaussian = vtkImageGaussianSmooth()
-        gaussian.SetStandardDeviation(*tissue['GAUSSIAN_STANDARD_DEVIATION'])
-        gaussian.SetRadiusFactors(*tissue['GAUSSIAN_RADIUS_FACTORS'])
-        gaussian.SetInputConnection(shrinker.GetOutputPort())
-        last_connection = gaussian
-    # Time the isocontouring.
-    ict = collections.defaultdict()
-    iso_value = tissue['VALUE']
-    if flying_edges:
-        iso_surface = vtkFlyingEdges3D()
-        iso_surface.SetInputConnection(last_connection.GetOutputPort())
-        iso_surface.ComputeScalarsOff()
-        iso_surface.ComputeGradientsOff()
-        iso_surface.ComputeNormalsOff()
-        iso_surface.SetValue(0, iso_value)
-        timer = vtkExecutionTimer()
-        timer.SetFilter(iso_surface)
-        iso_surface.Update()
-        ict['Flying Edges'] = timer.GetElapsedWallClockTime()
-    else:
-        iso_surface = vtkMarchingCubes()
-        iso_surface.SetInputConnection(last_connection.GetOutputPort())
-        iso_surface.ComputeScalarsOff()
-        iso_surface.ComputeGradientsOff()
-        iso_surface.ComputeNormalsOff()
-        iso_surface.SetValue(0, iso_value)
-        timer = vtkExecutionTimer()
-        timer.SetFilter(iso_surface)
-        iso_surface.Update()
-        ict['Marching Cubes'] = timer.GetElapsedWallClockTime()
-
-    so = SliceOrder()
-    # transform = so.get(tissue['SLICE_ORDER'])
-    # Match Frog.py
-    transform = so.get('hfap')
-    transform.Scale(1, -1, 1)
-    tf = vtkTransformPolyDataFilter()
-    tf.SetTransform(transform)
-    tf.SetInputConnection(iso_surface.GetOutputPort())
-    last_connection = tf
-
-    if decimate:
-        decimator = vtkDecimatePro()
-        decimator.SetInputConnection(last_connection.GetOutputPort())
-        decimator.SetFeatureAngle(tissue['DECIMATE_ANGLE'])
-        decimator.MaximumIterations = tissue['DECIMATE_ITERATIONS']
-        decimator.PreserveTopologyOn()
-        decimator.SetErrorIsAbsolute(1)
-        decimator.SetAbsoluteError(tissue['DECIMATE_ERROR'])
-        decimator.SetTargetReduction(tissue['DECIMATE_REDUCTION'])
-        last_connection = decimator
-
-    smoother = vtkWindowedSincPolyDataFilter()
-    smoother.SetInputConnection(last_connection.GetOutputPort())
-    smoother.SetNumberOfIterations(tissue['SMOOTH_ITERATIONS'])
-    smoother.BoundarySmoothingOff()
-    smoother.FeatureEdgeSmoothingOff()
-    smoother.SetFeatureAngle(tissue['SMOOTH_ANGLE'])
-    smoother.SetPassBand(tissue['SMOOTH_FACTOR'])
-    smoother.NonManifoldSmoothingOn()
-    smoother.NormalizeCoordinatesOff()
-    smoother.Update()
-
-    normals = vtkPolyDataNormals()
-    normals.SetInputConnection(smoother.GetOutputPort())
-    normals.SetFeatureAngle(tissue['FEATURE_ANGLE'])
-
-    stripper = vtkStripper()
-    stripper.SetInputConnection(normals.GetOutputPort())
-
-    mapper = vtkPolyDataMapper()
-    mapper.SetInputConnection(stripper.GetOutputPort())
-
-    # Create iso-surface
-    contour = vtkContourFilter()
-    contour.SetInputConnection(reader.GetOutputPort())
-    contour.SetValue(0, iso_value)
-
-    actor = vtkActor()
-    actor.SetMapper(mapper)
-    actor.GetProperty().SetOpacity(tissue['OPACITY'])
-    actor.GetProperty().SetDiffuseColor(lut.GetTableValue(tissue['TISSUE'])[:3])
-    actor.GetProperty().SetSpecular(0.5)
-    actor.GetProperty().SetSpecularPower(10)
-
-    return ict, actor
-
-
-class SliceOrder:
-    """
-    These transformations permute image and other geometric data to maintain proper
-     orientation regardless of the acquisition order. After applying these transforms with
-    vtkTransformFilter, a view up of 0,-1,0 will result in the body part
-    facing the viewer.
-    NOTE: some transformations have a -1 scale factor for one of the components.
-          To ensure proper polygon orientation and normal direction, you must
-          apply the vtkPolyDataNormals filter.
-
-    Naming (the nomenclature is medical):
-    si - superior to inferior (top to bottom)
-    is - inferior to superior (bottom to top)
-    ap - anterior to posterior (front to back)
-    pa - posterior to anterior (back to front)
-    lr - left to right
-    rl - right to left
-    """
-
-    def __init__(self):
-        self.si_mat = vtkMatrix4x4()
-        self.si_mat.Zero()
-        self.si_mat.SetElement(0, 0, 1)
-        self.si_mat.SetElement(1, 2, 1)
-        self.si_mat.SetElement(2, 1, -1)
-        self.si_mat.SetElement(3, 3, 1)
-
-        self.is_mat = vtkMatrix4x4()
-        self.is_mat.Zero()
-        self.is_mat.SetElement(0, 0, 1)
-        self.is_mat.SetElement(1, 2, -1)
-        self.is_mat.SetElement(2, 1, -1)
-        self.is_mat.SetElement(3, 3, 1)
-
-        self.lr_mat = vtkMatrix4x4()
-        self.lr_mat.Zero()
-        self.lr_mat.SetElement(0, 2, -1)
-        self.lr_mat.SetElement(1, 1, -1)
-        self.lr_mat.SetElement(2, 0, 1)
-        self.lr_mat.SetElement(3, 3, 1)
-
-        self.rl_mat = vtkMatrix4x4()
-        self.rl_mat.Zero()
-        self.rl_mat.SetElement(0, 2, 1)
-        self.rl_mat.SetElement(1, 1, -1)
-        self.rl_mat.SetElement(2, 0, 1)
-        self.rl_mat.SetElement(3, 3, 1)
-
-        """
-        The previous transforms assume radiological views of the slices (viewed from the feet). other
-        modalities such as physical sectioning may view from the head. These transforms modify the original
-        with a 180° rotation about y
-        """
-
-        self.hf_mat = vtkMatrix4x4()
-        self.hf_mat.Zero()
-        self.hf_mat.SetElement(0, 0, -1)
-        self.hf_mat.SetElement(1, 1, 1)
-        self.hf_mat.SetElement(2, 2, -1)
-        self.hf_mat.SetElement(3, 3, 1)
-
-    def s_i(self):
-        t = vtkTransform()
-        t.SetMatrix(self.si_mat)
-        return t
-
-    def i_s(self):
-        t = vtkTransform()
-        t.SetMatrix(self.is_mat)
-        return t
-
-    @staticmethod
-    def a_p():
-        t = vtkTransform()
-        return t.Scale(1, -1, 1)
-
-    @staticmethod
-    def p_a():
-        t = vtkTransform()
-        return t.Scale(1, -1, -1)
-
-    def l_r(self):
-        t = vtkTransform()
-        t.SetMatrix(self.lr_mat)
-        t.Update()
-        return t
-
-    def r_l(self):
-        t = vtkTransform()
-        t.SetMatrix(self.lr_mat)
-        return t
-
-    def h_f(self):
-        t = vtkTransform()
-        t.SetMatrix(self.hf_mat)
-        return t
-
-    def hf_si(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.si_mat)
-        return t
-
-    def hf_is(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.is_mat)
-        return t
-
-    def hf_ap(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Scale(1, -1, 1)
-        return t
-
-    def hf_pa(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Scale(1, -1, -1)
-        return t
-
-    def hf_lr(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.lr_mat)
-        return t
-
-    def hf_rl(self):
-        t = vtkTransform()
-        t.Concatenate(self.hf_mat)
-        t.Concatenate(self.rl_mat)
-        return t
-
-    def get(self, order):
-        """
-        Returns the vtkTransform corresponding to the slice order.
-
-        :param order: The slice order
-        :return: The vtkTransform to use
-        """
-        if order == 'si':
-            return self.s_i()
-        elif order == 'is':
-            return self.i_s()
-        elif order == 'ap':
-            return self.a_p()
-        elif order == 'pa':
-            return self.p_a()
-        elif order == 'lr':
-            return self.l_r()
-        elif order == 'rl':
-            return self.r_l()
-        elif order == 'hf':
-            return self.h_f()
-        elif order == 'hfsi':
-            return self.hf_si()
-        elif order == 'hfis':
-            return self.hf_is()
-        elif order == 'hfap':
-            return self.hf_ap()
-        elif order == 'hfpa':
-            return self.hf_pa()
-        elif order == 'hflr':
-            return self.hf_lr()
-        elif order == 'hfrl':
-            return self.hf_rl()
-        else:
-            s = 'No such transform "{:s}" exists.'.format(order)
-            raise Exception(s)
-
-
-def default_parameters():
-    p = dict()
-    p['NAME'] = ''
-    p['TISSUE'] = '1'
-    p['START_SLICE'] = '0'
-    p['END_SLICE'] = '255'
-    p['STUDY'] = 'frogtissue'
-    p['VALUE'] = 127.5
-    p['ROWS'] = 470
-    p['COLUMNS'] = 500
-    p['HEADER_SIZE'] = 0
-    p['PIXEL_SIZE'] = 1
-    p['SPACING'] = 1.5
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 138
-    p['REDUCTION'] = 1
-    p['FEATURE_ANGLE'] = 60
-    p['DECIMATE_ANGLE'] = 60
-    p['SMOOTH_ANGLE'] = 60
-    p['SMOOTH_ITERATIONS'] = 10
-    p['SMOOTH_FACTOR'] = 0.1
-    p['DECIMATE_ITERATIONS'] = 1
-    p['DECIMATE_REDUCTION'] = 1
-    p['DECIMATE_ERROR'] = 0.0002
-    p['DECIMATE_ERROR_INCREMENT'] = 0.0002
-    p['ISLAND_AREA'] = 4
-    p['ISLAND_REPLACE'] = -1
-    p['GAUSSIAN_STANDARD_DEVIATION'] = [2, 2, 2]
-    p['GAUSSIAN_RADIUS_FACTORS'] = [2, 2, 2]
-    p['VOI'] = [0, p['COLUMNS'] - 1, 0, p['ROWS'] - 1, 0, p['END_SLICE']]
-    p['SAMPLE_RATE'] = [1, 1, 1]
-    p['OPACITY'] = 1.0
-    return p
-
-
-def blood():
-    p = frog()
-    p['NAME'] = 'blood'
-    p['TISSUE'] = 1
-    p['START_SLICE'] = 14
-    p['END_SLICE'] = 131
-    p['VALUE'] = 4
-    p['VOI'] = [33, 406, 62, 425, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def brain():
-    p = frog()
-    p['NAME'] = 'brain'
-    p['TISSUE'] = 2
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 33
-    p['VOI'] = [349, 436, 211, 252, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def brainbin():
-    p = frog()
-    p['NAME'] = 'brainbin'
-    p['TISSUE'] = 2
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 33
-    p['VOI'] = [349, 436, 211, 252, p['END_SLICE'], p['START_SLICE']]
-    p['GAUSSIAN_STANDARD_DEVIATION'] = [0, 0, 0]
-    p['DECIMATE_ITERATIONS'] = 0
-    return p
-
-
-def duodenum():
-    p = frog()
-    p['NAME'] = 'duodenum'
-    p['TISSUE'] = 3
-    p['START_SLICE'] = 35
-    p['END_SLICE'] = 105
-    p['VOI'] = [189, 248, 191, 284, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def eye_retna():
-    p = frog()
-    p['NAME'] = 'eye_retna'
-    p['TISSUE'] = 4
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 41
-    p['VOI'] = [342, 438, 180, 285, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def eye_white():
-    p = frog()
-    p['NAME'] = 'eye_white'
-    p['TISSUE'] = 5
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 37
-    p['VOI'] = [389, 433, 183, 282, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def frog():
-    p = default_parameters()
-    p['ROWS'] = 470
-    p['COLUMNS'] = 500
-    p['STUDY'] = 'frogtissue'
-    p['SLICE_ORDER'] = 'si'
-    p['PIXEL_SIZE'] = 1
-    p['SPACING'] = 1.5
-    p['VALUE'] = 127.5
-    p['SAMPLE_RATE'] = [1, 1, 1]
-    p['GAUSSIAN_STANDARD_DEVIATION'] = [2, 2, 2]
-    p['DECIMATE_REDUCTION'] = 0.95
-    p['DECIMATE_ITERATIONS'] = 5
-    p['DECIMATE_ERROR'] = 0.0002
-    p['DECIMATE_ERROR_INCREMENT'] = 0.0002
-    p['SMOOTH_FACTOR'] = 0.1
-    return p
-
-
-def heart():
-    p = frog()
-    p['NAME'] = 'heart'
-    p['TISSUE'] = 6
-    p['START_SLICE'] = 49
-    p['END_SLICE'] = 93
-    p['VOI'] = [217, 299, 186, 266, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def ileum():
-    p = frog()
-    p['NAME'] = 'ileum'
-    p['TISSUE'] = 7
-    p['START_SLICE'] = 25
-    p['END_SLICE'] = 93
-    p['VOI'] = [172, 243, 201, 290, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def kidney():
-    p = frog()
-    p['NAME'] = 'kidney'
-    p['TISSUE'] = 8
-    p['START_SLICE'] = 24
-    p['END_SLICE'] = 78
-    p['VOI'] = [116, 238, 193, 263, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def l_intestine():
-    p = frog()
-    p['NAME'] = 'l_intestine'
-    p['TISSUE'] = 9
-    p['START_SLICE'] = 56
-    p['END_SLICE'] = 106
-    p['VOI'] = [115, 224, 209, 284, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def liver():
-    p = frog()
-    p['NAME'] = 'liver'
-    p['TISSUE'] = 10
-    p['START_SLICE'] = 25
-    p['END_SLICE'] = 126
-    p['VOI'] = [167, 297, 154, 304, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def lung():
-    p = frog()
-    p['NAME'] = 'lung'
-    p['TISSUE'] = 11
-    p['START_SLICE'] = 24
-    p['END_SLICE'] = 59
-    p['VOI'] = [222, 324, 157, 291, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def nerve():
-    p = frog()
-    p['NAME'] = 'nerve'
-    p['TISSUE'] = 12
-    p['START_SLICE'] = 7
-    p['END_SLICE'] = 113
-    p['VOI'] = [79, 403, 63, 394, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def skin():
-    p = default_parameters()
-    p['NAME'] = 'skin'
-    p['TISSUE'] = 0
-    p['ROWS'] = 470
-    p['COLUMNS'] = 500
-    p['STUDY'] = 'frog'
-    p['SLICE_ORDER'] = 'si'
-    p['PIXEL_SIZE'] = 1
-    p['SPACING'] = 1.5
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 138
-    p['VOI'] = [0, 499, 0, 469, p['START_SLICE'], p['END_SLICE']]
-    p['VALUE'] = 10.5
-    p['SAMPLE_RATE'] = [2, 2, 1]
-    p['DECIMATE_REDUCTION'] = 0.95
-    p['DECIMATE_ITERATIONS'] = 10
-    p['DECIMATE_ERROR'] = 0.0002
-    p['DECIMATE_ERROR_INCREMENT'] = 0.0002
-    p['FEATURE_ANGLE'] = 60
-    p['OPACITY'] = 0.4
-    return p
-
-
-def skeleton():
-    p = frog()
-    p['STUDY'] = 'frogtissue'
-    p['NAME'] = 'skeleton'
-    p['TISSUE'] = 13
-    p['VALUE'] = 64.5
-    p['START_SLICE'] = 1
-    p['END_SLICE'] = 136
-    p['VOI'] = [23, 479, 8, 469, p['START_SLICE'], p['END_SLICE']]
-    p['GAUSSIAN_STANDARD_DEVIATION'] = [1.5, 1.5, 1]
-    return p
-
-
-def spleen():
-    p = frog()
-    p['NAME'] = 'spleen'
-    p['TISSUE'] = 14
-    p['START_SLICE'] = 45
-    p['END_SLICE'] = 68
-    p['VOI'] = [166, 219, 195, 231, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def stomach():
-    p = frog()
-    p['NAME'] = 'stomach'
-    p['TISSUE'] = 15
-    p['START_SLICE'] = 26
-    p['END_SLICE'] = 119
-    p['VOI'] = [143, 365, 158, 297, p['START_SLICE'], p['END_SLICE']]
-    return p
-
-
-def tissue_parameters():
-    t = dict()
-    t['blood'] = blood()
-    t['brain'] = brain()
-    t['brainbin'] = brainbin()
-    t['duodenum'] = duodenum()
-    t['eye_retna'] = eye_retna()
-    t['eye_white'] = eye_white()
-    t['frog'] = frog()
-    t['heart'] = heart()
-    t['ileum'] = ileum()
-    t['kidney'] = kidney()
-    t['l_intestine'] = l_intestine()
-    t['liver'] = liver()
-    t['lung'] = lung()
-    t['nerve'] = nerve()
-    t['skin'] = skin()
-    t['skeleton'] = skeleton()
-    t['spleen'] = spleen()
-    t['stomach'] = stomach()
-
-    return t
-
-
-def create_frog_lut(colors):
-    lut = vtkLookupTable()
-    lut.SetNumberOfColors(16)
-    lut.SetTableRange(0, 15)
-    lut.Build()
-
-    lut.SetTableValue(0, colors.GetColor4d('LimeGreen'))  # skin
-    lut.SetTableValue(1, colors.GetColor4d('salmon'))  # blood
-    lut.SetTableValue(2, colors.GetColor4d('beige'))  # brain
-    lut.SetTableValue(3, colors.GetColor4d('orange'))  # duodenum
-    lut.SetTableValue(4, colors.GetColor4d('misty_rose'))  # eye_retina
-    lut.SetTableValue(5, colors.GetColor4d('white'))  # eye_white
-    lut.SetTableValue(6, colors.GetColor4d('tomato'))  # heart
-    lut.SetTableValue(7, colors.GetColor4d('raspberry'))  # ileum
-    lut.SetTableValue(8, colors.GetColor4d('banana'))  # kidney
-    lut.SetTableValue(9, colors.GetColor4d('peru'))  # l_intestine
-    lut.SetTableValue(10, colors.GetColor4d('pink'))  # liver
-    lut.SetTableValue(11, colors.GetColor4d('powder_blue'))  # lung
-    lut.SetTableValue(12, colors.GetColor4d('carrot'))  # nerve
-    lut.SetTableValue(13, colors.GetColor4d('wheat'))  # skeleton
-    lut.SetTableValue(14, colors.GetColor4d('violet'))  # spleen
-    lut.SetTableValue(15, colors.GetColor4d('plum'))  # stomach
-
-    return lut
-
-
-def check_for_required_parameters(tissue, parameters):
-    required = {'NAME', 'END_SLICE', 'TISSUE', 'STUDY', 'ROWS',
-                'COLUMNS', 'VALUE', 'SPACING',
-                'GAUSSIAN_STANDARD_DEVIATION', 'VOI',
-                'DECIMATE_ITERATIONS'}
-    k = set(parameters.keys())
-    s = None
-    if len(k) == 0:
-        s = 'Missing parameters for {:11s}: {:s}'.format(tissue, ', '.join(map(str, required)))
-    else:
-        d = required.difference(k)
-        if d:
-            s = 'Missing parameters for {:11s}: {:s}'.format(tissue, ', '.join(map(str, d)))
-    return s
-
-
-def format_timings(ict):
-    res = list()
-    total = 0
-    sk = sorted(ict.keys())
-    for k in sk:
-        sigma = 0
-        res.append('{:11s}'.format(k))
-        skk = sorted(ict[k].keys())
-        for kk in skk:
-            sigma += ict[k][kk]
-            res.append('{:11s}{:13s} {:5.2f}s'.format(' ', kk, ict[k][kk]))
-        total += sigma
-        res.append('Subtotal: {:5.2f}s'.format(sigma))
-    res.append('   Total: {:5.2f}s'.format(total))
-    return res
-
-
-if __name__ == '__main__':
-    import sys
-
-    data_folder, tissue, view, flying_edges, decimate = get_program_parameters(sys.argv)
-    main(data_folder, tissue, view, flying_edges, decimate)
diff --git a/src/Python/Visualization/FroggieSurface.md b/src/Python/Visualization/FroggieSurface.md
new file mode 100644
index 0000000000000000000000000000000000000000..fb9b119a9d89565ee1b0e8ce7c79e3dc90c29c47
--- /dev/null
+++ b/src/Python/Visualization/FroggieSurface.md
@@ -0,0 +1,43 @@
+### Description
+
+Frog organs along with a translucent skin are reconstructed from the original segmented data.
+
+By default the frog is oriented so that we look down on the dorsal (posterior) surface and the superior surface faces the top of the screen. The frog is rendered with the skin being translucent so that you can see the internal organs.
+
+In the lower left of the image there is a prop assembly with labelled XYZ axes and a cube labelled with anatomical orientations:
+
+- **Sagittal plane**
+  - L - left
+  - R - right
+- **Coronal plane**
+  - A - anterior
+  - P - posterior
+- **Transverse plane**
+  - S - superior  
+  - I - inferior
+
+This prop assembly can be moved and resized.
+
+Individual tissues can be specified by using the "**-t**" option e.g. "**-t skin skeleton**".
+
+We use vtkFlyingEdges3D to take the 3D structured point set and generate the iso-surfaces. However, if desired, you can specify vtkMarchingCubes instead, use the option "**-m**".
+
+The parameters used to generate the example image are loaded from a JSON file containing the data needed to access and generate the actors for each tissue along with other supplementary data such as the data file names. This means that the user need only load this one file in order to generate the data for rendering. This file is called:
+
+``` text
+<DATA>/Frog_mhd.json
+```
+
+Where `<DATA>` is the path to `?vtk-?examples/src/Testing/Data`.
+
+For information about the parameters in the JSON file, please see [Frog_mhd_format](../../Documentation/Frog_mhd_format.md).
+
+The code uses a general way of specifying transformations that can permute image and other geometric data in order to maintain proper orientation regardless of the acquisition order. See the class **SliceOrder**.
+
+The dataset was prepared at the Lawrence Berkeley National Laboratories and is included with their permission. The data was acquired by physically slicing the frog and photographing the slices. The original segmented data is in the form of tissue masks with one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500 pixels.
+
+To accommodate the volume readers in VTK, the mask files were processed and combined into one vtkMetaImageReader file, called 'frogtissue.mhd'. Integer numbers 1-15 are used to represent the 15 tissues. A similar process was done for the frog skin with the result being stored in a file called 'frog.mhd'.
+
+
+!!! info
+    Mutually exclusive options "***-a, -b, -c, -d**" are provided to let you generate approximations to the following figures: [Figure 12-9a](../../../VTKBook/12Chapter12/#Figure%2012-9a), [Figure 12-9b](../../../VTKBook/12Chapter12/#Figure%2012-9b), [Figure 12-9c](../../../VTKBook/12Chapter12/#Figure%2012-9c), and [Figure 12-9d](../../../VTKBook/12Chapter12/#Figure%2012-9d) in [Chapter 12](../../../VTKBook/12Chapter12) of the [VTK Textbook](../../../VTKBook/01Chapter1).
diff --git a/src/Python/Visualization/FroggieSurface.py b/src/Python/Visualization/FroggieSurface.py
new file mode 100755
index 0000000000000000000000000000000000000000..1d32e96351f63be338f267119a705dcfe95934a2
--- /dev/null
+++ b/src/Python/Visualization/FroggieSurface.py
@@ -0,0 +1,747 @@
+#!/usr/bin/env python3
+
+import copy
+import json
+from pathlib import Path
+
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkInteractionStyle
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingOpenGL2
+from vtkmodules.vtkCommonColor import vtkNamedColors
+from vtkmodules.vtkCommonCore import vtkLookupTable
+from vtkmodules.vtkCommonMath import vtkMatrix4x4
+from vtkmodules.vtkCommonTransforms import vtkTransform
+from vtkmodules.vtkFiltersCore import (
+    vtkDecimatePro,
+    vtkFlyingEdges3D,
+    vtkMarchingCubes,
+    vtkPolyDataNormals,
+    vtkStripper,
+    vtkWindowedSincPolyDataFilter
+)
+from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter
+from vtkmodules.vtkIOImage import vtkMetaImageReader
+from vtkmodules.vtkImagingCore import (
+    vtkImageShrink3D,
+    vtkImageThreshold
+)
+from vtkmodules.vtkImagingGeneral import vtkImageGaussianSmooth
+from vtkmodules.vtkImagingMorphological import vtkImageIslandRemoval2D
+from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
+from vtkmodules.vtkInteractionWidgets import (
+    vtkCameraOrientationWidget,
+    vtkOrientationMarkerWidget
+)
+from vtkmodules.vtkRenderingAnnotation import (
+    vtkAnnotatedCubeActor,
+    vtkAxesActor
+)
+from vtkmodules.vtkRenderingCore import (
+    vtkActor,
+    vtkPolyDataMapper,
+    vtkPropAssembly,
+    vtkRenderWindow,
+    vtkRenderWindowInteractor,
+    vtkRenderer
+)
+
+
+def get_program_parameters(argv):
+    import argparse
+    description = 'Display all frog parts and translucent skin.'
+    epilogue = '''
+All the tissues (except brainbin) are used by default.
+
+-t allows you to specify selected tissues
+Note:
+   If you want to use brainbin (the brain with no gaussian smoothing),
+    instead of brain, then request it with -t brainbin
+    '''
+    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
+                                     formatter_class=argparse.RawDescriptionHelpFormatter)
+
+    group = parser.add_mutually_exclusive_group()
+    group.add_argument('-a', action='store_const', dest='view', const='a',
+                       help='The view corresponds to Fig 12-9a in the VTK Textbook')
+    group.add_argument('-b', action='store_const', dest='view', const='b',
+                       help='The view corresponds to Fig 12-9b in the VTK Textbook')
+    group.add_argument('-c', action='store_const', dest='view', const='c',
+                       help='The view corresponds to Fig 12-9c in the VTK Textbook')
+    group.add_argument('-d', action='store_const', dest='view', const='d',
+                       help='The view corresponds to Fig 12-9d in the VTK Textbook')
+    parser.set_defaults(type=None)
+
+    parser.add_argument('file_name', help='The path to the JSON file e.g. Frog_mhd.json.')
+    parser.add_argument('-t', nargs='+', dest='tissues', action='append', help='Select one or more tissues.')
+    parser.add_argument('-m', action='store_false', dest='flying_edges',
+                        help='Use flying edges by default, marching cubes if set.')
+    # -o: obliterate a synonym for decimation.
+    parser.add_argument('-o', action='store_true', dest='decimation', help='Decimate if set.')
+    args = parser.parse_args()
+    return args.file_name, args.view, args.tissues, args.flying_edges, args.decimation
+
+
+def main(fn, select_figure, chosen_tissues, flying_edges, decimate):
+    fn_path = Path(fn)
+    if not fn_path.suffix:
+        fn_path = fn_path.with_suffix(".json")
+    if not fn_path.is_file():
+        print('Unable to find: ', fn_path)
+    parsed_ok, parameters = parse_json(fn_path)
+    if not parsed_ok:
+        print('Unable to parse the JSON file.')
+        return
+
+    tissues = list()
+    indices = dict()
+    for n in parameters['names']:
+        if n != 'brainbin':
+            tissues.append(n)
+            indices[n] = parameters[n]['tissue']
+    color_lut = create_tissue_lut(indices, parameters['colors'])
+
+    if select_figure:
+        if select_figure == 'b':
+            # No skin.
+            tissues = parameters['fig12-9b']
+        if select_figure in ['c', 'd']:
+            # No skin, blood and skeleton.
+            tissues = parameters['fig12-9cd']
+
+    if chosen_tissues:
+        chosen_tissues = [x.lower() for x in chosen_tissues[0]]
+        res = list()
+        has_brainbin = False
+        if 'brainbin' in chosen_tissues:
+            print('Using brainbin instead of brain.')
+            res.append('brainbin')
+            indices.pop('brain', None)
+            indices['brainbin'] = 2
+            parameters['colors'].pop('brain', None)
+            parameters['colors']['brainbin'] = 'beige'
+            has_brainbin = True
+        for ct in chosen_tissues:
+            if has_brainbin and ct in ['brain', 'brainbin']:
+                continue
+            if ct in tissues:
+                res.append(ct)
+            else:
+                print(f'Tissue: {ct} is not available.')
+                print(f'Available tissues are: {", ".join(tissues)} and brainbin')
+                return
+        if len(res) == 1 and 'skin' in res:
+            parameters['skin']['opacity'] = 1.0
+        tissues = res
+
+    colors = vtkNamedColors()
+    colors.SetColor("ParaViewBkg", [82, 87, 110, 255])
+
+    # Setup render window, renderer, and interactor.
+    ren = vtkRenderer()
+    ren_win = vtkRenderWindow()
+    ren_win.AddRenderer(ren)
+    iren = vtkRenderWindowInteractor()
+    iren.SetRenderWindow(ren_win)
+    style = vtkInteractorStyleTrackballCamera()
+    iren.SetInteractorStyle(style)
+
+    color_size = len(max(parameters['colors'].values(), key=len))
+    name_size = len(max(parameters['names'], key=len))
+    int_size = 2
+    line = '-' * (7 + name_size + color_size)
+    res = [line,
+           f'{"Tissue":<{name_size}s}{" Label "}{"Color"}',
+           line]
+
+    so = SliceOrder()
+
+    for name in tissues:
+        actor = create_tissue_actor(name, parameters[name], parameters['mhd_files'], flying_edges, decimate,
+                                    color_lut, so)
+        ren.AddActor(actor)
+        res.append(f'{name:<{name_size}s} {indices[name]:{int_size + 3}d} {parameters["colors"][name]:<{color_size}s}')
+
+    res.append(line)
+    print('\n'.join(res))
+
+    ren_win.SetSize(1024, 1024)
+    ren_win.SetWindowName('FroggieSurface')
+
+    ren.SetBackground(colors.GetColor3d('ParaViewBkg'))
+
+    #  Final view
+    camera = ren.GetActiveCamera()
+    if select_figure:
+        if select_figure == 'a':
+            # Fig 12-9a in the VTK Textbook
+            camera.SetPosition(742.731237, -441.329635, -877.192015)
+            camera.SetFocalPoint(247.637687, 120.680880, -253.487473)
+            camera.SetViewUp(-0.323882, -0.816232, 0.478398)
+            camera.SetDistance(974.669585)
+            camera.SetClippingRange(311.646383, 1803.630763)
+        elif select_figure == 'b':
+            # Fig 12-9b in the VTK Textbook
+            camera.SetPosition(717.356065, -429.889054, -845.381584)
+            camera.SetFocalPoint(243.071719, 100.996487, -247.446340)
+            camera.SetViewUp(-0.320495, -0.820148, 0.473962)
+            camera.SetDistance(929.683631)
+            camera.SetClippingRange(293.464446, 1732.794957)
+        elif select_figure == 'c':
+            # Fig 12-9c in the VTK Textbook
+            camera.SetPosition(447.560023, -136.611491, -454.753689)
+            camera.SetFocalPoint(253.142277, 91.949451, -238.583973)
+            camera.SetViewUp(-0.425438, -0.786048, 0.448477)
+            camera.SetDistance(369.821187)
+            camera.SetClippingRange(0.829116, 829.115939)
+        elif select_figure == 'd':
+            # Fig 12-9d in the VTK Textbook
+            camera.SetPosition(347.826249, -469.633647, -236.234262)
+            camera.SetFocalPoint(296.893207, 89.307704, -225.156581)
+            camera.SetViewUp(-0.687345, -0.076948, 0.722244)
+            camera.SetDistance(561.366478)
+            camera.SetClippingRange(347.962064, 839.649856)
+    else:
+        # Orient so that we look down on the dorsal surface and
+        #   the superior surface faces the top of the screen.
+        transform = vtkTransform()
+        transform.SetMatrix(camera.GetModelTransformMatrix())
+        transform.RotateY(-90)
+        transform.RotateZ(90)
+        camera.SetModelTransformMatrix(transform.GetMatrix())
+        ren.ResetCamera()
+
+    if select_figure:
+        # Superior Anterior Left
+        labels = 'sal'
+    else:
+        # Right Superior Posterior
+        labels = 'rsp'
+
+    cow = vtkCameraOrientationWidget()
+    cow.SetParentRenderer(ren)
+    # Turn off if you do not want it.
+    cow.On()
+    cow.EnabledOn()
+
+    axes = make_cube_actor(labels, colors)
+    om = vtkOrientationMarkerWidget()
+    om.SetOrientationMarker(axes)
+    # Position upper left in the viewport.
+    # om.SetViewport(0.0, 0.8, 0.2, 1.0)
+    # Position lower left in the viewport.
+    om.SetViewport(0, 0, 0.2, 0.2)
+    om.SetInteractor(iren)
+    om.EnabledOn()
+    om.InteractiveOn()
+
+    ren_win.Render()
+
+    iren.Start()
+
+
+def parse_json(fn_path):
+    """
+    Parse the JSON file selecting the components that we want.
+
+    We also check that the file paths are valid.
+
+    :param fn_path: The path the JSON file.
+    :return: A dictionary of the parameters that we require.
+    """
+    with open(fn_path) as data_file:
+        json_data = json.load(data_file)
+    paths_ok = True
+    parameters = dict()
+    # The names of the tissues as a list.
+    parameters['names'] = list()
+    for k, v in json_data.items():
+        if k == 'files':
+            if 'root' in v:
+                root = Path(v['root'])
+                if not root.exists():
+                    print(f'Bad path: {root}')
+                    paths_ok = False
+                else:
+                    if 'mhd_files' not in v:
+                        print('Expected mhd files.')
+                        paths_ok = False
+                        continue
+                    for kk in v:
+                        if kk == 'mhd_files':
+                            if len(v[kk]) != 2:
+                                print(f'Expected two file names.')
+                                paths_ok = False
+                            # The stem of the file path becomes the key.
+                            path_map = dict()
+                            for p in list(map(lambda pp: root / pp, v[kk])):
+                                path_map[p.stem] = p
+                                if not p.is_file():
+                                    paths_ok = False
+                                    print(f'Not a file {p}')
+                            if paths_ok:
+                                parameters[kk] = path_map
+            else:
+                paths_ok = False
+                print('Missing the key "root" and/or the key "files" for the files.')
+        else:
+            if k in ['tissues', 'figures']:
+                for kk, vv in v.items():
+                    parameters[kk] = vv
+            if k == "tissue_parameters":
+                # Assemble the parameters for each tissue.
+                # Create the base parameters.
+                bp = dict()
+                for kk, vv in v['default'].items():
+                    bp[kk.lower()] = vv
+                frog = copy.deepcopy(bp)
+                for kk, vv in v['frog'].items():
+                    frog[kk.lower()] = vv
+                for kk, vv in v.items():
+                    if kk not in ['default', 'frog', 'parameter types']:
+                        if kk == 'skin':
+                            parameters[kk] = copy.deepcopy(bp)
+                        else:
+                            parameters[kk] = copy.deepcopy(frog)
+                        for kkk, vvv in vv.items():
+                            parameters[kk][kkk.lower()] = vvv
+                            if kkk == 'NAME':
+                                parameters['names'].append(vvv)
+    return paths_ok, parameters
+
+
+def create_tissue_actor(name, tissue, files, flying_edges, decimate, lut, so):
+    """
+    Create the actor for a specific tissue.
+
+    :param name: The tissue name.
+    :param tissue: The tissue parameters.
+    :param files: The path to the tissue files.
+    :param flying_edges: If true use flying edges.
+    :param decimate: If true decimate.
+    :param lut: The color lookup table for the tissues.
+    :param so: The transforms corresponding to the slice order.
+    :return: The actor.
+    """
+
+    pixel_size = tissue['pixel_size']
+    spacing = tissue['spacing']
+    start_slice = tissue['start_slice']
+    data_spacing = [pixel_size, pixel_size, spacing]
+    columns = tissue['columns']
+    rows = tissue['rows']
+    data_origin = [-(columns / 2.0) * pixel_size, -(rows / 2.0) * pixel_size, start_slice * spacing]
+
+    voi = [
+        tissue['start_column'],
+        tissue['end_column'],
+        tissue['start_row'],
+        tissue['end_row'],
+        tissue['start_slice'],
+        tissue['end_slice'],
+    ]
+    # Adjust y bounds for PNM coordinate system.
+    tmp = voi[2]
+    voi[2] = rows - voi[3] - 1
+    voi[3] = rows - tmp - 1
+
+    if name == 'skin':
+        fn = files['frog']
+    else:
+        fn = files['frogtissue']
+
+    reader = vtkMetaImageReader()
+    reader.SetFileName(str(fn))
+    reader.SetDataSpacing(data_spacing)
+    reader.SetDataOrigin(data_origin)
+    reader.SetDataExtent(voi)
+    reader.Update()
+
+    last_connection = reader
+
+    if not name == 'skin':
+        if tissue['island_replace'] >= 0:
+            island_remover = vtkImageIslandRemoval2D()
+            island_remover.SetAreaThreshold(tissue['island_area'])
+            island_remover.SetIslandValue(tissue['island_replace'])
+            island_remover.SetReplaceValue(tissue['tissue'])
+            island_remover.SetInput(last_connection.GetOutput())
+            island_remover.Update()
+            last_connection = island_remover
+
+        select_tissue = vtkImageThreshold()
+        select_tissue.ThresholdBetween(tissue['tissue'], tissue['tissue'])
+        select_tissue.SetInValue(255)
+        select_tissue.SetOutValue(0)
+        select_tissue.SetInputConnection(last_connection.GetOutputPort())
+        last_connection = select_tissue
+
+    sample_rate = [
+        tissue['sample_rate_column'],
+        tissue['sample_rate_row'],
+        tissue['sample_rate_slice'],
+    ]
+
+    shrinker = vtkImageShrink3D()
+    shrinker.SetInputConnection(last_connection.GetOutputPort())
+    shrinker.SetShrinkFactors(sample_rate)
+    shrinker.AveragingOn()
+    last_connection = shrinker
+
+    gsd = [
+        tissue['gaussian_standard_deviation_column'],
+        tissue['gaussian_standard_deviation_row'],
+        tissue['gaussian_standard_deviation_slice'],
+    ]
+
+    if not all(v == 0 for v in gsd):
+        grf = [
+            tissue['gaussian_radius_factor_column'],
+            tissue['gaussian_radius_factor_row'],
+            tissue['gaussian_radius_factor_slice'],
+        ]
+
+        gaussian = vtkImageGaussianSmooth()
+        gaussian.SetStandardDeviation(*gsd)
+        gaussian.SetRadiusFactors(*grf)
+        gaussian.SetInputConnection(shrinker.GetOutputPort())
+        last_connection = gaussian
+
+    iso_value = tissue['value']
+    if flying_edges:
+        iso_surface = vtkFlyingEdges3D()
+        iso_surface.SetInputConnection(last_connection.GetOutputPort())
+        iso_surface.ComputeScalarsOff()
+        iso_surface.ComputeGradientsOff()
+        iso_surface.ComputeNormalsOff()
+        iso_surface.SetValue(0, iso_value)
+        iso_surface.Update()
+    else:
+        iso_surface = vtkMarchingCubes()
+        iso_surface.SetInputConnection(last_connection.GetOutputPort())
+        iso_surface.ComputeScalarsOff()
+        iso_surface.ComputeGradientsOff()
+        iso_surface.ComputeNormalsOff()
+        iso_surface.SetValue(0, iso_value)
+        iso_surface.Update()
+
+    transform = so.get(tissue['slice_order'])
+    tf = vtkTransformPolyDataFilter()
+    tf.SetTransform(transform)
+    tf.SetInputConnection(iso_surface.GetOutputPort())
+    last_connection = tf
+
+    if decimate:
+        decimator = vtkDecimatePro()
+        decimator.SetInputConnection(last_connection.GetOutputPort())
+        decimator.SetFeatureAngle(tissue['decimate_angle'])
+        decimator.PreserveTopologyOn()
+        decimator.SetErrorIsAbsolute(1)
+        decimator.SetAbsoluteError(tissue['decimate_error'])
+        decimator.SetTargetReduction(tissue['decimate_reduction'])
+        last_connection = decimator
+
+    smoother = vtkWindowedSincPolyDataFilter()
+    smoother.SetInputConnection(last_connection.GetOutputPort())
+    smoother.SetNumberOfIterations(tissue['smooth_iterations'])
+    smoother.BoundarySmoothingOff()
+    smoother.FeatureEdgeSmoothingOff()
+    smoother.SetFeatureAngle(tissue['smooth_angle'])
+    smoother.SetPassBand(tissue['smooth_factor'])
+    smoother.NonManifoldSmoothingOn()
+    smoother.NormalizeCoordinatesOff()
+    smoother.Update()
+
+    normals = vtkPolyDataNormals()
+    normals.SetInputConnection(smoother.GetOutputPort())
+    normals.SetFeatureAngle(tissue['feature_angle'])
+
+    stripper = vtkStripper()
+    stripper.SetInputConnection(normals.GetOutputPort())
+
+    mapper = vtkPolyDataMapper()
+    mapper.SetInputConnection(stripper.GetOutputPort())
+
+    actor = vtkActor()
+    actor.SetMapper(mapper)
+    actor.GetProperty().SetOpacity(tissue['opacity'])
+    actor.GetProperty().SetDiffuseColor(lut.GetTableValue(tissue['tissue'])[:3])
+    actor.GetProperty().SetSpecular(0.5)
+    actor.GetProperty().SetSpecularPower(10)
+
+    return actor
+
+
+class SliceOrder:
+    """
+    These transformations permute image and other geometric data to maintain proper
+     orientation regardless of the acquisition order. After applying these transforms with
+    vtkTransformFilter, a view up of 0, -1, 0 will result in the body part
+    facing the viewer.
+    NOTE: some transformations have a -1 scale factor for one of the components.
+          To ensure proper polygon orientation and normal direction, you must
+          apply the vtkPolyDataNormals filter.
+
+    Naming (the nomenclature is medical):
+    si - superior to inferior (top to bottom)
+    is - inferior to superior (bottom to top)
+    ap - anterior to posterior (front to back)
+    pa - posterior to anterior (back to front)
+    lr - left to right
+    rl - right to left
+    """
+
+    def __init__(self):
+        self.si_mat = vtkMatrix4x4()
+        self.si_mat.Zero()
+        self.si_mat.SetElement(0, 0, 1)
+        self.si_mat.SetElement(1, 2, 1)
+        self.si_mat.SetElement(2, 1, -1)
+        self.si_mat.SetElement(3, 3, 1)
+
+        self.is_mat = vtkMatrix4x4()
+        self.is_mat.Zero()
+        self.is_mat.SetElement(0, 0, 1)
+        self.is_mat.SetElement(1, 2, -1)
+        self.is_mat.SetElement(2, 1, -1)
+        self.is_mat.SetElement(3, 3, 1)
+
+        self.lr_mat = vtkMatrix4x4()
+        self.lr_mat.Zero()
+        self.lr_mat.SetElement(0, 2, -1)
+        self.lr_mat.SetElement(1, 1, -1)
+        self.lr_mat.SetElement(2, 0, 1)
+        self.lr_mat.SetElement(3, 3, 1)
+
+        self.rl_mat = vtkMatrix4x4()
+        self.rl_mat.Zero()
+        self.rl_mat.SetElement(0, 2, 1)
+        self.rl_mat.SetElement(1, 1, -1)
+        self.rl_mat.SetElement(2, 0, 1)
+        self.rl_mat.SetElement(3, 3, 1)
+
+        """
+        The previous transforms assume radiological views of the slices
+         (viewed from the feet).
+        Other modalities such as physical sectioning may view from the head.
+        The following transforms modify the original with a 180° rotation about y
+        """
+
+        self.hf_mat = vtkMatrix4x4()
+        self.hf_mat.Zero()
+        self.hf_mat.SetElement(0, 0, -1)
+        self.hf_mat.SetElement(1, 1, 1)
+        self.hf_mat.SetElement(2, 2, -1)
+        self.hf_mat.SetElement(3, 3, 1)
+
+        self.transform = dict()
+
+        si_trans = vtkTransform()
+        si_trans.SetMatrix(self.si_mat)
+        self.transform['si'] = si_trans
+
+        is_trans = vtkTransform()
+        is_trans.SetMatrix(self.is_mat)
+        self.transform['is'] = is_trans
+
+        ap_trans = vtkTransform()
+        ap_trans.Scale(1, -1, 1)
+        self.transform['ap'] = ap_trans
+
+        pa_trans = vtkTransform()
+        pa_trans.Scale(1, -1, -1)
+        self.transform['pa'] = pa_trans
+
+        lr_trans = vtkTransform()
+        lr_trans.SetMatrix(self.lr_mat)
+        self.transform['lr'] = lr_trans
+
+        rl_trans = vtkTransform()
+        rl_trans.SetMatrix(self.rl_mat)
+        self.transform['rl'] = rl_trans
+
+        hf_trans = vtkTransform()
+        hf_trans.SetMatrix(self.hf_mat)
+        self.transform['hf'] = hf_trans
+
+        hf_si_trans = vtkTransform()
+        hf_si_trans.SetMatrix(self.hf_mat)
+        hf_si_trans.Concatenate(self.si_mat)
+        self.transform['hfsi'] = hf_si_trans
+
+        hf_is_trans = vtkTransform()
+        hf_is_trans.SetMatrix(self.hf_mat)
+        hf_is_trans.Concatenate(self.is_mat)
+        self.transform['hfis'] = hf_is_trans
+
+        hf_ap_trans = vtkTransform()
+        hf_ap_trans.SetMatrix(self.hf_mat)
+        hf_ap_trans.Scale(1, -1, 1)
+        self.transform['hfap'] = hf_ap_trans
+
+        hf_pa_trans = vtkTransform()
+        hf_pa_trans.SetMatrix(self.hf_mat)
+        hf_pa_trans.Scale(1, -1, -1)
+        self.transform['hfpa'] = hf_pa_trans
+
+        hf_lr_trans = vtkTransform()
+        hf_lr_trans.SetMatrix(self.hf_mat)
+        hf_lr_trans.Concatenate(self.lr_mat)
+        self.transform['hflr'] = hf_lr_trans
+
+        hf_rl_trans = vtkTransform()
+        hf_rl_trans.SetMatrix(self.hf_mat)
+        hf_rl_trans.Concatenate(self.rl_mat)
+        self.transform['hfrl'] = hf_rl_trans
+
+    def print_transform(self, order):
+        """
+        Print the homogenous matrix corresponding to the slice order.
+        :param order: The slice order.
+        :return:
+        """
+        print(order)
+        m = self.transform[order].GetMatrix()
+        for i in range(0, 4):
+            row = list()
+            for j in range(0, 4):
+                row.append(f'{m.GetElement(i, j):6.2g}')
+            print(' '.join(row))
+
+    def print_all_transforms(self):
+        """
+        Print all the homogenous matrices corresponding to the slice orders.
+        :return:
+        """
+        for k in self.transform.keys():
+            self.print_transform(k)
+
+    def get(self, order):
+        """
+        Returns the vtkTransform corresponding to the slice order.
+
+        :param order: The slice order.
+        :return: The vtkTransform to use.
+        """
+        if order in self.transform.keys():
+            return self.transform[order]
+        else:
+            s = 'No such transform "{:s}" exists.'.format(order)
+            raise Exception(s)
+
+
+def create_tissue_lut(indices, colors):
+    """
+    Create the lookup table for the frog tissues.
+
+    Each table value corresponds the color of one of the frog tissues.
+
+    :param indices: The tissue name and index.
+    :param colors: The tissue name and color.
+    :return: The lookup table.
+    """
+    lut = vtkLookupTable()
+    lut.SetNumberOfColors(len(colors))
+    lut.SetTableRange(0, len(colors) - 1)
+    lut.Build()
+
+    nc = vtkNamedColors()
+
+    for k in indices.keys():
+        lut.SetTableValue(indices[k], nc.GetColor4d(colors[k]))
+
+    return lut
+
+
+def make_axes_actor(scale, xyz_labels):
+    """
+    :param scale: Sets the scale and direction of the axes.
+    :param xyz_labels: Labels for the axes.
+    :return: The axes actor.
+    """
+    axes = vtkAxesActor()
+    axes.SetScale(scale)
+    axes.SetShaftTypeToCylinder()
+    axes.SetXAxisLabelText(xyz_labels[0])
+    axes.SetYAxisLabelText(xyz_labels[1])
+    axes.SetZAxisLabelText(xyz_labels[2])
+    axes.SetCylinderRadius(0.5 * axes.GetCylinderRadius())
+    axes.SetConeRadius(1.025 * axes.GetConeRadius())
+    axes.SetSphereRadius(1.5 * axes.GetSphereRadius())
+    tprop = axes.GetXAxisCaptionActor2D().GetCaptionTextProperty()
+    tprop.ItalicOn()
+    tprop.ShadowOn()
+    tprop.SetFontFamilyToTimes()
+    # Use the same text properties on the other two axes.
+    axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().ShallowCopy(tprop)
+    axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().ShallowCopy(tprop)
+    return axes
+
+
+def make_annotated_cube_actor(cube_labels, colors):
+    """
+    :param cube_labels: The labels for the cube faces.
+    :param colors: Used to determine the cube color.
+    :return: The annotated cube actor.
+    """
+    # A cube with labeled faces.
+    cube = vtkAnnotatedCubeActor()
+    cube.SetXPlusFaceText(cube_labels[0])
+    cube.SetXMinusFaceText(cube_labels[1])
+    cube.SetYPlusFaceText(cube_labels[2])
+    cube.SetYMinusFaceText(cube_labels[3])
+    cube.SetZPlusFaceText(cube_labels[4])
+    cube.SetZMinusFaceText(cube_labels[5])
+    cube.SetFaceTextScale(0.5)
+    cube.GetCubeProperty().SetColor(colors.GetColor3d('Gainsboro'))
+
+    cube.GetTextEdgesProperty().SetColor(colors.GetColor3d('LightSlateGray'))
+
+    # Change the vector text colors.
+    cube.GetXPlusFaceProperty().SetColor(colors.GetColor3d('Tomato'))
+    cube.GetXMinusFaceProperty().SetColor(colors.GetColor3d('Tomato'))
+    cube.GetYPlusFaceProperty().SetColor(colors.GetColor3d('DeepSkyBlue'))
+    cube.GetYMinusFaceProperty().SetColor(colors.GetColor3d('DeepSkyBlue'))
+    cube.GetZPlusFaceProperty().SetColor(colors.GetColor3d('SeaGreen'))
+    cube.GetZMinusFaceProperty().SetColor(colors.GetColor3d('SeaGreen'))
+    return cube
+
+
+def make_cube_actor(label_selector, colors):
+    """
+    :param label_selector: The selector used to define labels for the axes and cube.
+    :param colors: Used to set the colors of the cube faces.
+    :return: The combined axes and annotated cube prop.
+    """
+    if label_selector == 'sal':
+        # xyz_labels = ['S', 'A', 'L']
+        xyz_labels = ['+X', '+Y', '+Z']
+        cube_labels = ['S', 'I', 'A', 'P', 'L', 'R']
+        scale = [1.5, 1.5, 1.5]
+    elif label_selector == 'rsp':
+        # xyz_labels = ['R', 'S', 'P']
+        xyz_labels = ['+X', '+Y', '+Z']
+        cube_labels = ['R', 'L', 'S', 'I', 'P', 'A']
+        scale = [1.5, 1.5, 1.5]
+    else:
+        xyz_labels = ['+X', '+Y', '+Z']
+        cube_labels = ['+X', '-X', '+Y', '-Y', '+Z', '-Z']
+        scale = [1.5, 1.5, 1.5]
+
+    # We are combining a vtkAxesActor and a vtkAnnotatedCubeActor
+    # into a vtkPropAssembly
+    cube = make_annotated_cube_actor(cube_labels, colors)
+    axes = make_axes_actor(scale, xyz_labels)
+
+    # Combine orientation markers into one with an assembly.
+    assembly = vtkPropAssembly()
+    assembly.AddPart(axes)
+    assembly.AddPart(cube)
+    return assembly
+
+
+if __name__ == '__main__':
+    import sys
+
+    data_folder, view, selected_tissues, use_flying_edges, use_decimate = get_program_parameters(sys.argv)
+    main(data_folder, view, selected_tissues, use_flying_edges, use_decimate)
diff --git a/src/Python/Visualization/FroggieView.md b/src/Python/Visualization/FroggieView.md
new file mode 100644
index 0000000000000000000000000000000000000000..b7509f18fa321ea8b07246f0c21c3c0f491c1195
--- /dev/null
+++ b/src/Python/Visualization/FroggieView.md
@@ -0,0 +1,44 @@
+### Description
+
+Frog organs along with a translucent skin are reconstructed from the original segmented data.
+
+By default the frog is oriented so that we look down on the dorsal (posterior) surface and the superior surface faces the top of the screen. The frog is rendered with the skin being translucent so that you can see the internal organs.
+
+In the lower left of the image there is a prop assembly with labelled XYZ axes and a cube labelled with anatomical orientations:
+
+- **Sagittal plane**
+  - L - left
+  - R - right
+- **Coronal plane**
+  - A - anterior
+  - P - posterior
+- **Transverse plane**
+  - S - superior  
+  - I - inferior
+
+This prop assembly can be moved and resized.
+
+The opacity of eaxh tissue is controlled by a slider, additionally you can turn all the sliders on or off by pressing the "**n**" key.
+
+If the option "**-n**" is selected, no sliders will displayed.
+
+Individual tissues can be specified by using the "**-t**" option e.g. "**-t skin skeleton**".
+
+The parameters used to generate the example image are loaded from a JSON file containing the data needed to access and generate the actors for each tissue along with other supplementary data such as the data file names. This means that the user need only load this one file in order to generate the data for rendering. This file is called:
+
+``` text
+<DATA>/Frog_vtk.json
+```
+
+Where `<DATA>` is the path to `?vtk-?examples/src/Testing/Data`.
+
+For information about the parameters in the JSON file, please see [Frog_vtk_format](../../Documentation/Frog_vtk_format.md).
+
+The code uses a general way of specifying transformations that can permute image and other geometric data in order to maintain proper orientation regardless of the acquisition order. See the class **SliceOrder**.
+
+The dataset was prepared at the Lawrence Berkeley National Laboratories. It is included with their permission. The data was acquired by physically slicing the frog and photographing the slices. The original segmented data is in the form of tissue masks with one file per tissue. There are 136 slices per tissue and 15 different tissues. Each slice is 470 by 500 pixels.
+
+This example uses the `*.vtk` tissue files. These were pre-processed using the original data so that loading is much faster.
+
+!!! info
+    Mutually exclusive options "***-a -b -c -d**" are provided to let you generate approximations to the following figures: [Figure 12-9a](../../../VTKBook/12Chapter12/#Figure%2012-9a), [Figure 12-9b](../../../VTKBook/12Chapter12/#Figure%2012-9b), [Figure 12-9c](../../../VTKBook/12Chapter12/#Figure%2012-9c), and [Figure 12-9d](../../../VTKBook/12Chapter12/#Figure%2012-9d) in [Chapter 12](../../../VTKBook/12Chapter12) of the [VTK Textbook](../../../VTKBook/01Chapter1).
diff --git a/src/Python/Visualization/FroggieView.py b/src/Python/Visualization/FroggieView.py
new file mode 100755
index 0000000000000000000000000000000000000000..02362b0126acb6699498bb592248939966f42c85
--- /dev/null
+++ b/src/Python/Visualization/FroggieView.py
@@ -0,0 +1,740 @@
+#!/usr/bin/env python3
+
+import json
+from pathlib import Path
+
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkInteractionStyle
+# noinspection PyUnresolvedReferences
+import vtkmodules.vtkRenderingOpenGL2
+from vtkmodules.vtkCommonColor import vtkNamedColors
+from vtkmodules.vtkCommonCore import (
+    vtkCommand,
+    vtkLookupTable
+)
+from vtkmodules.vtkCommonMath import vtkMatrix4x4
+from vtkmodules.vtkCommonTransforms import vtkTransform
+from vtkmodules.vtkFiltersCore import vtkPolyDataNormals
+from vtkmodules.vtkFiltersGeneral import vtkTransformPolyDataFilter
+from vtkmodules.vtkIOLegacy import vtkPolyDataReader
+from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
+from vtkmodules.vtkInteractionWidgets import (
+    vtkCameraOrientationWidget,
+    vtkOrientationMarkerWidget,
+    vtkSliderRepresentation2D,
+    vtkSliderWidget
+)
+from vtkmodules.vtkRenderingAnnotation import (
+    vtkAxesActor,
+    vtkAnnotatedCubeActor,
+)
+from vtkmodules.vtkRenderingCore import (
+    vtkActor,
+    vtkPolyDataMapper,
+    vtkPropAssembly,
+    vtkRenderWindow,
+    vtkRenderWindowInteractor,
+    vtkRenderer
+)
+
+
+def get_program_parameters(argv):
+    import argparse
+    description = 'Use sliders to control the display of the frog tissues.'
+    epilogue = '''
+
+The available tissues are:
+    blood brain duodenum eye_retna eye_white heart ileum kidney
+    l_intestine liver lung nerve skeleton spleen stomach skin
+
+All these tissues are used by default.
+
+-t allows you to specify selected tissues
+
+Note:
+   There is an additional tissue called brainbin.
+   This is the brain with no gaussian smoothing.
+   You can use it instead of brain, just request it with -t brainbin
+    '''
+    parser = argparse.ArgumentParser(description=description, epilog=epilogue,
+                                     formatter_class=argparse.RawDescriptionHelpFormatter)
+
+    group = parser.add_mutually_exclusive_group()
+    group.add_argument('-a', action='store_const', dest='view', const='a',
+                       help='The view corresponds to Fig 12-9a in the VTK Textbook')
+    group.add_argument('-b', action='store_const', dest='view', const='b',
+                       help='The view corresponds to Fig 12-9b in the VTK Textbook')
+    group.add_argument('-c', action='store_const', dest='view', const='c',
+                       help='The view corresponds to Fig 12-9c in the VTK Textbook')
+    group.add_argument('-d', action='store_const', dest='view', const='d',
+                       help='The view corresponds to Fig 12-9d in the VTK Textbook')
+    parser.set_defaults(type=None)
+
+    parser.add_argument('file_name', help='The path to the JSON file e.g. Frog_vtk.json.')
+    parser.add_argument('-n', action='store_true', dest='omit_sliders', help='No sliders.')
+    parser.add_argument('-t', nargs='+', dest='tissues', action='append', help='Select one or more tissues.')
+    args = parser.parse_args()
+    return args.file_name, args.view, args.omit_sliders, args.tissues
+
+
+def main(fn, select_figure, no_sliders, chosen_tissues):
+    fn_path = Path(fn)
+    if not fn_path.suffix:
+        fn_path = fn_path.with_suffix(".json")
+    if not fn_path.is_file():
+        print('Unable to find: ', fn_path)
+    parsed_ok, parameters = parse_json(fn_path)
+    if not parsed_ok:
+        print('Unable to parse the JSON file.')
+        return
+
+    color_lut = create_tissue_lut(parameters['indices'], parameters['colors'])
+
+    tissues = parameters['names']
+    if select_figure:
+        if select_figure == 'b':
+            # No skin.
+            tissues = parameters['fig12-9b']
+        if select_figure in ['c', 'd']:
+            # No skin, blood and skeleton.
+            tissues = parameters['fig12-9cd']
+
+    if chosen_tissues:
+        chosen_tissues = [x.lower() for x in chosen_tissues[0]]
+        res = list()
+        has_brainbin = False
+        if 'brainbin' in chosen_tissues:
+            print('Using brainbin instead of brain.')
+            res.append('brainbin')
+            parameters['indices'].pop('brain', None)
+            parameters['indices']['brainbin'] = 2
+            parameters['colors'].pop('brain', None)
+            parameters['colors']['brainbin'] = 'beige'
+            has_brainbin = True
+        for ct in chosen_tissues:
+            if has_brainbin and ct in ['brain', 'brainbin']:
+                continue
+            if ct in tissues:
+                res.append(ct)
+            else:
+                print(f'Tissue: {ct} is not available.')
+                print(f'Available tissues are: {", ".join(tissues)} and brainbin')
+                return
+        if len(res) == 1 and 'skin' in res:
+            parameters['opacity']['skin'] = 1.0
+        tissues = res
+
+    colors = vtkNamedColors()
+    colors.SetColor("ParaViewBkg", [82, 87, 110, 255])
+
+    # Setup render window, renderers, and interactor.
+    ren = vtkRenderer()
+    ren_win = vtkRenderWindow()
+    ren_win.AddRenderer(ren)
+    iren = vtkRenderWindowInteractor()
+    iren.SetRenderWindow(ren_win)
+    style = vtkInteractorStyleTrackballCamera()
+    iren.SetInteractorStyle(style)
+
+    sliders = dict()
+    left_step_size = 1.0 / 9
+    left_pos_y = 0.275
+    left_pos_x0 = 0.02
+    left_pos_x1 = 0.18
+    right_step_size = 1.0 / 9
+    right_pos_y = 0.05
+    right_pos_x0 = 0.8 + 0.02
+    right_pos_x1 = 0.8 + 0.18
+
+    slider_count = 0
+
+    color_size = len(max(parameters['colors'].values(), key=len))
+    name_size = len(max(parameters['names'], key=len))
+    int_size = 2
+    line = '-' * (7 + name_size + color_size)
+    res = [line,
+           f'{"Tissue":<{name_size}s}{" Label "}{"Color"}',
+           line]
+
+    for tissue in tissues:
+        reader = vtkPolyDataReader()
+        reader.SetFileName(parameters['vtk_files'][tissue])
+        reader.Update()
+
+        trans = SliceOrder().get(parameters['orientation'][tissue])
+        trans.Scale(1, -1, -1)
+
+        tf = vtkTransformPolyDataFilter()
+        tf.SetInputConnection(reader.GetOutputPort())
+        tf.SetTransform(trans)
+        tf.SetInputConnection(reader.GetOutputPort())
+
+        normals = vtkPolyDataNormals()
+        normals.SetInputConnection(tf.GetOutputPort())
+        normals.SetFeatureAngle(60.0)
+
+        mapper = vtkPolyDataMapper()
+        mapper.SetInputConnection(normals.GetOutputPort())
+
+        actor = vtkActor()
+        actor.SetMapper(mapper)
+
+        actor.GetProperty().SetOpacity(parameters['opacity'][tissue])
+        actor.GetProperty().SetDiffuseColor(color_lut.GetTableValue(parameters['indices'][tissue])[:3])
+        actor.GetProperty().SetSpecular(0.2)
+        actor.GetProperty().SetSpecularPower(10)
+
+        ren.AddActor(actor)
+
+        if not no_sliders:
+            slider_properties = SliderProperties()
+            slider_properties.value_initial = parameters['opacity'][tissue]
+            slider_properties.title = tissue
+
+            # Screen coordinates.
+            if slider_count < 7:
+                slider_properties.p1 = [left_pos_x0, left_pos_y]
+                slider_properties.p2 = [left_pos_x1, left_pos_y]
+                left_pos_y += left_step_size
+            else:
+                slider_properties.p1 = [right_pos_x0, right_pos_y]
+                slider_properties.p2 = [right_pos_x1, right_pos_y]
+                right_pos_y += right_step_size
+
+            slider_widget = make_slider_widget(slider_properties, color_lut, parameters['indices'][tissue])
+            slider_widget.SetInteractor(iren)
+            slider_widget.SetAnimationModeToAnimate()
+            slider_widget.EnabledOn()
+
+            cb = SliderCallback(actor.GetProperty())
+            slider_widget.AddObserver(vtkCommand.InteractionEvent, cb)
+            sliders[tissue] = slider_widget
+            slider_count += 1
+
+        res.append(
+            f'{tissue:<{name_size}s} {parameters["indices"][tissue]:{int_size + 3}d}'
+            f' {parameters["colors"][tissue]:<{color_size}s}')
+
+    res.append(line)
+    print('\n'.join(res))
+
+    if no_sliders:
+        ren_win.SetSize(1024, 1024)
+    else:
+        ren_win.SetSize(1024 + 400, 1024)
+    ren_win.SetWindowName('FroggieView')
+
+    ren.SetBackground(colors.GetColor3d('ParaViewBkg'))
+
+    camera = ren.GetActiveCamera()
+    if select_figure:
+        if select_figure == 'a':
+            # Fig 12-9a in the VTK Textbook
+            camera.SetPosition(495.722368, -447.474954, -646.308030)
+            camera.SetFocalPoint(137.612066, -40.962376, -195.171023)
+            camera.SetViewUp(-0.323882, -0.816232, 0.478398)
+            camera.SetDistance(704.996499)
+            camera.SetClippingRange(319.797039, 1809.449285)
+        elif select_figure == 'b':
+            # Fig 12-9b in the VTK Textbook
+            camera.SetPosition(478.683494, -420.477744, -643.112038)
+            camera.SetFocalPoint(135.624874, -36.478435, -210.614440)
+            camera.SetViewUp(-0.320495, -0.820148, 0.473962)
+            camera.SetDistance(672.457328)
+            camera.SetClippingRange(307.326771, 1765.990822)
+        elif select_figure == 'c':
+            # Fig 12-9c in the VTK Textbook
+            camera.SetPosition(201.363313, -147.260834, -229.885066)
+            camera.SetFocalPoint(140.626206, -75.857216, -162.352531)
+            camera.SetViewUp(-0.425438, -0.786048, 0.448477)
+            camera.SetDistance(115.534047)
+            camera.SetClippingRange(7.109870, 854.091718)
+        elif select_figure == 'd':
+            # Fig 12-9d in the VTK Textbook
+            camera.SetPosition(115.361727, -484.656410, -6.193827)
+            camera.SetFocalPoint(49.126343, 98.501094, 1.323317)
+            camera.SetViewUp(-0.649127, -0.083475, 0.756086)
+            camera.SetDistance(586.955116)
+            camera.SetClippingRange(360.549218, 866.876230)
+    else:
+        # Orient so that we look down on the dorsal surface and
+        #   the superior surface faces the top of the screen.
+        transform = vtkTransform()
+        transform.SetMatrix(camera.GetModelTransformMatrix())
+        transform.RotateY(-90)
+        transform.RotateZ(90)
+        camera.SetModelTransformMatrix(transform.GetMatrix())
+        ren.ResetCamera()
+
+    if select_figure:
+        # Superior Anterior Left
+        labels = 'sal'
+    else:
+        # Right Superior Posterior
+        labels = 'rsp'
+
+    cow = vtkCameraOrientationWidget()
+    cow.SetParentRenderer(ren)
+    if no_sliders:
+        # Turn off if you do not want it.
+        cow.On()
+        cow.EnabledOn()
+    else:
+        cow.Off()
+        cow.EnabledOff()
+
+    axes = make_cube_actor(labels, colors)
+    om = vtkOrientationMarkerWidget()
+    om.SetOrientationMarker(axes)
+    # Position upper left in the viewport.
+    # om.SetViewport(0.0, 0.8, 0.2, 1.0)
+    # Position lower left in the viewport.
+    om.SetViewport(0, 0, 0.2, 0.2)
+    om.SetInteractor(iren)
+    om.EnabledOn()
+    om.InteractiveOn()
+
+    ren_win.Render()
+
+    slider_toggle = SliderToggleCallback(sliders)
+    iren.AddObserver('KeyPressEvent', slider_toggle)
+
+    iren.Start()
+
+
+def parse_json(fn_path):
+    """
+    Parse the JSON file selecting the components that we want.
+
+    We also check that the file paths are valid.
+
+    :param fn_path: The path the JSON file.
+    :return: A dictionary of the parameters that we require.
+    """
+    with open(fn_path) as data_file:
+        json_data = json.load(data_file)
+    paths_ok = True
+    parameters = dict()
+    for k, v in json_data.items():
+        if k == 'files':
+            if 'root' in v:
+                root = Path(v['root'])
+                if not root.exists():
+                    print(f'Bad path: {root}')
+                    paths_ok = False
+                else:
+                    if 'vtk_files' not in v:
+                        print('Expected vtk files.')
+                        paths_ok = False
+                        continue
+                    for kk in v:
+                        if kk == 'vtk_files':
+                            if len(v[kk]) != 17:
+                                print(f'Expected seventeen file names.')
+                                paths_ok = False
+                            # The stem of the file path becomes the key.
+                            path_map = dict()
+                            for p in list(map(lambda pp: root / pp, v[kk])):
+                                path_map[p.stem] = p
+                                if not p.is_file():
+                                    paths_ok = False
+                                    print(f'Not a file {p}')
+                            if paths_ok:
+                                parameters[kk] = path_map
+            else:
+                paths_ok = False
+                print('Missing the key "root" and/or the key "files" for the files.')
+        else:
+            if k in ['tissues', 'figures']:
+                for kk, vv in v.items():
+                    parameters[kk] = vv
+    return paths_ok, parameters
+
+
+class SliceOrder:
+    """
+    These transformations permute image and other geometric data to maintain proper
+     orientation regardless of the acquisition order. After applying these transforms with
+    vtkTransformFilter, a view up of 0, -1, 0 will result in the body part
+    facing the viewer.
+    NOTE: some transformations have a -1 scale factor for one of the components.
+          To ensure proper polygon orientation and normal direction, you must
+          apply the vtkPolyDataNormals filter.
+
+    Naming (the nomenclature is medical):
+    si - superior to inferior (top to bottom)
+    is - inferior to superior (bottom to top)
+    ap - anterior to posterior (front to back)
+    pa - posterior to anterior (back to front)
+    lr - left to right
+    rl - right to left
+    """
+
+    def __init__(self):
+        self.si_mat = vtkMatrix4x4()
+        self.si_mat.Zero()
+        self.si_mat.SetElement(0, 0, 1)
+        self.si_mat.SetElement(1, 2, 1)
+        self.si_mat.SetElement(2, 1, -1)
+        self.si_mat.SetElement(3, 3, 1)
+
+        self.is_mat = vtkMatrix4x4()
+        self.is_mat.Zero()
+        self.is_mat.SetElement(0, 0, 1)
+        self.is_mat.SetElement(1, 2, -1)
+        self.is_mat.SetElement(2, 1, -1)
+        self.is_mat.SetElement(3, 3, 1)
+
+        self.lr_mat = vtkMatrix4x4()
+        self.lr_mat.Zero()
+        self.lr_mat.SetElement(0, 2, -1)
+        self.lr_mat.SetElement(1, 1, -1)
+        self.lr_mat.SetElement(2, 0, 1)
+        self.lr_mat.SetElement(3, 3, 1)
+
+        self.rl_mat = vtkMatrix4x4()
+        self.rl_mat.Zero()
+        self.rl_mat.SetElement(0, 2, 1)
+        self.rl_mat.SetElement(1, 1, -1)
+        self.rl_mat.SetElement(2, 0, 1)
+        self.rl_mat.SetElement(3, 3, 1)
+
+        """
+        The previous transforms assume radiological views of the slices
+         (viewed from the feet).
+        Other modalities such as physical sectioning may view from the head.
+        The following transforms modify the original with a 180° rotation about y
+        """
+
+        self.hf_mat = vtkMatrix4x4()
+        self.hf_mat.Zero()
+        self.hf_mat.SetElement(0, 0, -1)
+        self.hf_mat.SetElement(1, 1, 1)
+        self.hf_mat.SetElement(2, 2, -1)
+        self.hf_mat.SetElement(3, 3, 1)
+
+        self.transform = dict()
+
+        si_trans = vtkTransform()
+        si_trans.SetMatrix(self.si_mat)
+        self.transform['si'] = si_trans
+
+        is_trans = vtkTransform()
+        is_trans.SetMatrix(self.is_mat)
+        self.transform['is'] = is_trans
+
+        ap_trans = vtkTransform()
+        ap_trans.Scale(1, -1, 1)
+        self.transform['ap'] = ap_trans
+
+        pa_trans = vtkTransform()
+        pa_trans.Scale(1, -1, -1)
+        self.transform['pa'] = pa_trans
+
+        lr_trans = vtkTransform()
+        lr_trans.SetMatrix(self.lr_mat)
+        self.transform['lr'] = lr_trans
+
+        rl_trans = vtkTransform()
+        rl_trans.SetMatrix(self.rl_mat)
+        self.transform['rl'] = rl_trans
+
+        hf_trans = vtkTransform()
+        hf_trans.SetMatrix(self.hf_mat)
+        self.transform['hf'] = hf_trans
+
+        hf_si_trans = vtkTransform()
+        hf_si_trans.SetMatrix(self.hf_mat)
+        hf_si_trans.Concatenate(self.si_mat)
+        self.transform['hfsi'] = hf_si_trans
+
+        hf_is_trans = vtkTransform()
+        hf_is_trans.SetMatrix(self.hf_mat)
+        hf_is_trans.Concatenate(self.is_mat)
+        self.transform['hfis'] = hf_is_trans
+
+        hf_ap_trans = vtkTransform()
+        hf_ap_trans.SetMatrix(self.hf_mat)
+        hf_ap_trans.Scale(1, -1, 1)
+        self.transform['hfap'] = hf_ap_trans
+
+        hf_pa_trans = vtkTransform()
+        hf_pa_trans.SetMatrix(self.hf_mat)
+        hf_pa_trans.Scale(1, -1, -1)
+        self.transform['hfpa'] = hf_pa_trans
+
+        hf_lr_trans = vtkTransform()
+        hf_lr_trans.SetMatrix(self.hf_mat)
+        hf_lr_trans.Concatenate(self.lr_mat)
+        self.transform['hflr'] = hf_lr_trans
+
+        hf_rl_trans = vtkTransform()
+        hf_rl_trans.SetMatrix(self.hf_mat)
+        hf_rl_trans.Concatenate(self.rl_mat)
+        self.transform['hfrl'] = hf_rl_trans
+
+        # Identity
+        self.transform['I'] = vtkTransform()
+
+        # Zero
+        z_trans = vtkTransform()
+        z_trans.Scale(0, 0, 0)
+        self.transform['Z'] = z_trans
+
+    def print_transform(self, order):
+        """
+        Print the homogenous matrix corresponding to the slice order.
+        :param order: The slice order.
+        :return:
+        """
+        print(order)
+        m = self.transform[order].GetMatrix()
+        for i in range(0, 4):
+            row = list()
+            for j in range(0, 4):
+                row.append(f'{m.GetElement(i, j):6.2g}')
+            print(' '.join(row))
+
+    def print_all_transforms(self):
+        """
+        Print all the homogenous matrices corresponding to the slice orders.
+        :return:
+        """
+        for k in self.transform.keys():
+            self.print_transform(k)
+
+    def get(self, order):
+        """
+        Returns the vtkTransform corresponding to the slice order.
+
+        :param order: The slice order.
+        :return: The vtkTransform to use.
+        """
+        if order in self.transform.keys():
+            return self.transform[order]
+        else:
+            s = 'No such transform "{:s}" exists.'.format(order)
+            raise Exception(s)
+
+
+def create_tissue_lut(indices, colors):
+    """
+    Create the lookup table for the frog tissues.
+
+    Each table value corresponds the color of one of the frog tissues.
+
+    :param indices: The tissue name and index.
+    :param colors: The tissue name and color.
+    :return: The lookup table.
+    """
+    lut = vtkLookupTable()
+    lut.SetNumberOfColors(len(colors))
+    lut.SetTableRange(0, len(colors) - 1)
+    lut.Build()
+
+    nc = vtkNamedColors()
+
+    for k in indices.keys():
+        lut.SetTableValue(indices[k], nc.GetColor4d(colors[k]))
+
+    return lut
+
+
+def make_axes_actor(scale, xyz_labels):
+    """
+    :param scale: Sets the scale and direction of the axes.
+    :param xyz_labels: Labels for the axes.
+    :return: The axes actor.
+    """
+    axes = vtkAxesActor()
+    axes.SetScale(scale)
+    axes.SetShaftTypeToCylinder()
+    axes.SetXAxisLabelText(xyz_labels[0])
+    axes.SetYAxisLabelText(xyz_labels[1])
+    axes.SetZAxisLabelText(xyz_labels[2])
+    axes.SetCylinderRadius(0.5 * axes.GetCylinderRadius())
+    axes.SetConeRadius(1.025 * axes.GetConeRadius())
+    axes.SetSphereRadius(1.5 * axes.GetSphereRadius())
+    tprop = axes.GetXAxisCaptionActor2D().GetCaptionTextProperty()
+    tprop.ItalicOn()
+    tprop.ShadowOn()
+    tprop.SetFontFamilyToTimes()
+    # Use the same text properties on the other two axes.
+    axes.GetYAxisCaptionActor2D().GetCaptionTextProperty().ShallowCopy(tprop)
+    axes.GetZAxisCaptionActor2D().GetCaptionTextProperty().ShallowCopy(tprop)
+    return axes
+
+
+def make_annotated_cube_actor(cube_labels, colors):
+    """
+    :param cube_labels: The labels for the cube faces.
+    :param colors: Used to determine the cube color.
+    :return: The annotated cube actor.
+    """
+    # A cube with labeled faces.
+    cube = vtkAnnotatedCubeActor()
+    cube.SetXPlusFaceText(cube_labels[0])
+    cube.SetXMinusFaceText(cube_labels[1])
+    cube.SetYPlusFaceText(cube_labels[2])
+    cube.SetYMinusFaceText(cube_labels[3])
+    cube.SetZPlusFaceText(cube_labels[4])
+    cube.SetZMinusFaceText(cube_labels[5])
+    cube.SetFaceTextScale(0.5)
+    cube.GetCubeProperty().SetColor(colors.GetColor3d('Gainsboro'))
+
+    cube.GetTextEdgesProperty().SetColor(colors.GetColor3d('LightSlateGray'))
+
+    # Change the vector text colors.
+    cube.GetXPlusFaceProperty().SetColor(colors.GetColor3d('Tomato'))
+    cube.GetXMinusFaceProperty().SetColor(colors.GetColor3d('Tomato'))
+    cube.GetYPlusFaceProperty().SetColor(colors.GetColor3d('DeepSkyBlue'))
+    cube.GetYMinusFaceProperty().SetColor(colors.GetColor3d('DeepSkyBlue'))
+    cube.GetZPlusFaceProperty().SetColor(colors.GetColor3d('SeaGreen'))
+    cube.GetZMinusFaceProperty().SetColor(colors.GetColor3d('SeaGreen'))
+    return cube
+
+
+def make_cube_actor(label_selector, colors):
+    """
+    :param label_selector: The selector used to define labels for the axes and cube.
+    :param colors: Used to set the colors of the cube faces.
+    :return: The combined axes and annotated cube prop.
+    """
+    if label_selector == 'sal':
+        # xyz_labels = ['S', 'A', 'L']
+        xyz_labels = ['+X', '+Y', '+Z']
+        cube_labels = ['S', 'I', 'A', 'P', 'L', 'R']
+        scale = [1.5, 1.5, 1.5]
+    elif label_selector == 'rsp':
+        # xyz_labels = ['R', 'S', 'P']
+        xyz_labels = ['+X', '+Y', '+Z']
+        cube_labels = ['R', 'L', 'S', 'I', 'P', 'A']
+        scale = [1.5, 1.5, 1.5]
+    else:
+        xyz_labels = ['+X', '+Y', '+Z']
+        cube_labels = ['+X', '-X', '+Y', '-Y', '+Z', '-Z']
+        scale = [1.5, 1.5, 1.5]
+
+    # We are combining a vtkAxesActor and a vtkAnnotatedCubeActor
+    # into a vtkPropAssembly
+    cube = make_annotated_cube_actor(cube_labels, colors)
+    axes = make_axes_actor(scale, xyz_labels)
+
+    # Combine orientation markers into one with an assembly.
+    assembly = vtkPropAssembly()
+    assembly.AddPart(axes)
+    assembly.AddPart(cube)
+    return assembly
+
+
+class SliderProperties:
+    tube_width = 0.004
+    slider_length = 0.015
+    slider_width = 0.008
+    end_cap_length = 0.008
+    end_cap_width = 0.02
+    title_height = 0.02
+    label_height = 0.02
+
+    value_minimum = 0.0
+    value_maximum = 1.0
+    value_initial = 1.0
+
+    p1 = [0.02, 0.1]
+    p2 = [0.18, 0.1]
+
+    title = None
+
+    title_color = 'Black'
+    label_color = 'Black'
+    value_color = 'DarkSlateGray'
+    slider_color = 'BurlyWood'
+    selected_color = 'Lime'
+    bar_color = 'Black'
+    bar_ends_color = 'Indigo'
+
+
+def make_slider_widget(properties, lut, idx):
+    """
+    Make the slider widget.
+
+    :param properties: The slider properties.
+    :param lut: The color lookup table.
+    :param idx: The tissue index.
+    :return: The slider widget.
+    """
+    slider = vtkSliderRepresentation2D()
+
+    slider.SetMinimumValue(properties.value_minimum)
+    slider.SetMaximumValue(properties.value_maximum)
+    slider.SetValue(properties.value_initial)
+    slider.SetTitleText(properties.title)
+
+    slider.GetPoint1Coordinate().SetCoordinateSystemToNormalizedDisplay()
+    slider.GetPoint1Coordinate().SetValue(properties.p1[0], properties.p1[1])
+    slider.GetPoint2Coordinate().SetCoordinateSystemToNormalizedDisplay()
+    slider.GetPoint2Coordinate().SetValue(properties.p2[0], properties.p2[1])
+
+    slider.SetTubeWidth(properties.tube_width)
+    slider.SetSliderLength(properties.slider_length)
+    slider.SetSliderWidth(properties.slider_width)
+    slider.SetEndCapLength(properties.end_cap_length)
+    slider.SetEndCapWidth(properties.end_cap_width)
+    slider.SetTitleHeight(properties.title_height)
+    slider.SetLabelHeight(properties.label_height)
+
+    colors = vtkNamedColors()
+    # Set the colors of the slider components.
+    # Change the color of the bar.
+    slider.GetTubeProperty().SetColor(colors.GetColor3d(properties.bar_color))
+    # Change the color of the ends of the bar.
+    slider.GetCapProperty().SetColor(colors.GetColor3d(properties.bar_ends_color))
+    # Change the color of the knob that slides.
+    slider.GetSliderProperty().SetColor(colors.GetColor3d(properties.slider_color))
+    # Change the color of the knob when the mouse is held on it.
+    slider.GetSelectedProperty().SetColor(colors.GetColor3d(properties.selected_color))
+    # Change the color of the text displaying the value.
+    slider.GetLabelProperty().SetColor(colors.GetColor3d(properties.value_color))
+    #  Use the one color for the labels.
+    # slider.GetTitleProperty().SetColor(colors.GetColor3d(properties.label_color))
+    # Change the color of the text indicating what the slider controls
+    if idx in range(0, 16):
+        slider.GetTitleProperty().SetColor(lut.GetTableValue(idx)[:3])
+        slider.GetTitleProperty().ShadowOff()
+    else:
+        slider.GetTitleProperty().SetColor(colors.GetColor3d(properties.title_color))
+
+    slider_widget = vtkSliderWidget()
+    slider_widget.SetRepresentation(slider)
+
+    return slider_widget
+
+
+class SliderCallback:
+    def __init__(self, actor_property):
+        self.actor_property = actor_property
+
+    def __call__(self, caller, ev):
+        slider_widget = caller
+        value = slider_widget.GetRepresentation().GetValue()
+        self.actor_property.SetOpacity(value)
+
+
+class SliderToggleCallback:
+    def __init__(self, sliders):
+        self.sliders = sliders
+
+    def __call__(self, caller, ev):
+        if caller.GetKeyCode() == "n":
+            for k, v in self.sliders.items():
+                if v.GetEnabled():
+                    v.Off()
+                else:
+                    v.On()
+
+
+if __name__ == '__main__':
+    import sys
+
+    data_folder, view, omit_sliders, selected_tissues = get_program_parameters(sys.argv)
+    main(data_folder, view, omit_sliders, selected_tissues)
diff --git a/src/Testing/Baseline/Cxx/Visualization/TestFroggieSurface.png b/src/Testing/Baseline/Cxx/Visualization/TestFroggieSurface.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9137661da8cd7c9504eafc0a1e457fd9fe232e9
--- /dev/null
+++ b/src/Testing/Baseline/Cxx/Visualization/TestFroggieSurface.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5845d7379d8104cf22d4c941858f8eec307866408c2546de3d534d176341c4da
+size 463491
diff --git a/src/Testing/Baseline/Cxx/Visualization/TestFroggieView.png b/src/Testing/Baseline/Cxx/Visualization/TestFroggieView.png
new file mode 100644
index 0000000000000000000000000000000000000000..18db1c149f21593674c5d05251c9aba5f67e5a0d
--- /dev/null
+++ b/src/Testing/Baseline/Cxx/Visualization/TestFroggieView.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:712ea6b74f30943443adcbf97905b7568640cf50121a963156b34da42b242390
+size 496229
diff --git a/src/Testing/Baseline/Python/Visualization/TestFrog.png b/src/Testing/Baseline/Python/Visualization/TestFrog.png
deleted file mode 100644
index f580e37a7aa4c437b2dbcbbd2ba2e3751be28922..0000000000000000000000000000000000000000
--- a/src/Testing/Baseline/Python/Visualization/TestFrog.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:02432541767e462fc08771825c99f831fd75334df267a079e9781083fc8d6ce0
-size 213291
diff --git a/src/Testing/Baseline/Python/Visualization/TestFrogDemo.png b/src/Testing/Baseline/Python/Visualization/TestFrogDemo.png
deleted file mode 100644
index 38f77c36807fa5d8bb33c4961889a90ee1abf650..0000000000000000000000000000000000000000
--- a/src/Testing/Baseline/Python/Visualization/TestFrogDemo.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:192f215cf6fa0c1c56252be17e8e04925302412e577800e3466e9d10a63c0c5e
-size 180865
diff --git a/src/Testing/Baseline/Python/Visualization/TestFrogReconstruction.png b/src/Testing/Baseline/Python/Visualization/TestFrogReconstruction.png
deleted file mode 100644
index 8e6f572cd026679f301303c5b555e486f3cee91f..0000000000000000000000000000000000000000
--- a/src/Testing/Baseline/Python/Visualization/TestFrogReconstruction.png
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:53d97ce4e03286f9b287d3c49bde50660412a016133f7b134bad1a5dfb57d960
-size 221828
diff --git a/src/Testing/Baseline/Python/Visualization/TestFroggieSurface.png b/src/Testing/Baseline/Python/Visualization/TestFroggieSurface.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9137661da8cd7c9504eafc0a1e457fd9fe232e9
--- /dev/null
+++ b/src/Testing/Baseline/Python/Visualization/TestFroggieSurface.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5845d7379d8104cf22d4c941858f8eec307866408c2546de3d534d176341c4da
+size 463491
diff --git a/src/Testing/Baseline/Python/Visualization/TestFroggieView.png b/src/Testing/Baseline/Python/Visualization/TestFroggieView.png
new file mode 100644
index 0000000000000000000000000000000000000000..18db1c149f21593674c5d05251c9aba5f67e5a0d
--- /dev/null
+++ b/src/Testing/Baseline/Python/Visualization/TestFroggieView.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:712ea6b74f30943443adcbf97905b7568640cf50121a963156b34da42b242390
+size 496229
diff --git a/src/Testing/Data/Frog_mhd.json b/src/Testing/Data/Frog_mhd.json
new file mode 100644
index 0000000000000000000000000000000000000000..e012777f744c4088c7cd753097079277d8ab7bb1
--- /dev/null
+++ b/src/Testing/Data/Frog_mhd.json
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e7252acb0d58d79f492aac6953e1729503423b07a3060177fa6cf1a1097f7764
+size 7985
diff --git a/src/Testing/Data/Frog_vtk.json b/src/Testing/Data/Frog_vtk.json
new file mode 100644
index 0000000000000000000000000000000000000000..b8f701636948bac2792f52f95d8d89e9d23b33ab
--- /dev/null
+++ b/src/Testing/Data/Frog_vtk.json
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:73de26d1bd204e2875ecc2375aee71995c886c81833e52612435f2337cd424dc
+size 2910