绘制直方图轮廓线是在处理数据较为常用的一种手段,本文根据ROOT官方教程ContourList.C,来讲述绘制轮廓线的方法。
首先在画板c中绘制一幅横坐标为周期函数,纵坐标为正弦函数的图像。根据所选的几个轮廓值,绘制不同颜色的图像;画板c1是根据所选的轮廓值,绘制出图像的分界线。
下面给出具体的代码步骤:
定义pi值:
const Double_t PI = TMath::Pi();
新建画板:
TCanvas* c = new TCanvas("c","Contour List",0,0,600,600);
设置画板右边余量:
c->SetRightMargin(0.15);
设置画板顶部余量:
c->SetTopMargin(0.15);
定义变量数量:
Int_t nZsamples = 80;
Int_t nPhiSamples = 80;
定义波长(横坐标长度):
Double_t HofZwavelength = 4.0; // 4 meters
设置横纵坐标bin值:
Double_t dZ = HofZwavelength/(Double_t)(nZsamples - 1);
Double_t dPhi = 2*PI/(Double_t)(nPhiSamples - 1);
定义变量数组:
TArrayD z(nZsamples);
TArrayD HofZ(nZsamples);
TArrayD phi(nPhiSamples);
TArrayD FofPhi(nPhiSamples);
设置离散的Z和Phi值:
for ( i = 0; i < nZsamples; i++) {
z[i] = (i)*dZ - HofZwavelength/2.0;
HofZ[i] = SawTooth(z[i], HofZwavelength);
}
for(Int_t i=0; i < nPhiSamples; i++){
phi[i] = (i)*dPhi;
FofPhi[i] = sin(phi[i]);
}
创建直方图:
TH2D *HistStreamFn = new TH2D("HstreamFn", "#splitline{Histogram with negative and positive contents. Six contours are defined.}{It is plotted with options CONT LIST to retrieve the contours points in TGraphs}", nZsamples, z[0], z[nZsamples-1], nPhiSamples, phi[0], phi[nPhiSamples-1]);
加载直方图数据:
for (Int_t i = 0; i < nZsamples; i++) {
for(Int_t j = 0; j < nPhiSamples; j++){
HistStreamFn->SetBinContent(i,j, HofZ[i]*FofPhi[j]);
}
}
设置选项统计(0代表不显示统计信息):
gStyle->SetOptStat(0);
设置标题宽度:
gStyle->SetTitleW(0.99);
设置标题高度:
gStyle->SetTitleH(0.08);
设置轮廓数值:
Double_t contours[6];
contours[0] = -0.7;
contours[1] = -0.5;
contours[2] = -0.1;
contours[3] = 0.1;
contours[4] = 0.4;
contours[5] = 0.8;
将轮廓值导入直方图:
HistStreamFn->SetContour(6, contours);
将轮廓绘制为填充区域并保存点:
"CONT Z LIST"画法是指:根据Contour值进行划分轮廓,每个区域使用不同颜色绘制。
HistStreamFn->Draw("CONT Z LIST");
c->Update(); // 需要强制绘图并在TGraphs中检索轮廓
获取轮廓:
TObjArray *conts = (TObjArray*)gROOT->GetListOfSpecials()->FindObject("contours");
TList* contLevel = NULL;
TGraph* curv = NULL;
TGraph* gc = NULL;
定义图型数量和总轮廓个数:
Int_t nGraphs = 0;
Int_t TotalConts = 0;
将获取的轮廓个数提取到变量TotalConts中:
if (conts == NULL){
printf("*** No Contours Were Extracted!\n");
TotalConts = 0;
return 0;
} else {
TotalConts = conts->GetSize();
}
输出轮廓数量:
printf("TotalConts = %d\n", TotalConts);
输出每个框架有多少个图形并记录图型总量:
for(i = 0; i < TotalConts; i++){
contLevel = (TList*)conts->At(i);
printf("Contour %d has %d Graphs\n", i, contLevel->GetSize());
nGraphs += contLevel->GetSize();
}
图形数量归零:
nGraphs = 0;
创建第二个画板并设置顶部余量:
TCanvas* c1 = new TCanvas("c1","Contour List",610,0,600,600);
c1->SetTopMargin(0.15);
创建第二个直方图:
TH2F *hr = new TH2F("hr", "#splitline{Negative contours are returned first (highest to lowest). Positive contours are returned from}{lowest to highest. On this plot Negative contours are drawn in red and positive contours in blue.}", 2, -2, 2, 2, 0, 6.5);
绘制直方图:
hr->Draw();
设置文本框:
Double_t xval0, yval0, zval0;
TLatex l;
l.SetTextSize(0.03);
char val[20];
绘制第二张图的轮廓:
for(i = 0; i < TotalConts; i++){
contLevel = (TList*)conts->At(i);
if (i<3) zval0 = contours[2-i]; //zcal0记为轮廓值
else zval0 = contours[i];
printf("Z-Level Passed in as: Z = %f\n", zval0);
curv = (TGraph*)contLevel->First(); //从此级别的曲线列表中获取第一张图
for(j = 0; j < contLevel->GetSize(); j++){
curv->GetPoint(0, xval0, yval0);
if (zval0<0) curv->SetLineColor(kRed); //设置画线为红色
if (zval0>0) curv->SetLineColor(kBlue); //设置画线为蓝色
nGraphs ++;
printf("\tGraph: %d -- %d Elements\n", nGraphs,curv->GetN());
gc = (TGraph*)curv->Clone(); //克隆图形
gc->Draw("C"); //绘制轮廓线
sprintf(val,"%g",zval0); //将zval0转换为val文本值
l.DrawLatex(xval0,yval0,val); //绘制文本(x位置,y位置,数值)
curv = (TGraph*)contLevel->After(curv); //获取下一张图
}
}
刷新画板:
c1->Update();
输出总轮廓种类和总轮廓线数量:
printf("\n\n\tExtracted %d Contours and %d Graphs \n", TotalConts, nGraphs );
设置标题宽度:
gStyle->SetTitleW(0.);
设置标题高度:
gStyle->SetTitleH(0.);
代码地址:https://github.com/root-project/root/blob/master/tutorials/hist/ContourList.C