diff --git a/README/ReleaseNotes/v642/index.md b/README/ReleaseNotes/v642/index.md index 3161e2ec44078..953c6e2001eb4 100644 --- a/README/ReleaseNotes/v642/index.md +++ b/README/ReleaseNotes/v642/index.md @@ -107,6 +107,17 @@ or read the bin count from the relevant histogram or plot frame instead. ## Graphics and GUI +### New POLF and POLN draw options for TH2 + +Since ROOT 6.36 implementation of "POL" draw option was changed. Angle and radius range automatically scaled to visible histogram range filling full 2*Pi angle and full radius range. +This let display TH2 in polar coordinates for any provided range settings, but produced plots are not intuitive. Therefore two new options for polar coordinates were introduced. + +"POLF" - fixed polar coordinates. In such case full histogram X range mapped to -PI .. +Pi. +And Y axis mapped to radius. In case of histogram zooming angle and radius of each bin remains +the same (therefore name "fixed"), just number of displayed bins are reduced. + +"POLN" - natural polar coordinates. In this case X axis directly represents angle value in radians (therefore name "natural") and Y axis is just radius. + ### Store canvas as HTML file Now canvas (or several canvases) can be stored in portable HTML file. diff --git a/hist/histpainter/inc/Hoption.h b/hist/histpainter/inc/Hoption.h index a1c12e25deb7b..fc899f3e8c886 100644 --- a/hist/histpainter/inc/Hoption.h +++ b/hist/histpainter/inc/Hoption.h @@ -41,6 +41,7 @@ typedef struct Hoption_t { int Box; ///< "BOX" Draw 2D plot with proportional Boxes. int Char; ///< "CHAR" Draw 2D plot with a character set. int Color; ///< "COL" Draw 2D plot with Colored boxes. + int Polar; ///< "POL" Draw 2D plot with Polar coordinates. int Contour; ///< "CONTn" Draw 2D plot as a Contour plot (0 <= n <= 5). int Func; ///< "FUNC" Draw only the function (for example in case of fit). int Hist; ///< "HIST" Draw only the histogram. diff --git a/hist/histpainter/src/THistPainter.cxx b/hist/histpainter/src/THistPainter.cxx index 1a879742f0334..dd2bfc7eb0011 100644 --- a/hist/histpainter/src/THistPainter.cxx +++ b/hist/histpainter/src/THistPainter.cxx @@ -309,7 +309,9 @@ using `TH1::GetOption`: | "SAME0" | Same as "SAME" but do not use the z-axis range of the first plot. | | "SAMES0" | Same as "SAMES" but do not use the z-axis range of the first plot. | | "CYL" | Use Cylindrical coordinates. The X coordinate is mapped on the angle and the Y coordinate on the cylinder length.| -| "POL" | Use Polar coordinates. The X coordinate is mapped on the angle and the Y coordinate on the radius.| +| "POL" | Use Polar coordinates. The visible X range mapped on the angle and the visible Y coordinate on the radius.| +| "POLF" | Fixed Polar coordinates. The histogram X coordinate mapped on the angle and the Y coordinate on the radius.| +| "POLN" | Natural Polar coordinates. The X coordinate directly represent angle in radian and the Y coordinate is the radius.| | "SPH" | Use Spherical coordinates. The X coordinate is mapped on the latitude and the Y coordinate on the longitude.| | "PSR" | Use PseudoRapidity/Phi coordinates. The X coordinate is mapped on Phi.| | "SURF" | Draw a surface plot with hidden line removal.| @@ -4063,6 +4065,7 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) Hoption.Lego = Hoption.Surf = Hoption.Off = Hoption.Tri = 0; Hoption.Proj = Hoption.AxisPos = Hoption.Spec = Hoption.Pie = 0; Hoption.Candle = 0; + Hoption.Polar = 0; // special 2D options Hoption.List = 0; @@ -4334,7 +4337,9 @@ Int_t THistPainter::MakeChopt(Option_t *choptin) l = strstr(chopt,"AXIS"); if (l) { Hoption.Axis = 1; memcpy(l," ",4); } l = strstr(chopt,"AXIG"); if (l) { Hoption.Axis = 2; memcpy(l," ",4); } l = strstr(chopt,"SCAT"); if (l) { Hoption.Scat = 1; memcpy(l," ",4); } - l = strstr(chopt,"POL"); if (l) { Hoption.System = kPOLAR; memcpy(l," ",3); } + l = strstr(chopt,"POLN"); if (l) { Hoption.System = kPOLAR; Hoption.Polar = 3; memcpy(l," ",4); } + l = strstr(chopt,"POLF"); if (l) { Hoption.System = kPOLAR; Hoption.Polar = 2; memcpy(l," ",4); } + l = strstr(chopt,"POL"); if (l) { Hoption.System = kPOLAR; Hoption.Polar = 1; memcpy(l," ",3); } l = strstr(chopt,"CYL"); if (l) { Hoption.System = kCYLINDRICAL; memcpy(l," ",3); } l = strstr(chopt,"SPH"); if (l) { Hoption.System = kSPHERICAL; memcpy(l," ",3); } l = strstr(chopt,"PSR"); if (l) { Hoption.System = kRAPIDITY; memcpy(l," ",3); } @@ -5838,8 +5843,8 @@ void THistPainter::PaintColorLevels(Option_t*) // Initialize the levels on the Z axis Int_t ncolors = gStyle->GetNumberOfColors(); - Int_t ndiv = fH->GetContour(); - if (ndiv == 0 ) { + Int_t ndiv = fH->GetContour(); + if (ndiv == 0) { ndiv = gStyle->GetNumberContours(); fH->SetContour(ndiv); } @@ -5847,6 +5852,41 @@ void THistPainter::PaintColorLevels(Option_t*) if (!fH->TestBit(TH1::kUserContour)) fH->SetContour(ndiv); Double_t scale = (dz ? ndivz / dz : 1.0); + Double_t xmin = gPad->GetUxmin(); + Double_t xmax = gPad->GetUxmax(); + Double_t ymin = gPad->GetUymin(); + Double_t ymax = gPad->GetUymax(); + + // range used for polar coordinates + Double_t pxmin = xmin, pxmax = xmax, pymin = ymin, pymax = ymax; + if ((Hoption.System == kPOLAR) && (Hoption.Polar > 1)) { + pxmin = fXaxis->GetXmin(); + pxmax = fXaxis->GetXmax(); + if (Hoption.Logx) { + if (pxmax <= 0) + return; + pxmax = TMath::Log10(pxmax); + if (pxmin <= 0) + pxmin = pxmax - 5; + else + pxmin = TMath::Log10(pxmin); + } + pymin = fYaxis->GetXmin(); + pymax = fYaxis->GetXmax(); + if (Hoption.Logy) { + if (pymax <= 0) + return; + pymax = TMath::Log10(pymax); + if (pymin <= 0) + pymin = pymax - 5; + else + pymin = TMath::Log10(pymin); + } else if ((pymax > 0) && (pymin >= 0)) { + // force minimal radius to 0 to display natural polar graphics + pymin = 0; + } + } + Int_t color; TProfile2D* prof2d = dynamic_cast(fH); for (Int_t j=Hparam.yfirst; j<=Hparam.ylast;j++) { @@ -5873,35 +5913,36 @@ void THistPainter::PaintColorLevels(Option_t*) } } - if (Hoption.Logz) { - if (z > 0) z = TMath::Log10(z); - else z = zmin; - } - if (z < zmin && !Hoption.Zero) continue; + if (Hoption.Logz) + z = z > 0 ? TMath::Log10(z) : zmin; + if (z < zmin && !Hoption.Zero) + continue; xup = xk + xstep; xlow = xk; if (Hoption.Logx) { - if (xup > 0) xup = TMath::Log10(xup); - else continue; - if (xlow > 0) xlow = TMath::Log10(xlow); - else continue; + if ((xup <= 0) || (xlow <= 0)) + continue; + xup = TMath::Log10(xup); + xlow = TMath::Log10(xlow); } yup = yk + ystep; ylow = yk; if (Hoption.Logy) { - if (yup > 0) yup = TMath::Log10(yup); - else continue; - if (ylow > 0) ylow = TMath::Log10(ylow); - else continue; - } - if (xup < gPad->GetUxmin()) continue; - if (yup < gPad->GetUymin()) continue; - if (xlow > gPad->GetUxmax()) continue; - if (ylow > gPad->GetUymax()) continue; - if (xlow < gPad->GetUxmin()) xlow = gPad->GetUxmin(); - if (ylow < gPad->GetUymin()) ylow = gPad->GetUymin(); - if (xup > gPad->GetUxmax()) xup = gPad->GetUxmax(); - if (yup > gPad->GetUymax()) yup = gPad->GetUymax(); + if ((yup <= 0) || (ylow <= 0)) + continue; + yup = TMath::Log10(yup); + ylow = TMath::Log10(ylow); + } + if ((xup < xmin) || (yup < ymin) || (xlow > xmax) || (ylow > ymax)) + continue; + if (xlow < xmin) + xlow = xmin; + if (ylow < ymin) + ylow = ymin; + if (xup > xmax) + xup = xmax; + if (yup > ymax) + yup = ymax; if (fH->TestBit(TH1::kUserContour)) { zc = fH->GetContourLevelPad(0); @@ -5920,21 +5961,29 @@ void THistPainter::PaintColorLevels(Option_t*) } Int_t theColor = Int_t((color+0.99)*Float_t(ncolors)/Float_t(ndivz)); - if (theColor > ncolors-1) theColor = ncolors-1; + if (theColor > ncolors-1) + theColor = ncolors-1; auto fillColor = gStyle->GetColorPalette(theColor); if (Hoption.System != kPOLAR) { fH->SetFillColor(fillColor); fH->TAttFill::Modify(); gPad->PaintBox(xlow, ylow, xup, yup); } else { - Double_t midx = (gPad->GetUxmin() + gPad->GetUxmax()) / 2, - midy = (gPad->GetUymin() + gPad->GetUymax()) / 2, - a1 = (xlow - gPad->GetUxmin()) / (gPad->GetUxmax() - gPad->GetUxmin()) * 360, - a2 = (xup - gPad->GetUxmin()) / (gPad->GetUxmax() - gPad->GetUxmin()) * 360, - rx = gPad->GetUxmax() - gPad->GetUxmin(), - ry = gPad->GetUymax() - gPad->GetUymin(), - r1 = (ylow - gPad->GetUymin()) / (gPad->GetUymax() - gPad->GetUymin()) * rx / 2, - r2 = (yup - gPad->GetUymin()) / (gPad->GetUymax() - gPad->GetUymin()) * rx / 2; + Double_t midx = (xmin + xmax) / 2; + Double_t midy = (ymin + ymax) / 2; + Double_t rx = xmax - xmin; + Double_t ry = ymax - ymin; + Double_t a1, a2; + + if (Hoption.Polar == 3) { + a1 = xlow / TMath::Pi() * 180; + a2 = xup / TMath::Pi() * 180; + } else { + a1 = ((xlow - pxmin) / (pxmax - pxmin) - 0.5) * 360; + a2 = ((xup - pxmin) / (pxmax - pxmin) - 0.5) * 360; + } + Double_t r1 = (ylow - pymin) / (pymax - pymin) * rx / 2; + Double_t r2 = (yup - pymin) / (pymax - pymin) * rx / 2; TCrown crown(midx, midy, r1, r2, a1, a2); crown.SetYXRatio(rx > 0 ? ry / rx : 1);