From 5ff62ec082b0e18a8453cdc3b5e7995816f64bec Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 24 Oct 2025 14:09:05 +0200 Subject: [PATCH 1/7] Implement TScatter2D (5D plots) --- core/base/inc/TVirtualPad.h | 1 + graf2d/gpad/inc/TPad.h | 1 + graf2d/gpad/src/TPad.cxx | 25 +- hist/hist/CMakeLists.txt | 2 + hist/hist/inc/LinkDef.h | 1 + hist/hist/inc/TScatter2D.h | 73 ++++ hist/hist/inc/TVirtualGraphPainter.h | 2 + hist/hist/src/TScatter.cxx | 11 +- hist/hist/src/TScatter2D.cxx | 270 ++++++++++++++ hist/histpainter/inc/TGraphPainter.h | 2 + hist/histpainter/src/TGraphPainter.cxx | 350 ++++++++++++++---- .../visualisation/graphs/gr006_scatter.C | 42 ++- .../visualisation/graphs/gr019_scatter2d.C | 53 +++ 13 files changed, 737 insertions(+), 96 deletions(-) create mode 100644 hist/hist/inc/TScatter2D.h create mode 100644 hist/hist/src/TScatter2D.cxx create mode 100644 tutorials/visualisation/graphs/gr019_scatter2d.C diff --git a/core/base/inc/TVirtualPad.h b/core/base/inc/TVirtualPad.h index ab8a71434d9c2..9e527e1559286 100644 --- a/core/base/inc/TVirtualPad.h +++ b/core/base/inc/TVirtualPad.h @@ -189,6 +189,7 @@ class TVirtualPad : public TObject, public TAttLine, public TAttFill, virtual void PaintPolyLineNDC(Int_t n, Double_t *x, Double_t *y, Option_t *option="") = 0; virtual void PaintPolyMarker(Int_t n, Float_t *x, Float_t *y, Option_t *option="") = 0; virtual void PaintPolyMarker(Int_t n, Double_t *x, Double_t *y, Option_t *option="") = 0; + virtual void PaintMarker3D(Double_t x, Double_t y, Double_t z) = 0; virtual void PaintModified() = 0; virtual void PaintText(Double_t x, Double_t y, const char *text) = 0; virtual void PaintText(Double_t x, Double_t y, const wchar_t *text) = 0; diff --git a/graf2d/gpad/inc/TPad.h b/graf2d/gpad/inc/TPad.h index 5c0d74f3b6c63..5bc9c9f481276 100644 --- a/graf2d/gpad/inc/TPad.h +++ b/graf2d/gpad/inc/TPad.h @@ -301,6 +301,7 @@ friend class TWebCanvas; void PaintPolyLineNDC(Int_t n, Double_t *x, Double_t *y, Option_t *option="") override; void PaintPolyMarker(Int_t n, Float_t *x, Float_t *y, Option_t *option="") override; void PaintPolyMarker(Int_t n, Double_t *x, Double_t *y, Option_t *option="") override; + void PaintMarker3D(Double_t x, Double_t y, Double_t z) override; void PaintModified() override; void PaintText(Double_t x, Double_t y, const char *text) override; void PaintText(Double_t x, Double_t y, const wchar_t *text) override; diff --git a/graf2d/gpad/src/TPad.cxx b/graf2d/gpad/src/TPad.cxx index ca11fa203a18d..7b60ee326fb86 100644 --- a/graf2d/gpad/src/TPad.cxx +++ b/graf2d/gpad/src/TPad.cxx @@ -4491,8 +4491,8 @@ void TPad::PaintLine3D(Float_t *p1, Float_t *p2) void TPad::PaintLine3D(Double_t *p1, Double_t *p2) { - //take into account perspective view if (!fView) return; + // convert from 3-D to 2-D pad coordinate system Double_t xpad[6]; Double_t temp[3]; @@ -4504,6 +4504,29 @@ void TPad::PaintLine3D(Double_t *p1, Double_t *p2) PaintLine(xpad[0],xpad[1],xpad[3],xpad[4]); } +//////////////////////////////////////////////////////////////////////////////// +/// Paint 3-D marker in the CurrentPad. + +void TPad::PaintMarker3D(Double_t x, Double_t y, Double_t z) +{ + if (!fView) return; + + Double_t rmin[3], rmax[3]; + fView->GetRange(rmin, rmax); + + // convert from 3-D to 2-D pad coordinate system + Double_t xpad[3]; + Double_t temp[3]; + temp[0] = x; + temp[1] = y; + temp[2] = z; + if (xrmax[0]) return; + if (yrmax[1]) return; + if (zrmax[2]) return; + fView->WCtoNDC(temp, &xpad[0]); + PaintPolyMarker(1, &xpad[0], &xpad[1]); +} + //////////////////////////////////////////////////////////////////////////////// /// Paint polyline in CurrentPad World coordinates. diff --git a/hist/hist/CMakeLists.txt b/hist/hist/CMakeLists.txt index 1fce5ad5c0f35..8b2d06bcc293f 100644 --- a/hist/hist/CMakeLists.txt +++ b/hist/hist/CMakeLists.txt @@ -43,6 +43,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Hist TGraphSmooth.h TGraphTime.h TScatter.h + TScatter2D.h TH1C.h TH1D.h TH1F.h @@ -136,6 +137,7 @@ ROOT_STANDARD_LIBRARY_PACKAGE(Hist TGraphSmooth.cxx TGraphTime.cxx TScatter.cxx + TScatter2D.cxx TH1.cxx TH1K.cxx TH1Merger.cxx diff --git a/hist/hist/inc/LinkDef.h b/hist/hist/inc/LinkDef.h index 23ff0bbd814ee..4ca3476b581b9 100644 --- a/hist/hist/inc/LinkDef.h +++ b/hist/hist/inc/LinkDef.h @@ -48,6 +48,7 @@ #pragma link C++ class TGraphMultiErrors+; #pragma link C++ class TGraphBentErrors+; #pragma link C++ class TScatter+; +#pragma link C++ class TScatter2D+; #pragma link C++ class TGraph2D-; #pragma link C++ class TGraph2DErrors-; #pragma link C++ class TGraph2DAsymmErrors-; diff --git a/hist/hist/inc/TScatter2D.h b/hist/hist/inc/TScatter2D.h new file mode 100644 index 0000000000000..a409e75148e4a --- /dev/null +++ b/hist/hist/inc/TScatter2D.h @@ -0,0 +1,73 @@ +// @(#)root/hist:$Id$ +// Author: Olivier Couet 23/09/2025 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + +#ifndef ROOT_TScatter2D +#define ROOT_TScatter2D + + +////////////////////////////////////////////////////////////////////////// +// // +// TScatter2D // +// // +// A scatter plot able to draw five variables on a single plot // +// // +////////////////////////////////////////////////////////////////////////// + +#include "TNamed.h" +#include "TAttLine.h" +#include "TAttFill.h" +#include "TAttMarker.h" +#include "TGraph2D.h" + +class TH3F; + +class TScatter2D : public TNamed, public TAttLine, public TAttFill, public TAttMarker { + +protected: + Int_t fNpoints{-1}; ///< Number of points of arrays fX, fY and fZ + TGraph2D *fGraph{nullptr}; ///< Pointer to graph holding X, Y and Z positions + Double_t *fColor{nullptr}; ///< [fNpoints] array of colors + Double_t *fSize{nullptr}; ///< [fNpoints] array of marker sizes + Double_t fMaxMarkerSize{5.}; ///< Largest marker size used to paint the markers + Double_t fMinMarkerSize{1.}; ///< Smallest marker size used to paint the markers + Double_t fMargin{.1}; ///< Margin around the plot in % + +public: + TScatter2D(); + TScatter2D(Int_t n); + TScatter2D(Int_t n, Double_t *x, Double_t *y, Double_t *z, const Double_t *col = nullptr, const Double_t *size = nullptr); + ~TScatter2D() override; + + Int_t DistancetoPrimitive(Int_t px, Int_t py) override; + void ExecuteEvent(Int_t event, Int_t px, Int_t py) override; + Double_t *GetColor() const {return fColor;} ///< Get the array of colors + Double_t *GetSize() const {return fSize;} ///< Get the array of marker sizes + Double_t GetMargin() const {return fMargin;} ///< Set the margin around the plot in % + Double_t GetMaxMarkerSize() const {return fMaxMarkerSize;} ///< Get the largest marker size used to paint the markers + Double_t GetMinMarkerSize() const {return fMinMarkerSize;} ///< Get the smallest marker size used to paint the markers + TGraph2D *GetGraph() const {return fGraph;} ///< Get the graph holding X, Y and Z positions + TH2D *GetHistogram() const; ///< Get the graph histogram used for drawing axis + TAxis *GetXaxis() const ; + TAxis *GetYaxis() const ; + TAxis *GetZaxis() const ; + + void SetMaxMarkerSize(Double_t max) {fMaxMarkerSize = max;} ///< Set the largest marker size used to paint the markers + void SetMinMarkerSize(Double_t min) {fMinMarkerSize = min;} ///< Set the smallest marker size used to paint the markers + void SetMargin(Double_t); + void Print(Option_t *chopt="") const override; + void SavePrimitive(std::ostream &out, Option_t *option = "") override; + void Paint(Option_t *chopt="") override; + + + ClassDefOverride(TScatter2D,1) //A 2D scatter plot +}; +#endif + diff --git a/hist/hist/inc/TVirtualGraphPainter.h b/hist/hist/inc/TVirtualGraphPainter.h index 4bf8d559ab3b2..19ad070a06863 100644 --- a/hist/hist/inc/TVirtualGraphPainter.h +++ b/hist/hist/inc/TVirtualGraphPainter.h @@ -23,6 +23,7 @@ class TGraph; class TScatter; +class TScatter2D; class TF1; class TVirtualGraphPainter : public TObject { @@ -42,6 +43,7 @@ class TVirtualGraphPainter : public TObject { virtual void PaintGraph(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) = 0; virtual void PaintGrapHist(TGraph *theGraph, Int_t npoints, const Double_t *x, const Double_t *y, Option_t *chopt) = 0; virtual void PaintScatter(TScatter *theScatter, Option_t *option) = 0; + virtual void PaintScatter2D(TScatter2D *theScatter, Option_t *option) = 0; virtual void PaintStats(TGraph *theGraph, TF1 *fit) = 0; virtual void SetHighlight(TGraph *theGraph) = 0; diff --git a/hist/hist/src/TScatter.cxx b/hist/hist/src/TScatter.cxx index 0cd1f6833a005..13476f84d3e60 100644 --- a/hist/hist/src/TScatter.cxx +++ b/hist/hist/src/TScatter.cxx @@ -11,20 +11,11 @@ #include "TROOT.h" -#include "TBuffer.h" #include "TScatter.h" -#include "TStyle.h" -#include "TMath.h" -#include "TVirtualPad.h" #include "TH2.h" #include "TVirtualGraphPainter.h" -#include "strtok.h" - -#include -#include -#include -#include + #include //////////////////////////////////////////////////////////////////////////////// diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx new file mode 100644 index 0000000000000..a39b46fd55b3f --- /dev/null +++ b/hist/hist/src/TScatter2D.cxx @@ -0,0 +1,270 @@ +// @(#)root/hist:$Id$ +// Author: Olivier Couet 23/09/2025 + +/************************************************************************* + * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. * + * All rights reserved. * + * * + * For the licensing terms see $ROOTSYS/LICENSE. * + * For the list of contributors see $ROOTSYS/README/CREDITS. * + *************************************************************************/ + + +#include "TROOT.h" +#include "TScatter2D.h" +#include "TH1.h" +#include "TVirtualGraphPainter.h" + +#include + + +//////////////////////////////////////////////////////////////////////////////// + +/** \class TScatter2D + \ingroup Graphs +A TScatter2D is able to draw give variables scatter plot on a single plot. The three first +variables are the x, y and z position of the markers (stored in a TGraph2D), the fourth is +mapped on the current color map and the fifth on the marker size. + +The following example demonstrates how it works: + +Begin_Macro(source) +../../../tutorials/visualisation/graphs/gr019_scatter2d.C +End_Macro + +### TScatter2D's plotting options +TScatter2D can be drawn with the following options: + +| Option | Description | +|----------|-------------------------------------------------------------------| +| "SAME" | Superimpose on previous picture in the same pad.| + +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// TScatter2D default constructor. + +TScatter2D::TScatter2D() +{ +} + +//////////////////////////////////////////////////////////////////////////////// +/// TScatter2D normal constructor. +/// +/// the arrays are preset to zero + +TScatter2D::TScatter2D(Int_t n) +{ + fGraph = new TGraph2D(n); + fNpoints = fGraph->GetN(); + + fColor = new Double_t[fNpoints]; + fSize = new Double_t[fNpoints]; + + memset(fColor, 0, fNpoints * sizeof(Double_t)); + memset(fSize, 0, fNpoints * sizeof(Double_t)); + fMaxMarkerSize = 5.; + fMinMarkerSize = 1.; + fMargin = 0.1; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// TScatter2D normal constructor. + +TScatter2D::TScatter2D(Int_t n, Double_t *x, Double_t *y, Double_t *z, const Double_t *col, const Double_t *size) +{ + Bool_t status = TH1::AddDirectoryStatus(); + TH1::AddDirectory(kFALSE); + fGraph = new TGraph2D(n, x, y, z); + fNpoints = fGraph->GetN(); + + Int_t bufsize = sizeof(Double_t) * fNpoints; + if (col) { + fColor = new Double_t[fNpoints]; + memcpy(fColor, col, bufsize); + } + if (size) { + fSize = new Double_t[fNpoints]; + memcpy(fSize, size, bufsize); + } + + fMaxMarkerSize = 5.; + fMinMarkerSize = 1.; + fMargin = 0.1; + + TH1::AddDirectory(status); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// TScatter2D default destructor. + +TScatter2D::~TScatter2D() +{ + delete fGraph; + delete [] fColor; + delete [] fSize; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Compute distance from point px,py,pz to a scatter plot. +/// +/// Compute the closest distance of approach from point px,py,pz to this scatter plot. +/// The distance is computed in pixels units. + +Int_t TScatter2D::DistancetoPrimitive(Int_t px, Int_t py) +{ + Int_t distance = 9999; + if (fGraph) distance = fGraph->DistancetoPrimitive(px, py); + return distance; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Execute action corresponding to one event. +/// +/// This member function is called when a graph is clicked with the locator +/// +/// If Left button clicked on one of the line end points, this point +/// follows the cursor until button is released. +/// +/// if Middle button clicked, the line is moved parallel to itself +/// until the button is released. + +void TScatter2D::ExecuteEvent(Int_t event, Int_t px, Int_t py) +{ + if (fGraph) fGraph->ExecuteEvent(event, px, py); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Returns a pointer to the histogram used to draw the axis + +TH2D *TScatter2D::GetHistogram() const +{ + return fGraph->GetHistogram();; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Get the scatter's x axis. + +TAxis *TScatter2D::GetXaxis() const +{ + return fGraph->GetXaxis(); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Get the scatter's y axis. + +TAxis *TScatter2D::GetYaxis() const +{ + return fGraph->GetYaxis(); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Get the scatter's z axis. + +TAxis *TScatter2D::GetZaxis() const +{ + return fGraph->GetZaxis(); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Paint this scatter plot with its current attributes. + +void TScatter2D::Paint(Option_t *option) +{ + TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter(); + if (painter) painter->PaintScatter2D(this, option); +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Print graph and errors values. + +void TScatter2D::Print(Option_t *) const +{ + Double_t *X = fGraph->GetX(); + Double_t *Y = fGraph->GetY(); + Double_t *Z = fGraph->GetZ(); + for (Int_t i = 0; i < fNpoints; i++) { + printf("x[%d]=%g, y[%d]=%g, z[%d]=%g", i, X[i], i, Y[i], i, Z[i]); + if (fColor) printf(", color[%d]=%g", i, fColor[i]); + if (fSize) printf(", size[%d]=%g", i, fSize[i]); + printf("\n"); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Set the margin around the plot in % + +void TScatter2D::SetMargin(Double_t margin) +{ + if (fMargin != margin) { + fMargin = margin; + } +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Save primitive as a C++ statement(s) on output stream out + +void TScatter2D::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/) +{ + char quote = '"'; + out << " " << std::endl; + static Int_t frameNumber = 1000; + frameNumber++; + + Int_t i; + Double_t *X = fGraph->GetX(); + Double_t *Y = fGraph->GetY(); + Double_t *Z = fGraph->GetZ(); + TString fXName = TString::Format("%s_fx%d",GetName(),frameNumber); + TString fYName = TString::Format("%s_fy%d", GetName(),frameNumber); + TString fZName = TString::Format("%s_fz%d", GetName(),frameNumber); + TString fColorName = TString::Format("%s_fcolor%d",GetName(),frameNumber); + TString fSizeName = TString::Format("%s_fsize%d",GetName(),frameNumber); + out << " Double_t " << fXName << "[" << fNpoints << "] = {" << std::endl; + for (i = 0; i < fNpoints-1; i++) out << " " << X[i] << "," << std::endl; + out << " " << X[fNpoints-1] << "};" << std::endl; + out << " Double_t " << fYName << "[" << fNpoints << "] = {" << std::endl; + for (i = 0; i < fNpoints-1; i++) out << " " << Y[i] << "," << std::endl; + out << " " << Y[fNpoints-1] << "};" << std::endl; + out << " Double_t " << fZName << "[" << fNpoints << "] = {" << std::endl; + for (i = 0; i < fNpoints-1; i++) out << " " << Z[i] << "," << std::endl; + out << " " << Z[fNpoints-1] << "};" << std::endl; + out << " Double_t " << fColorName << "[" << fNpoints << "] = {" << std::endl; + for (i = 0; i < fNpoints-1; i++) out << " " << fColor[i] << "," << std::endl; + out << " " << fColor[fNpoints-1] << "};" << std::endl; + out << " Double_t " << fSizeName << "[" << fNpoints << "] = {" << std::endl; + for (i = 0; i < fNpoints-1; i++) out << " " << fSize[i] << "," << std::endl; + out << " " << fSize[fNpoints-1] << "};" << std::endl; + + if (gROOT->ClassSaved(TScatter2D::Class())) + out << " "; + else + out << " TScatter2D *"; + out << "scat = new TScatter2D(" << fNpoints << "," << fXName << "," << fYName << "," << fZName << "," + << fColorName << "," << fSizeName << ");" << std::endl; + + out << " scat->SetName(" << quote << GetName() << quote << ");" << std::endl; + out << " scat->SetTitle(" << quote << GetTitle() << quote << ");" << std::endl; + out << " scat->SetMargin(" << GetMargin() << ");" << std::endl; + out << " scat->SetMinMarkerSize(" << GetMinMarkerSize() << ");" << std::endl; + out << " scat->SetMaxMarkerSize(" << GetMaxMarkerSize() << ");" << std::endl; + + SaveFillAttributes(out, "scat", 0, 1001); + SaveLineAttributes(out, "scat", 1, 1, 1); + SaveMarkerAttributes(out, "scat", 1, 1, 1); + + out << " scat->Draw(" << quote << option << quote << ");" << std::endl; +} diff --git a/hist/histpainter/inc/TGraphPainter.h b/hist/histpainter/inc/TGraphPainter.h index 8d360d2116c36..da2ea50367788 100644 --- a/hist/histpainter/inc/TGraphPainter.h +++ b/hist/histpainter/inc/TGraphPainter.h @@ -27,6 +27,7 @@ class TGraph; class TF1; class TScatter; +class TScatter2D; class TGraphPainter : public TVirtualGraphPainter { @@ -56,6 +57,7 @@ class TGraphPainter : public TVirtualGraphPainter { void PaintGraphReverse(TGraph *theGraph, Option_t *option); void PaintGraphSimple(TGraph *theGraph, Option_t *option); void PaintScatter(TScatter *theScatter, Option_t *option) override; + void PaintScatter2D(TScatter2D *theScatter, Option_t *option) override; void PaintPolyLineHatches(TGraph *theGraph, Int_t n, const Double_t *x, const Double_t *y); void PaintStats(TGraph *theGraph, TF1 *fit) override; void SetHighlight(TGraph *theGraph) override; diff --git a/hist/histpainter/src/TGraphPainter.cxx b/hist/histpainter/src/TGraphPainter.cxx index eb51453dd2bb6..635ea603119d0 100644 --- a/hist/histpainter/src/TGraphPainter.cxx +++ b/hist/histpainter/src/TGraphPainter.cxx @@ -29,6 +29,8 @@ #include "TGraphPolar.h" #include "TGraphQQ.h" #include "TScatter.h" +#include "TScatter2D.h" +#include "TGraph2D.h" #include "TPaletteAxis.h" #include "TLatex.h" #include "TArrow.h" @@ -4370,6 +4372,8 @@ void TGraphPainter::PaintGraphReverse(TGraph *theGraph, Option_t *option) void TGraphPainter::PaintScatter(TScatter *theScatter, Option_t* chopt) { + TGraph* theGraph = theScatter->GetGraph(); + Int_t optionAxis, optionSkipCol; TString opt = chopt; @@ -4378,35 +4382,26 @@ void TGraphPainter::PaintScatter(TScatter *theScatter, Option_t* chopt) if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0; if (opt.Contains("SKIPCOL")) optionSkipCol = 1; else optionSkipCol = 0; - double *theX = theScatter->GetGraph()->GetX(); - double *theY = theScatter->GetGraph()->GetY(); - int n = theScatter->GetGraph()->GetN(); + double *theX = theGraph->GetX(); + double *theY = theGraph->GetY(); + int n = theGraph->GetN(); double *theColor = theScatter->GetColor(); double *theSize = theScatter->GetSize(); double MinMarkerSize = theScatter->GetMinMarkerSize(); double MaxMarkerSize = theScatter->GetMaxMarkerSize(); - double minx = DBL_MAX; - double maxx = -DBL_MAX; - double miny = DBL_MAX; - double maxy = -DBL_MAX; - double minc = DBL_MAX; - double maxc = -DBL_MAX; - double mins = DBL_MAX; - double maxs = -DBL_MAX; - for (int i=0; iGetHistogram(); - if (optionAxis) h->Paint(" "); - if (h->GetMinimum() < h->GetMaximum()) { - if (mincGetMinimum()) minc = h->GetMinimum(); - if (maxc>h->GetMaximum()) maxc = h->GetMaximum(); - } else { - Error("PaintScatter", "Mininal (%g) and Maximal (%g) values of the internal histogram are not valid",h->GetMinimum(),h->GetMaximum()); - } + if (optionAxis) { + h->Paint(" "); + if (h->GetMinimum() < h->GetMaximum()) { + if (mincGetMinimum()) minc = h->GetMinimum(); + if (maxc>h->GetMaximum()) maxc = h->GetMaximum(); + } else { + Error("PaintScatter", "Mininal (%g) and Maximal (%g) values of the internal histogram are not valid",h->GetMinimum(),h->GetMaximum()); + } - // Define and paint palette - if (theColor) { - TPaletteAxis *palette; - TList *functions = theScatter->GetGraph()->GetListOfFunctions(); - palette = (TPaletteAxis*)functions->FindObject("palette"); - TView *view = gPad->GetView(); - if (palette) { - if (view) { - if (!palette->TestBit(TPaletteAxis::kHasView)) { - functions->Remove(palette); - delete palette; palette = nullptr; - } - } else { - if (palette->TestBit(TPaletteAxis::kHasView)) { - functions->Remove(palette); - delete palette; palette = nullptr; + // Define and paint palette + if (theColor) { + TPaletteAxis *palette; + TList *functions = theGraph->GetListOfFunctions(); + palette = (TPaletteAxis*)functions->FindObject("palette"); + TView *view = gPad->GetView(); + if (palette) { + if (view) { + if (!palette->TestBit(TPaletteAxis::kHasView)) { + functions->Remove(palette); + delete palette; palette = nullptr; + } + } else { + if (palette->TestBit(TPaletteAxis::kHasView)) { + functions->Remove(palette); + delete palette; palette = nullptr; + } } } + if (!palette) { + Double_t xup = gPad->GetUxmax(); + Double_t x2 = gPad->PadtoX(gPad->GetX2()); + Double_t ymin = gPad->PadtoY(gPad->GetUymin()); + Double_t ymax = gPad->PadtoY(gPad->GetUymax()); + Double_t xr = 0.05*(gPad->GetX2() - gPad->GetX1()); + Double_t xmin = gPad->PadtoX(xup +0.1*xr); + Double_t xmax = gPad->PadtoX(xup + xr); + if (xmax > x2) xmax = gPad->PadtoX(gPad->GetX2()-0.01*xr); + palette = new TPaletteAxis(xmin,ymin,xmax,ymax,minc,maxc); + palette->SetLabelColor(h->GetZaxis()->GetLabelColor()); + palette->SetLabelFont(h->GetZaxis()->GetLabelFont()); + palette->SetLabelOffset(h->GetZaxis()->GetLabelOffset()); + palette->SetLabelSize(h->GetZaxis()->GetLabelSize()); + palette->SetTitleOffset(h->GetZaxis()->GetTitleOffset()); + palette->SetTitleSize(h->GetZaxis()->GetTitleSize()); + palette->SetNdivisions(h->GetZaxis()->GetNdivisions()); + palette->SetTitle(h->GetZaxis()->GetTitle()); + palette->SetTitleColor(h->GetZaxis()->GetTitleColor()); + palette->SetTitleFont(h->GetZaxis()->GetTitleFont()); + + functions->AddFirst(palette); + } + if (palette) palette->Paint(); } - if (!palette) { - Double_t xup = gPad->GetUxmax(); - Double_t x2 = gPad->PadtoX(gPad->GetX2()); - Double_t ymin = gPad->PadtoY(gPad->GetUymin()); - Double_t ymax = gPad->PadtoY(gPad->GetUymax()); - Double_t xr = 0.05*(gPad->GetX2() - gPad->GetX1()); - Double_t xmin = gPad->PadtoX(xup +0.1*xr); - Double_t xmax = gPad->PadtoX(xup + xr); - if (xmax > x2) xmax = gPad->PadtoX(gPad->GetX2()-0.01*xr); - palette = new TPaletteAxis(xmin,ymin,xmax,ymax,minc,maxc); - palette->SetLabelColor(h->GetZaxis()->GetLabelColor()); - palette->SetLabelFont(h->GetZaxis()->GetLabelFont()); - palette->SetLabelOffset(h->GetZaxis()->GetLabelOffset()); - palette->SetLabelSize(h->GetZaxis()->GetLabelSize()); - palette->SetTitleOffset(h->GetZaxis()->GetTitleOffset()); - palette->SetTitleSize(h->GetZaxis()->GetTitleSize()); - palette->SetNdivisions(h->GetZaxis()->GetNdivisions()); - palette->SetTitle(h->GetZaxis()->GetTitle()); - palette->SetTitleColor(h->GetZaxis()->GetTitleColor()); - palette->SetTitleFont(h->GetZaxis()->GetTitleFont()); - - functions->AddFirst(palette); + } else { + TScatter *s; + TIter next(gPad->GetListOfPrimitives()); + while ((s = (TScatter *)next())) { + if (!s->InheritsFrom(TScatter::Class())) continue; + if (theColor) { + double *ColorInPad = s->GetColor(); + if (ColorInPad) { + minc = TMath::MinElement(n, ColorInPad); + maxc = TMath::MaxElement(n, ColorInPad); + } + } + if (theSize) { + double *SizeInPad = s->GetSize(); + if (SizeInPad) { + mins = TMath::MinElement(n, SizeInPad); + maxs = TMath::MaxElement(n, SizeInPad); + } + } + break; } - if (palette) palette->Paint(); } // Draw markers @@ -4565,6 +4583,198 @@ void TGraphPainter::PaintScatter(TScatter *theScatter, Option_t* chopt) } +//////////////////////////////////////////////////////////////////////////////// +/// Paint a scatter plot + +void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) +{ + + TGraph2D* theGraph = theScatter->GetGraph(); + + Int_t optionSAME = 0, optionSkipCol = 0; + + TString opt = chopt; + opt.ToUpper(); + + if (opt.Contains("SAME")) { + optionSAME = 1; + opt.ReplaceAll("SAME"," "); + } + if (opt.Contains("SKIPCOL")) { + optionSkipCol = 1; + opt.ReplaceAll("SKIPCOL"," "); + } + + opt.Append("TRI0"); + + double *theX = theGraph->GetX(); + double *theY = theGraph->GetY(); + double *theZ = theGraph->GetZ(); + int n = theGraph->GetN(); + double *theColor = theScatter->GetColor(); + double *theSize = theScatter->GetSize(); + double MinMarkerSize = theScatter->GetMinMarkerSize(); + double MaxMarkerSize = theScatter->GetMaxMarkerSize(); + + double minc = 0, maxc = 0., mins = 0., maxs = 0.; + if (theColor) { + minc = TMath::MinElement(n, theColor); + maxc = TMath::MaxElement(n, theColor); + } + if (theSize) { + mins = TMath::MinElement(n, theSize); + maxs = TMath::MaxElement(n, theSize); + } + + // Make sure minimum and maximum values are different + Double_t d, e = 0.1; + if (theColor) { + if (minc == maxc) { + if (theColor[0] == 0.) { + minc = -e; + maxc = e; + } else { + d = TMath::Abs(theColor[0]*e); + minc = theColor[0] - d; + maxc = theColor[0] + d; + } + } + } + if (theSize) { + if (mins == maxs) { + if (theSize[0] == 0.) { + mins = -e; + maxs = e; + } else { + d = TMath::Abs(theSize[0]*e); + mins = theSize[0] - d; + maxs = theSize[0] + d; + } + } + } + + theGraph->SetTitle(theScatter->GetTitle()); + + if (!optionSAME) { + theGraph->Paint(opt.Data()); + + // Define and paint palette + if (theColor) { + TPaletteAxis *palette; + TList *functions = theScatter->GetGraph()->GetListOfFunctions(); + palette = (TPaletteAxis*)functions->FindObject("palette"); + TView *view = gPad->GetView(); + if (palette) { + if (view) { + if (!palette->TestBit(TPaletteAxis::kHasView)) { + functions->Remove(palette); + delete palette; palette = nullptr; + } + } else { + if (palette->TestBit(TPaletteAxis::kHasView)) { + functions->Remove(palette); + delete palette; palette = nullptr; + } + } + } + if (!palette) { + Double_t xup = gPad->GetUxmax(); + Double_t x2 = gPad->PadtoX(gPad->GetX2()); + Double_t ymin = gPad->PadtoY(gPad->GetUymin()); + Double_t ymax = gPad->PadtoY(gPad->GetUymax()); + Double_t xr = 0.05*(gPad->GetX2() - gPad->GetX1()); + Double_t xmin = gPad->PadtoX(xup +0.1*xr); + Double_t xmax = gPad->PadtoX(xup + xr); + if (xmax > x2) xmax = gPad->PadtoX(gPad->GetX2()-0.01*xr); + palette = new TPaletteAxis(xmin,ymin,xmax,ymax,minc,maxc); + palette->SetLabelColor(theGraph->GetZaxis()->GetLabelColor()); + palette->SetLabelFont(theGraph->GetZaxis()->GetLabelFont()); + palette->SetLabelOffset(theGraph->GetZaxis()->GetLabelOffset()); + palette->SetLabelSize(theGraph->GetZaxis()->GetLabelSize()); + // palette->SetTitleOffset(theGraph->GetZaxis()->GetTitleOffset()); + // palette->SetTitleSize(theGraph->GetZaxis()->GetTitleSize()); + palette->SetNdivisions(theGraph->GetZaxis()->GetNdivisions()); + // palette->SetTitle(theGraph->GetZaxis()->GetTitle()); + // palette->SetTitleColor(theGraph->GetZaxis()->GetTitleColor()); + // palette->SetTitleFont(theGraph->GetZaxis()->GetTitleFont()); + + functions->AddFirst(palette); + } + if (palette) palette->Paint(); + } + } else { + TScatter2D *s2; + TIter next(gPad->GetListOfPrimitives()); + while ((s2 = (TScatter2D *)next())) { + if (!s2->InheritsFrom(TScatter2D::Class())) continue; + if (theColor) { + double *ColorInPad = s2->GetColor(); + if (ColorInPad) { + minc = TMath::MinElement(n, ColorInPad); + maxc = TMath::MaxElement(n, ColorInPad); + } + } + if (theSize) { + double *SizeInPad = s2->GetSize(); + if (SizeInPad) { + mins = TMath::MinElement(n, SizeInPad); + maxs = TMath::MaxElement(n, SizeInPad); + } + } + break; + } + } + + // Draw markers + auto nbcol = gStyle->GetNumberOfColors(); + int logx = gPad->GetLogx(); + int logy = gPad->GetLogy(); + int logz = gPad->GetLogz(); + int nc; + double x,y,z,c, ms; + for (Int_t i = 0; i < n; i++) { + if (theColor) { + c = theColor[i]; + if (cmaxc) { + if (optionSkipCol) continue; + c = maxc; + } + nc = TMath::Nint(((c-minc)/(maxc-minc))*(nbcol-1)); + if (nc > nbcol-1) nc = nbcol-1; + theScatter->SetMarkerColor(gStyle->GetColorPalette(nc)); + } + if (theSize) { + ms = (MaxMarkerSize-MinMarkerSize)*((theSize[i]-mins)/(maxs-mins))+MinMarkerSize; + theScatter->SetMarkerSize(ms); + } + theScatter->TAttMarker::Modify(); + if (logx) { + if (theX[i]>0) x = log10(theX[i]); + else break; + } else { + x = theX[i]; + } + if (logy) { + if (theY[i]>0) y = log10(theY[i]); + else break; + } else { + y = theY[i]; + } + if (logz) { + if (theZ[i]>0) z = log10(theZ[i]); + else break; + } else { + z = theZ[i]; + } + gPad->PaintMarker3D(x, y, z); + } +} + + //////////////////////////////////////////////////////////////////////////////// /// Paint a simple graph, without errors bars. diff --git a/tutorials/visualisation/graphs/gr006_scatter.C b/tutorials/visualisation/graphs/gr006_scatter.C index b02839ee9761b..476c1859a763a 100644 --- a/tutorials/visualisation/graphs/gr006_scatter.C +++ b/tutorials/visualisation/graphs/gr006_scatter.C @@ -16,28 +16,40 @@ void gr006_scatter() gStyle->SetPalette(kBird, 0, 0.6); // define a transparent palette const int n = 175; - double x[n]; - double y[n]; - double c[n]; - double s[n]; + double x1[n]; + double y1[n]; + double c1[n]; + double s1[n]; + double x2[n]; + double y2[n]; + double c2[n]; + double s2[n]; // Define four random data sets auto r = new TRandom(); for (int i=0; iRndm(i); - y[i] = 200*r->Rndm(i); - c[i] = 300*r->Rndm(i); - s[i] = 400*r->Rndm(i); + x1[i] = 100*r->Rndm(i); + y1[i] = 200*r->Rndm(i); + c1[i] = 300*r->Rndm(i); + s1[i] = 400*r->Rndm(i); + x2[i] = 100*r->Rndm(i); + y2[i] = 200*r->Rndm(i); + c2[i] = 100*r->Rndm(i); + s2[i] = 200*r->Rndm(i); } - auto scatter = new TScatter(n, x, y, c, s); - scatter->SetMarkerStyle(20); - scatter->SetTitle("Scatter plot title;X title;Y title;Z title"); - scatter->GetXaxis()->SetRangeUser(20.,90.); - scatter->GetYaxis()->SetRangeUser(55.,90.); - scatter->GetZaxis()->SetRangeUser(10.,200.); + auto scatter1 = new TScatter(n, x1, y1, c1, s1); + scatter1->SetMarkerStyle(20); + scatter1->SetTitle("Scatter plot title;X title;Y title;Z title"); + scatter1->GetXaxis()->SetRangeUser(20.,90.); + scatter1->GetYaxis()->SetRangeUser(55.,90.); + scatter1->GetZaxis()->SetRangeUser(10.,200.); // an alternative way to zoom the Z-axis: // scatter->GetHistogram()->SetMinimum(10); // scatter->GetHistogram()->SetMaximum(200); - scatter->Draw("A"); + scatter1->Draw("A"); + + auto scatter2 = new TScatter(n, x2, y2, c2, s2); + scatter2->SetMarkerStyle(21); + scatter2->Draw(); } diff --git a/tutorials/visualisation/graphs/gr019_scatter2d.C b/tutorials/visualisation/graphs/gr019_scatter2d.C new file mode 100644 index 0000000000000..58152f2d7838d --- /dev/null +++ b/tutorials/visualisation/graphs/gr019_scatter2d.C @@ -0,0 +1,53 @@ +/// \file +/// \ingroup tutorial_graphs +/// \notebook +/// Draw a 2D scatter plot. +/// +/// \macro_image +/// \macro_code +/// +/// \author Olivier Couet + +void gr019_scatter2d() +{ + auto canvas = new TCanvas(); +// canvas->SetRightMargin(0.14); + gStyle->SetPalette(kBird, 0, 0.6); // define a transparent palette + + const int n = 50; + double x1[n]; + double y1[n]; + double z1[n]; + double c1[n]; + double s1[n]; + double x2[n]; + double y2[n]; + double z2[n]; + double c2[n]; + double s2[n]; + + // Define four random data set + auto r = new TRandom(); + for (int i=0; iRndm(i); + y1[i] = 200*r->Rndm(i); + z1[i] = 10*r->Rndm(i); + c1[i] = 100*r->Rndm(i); + s1[i] = 400*r->Rndm(i); + x2[i] = 100*r->Rndm(i); + y2[i] = 200*r->Rndm(i); + z2[i] = 10*r->Rndm(i); + c2[i] = 50*r->Rndm(i); + s2[i] = 100*r->Rndm(i); + } + + auto scatter1 = new TScatter2D(n, x1, y1, z1, c1, s1); + scatter1->SetTitle("Scatter plot title;X title;Y title;Z title;C title"); + scatter1->SetMarkerStyle(20); + + auto scatter2 = new TScatter2D(n, x2, y2, z2, c2, s2); + scatter2->SetMarkerStyle(21); + + scatter1->Draw(); + scatter2->Draw("SAME"); +} From 4096f75ee6cd08ea52f3e824d0f19254eb7991e0 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 24 Oct 2025 15:03:26 +0200 Subject: [PATCH 2/7] Fix typo --- hist/hist/src/TScatter2D.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx index a39b46fd55b3f..0205ae96c8311 100644 --- a/hist/hist/src/TScatter2D.cxx +++ b/hist/hist/src/TScatter2D.cxx @@ -22,7 +22,7 @@ /** \class TScatter2D \ingroup Graphs -A TScatter2D is able to draw give variables scatter plot on a single plot. The three first +A TScatter2D is able to draw five variables scatter plot on a single plot. The three first variables are the x, y and z position of the markers (stored in a TGraph2D), the fourth is mapped on the current color map and the fifth on the marker size. From 4ea121d87075a950ffdf1b626bfe179569dfb188 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 24 Oct 2025 15:37:31 +0200 Subject: [PATCH 3/7] Add protection against null fGraph --- hist/hist/src/TScatter2D.cxx | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx index 0205ae96c8311..22890a5a6163f 100644 --- a/hist/hist/src/TScatter2D.cxx +++ b/hist/hist/src/TScatter2D.cxx @@ -145,7 +145,8 @@ void TScatter2D::ExecuteEvent(Int_t event, Int_t px, Int_t py) TH2D *TScatter2D::GetHistogram() const { - return fGraph->GetHistogram();; + if (fGraph) return fGraph->GetHistogram(); + else return nullptr; } @@ -154,7 +155,8 @@ TH2D *TScatter2D::GetHistogram() const TAxis *TScatter2D::GetXaxis() const { - return fGraph->GetXaxis(); + if (fGraph) return fGraph->GetXaxis(); + else return nullptr; } @@ -163,7 +165,8 @@ TAxis *TScatter2D::GetXaxis() const TAxis *TScatter2D::GetYaxis() const { - return fGraph->GetYaxis(); + if (fGraph) return fGraph->GetYaxis(); + else return nullptr; } @@ -172,7 +175,8 @@ TAxis *TScatter2D::GetYaxis() const TAxis *TScatter2D::GetZaxis() const { - return fGraph->GetZaxis(); + if (fGraph) return fGraph->GetZaxis(); + else return nullptr; } @@ -191,6 +195,8 @@ void TScatter2D::Paint(Option_t *option) void TScatter2D::Print(Option_t *) const { + if (!fGraph) return; + Double_t *X = fGraph->GetX(); Double_t *Y = fGraph->GetY(); Double_t *Z = fGraph->GetZ(); @@ -219,6 +225,8 @@ void TScatter2D::SetMargin(Double_t margin) void TScatter2D::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/) { + if (!fGraph) return; + char quote = '"'; out << " " << std::endl; static Int_t frameNumber = 1000; From 79c6fdd39ed1b21382cc1fca10c5d386c73f7021 Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 24 Oct 2025 16:09:59 +0200 Subject: [PATCH 4/7] Change SavePrimitives to the new way (like TScatter.cxx) --- hist/hist/src/TScatter2D.cxx | 65 ++++++++++-------------------------- 1 file changed, 18 insertions(+), 47 deletions(-) diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx index 22890a5a6163f..6150a821a7102 100644 --- a/hist/hist/src/TScatter2D.cxx +++ b/hist/hist/src/TScatter2D.cxx @@ -225,54 +225,25 @@ void TScatter2D::SetMargin(Double_t margin) void TScatter2D::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/) { - if (!fGraph) return; - - char quote = '"'; - out << " " << std::endl; - static Int_t frameNumber = 1000; - frameNumber++; - - Int_t i; - Double_t *X = fGraph->GetX(); - Double_t *Y = fGraph->GetY(); - Double_t *Z = fGraph->GetZ(); - TString fXName = TString::Format("%s_fx%d",GetName(),frameNumber); - TString fYName = TString::Format("%s_fy%d", GetName(),frameNumber); - TString fZName = TString::Format("%s_fz%d", GetName(),frameNumber); - TString fColorName = TString::Format("%s_fcolor%d",GetName(),frameNumber); - TString fSizeName = TString::Format("%s_fsize%d",GetName(),frameNumber); - out << " Double_t " << fXName << "[" << fNpoints << "] = {" << std::endl; - for (i = 0; i < fNpoints-1; i++) out << " " << X[i] << "," << std::endl; - out << " " << X[fNpoints-1] << "};" << std::endl; - out << " Double_t " << fYName << "[" << fNpoints << "] = {" << std::endl; - for (i = 0; i < fNpoints-1; i++) out << " " << Y[i] << "," << std::endl; - out << " " << Y[fNpoints-1] << "};" << std::endl; - out << " Double_t " << fZName << "[" << fNpoints << "] = {" << std::endl; - for (i = 0; i < fNpoints-1; i++) out << " " << Z[i] << "," << std::endl; - out << " " << Z[fNpoints-1] << "};" << std::endl; - out << " Double_t " << fColorName << "[" << fNpoints << "] = {" << std::endl; - for (i = 0; i < fNpoints-1; i++) out << " " << fColor[i] << "," << std::endl; - out << " " << fColor[fNpoints-1] << "};" << std::endl; - out << " Double_t " << fSizeName << "[" << fNpoints << "] = {" << std::endl; - for (i = 0; i < fNpoints-1; i++) out << " " << fSize[i] << "," << std::endl; - out << " " << fSize[fNpoints-1] << "};" << std::endl; - - if (gROOT->ClassSaved(TScatter2D::Class())) - out << " "; - else - out << " TScatter2D *"; - out << "scat = new TScatter2D(" << fNpoints << "," << fXName << "," << fYName << "," << fZName << "," - << fColorName << "," << fSizeName << ");" << std::endl; - - out << " scat->SetName(" << quote << GetName() << quote << ");" << std::endl; - out << " scat->SetTitle(" << quote << GetTitle() << quote << ");" << std::endl; - out << " scat->SetMargin(" << GetMargin() << ");" << std::endl; - out << " scat->SetMinMarkerSize(" << GetMinMarkerSize() << ");" << std::endl; - out << " scat->SetMaxMarkerSize(" << GetMaxMarkerSize() << ");" << std::endl; - + TString arr_x = SavePrimitiveVector(out, "scat_x", fNpoints, fGraph->GetX(), kTRUE); + TString arr_y = SavePrimitiveVector(out, "scat_y", fNpoints, fGraph->GetY()); + TString arr_z = SavePrimitiveVector(out, "scat_z", fNpoints, fGraph->GetZ()); + TString arr_col = SavePrimitiveVector(out, "scat_col", fNpoints, fColor); + TString arr_size = SavePrimitiveVector(out, "scat_size", fNpoints, fSize); + + SavePrimitiveConstructor(out, Class(), "scat", + TString::Format("%d, %s.data(), %s.data(), %s.data(), %s.data(), %s.data()", fNpoints, arr_x.Data(), + arr_y.Data(), arr_z.Data(), arr_col.Data(), arr_size.Data()), + kFALSE); + + SavePrimitiveNameTitle(out, "scat"); SaveFillAttributes(out, "scat", 0, 1001); SaveLineAttributes(out, "scat", 1, 1, 1); SaveMarkerAttributes(out, "scat", 1, 1, 1); - out << " scat->Draw(" << quote << option << quote << ");" << std::endl; -} + out << " scat->SetMargin(" << GetMargin() << ");\n"; + out << " scat->SetMinMarkerSize(" << GetMinMarkerSize() << ");\n"; + out << " scat->SetMaxMarkerSize(" << GetMaxMarkerSize() << ");\n"; + + SavePrimitiveDraw(out, "scat", option); +} \ No newline at end of file From d0901bcc9979e1dfe62fba616f7e5fc00e029d1a Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Thu, 30 Oct 2025 17:24:49 +0100 Subject: [PATCH 5/7] Implement log scales --- core/base/src/TObject.cxx | 2 +- hist/hist/src/TScatter2D.cxx | 15 +++-- hist/histpainter/inc/TPaletteAxis.h | 3 + hist/histpainter/src/TGraphPainter.cxx | 56 ++++++++++++++++--- hist/histpainter/src/TPaletteAxis.cxx | 41 ++++++++++---- tutorials/visualisation/graphs/canvas.C | 49 ++++++++++++++++ .../visualisation/graphs/gr019_scatter2d.C | 32 ++++++----- 7 files changed, 159 insertions(+), 39 deletions(-) create mode 100644 tutorials/visualisation/graphs/canvas.C diff --git a/core/base/src/TObject.cxx b/core/base/src/TObject.cxx index 4f41e83d3531c..1512ab7e1a026 100644 --- a/core/base/src/TObject.cxx +++ b/core/base/src/TObject.cxx @@ -795,7 +795,7 @@ TString TObject::SavePrimitiveVector(std::ostream &out, const char *prefix, Int_ out << " \n"; out << " std::vector " << vectame; - if (len > 0) { + if (len > 0 && arr) { const auto old_precision{out.precision()}; constexpr auto max_precision{std::numeric_limits::digits10 + 1}; out << std::setprecision(max_precision); diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx index 6150a821a7102..341ee92d49444 100644 --- a/hist/hist/src/TScatter2D.cxx +++ b/hist/hist/src/TScatter2D.cxx @@ -38,6 +38,13 @@ TScatter2D can be drawn with the following options: | Option | Description | |----------|-------------------------------------------------------------------| | "SAME" | Superimpose on previous picture in the same pad.| +| "LOGC" | Log scale for colors.| +| "LOGS" | Log scale for size.| + +In the case of the SAME option, the log scale for color and size is inherited from the +previously drawn TScatter2D. For example, if a TScatter2D is drawn on top of another one +that uses a log scale for color, the second TScatter2D will also use a log scale for its +colors, even if the log scale for color is not explicitly specified for the second plot. */ @@ -225,10 +232,10 @@ void TScatter2D::SetMargin(Double_t margin) void TScatter2D::SavePrimitive(std::ostream &out, Option_t *option /*= ""*/) { - TString arr_x = SavePrimitiveVector(out, "scat_x", fNpoints, fGraph->GetX(), kTRUE); - TString arr_y = SavePrimitiveVector(out, "scat_y", fNpoints, fGraph->GetY()); - TString arr_z = SavePrimitiveVector(out, "scat_z", fNpoints, fGraph->GetZ()); - TString arr_col = SavePrimitiveVector(out, "scat_col", fNpoints, fColor); + TString arr_x = SavePrimitiveVector(out, "scat_x", fNpoints, fGraph->GetX(), kTRUE); + TString arr_y = SavePrimitiveVector(out, "scat_y", fNpoints, fGraph->GetY()); + TString arr_z = SavePrimitiveVector(out, "scat_z", fNpoints, fGraph->GetZ()); + TString arr_col = SavePrimitiveVector(out, "scat_col", fNpoints, fColor); TString arr_size = SavePrimitiveVector(out, "scat_size", fNpoints, fSize); SavePrimitiveConstructor(out, Class(), "scat", diff --git a/hist/histpainter/inc/TPaletteAxis.h b/hist/histpainter/inc/TPaletteAxis.h index 291ab3e00f6e3..f597c009a89fd 100644 --- a/hist/histpainter/inc/TPaletteAxis.h +++ b/hist/histpainter/inc/TPaletteAxis.h @@ -30,6 +30,7 @@ class TPaletteAxis : public TPave { protected: TGaxis fAxis; ///< Palette axis TH1 *fH; ///GetZaxis()->SetNdivisions(ndiv); else fAxis.SetNdivisions(ndiv);} // *MENU* virtual void SetLabelColor(Int_t color=1) {if (fH) fH->GetZaxis()->SetLabelColor(color); else fAxis.SetLabelColor(color);} // *MENU* diff --git a/hist/histpainter/src/TGraphPainter.cxx b/hist/histpainter/src/TGraphPainter.cxx index 635ea603119d0..306053bfcca06 100644 --- a/hist/histpainter/src/TGraphPainter.cxx +++ b/hist/histpainter/src/TGraphPainter.cxx @@ -4591,7 +4591,7 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) TGraph2D* theGraph = theScatter->GetGraph(); - Int_t optionSAME = 0, optionSkipCol = 0; + Int_t optionSAME = 0, optionSkipCol = 0, optionLOGC = 1, optionLOGS = 0; TString opt = chopt; opt.ToUpper(); @@ -4604,6 +4604,14 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) optionSkipCol = 1; opt.ReplaceAll("SKIPCOL"," "); } + if (opt.Contains("LOGC")) { + optionLOGC = 2; + opt.ReplaceAll("LOGC"," "); + } + if (opt.Contains("LOGS")) { + optionLOGS = 1; + opt.ReplaceAll("LOGS"," "); + } opt.Append("TRI0"); @@ -4660,8 +4668,8 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) // Define and paint palette if (theColor) { - TPaletteAxis *palette; TList *functions = theScatter->GetGraph()->GetListOfFunctions(); + TPaletteAxis *palette = nullptr; palette = (TPaletteAxis*)functions->FindObject("palette"); TView *view = gPad->GetView(); if (palette) { @@ -4687,16 +4695,17 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) Double_t xmax = gPad->PadtoX(xup + xr); if (xmax > x2) xmax = gPad->PadtoX(gPad->GetX2()-0.01*xr); palette = new TPaletteAxis(xmin,ymin,xmax,ymax,minc,maxc); + palette->SetLog(optionLOGC); palette->SetLabelColor(theGraph->GetZaxis()->GetLabelColor()); palette->SetLabelFont(theGraph->GetZaxis()->GetLabelFont()); palette->SetLabelOffset(theGraph->GetZaxis()->GetLabelOffset()); palette->SetLabelSize(theGraph->GetZaxis()->GetLabelSize()); - // palette->SetTitleOffset(theGraph->GetZaxis()->GetTitleOffset()); - // palette->SetTitleSize(theGraph->GetZaxis()->GetTitleSize()); + //palette->SetTitleOffset(theGraph->GetZaxis()->GetTitleOffset()); + palette->SetTitleSize(theGraph->GetZaxis()->GetTitleSize()); palette->SetNdivisions(theGraph->GetZaxis()->GetNdivisions()); - // palette->SetTitle(theGraph->GetZaxis()->GetTitle()); - // palette->SetTitleColor(theGraph->GetZaxis()->GetTitleColor()); - // palette->SetTitleFont(theGraph->GetZaxis()->GetTitleFont()); + //palette->SetTitle(theGraph->GetTitle()); + //palette->SetTitleColor(theGraph->GetZaxis()->GetTitleColor()); + //palette->SetTitleFont(theGraph->GetZaxis()->GetTitleFont()); functions->AddFirst(palette); } @@ -4707,6 +4716,11 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) TIter next(gPad->GetListOfPrimitives()); while ((s2 = (TScatter2D *)next())) { if (!s2->InheritsFrom(TScatter2D::Class())) continue; + TString opt2 = s2->GetDrawOption(); + if (opt2.Contains("LOGC")) optionLOGC = 2; + else optionLOGC = 1; + if (opt2.Contains("LOGS")) optionLOGS = 1; + else optionLOGS = 0; if (theColor) { double *ColorInPad = s2->GetColor(); if (ColorInPad) { @@ -4730,11 +4744,29 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) int logx = gPad->GetLogx(); int logy = gPad->GetLogy(); int logz = gPad->GetLogz(); + int logc = 0; + if (optionLOGC == 2) logc =1; + if (theColor && logc) { + if (minc>0) minc = log10(minc); + if (maxc>0) maxc = log10(maxc); + } + if (theSize && optionLOGS) { + if (mins>0) mins = log10(mins); + if (maxs>0) maxs = log10(maxs); + } + theScatter->SetMarkerColor(theScatter->GetMarkerColor()); + theScatter->TAttMarker::Modify(); + double x,y,z,c,s,ms; int nc; - double x,y,z,c, ms; for (Int_t i = 0; i < n; i++) { if (theColor) { c = theColor[i]; + if (logc){ + if (theColor[i]>0) c = log10(theColor[i]); + else continue; + } else { + c = theColor[i]; + } if (cSetMarkerColor(gStyle->GetColorPalette(nc)); } if (theSize) { - ms = (MaxMarkerSize-MinMarkerSize)*((theSize[i]-mins)/(maxs-mins))+MinMarkerSize; + if (optionLOGS){ + if (theSize[i]>0) s = log10(theSize[i]); + else continue; + } else { + s = theSize[i]; + } + ms = (MaxMarkerSize-MinMarkerSize)*((s-mins)/(maxs-mins))+MinMarkerSize; theScatter->SetMarkerSize(ms); } theScatter->TAttMarker::Modify(); diff --git a/hist/histpainter/src/TPaletteAxis.cxx b/hist/histpainter/src/TPaletteAxis.cxx index 85a2d0c7a779c..4a80548c86078 100644 --- a/hist/histpainter/src/TPaletteAxis.cxx +++ b/hist/histpainter/src/TPaletteAxis.cxx @@ -118,6 +118,7 @@ End_Macro TPaletteAxis::TPaletteAxis() { fH = nullptr; + fLog = 0; SetName(""); } @@ -129,6 +130,7 @@ TPaletteAxis::TPaletteAxis(Double_t x1, Double_t y1, Double_t x2, Double_t y2, : TPave(x1, y1, x2, y2) { fH = h; + fLog = 0; if (!fH) return; SetName("palette"); TAxis *zaxis = fH->GetZaxis(); @@ -143,7 +145,8 @@ TPaletteAxis::TPaletteAxis(Double_t x1, Double_t y1, Double_t x2, Double_t y2, TPaletteAxis::TPaletteAxis(Double_t x1, Double_t y1, Double_t x2, Double_t y2, Double_t min, Double_t max) : TPave(x1, y1, x2, y2) { - fH = nullptr; + fH = nullptr; + fLog = 0; fAxis.SetWmin(min); fAxis.SetWmax(max); SetName("palette"); @@ -158,6 +161,7 @@ TPaletteAxis::TPaletteAxis(Double_t x1, Double_t y1, Double_t x2, Double_t y2, : TPave(x1, y1, x2, y2) { fH = nullptr; + fLog = 0; SetName("palette"); fAxis.ImportAxisAttributes(ax); if (gPad->GetView()) SetBit(kHasView); @@ -288,7 +292,7 @@ void TPaletteAxis::ExecuteEvent(Int_t event, Int_t px, Int_t py) if (fH->GetDimension() == 2) { Double_t zmin = fH->GetMinimum(); Double_t zmax = fH->GetMaximum(); - if (gPad->GetLogz()) { + if (GetLog()) { if (zmin <= 0 && zmax > 0) zmin = TMath::Min((Double_t)1, (Double_t)0.001 * zmax); zmin = TMath::Log10(zmin); @@ -298,7 +302,7 @@ void TPaletteAxis::ExecuteEvent(Int_t event, Int_t px, Int_t py) Double_t newmax = zmin + (zmax - zmin) * ratio2; if (newmin < zmin)newmin = fH->GetBinContent(fH->GetMinimumBin()); if (newmax > zmax)newmax = fH->GetBinContent(fH->GetMaximumBin()); - if (gPad->GetLogz()) { + if (GetLog()) { newmin = TMath::Exp(2.302585092994 * newmin); newmax = TMath::Exp(2.302585092994 * newmax); } @@ -315,6 +319,21 @@ void TPaletteAxis::ExecuteEvent(Int_t event, Int_t px, Int_t py) } } +//////////////////////////////////////////////////////////////////////////////// +/// Returns whether the palette is in log scale. +/// +/// By default, the palette axis is logarithmic if the TPad's option Logz is set. +/// However, in some cases, such as with TScatter2D, the color represents a fourth dimension, +/// and the log scale is not defined by the Z axis but by a dedicated setting specified +/// through a separate option. +/// +/// This method handles these various cases and returns the correct state of the palette axis. + +Int_t TPaletteAxis::GetLog() const +{ + if (fLog == 0) return gPad->GetLogz(); + return fLog-1; +} //////////////////////////////////////////////////////////////////////////////// /// Returns the color index of the bin (i,j). @@ -359,7 +378,7 @@ char *TPaletteAxis::GetObjectInfo(Int_t /* px */, Int_t py) const Int_t y2 = gPad->GetWh() - gPad->VtoPixel(fY2NDC); Int_t y = gPad->GetWh() - py; - if (gPad->GetLogz()) { + if (GetLog()) { if (zmin <= 0 && zmax > 0) zmin = TMath::Min((Double_t)1, (Double_t)0.001 * zmax); Double_t zminl = TMath::Log10(zmin); @@ -401,7 +420,7 @@ Int_t TPaletteAxis::GetValueColor(Double_t zc) Double_t wlmin = wmin; Double_t wlmax = wmax; - if (gPad->GetLogz()) { + if (GetLog()) { if (wmin <= 0 && wmax > 0) wmin = TMath::Min((Double_t)1, (Double_t)0.001 * wmax); wlmin = TMath::Log10(wmin); @@ -416,7 +435,7 @@ Int_t TPaletteAxis::GetValueColor(Double_t zc) Int_t theColor, color; Double_t scale = ndivz / (wlmax - wlmin); - if (fH->TestBit(TH1::kUserContour) && gPad->GetLogz()) zc = TMath::Log10(zc); + if (fH->TestBit(TH1::kUserContour) && GetLog()) zc = TMath::Log10(zc); if (zc < wlmin) zc = wlmin; color = Int_t(0.01 + (zc - wlmin) * scale); @@ -462,7 +481,7 @@ void TPaletteAxis::Paint(Option_t *) if (GetX2NDC()-GetX1NDC() > GetY2NDC()-GetY1NDC()) kHorizontal = true; - if (gPad->GetLogz()) { + if (GetLog()) { if (wmin <= 0 && wmax > 0) wmin = TMath::Min((Double_t)1, (Double_t)0.001 * wmax); wlmin = TMath::Log10(wmin); wlmax = TMath::Log10(wmax); @@ -517,7 +536,7 @@ void TPaletteAxis::Paint(Option_t *) if (fH) zc = fH->GetContourLevel(i); else zc = wlmin + i*dw; - if (fH && fH->TestBit(TH1::kUserContour) && gPad->GetLogz()) + if (fH && fH->TestBit(TH1::kUserContour) && GetLog()) zc = TMath::Log10(zc); w1 = zc; if (w1 < wlmin) w1 = wlmin; @@ -526,7 +545,7 @@ void TPaletteAxis::Paint(Option_t *) if (i < ndivz - 1) { if (fH) zc = fH->GetContourLevel(i + 1); else zc = wlmin + (i+1)*dw; - if (fH && fH->TestBit(TH1::kUserContour) && gPad->GetLogz()) + if (fH && fH->TestBit(TH1::kUserContour) && GetLog()) zc = TMath::Log10(zc); w2 = zc; } @@ -559,7 +578,7 @@ void TPaletteAxis::Paint(Option_t *) Double_t lsize = fAxis.GetLabelSize(); Double_t lsize_user = lsize*(gPad->GetUymax()-gPad->GetUymin()); Double_t zlab = fH->GetContourLevel(i); - if (gPad->GetLogz()&& !fH->TestBit(TH1::kUserContour)) { + if (GetLog()&& !fH->TestBit(TH1::kUserContour)) { zlab = TMath::Power(10, zlab); } // make sure labels dont overlap @@ -599,7 +618,7 @@ void TPaletteAxis::Paint(Option_t *) ndiv = TMath::Abs(ndiv); strncat(chopt, "N", 2); } - if (gPad->GetLogz()) { + if (GetLog()) { wmin = TMath::Power(10., wlmin); wmax = TMath::Power(10., wlmax); strncat(chopt, "G", 2); diff --git a/tutorials/visualisation/graphs/canvas.C b/tutorials/visualisation/graphs/canvas.C new file mode 100644 index 0000000000000..e3179e1758cc6 --- /dev/null +++ b/tutorials/visualisation/graphs/canvas.C @@ -0,0 +1,49 @@ +{ +//========= Macro generated from object: /Scatter plot title;X title;Y title;Z title +//========= by ROOT version6.37.01 + + std::vector scat_x_vect0{ + 15.43001532554629, 49.03009934350856, 85.44955085963024, 77.79588783159865, 1.423704251646998, 95.67470615729704, 14.48920760303738, 75.2201412804426, 6.504075974226008, 74.75467054173362, + 52.24243160337218, 15.31057963147762, 66.55026562511931, 97.2193180583419, 83.33713728934539, 78.22429211810244, 63.27881067991267, 84.99209536239518, 77.10582893341792, 79.89717656746519, + 61.35302595794211, 54.95494520291695, 93.44497565180077, 74.77831440046441, 82.9923786222936, 40.43268142268068, 26.17438640445475, 96.06434563174858, 20.08186317980293, 50.17736395820983, + 83.89658499509109, 33.43384386971598, 83.78137648105634, 64.85267383977781, 8.356185071170342, 48.28169131651529, 91.63509272038951, 71.01828819140803, 30.29926512390379, 26.45345376804475, + 92.18083843588843, 32.61425523087387, 62.83274348825226, 68.47975561395299, 27.05946750938897, 99.94536926969901, 32.28375334292655, 17.31065483763817, 30.62423616647725, 56.16554571315655 + }; + std::vector scat_y_vect1{ + 84.64903170242918, 178.853353019804, 104.0105079300703, 40.95906941220171, 92.1287016011776, 10.94613512977959, 155.8444139547649, 68.04533554241073, 184.3943812884393, 155.5118090473118, + 20.38295464590195, 66.24516425654302, 152.2381545044484, 171.7689721845093, 146.9021004624667, 163.3196334354582, 141.5058159269395, 73.79462039098155, 12.77840780094268, 149.3100943975153, + 142.9406211711469, 39.11789795383817, 0.8327689953148377, 72.63192189857375, 57.02703678980478, 92.31384759768858, 51.67416231706746, 11.16826413199307, 133.834490273148, 163.597160484642, + 91.04340197518482, 18.36379272863272, 187.8611200489107, 122.4159262143077, 32.15688811615114, 44.31845275685198, 187.877525482327, 186.0453828237954, 153.0503568239513, 31.88121272251015, + 21.77051687613133, 103.1816667877139, 48.92263012006887, 187.7438145689669, 36.38686547055846, 112.5355630181731, 159.4793659634891, 28.53452367708091, 152.3770534433427, 76.42625486478222 + }; + std::vector scat_z_vect2{ + 7.905995836481464, 3.836069423705346, 7.051348360255371, 5.868942588567743, 5.94781900756062, 9.47714833542706, 2.358731562271718, 6.109580211341391, 2.206818377599124, 3.061918262392287, + 9.494874672964229, 3.231267705559735, 8.316256580874338, 1.179391350597145, 9.142722943797722, 5.192035771906384, 6.577120861038575, 0.02185123041272167, 0.7584149856120359, 0.002405345439910893, + 9.606560571119203, 7.220790516585122, 4.094720268622047, 4.436325095593936, 3.736324673518544, 7.432848308235418, 4.474476622417576, 6.492108926177035, 6.161199240013967, 1.675747688859704, + 1.814027735963466, 1.603373475372794, 5.837444951757798, 0.4142332263290888, 3.396660657599574, 2.599975615739826, 8.13123459927739, 0.3960084728896624, 0.3960432950407273, 3.418949954211717, + 3.217090582475071, 5.237673465162524, 8.149661915376795, 6.565446332097063, 8.226322410628214, 9.76066222414376, 0.1822586450725797, 4.323667325079448, 3.145464202389126, 8.077180255204452 + }; + std::vector scat_col_vect3{ + 1, 9937.263936735706, 3347.600004635756, 8514.314410276724, 9343.961733393386, 7270.1761359349, 7829.560949467134, 3765.593399293727, 2626.853059045975, 1493.851379491391, + 980.4583853110686, 3761.391383595771, 8326.449277810765, 5205.144830979415, 9292.105971835568, 6884.085987694572, 8363.641197793198, 5882.503450848171, 8659.393540583564, 5362.490382976839, + 2245.989548973743, 6003.153496421883, 434.9745949730284, 4764.040787704296, 7497.412483207892, 1910.288021899763, 6233.953810296963, 2236.983967013661, 8837.873074226094, 1430.254378356042, + 1488.574533723297, 3502.564732916659, 6113.066817633818, 239.741713739932, 7752.906284295034, 8597.213444300009, 974.1091309115305, 6982.968472875666, 3757.532252930111, 6364.733506925414, + 2307.222853414718, 7138.869897462439, 5214.236802421518, 7698.488873429608, 413.4257463738329, 5638.285526074478, 3370.692967437213, 7533.591543324304, 9938.217992894368, 8231.146694161011 + }; + std::vector scat_size_vect4{ + 1937.083806842568, 7776.606539264333, 9277.679659426227, 2463.59272859991, 1496.268082410099, 9839.400174096243, 9393.701851367965, 2592.050535604362, 7032.171022146951, 1033.085370436312, + 5278.90410274268, 4209.626680240041, 4783.462975174196, 3418.781207874423, 8076.131567358982, 5311.88848428429, 5474.898274987945, 6776.1126253754, 4488.532133400447, 8780.877878889454, + 7403.252739459287, 1376.647921279075, 6740.493923425684, 7033.548904582869, 3273.261170834308, 4507.336253300316, 6288.582794368277, 420.2052112668759, 783.5548557341111, 743.9451385289442, + 1282.479837536814, 9372.937558218851, 6962.599065154802, 5974.497953429827, 7775.918878614914, 304.0613140910869, 6254.63055446745, 5172.711433842786, 4687.62397766114, 5254.553956910976, + 2355.595063418154, 3921.433174982673, 2512.246929109101, 5292.492574080833, 3799.084816128021, 3686.079131439334, 5781.304761767396, 7661.491362378013, 3292.276021093135, 838.0711171776069 + }; + TScatter2D *scat = new TScatter2D(50, scat_x_vect0.data(), scat_y_vect1.data(), scat_z_vect2.data(), scat_col_vect3.data(), scat_size_vect4.data()); + scat->SetName(""); + scat->SetTitle("Scatter plot title;X title;Y title;Z title"); + scat->SetFillColor(19); + scat->SetMarkerStyle(20); + scat->SetMargin(0.1); + scat->SetMinMarkerSize(1); + scat->SetMaxMarkerSize(5); + scat->Draw(); +} diff --git a/tutorials/visualisation/graphs/gr019_scatter2d.C b/tutorials/visualisation/graphs/gr019_scatter2d.C index 58152f2d7838d..7062dec8626b7 100644 --- a/tutorials/visualisation/graphs/gr019_scatter2d.C +++ b/tutorials/visualisation/graphs/gr019_scatter2d.C @@ -10,8 +10,8 @@ void gr019_scatter2d() { - auto canvas = new TCanvas(); -// canvas->SetRightMargin(0.14); + auto canvas = new TCanvas("canvas","canvas"); + canvas->SetRightMargin(0.14); gStyle->SetPalette(kBird, 0, 0.6); // define a transparent palette const int n = 50; @@ -29,25 +29,29 @@ void gr019_scatter2d() // Define four random data set auto r = new TRandom(); for (int i=0; iRndm(i); - y1[i] = 200*r->Rndm(i); - z1[i] = 10*r->Rndm(i); - c1[i] = 100*r->Rndm(i); - s1[i] = 400*r->Rndm(i); - x2[i] = 100*r->Rndm(i); - y2[i] = 200*r->Rndm(i); - z2[i] = 10*r->Rndm(i); - c2[i] = 50*r->Rndm(i); - s2[i] = 100*r->Rndm(i); + x1[i] = 100*r->Rndm(i); + y1[i] = 200*r->Rndm(i); + z1[i] = 10*r->Rndm(i); + c1[i] = 10000*r->Rndm(i); + s1[i] = 10000*r->Rndm(i); + x2[i] = 100*r->Rndm(i); + y2[i] = 200*r->Rndm(i); + z2[i] = 10*r->Rndm(i); + c2[i] = 5000*r->Rndm(i); + s2[i] = 100*r->Rndm(i); } + c1[0] = 1; auto scatter1 = new TScatter2D(n, x1, y1, z1, c1, s1); - scatter1->SetTitle("Scatter plot title;X title;Y title;Z title;C title"); + scatter1->SetTitle("Scatter plot title;X title;Y title;Z title"); scatter1->SetMarkerStyle(20); auto scatter2 = new TScatter2D(n, x2, y2, z2, c2, s2); scatter2->SetMarkerStyle(21); - scatter1->Draw(); + canvas->SetLogx(); + scatter1->Draw("logc "); scatter2->Draw("SAME"); + +scatter1->SaveAs("canvas.C"); } From 671f1b87915125eed0c2f2d62ff95a2dbd6d573c Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 31 Oct 2025 10:42:13 +0100 Subject: [PATCH 6/7] Complete Help, Add option P --- hist/hist/src/TScatter2D.cxx | 6 +++++- hist/histpainter/src/TGraphPainter.cxx | 8 ++++++-- tutorials/visualisation/graphs/gr019_scatter2d.C | 6 ++---- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx index 341ee92d49444..00ff6ca7ddb50 100644 --- a/hist/hist/src/TScatter2D.cxx +++ b/hist/hist/src/TScatter2D.cxx @@ -39,7 +39,11 @@ TScatter2D can be drawn with the following options: |----------|-------------------------------------------------------------------| | "SAME" | Superimpose on previous picture in the same pad.| | "LOGC" | Log scale for colors.| -| "LOGS" | Log scale for size.| +| "LOGS" | Log scale for sizes.| +| "FB" | Suppress the Front-Box.| +| "BB" | Suppress the Back-Box.| +| "A" | Suppress the axis.| +| "P" | Suppress the palette.| In the case of the SAME option, the log scale for color and size is inherited from the previously drawn TScatter2D. For example, if a TScatter2D is drawn on top of another one diff --git a/hist/histpainter/src/TGraphPainter.cxx b/hist/histpainter/src/TGraphPainter.cxx index 306053bfcca06..15dbcf78d272e 100644 --- a/hist/histpainter/src/TGraphPainter.cxx +++ b/hist/histpainter/src/TGraphPainter.cxx @@ -4591,7 +4591,7 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) TGraph2D* theGraph = theScatter->GetGraph(); - Int_t optionSAME = 0, optionSkipCol = 0, optionLOGC = 1, optionLOGS = 0; + Int_t optionSAME = 0, optionSkipCol = 0, optionLOGC = 1, optionLOGS = 0, optionP = 0; TString opt = chopt; opt.ToUpper(); @@ -4612,6 +4612,10 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) optionLOGS = 1; opt.ReplaceAll("LOGS"," "); } + if (opt.Contains("P")) { + optionP = 1; + opt.ReplaceAll("P"," "); + } opt.Append("TRI0"); @@ -4709,7 +4713,7 @@ void TGraphPainter::PaintScatter2D(TScatter2D *theScatter, Option_t* chopt) functions->AddFirst(palette); } - if (palette) palette->Paint(); + if (palette && !optionP) palette->Paint(); } } else { TScatter2D *s2; diff --git a/tutorials/visualisation/graphs/gr019_scatter2d.C b/tutorials/visualisation/graphs/gr019_scatter2d.C index 7062dec8626b7..7992a0bd1cd43 100644 --- a/tutorials/visualisation/graphs/gr019_scatter2d.C +++ b/tutorials/visualisation/graphs/gr019_scatter2d.C @@ -1,7 +1,7 @@ /// \file /// \ingroup tutorial_graphs /// \notebook -/// Draw a 2D scatter plot. +/// \preview Draw a 2D scatter plot. /// /// \macro_image /// \macro_code @@ -50,8 +50,6 @@ void gr019_scatter2d() scatter2->SetMarkerStyle(21); canvas->SetLogx(); - scatter1->Draw("logc "); + scatter1->Draw("logc"); scatter2->Draw("SAME"); - -scatter1->SaveAs("canvas.C"); } From ba863ba32a7b03d04baca5e6d3d4c65e1f63ceac Mon Sep 17 00:00:00 2001 From: Olivier Couet Date: Fri, 31 Oct 2025 10:47:01 +0100 Subject: [PATCH 7/7] Canavs.C was put in the PR by mistake --- tutorials/visualisation/graphs/canvas.C | 49 ------------------------- 1 file changed, 49 deletions(-) delete mode 100644 tutorials/visualisation/graphs/canvas.C diff --git a/tutorials/visualisation/graphs/canvas.C b/tutorials/visualisation/graphs/canvas.C deleted file mode 100644 index e3179e1758cc6..0000000000000 --- a/tutorials/visualisation/graphs/canvas.C +++ /dev/null @@ -1,49 +0,0 @@ -{ -//========= Macro generated from object: /Scatter plot title;X title;Y title;Z title -//========= by ROOT version6.37.01 - - std::vector scat_x_vect0{ - 15.43001532554629, 49.03009934350856, 85.44955085963024, 77.79588783159865, 1.423704251646998, 95.67470615729704, 14.48920760303738, 75.2201412804426, 6.504075974226008, 74.75467054173362, - 52.24243160337218, 15.31057963147762, 66.55026562511931, 97.2193180583419, 83.33713728934539, 78.22429211810244, 63.27881067991267, 84.99209536239518, 77.10582893341792, 79.89717656746519, - 61.35302595794211, 54.95494520291695, 93.44497565180077, 74.77831440046441, 82.9923786222936, 40.43268142268068, 26.17438640445475, 96.06434563174858, 20.08186317980293, 50.17736395820983, - 83.89658499509109, 33.43384386971598, 83.78137648105634, 64.85267383977781, 8.356185071170342, 48.28169131651529, 91.63509272038951, 71.01828819140803, 30.29926512390379, 26.45345376804475, - 92.18083843588843, 32.61425523087387, 62.83274348825226, 68.47975561395299, 27.05946750938897, 99.94536926969901, 32.28375334292655, 17.31065483763817, 30.62423616647725, 56.16554571315655 - }; - std::vector scat_y_vect1{ - 84.64903170242918, 178.853353019804, 104.0105079300703, 40.95906941220171, 92.1287016011776, 10.94613512977959, 155.8444139547649, 68.04533554241073, 184.3943812884393, 155.5118090473118, - 20.38295464590195, 66.24516425654302, 152.2381545044484, 171.7689721845093, 146.9021004624667, 163.3196334354582, 141.5058159269395, 73.79462039098155, 12.77840780094268, 149.3100943975153, - 142.9406211711469, 39.11789795383817, 0.8327689953148377, 72.63192189857375, 57.02703678980478, 92.31384759768858, 51.67416231706746, 11.16826413199307, 133.834490273148, 163.597160484642, - 91.04340197518482, 18.36379272863272, 187.8611200489107, 122.4159262143077, 32.15688811615114, 44.31845275685198, 187.877525482327, 186.0453828237954, 153.0503568239513, 31.88121272251015, - 21.77051687613133, 103.1816667877139, 48.92263012006887, 187.7438145689669, 36.38686547055846, 112.5355630181731, 159.4793659634891, 28.53452367708091, 152.3770534433427, 76.42625486478222 - }; - std::vector scat_z_vect2{ - 7.905995836481464, 3.836069423705346, 7.051348360255371, 5.868942588567743, 5.94781900756062, 9.47714833542706, 2.358731562271718, 6.109580211341391, 2.206818377599124, 3.061918262392287, - 9.494874672964229, 3.231267705559735, 8.316256580874338, 1.179391350597145, 9.142722943797722, 5.192035771906384, 6.577120861038575, 0.02185123041272167, 0.7584149856120359, 0.002405345439910893, - 9.606560571119203, 7.220790516585122, 4.094720268622047, 4.436325095593936, 3.736324673518544, 7.432848308235418, 4.474476622417576, 6.492108926177035, 6.161199240013967, 1.675747688859704, - 1.814027735963466, 1.603373475372794, 5.837444951757798, 0.4142332263290888, 3.396660657599574, 2.599975615739826, 8.13123459927739, 0.3960084728896624, 0.3960432950407273, 3.418949954211717, - 3.217090582475071, 5.237673465162524, 8.149661915376795, 6.565446332097063, 8.226322410628214, 9.76066222414376, 0.1822586450725797, 4.323667325079448, 3.145464202389126, 8.077180255204452 - }; - std::vector scat_col_vect3{ - 1, 9937.263936735706, 3347.600004635756, 8514.314410276724, 9343.961733393386, 7270.1761359349, 7829.560949467134, 3765.593399293727, 2626.853059045975, 1493.851379491391, - 980.4583853110686, 3761.391383595771, 8326.449277810765, 5205.144830979415, 9292.105971835568, 6884.085987694572, 8363.641197793198, 5882.503450848171, 8659.393540583564, 5362.490382976839, - 2245.989548973743, 6003.153496421883, 434.9745949730284, 4764.040787704296, 7497.412483207892, 1910.288021899763, 6233.953810296963, 2236.983967013661, 8837.873074226094, 1430.254378356042, - 1488.574533723297, 3502.564732916659, 6113.066817633818, 239.741713739932, 7752.906284295034, 8597.213444300009, 974.1091309115305, 6982.968472875666, 3757.532252930111, 6364.733506925414, - 2307.222853414718, 7138.869897462439, 5214.236802421518, 7698.488873429608, 413.4257463738329, 5638.285526074478, 3370.692967437213, 7533.591543324304, 9938.217992894368, 8231.146694161011 - }; - std::vector scat_size_vect4{ - 1937.083806842568, 7776.606539264333, 9277.679659426227, 2463.59272859991, 1496.268082410099, 9839.400174096243, 9393.701851367965, 2592.050535604362, 7032.171022146951, 1033.085370436312, - 5278.90410274268, 4209.626680240041, 4783.462975174196, 3418.781207874423, 8076.131567358982, 5311.88848428429, 5474.898274987945, 6776.1126253754, 4488.532133400447, 8780.877878889454, - 7403.252739459287, 1376.647921279075, 6740.493923425684, 7033.548904582869, 3273.261170834308, 4507.336253300316, 6288.582794368277, 420.2052112668759, 783.5548557341111, 743.9451385289442, - 1282.479837536814, 9372.937558218851, 6962.599065154802, 5974.497953429827, 7775.918878614914, 304.0613140910869, 6254.63055446745, 5172.711433842786, 4687.62397766114, 5254.553956910976, - 2355.595063418154, 3921.433174982673, 2512.246929109101, 5292.492574080833, 3799.084816128021, 3686.079131439334, 5781.304761767396, 7661.491362378013, 3292.276021093135, 838.0711171776069 - }; - TScatter2D *scat = new TScatter2D(50, scat_x_vect0.data(), scat_y_vect1.data(), scat_z_vect2.data(), scat_col_vect3.data(), scat_size_vect4.data()); - scat->SetName(""); - scat->SetTitle("Scatter plot title;X title;Y title;Z title"); - scat->SetFillColor(19); - scat->SetMarkerStyle(20); - scat->SetMargin(0.1); - scat->SetMinMarkerSize(1); - scat->SetMaxMarkerSize(5); - scat->Draw(); -}