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);