diff --git a/hist/hist/CMakeLists.txt b/hist/hist/CMakeLists.txt index cd75f69c397d7..65bcc760fd91b 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 2d3c26ede3083..7ad13780c6ca2 100644 --- a/hist/hist/inc/LinkDef.h +++ b/hist/hist/inc/LinkDef.h @@ -49,6 +49,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/TGraph2D.h b/hist/hist/inc/TGraph2D.h index 95c38681052a4..3bfc0f08eb6fc 100644 --- a/hist/hist/inc/TGraph2D.h +++ b/hist/hist/inc/TGraph2D.h @@ -95,6 +95,7 @@ class TGraph2D : public TNamed, public TAttLine, public TAttFill, public TAttMar virtual void Apply(TF2 *f); void Browse(TBrowser *) override; void Clear(Option_t *option="") override; + virtual void ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &zmin, Double_t &xmax, Double_t &ymax, Double_t &zmax) const; virtual void DirectoryAutoAdd(TDirectory *); Int_t DistancetoPrimitive(Int_t px, Int_t py) override; void Draw(Option_t *option="P0") override; diff --git a/hist/hist/inc/TScatter2D.h b/hist/hist/inc/TScatter2D.h new file mode 100644 index 0000000000000..385eb008195a8 --- /dev/null +++ b/hist/hist/inc/TScatter2D.h @@ -0,0 +1,75 @@ +// @(#)root/hist:$Id$ +// Author: Olivier Couet 03/12/2024 + +/************************************************************************* + * 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 + TH3F *fHistogram{nullptr}; ///< Pointer to histogram used for drawing axis + 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 + TH3F *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 SetHistogram(TH3F *h) {fHistogram = h;} + 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..093edf66e14e8 100644 --- a/hist/hist/inc/TVirtualGraphPainter.h +++ b/hist/hist/inc/TVirtualGraphPainter.h @@ -22,7 +22,9 @@ #include "TObject.h" class TGraph; +class TGraph2D; class TScatter; +class TScatter2D; class TF1; class TVirtualGraphPainter : public TObject { @@ -42,6 +44,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 PaintScatter(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/TGraph2D.cxx b/hist/hist/src/TGraph2D.cxx index 411ab195a08de..fadd19f123e01 100644 --- a/hist/hist/src/TGraph2D.cxx +++ b/hist/hist/src/TGraph2D.cxx @@ -1781,3 +1781,37 @@ void TGraph2D::Streamer(TBuffer &b) b.WriteClassBuffer(TGraph2D::Class(), this); } } + +//////////////////////////////////////////////////////////////////////////////// +/// Compute the x/y/z range of the points in this graph + +void TGraph2D::ComputeRange(Double_t &xmin, Double_t &ymin, Double_t &zmin, Double_t &xmax, Double_t &ymax, Double_t &zmax) const +{ + if (fNpoints <= 0) { + xmin = xmax = ymin = ymax = zmin = zmax = 0; + return; + } + xmin = xmax = fX[0]; + ymin = ymax = fY[0]; + zmin = zmax = fZ[0]; + + Double_t xminl = 0; // Positive minimum. Used in case of log scale along X axis. + Double_t yminl = 0; // Positive minimum. Used in case of log scale along Y axis. + Double_t zminl = 0; // Positive minimum. Used in case of log scale along Z axis. + + for (Int_t i = 1; i < fNpoints; i++) { + if (fX[i] < xmin) xmin = fX[i]; + if (fX[i] > xmax) xmax = fX[i]; + if (fY[i] < ymin) ymin = fY[i]; + if (fY[i] > ymax) ymax = fY[i]; + if (fZ[i] < zmin) zmin = fZ[i]; + if (fZ[i] > zmax) zmax = fZ[i]; + if (zmin>0 && (zminl==0 || zmin0 && (yminl==0 || ymin0 && (xminl==0 || xminGetLogz() && zminl>0) zmin = zminl; + if (gPad && gPad->GetLogy() && yminl>0) ymin = yminl; + if (gPad && gPad->GetLogx() && xminl>0) xmin = xminl; +} diff --git a/hist/hist/src/TScatter.cxx b/hist/hist/src/TScatter.cxx index 6bf8504115729..ae9b80b0c2e6c 100644 --- a/hist/hist/src/TScatter.cxx +++ b/hist/hist/src/TScatter.cxx @@ -13,17 +13,12 @@ #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 ClassImp(TScatter); @@ -83,8 +78,6 @@ TScatter::TScatter(Int_t n) //////////////////////////////////////////////////////////////////////////////// /// TScatter normal constructor. -/// -/// if ex or ey are null, the corresponding arrays are preset to zero TScatter::TScatter(Int_t n, const Double_t *x, const Double_t *y, const Double_t *col, const Double_t *size) { @@ -167,7 +160,7 @@ TH2F *TScatter::GetHistogram() const { if (!fHistogram) { // do not add the histogram to gDirectory - // use local TDirectory::TContect that will set temporarly gDirectory to a nullptr and + // use local TDirectory::TContext that will set temporarly gDirectory to a nullptr and // will avoid that histogram is added in the global directory TDirectory::TContext ctx(nullptr); double rwxmin, rwymin, rwxmax, rwymax; diff --git a/hist/hist/src/TScatter2D.cxx b/hist/hist/src/TScatter2D.cxx new file mode 100644 index 0000000000000..5ea99d57a81b4 --- /dev/null +++ b/hist/hist/src/TScatter2D.cxx @@ -0,0 +1,314 @@ +// @(#)root/hist:$Id$ +// Author: Olivier Couet 18/05/2022 + +/************************************************************************* + * 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 "TBuffer.h" +#include "TScatter2D.h" +#include "TVirtualPad.h" +#include "TH3.h" +#include "TVirtualGraphPainter.h" + +#include +#include + +ClassImp(TScatter2D); + + +//////////////////////////////////////////////////////////////////////////////// + +/** \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, 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/graphs/scatter2D.C +End_Macro + +### TScatter2D's plotting options +TScatter2D can be drawn with the following options: + +| Option | Description | +|----------|-------------------------------------------------------------------| +| "A" | Produce a new plot with Axis around the graph | + +*/ + + +//////////////////////////////////////////////////////////////////////////////// +/// 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) +{ + 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; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// TScatter2D default destructor. + +TScatter2D::~TScatter2D() +{ + delete fGraph; + delete fHistogram; + 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) +{ + // Are we on the axis? + Int_t distance; + if (this->GetHistogram()) { + distance = this->GetHistogram()->DistancetoPrimitive(px,py); + if (distance <= 5) return distance; + } + + TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter(); + /*if (painter) + return painter->DistancetoPrimitiveHelper(this->GetGraph(), px, py);*/ + return 0; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// 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) +{ + /* + TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter(); + if (painter) painter->ExecuteEventHelper(this->GetGraph(), event, px, py); + */ +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Returns a pointer to the histogram used to draw the axis + +TH3F *TScatter2D::GetHistogram() const +{ + if (!fHistogram) { + // do not add the histogram to gDirectory + // use local TDirectory::TContext that will set temporarly gDirectory to a nullptr and + // will avoid that histogram is added in the global directory + TDirectory::TContext ctx(nullptr); + double rwxmin, rwymin, rwzmin, rwxmax, rwymax, rwzmax; + int npt = 25; + fGraph->ComputeRange(rwxmin, rwymin, rwzmin, rwxmax, rwymax, rwzmax); + double dx = (rwxmax-rwxmin)*fMargin; + double dy = (rwymax-rwymin)*fMargin; + double dz = (rwymax-rwymin)*fMargin; + auto h = new TH3F(TString::Format("%s_h",GetName()),GetTitle(),npt,rwxmin-dx,rwxmax+dx,npt,rwymin-dy,rwymax+dy,npt,rwzmin-dz,rwzmax+dz); + h->SetBit(TH1::kNoStats); + h->SetDirectory(nullptr); + h->Sumw2(kFALSE); + const_cast(this)->fHistogram = h; + } + return fHistogram; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Get the scatter's x axis. + +TAxis *TScatter2D::GetXaxis() const +{ + auto h = GetHistogram(); + return h ? h->GetXaxis() : nullptr; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Get the scatter's y axis. + +TAxis *TScatter2D::GetYaxis() const +{ + auto h = GetHistogram(); + return h ? h->GetYaxis() : nullptr; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Get the scatter's z axis. + +TAxis *TScatter2D::GetZaxis() const +{ + auto h = GetHistogram(); + return h ? h->GetZaxis() : nullptr; +} + + +//////////////////////////////////////////////////////////////////////////////// +/// Paint this scatter plot with its current attributes. + +void TScatter2D::Paint(Option_t *option) +{ + TVirtualGraphPainter *painter = TVirtualGraphPainter::GetPainter(); + if (painter) painter->PaintScatter(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) { + delete fHistogram; + fHistogram = nullptr; + 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); + + if (fHistogram) { + TString hname = fHistogram->GetName(); + fHistogram->SetName(TString::Format("Graph_%s%d", hname.Data(), frameNumber)); + fHistogram->SavePrimitive(out, "nodraw"); + out << " scat->SetHistogram(" << fHistogram->GetName() << ");" << std::endl; + out << " " << std::endl; + fHistogram->SetName(hname); + } + + out << " scat->Draw(" << quote << option << quote << ");" << std::endl; +} diff --git a/hist/histpainter/inc/TGraphPainter.h b/hist/histpainter/inc/TGraphPainter.h index 8d360d2116c36..6947e876f1ba6 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 PaintScatter(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 014da7825d411..d4d3237b1929b 100644 --- a/hist/histpainter/src/TGraphPainter.cxx +++ b/hist/histpainter/src/TGraphPainter.cxx @@ -19,6 +19,7 @@ #include "TStyle.h" #include "TH1.h" #include "TH2.h" +#include "TH3.h" #include "TF1.h" #include "TPaveStats.h" #include "TGaxis.h" @@ -29,11 +30,13 @@ #include "TGraphPolar.h" #include "TGraphQQ.h" #include "TScatter.h" +#include "TScatter2D.h" #include "TPaletteAxis.h" #include "TLatex.h" #include "TArrow.h" #include "TFrame.h" #include "TMarker.h" +#include "TView.h" #include "TVirtualPadEditor.h" #include "TVirtualX.h" #include "TRegexp.h" @@ -4402,6 +4405,7 @@ void TGraphPainter::PaintScatter(TScatter *theScatter, Option_t* chopt) double *theX = theScatter->GetGraph()->GetX(); double *theY = theScatter->GetGraph()->GetY(); int n = theScatter->GetGraph()->GetN(); + if (n < 1) return; double *theColor = theScatter->GetColor(); double *theSize = theScatter->GetSize(); double MinMarkerSize = theScatter->GetMinMarkerSize(); @@ -4577,6 +4581,220 @@ void TGraphPainter::PaintScatter(TScatter *theScatter, Option_t* chopt) } } +//////////////////////////////////////////////////////////////////////////////// +/// Paint a scatter plot + +void TGraphPainter::PaintScatter(TScatter2D *theScatter, Option_t* chopt) +{ + + Int_t optionAxis; + + TString opt = chopt; + opt.ToUpper(); + + if (opt.Contains("A")) optionAxis = 1; else optionAxis = 0; + + double *theX = theScatter->GetGraph()->GetX(); + double *theY = theScatter->GetGraph()->GetY(); + double *theZ = theScatter->GetGraph()->GetZ(); + int n = theScatter->GetGraph()->GetN(); + if (n < 1) return; + 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 minz = DBL_MAX; + double maxz = -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->Draw(" "); + if (h->GetMinimum() != h->GetMaximum()) { + if (mincGetMinimum()) minc = h->GetMinimum(); + if (maxc>h->GetMaximum()) maxc = h->GetMaximum(); + } + TView *view = gPad ? gPad->GetView() : nullptr; + if (!view) { + Error("PaintScatter", "No TView in current pad"); + return; + } + + // Define and paint palette + if (theColor) { + TPaletteAxis *palette; + TList *functions = theScatter->GetGraph()->GetListOfFunctions(); + palette = (TPaletteAxis*)functions->FindObject("palette"); + if (palette) { + 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(); + } + + // Draw markers + auto nbcol = gStyle->GetNumberOfColors(); + int logx = gPad->GetLogx(); + int logy = gPad->GetLogy(); + int logz = gPad->GetLogz(); + int logc = 0; + if (theColor && logc) { + if (minc>0) minc = log10(minc); + if (maxc>0) maxc = log10(maxc); + } + theScatter->SetMarkerColor(theScatter->GetMarkerColor()); + theScatter->TAttMarker::Modify(); + double x,y,z,c,ms; + int nc; + Double_t temp1[3],temp2[3]; + for (int i=0; i0) c = log10(theColor[i]); + else continue; + } else { + c = theColor[i]; + } + if (cmaxc) continue; + 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); + } + if (theColor || theSize) 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]; + } + temp1[0] = x; temp1[1] = y; temp1[2] = z; + view->WCtoNDC(temp1, &temp2[0]); + gPad->PaintPolyMarker(1,temp2,temp2+1); + } +} + //////////////////////////////////////////////////////////////////////////////// /// Paint a simple graph, without errors bars. diff --git a/tutorials/graphs/scatter2.C b/tutorials/graphs/scatter2.C new file mode 100644 index 0000000000000..7a311a3f6dcff --- /dev/null +++ b/tutorials/graphs/scatter2.C @@ -0,0 +1,42 @@ +/// \file +/// \ingroup tutorial_graphs +/// \notebook +/// Draw a scatter plot. +/// +/// \macro_image +/// \macro_code +/// +/// \author Olivier Couet + +void scatter2() +{ + auto canvas = new TCanvas(); + canvas->SetRightMargin(0.14); + gStyle->SetPalette(kBird, 0, 0.6); // define a transparent palette + + const int n = 175; + double x[n]; + double y[n]; + double z[n]; + double c[n]; + double s[n]; + + // Define four random data set + auto r = new TRandom(); + for (int i=0; iRndm(i); + y[i] = 200*r->Rndm(i); + z[i] = 10*r->Rndm(i); + c[i] = 300*r->Rndm(i); + s[i] = 400*r->Rndm(i); + } + + auto scatter = new TScatter2D(n, x, y, z, c, s); + scatter->SetMarkerStyle(20); + scatter->SetTitle("Scatter plot title;X title;Y title;Z title;C title"); + scatter->GetXaxis()->SetRangeUser(20.,90.); + scatter->GetYaxis()->SetRangeUser(55.,90.); + scatter->GetZaxis()->SetRangeUser(0.,10.); + //scatter->GetCaxis()->SetRangeUser(0.,200.); + scatter->Draw(); +}