2.2.1 图表

图表的概念

最基本的数据可视化方法是使用由两个(TGraph)或三个(TGraph2D)数组组成的坐标表示数据的大小或位置,称作 Graph 。这与直方图(Histogram)不同。

ROOT 提供了许多图形类,如TGraph图表,TGraphErrors具有对称误差线的图表,TGraph2D由三个数组 X、Y 和 Z 组成的图表等。

图表的使用

TGraph支持批量创建和运算,TGraph的创建方法是:

// 创建了一个名字是name,标题是title,有n个坐标为x,y的点:
TGraph *gr = new TGraph("name", "title", number, x, y)
TGraph* gr = new TGraph("name", "title", number, x, y)
TGraph *gr = new TGraph(number, x, y)
auto gr = new TGraph(number, x, y)
auto gr = new TGraph()    // 使用AddPoint()函数添加坐标点
auto dt = new TGraph2D()    // 二维图表,其他形式同理

绘制图表前需要先定义坐标数组,然后使用TGraph构造图形。E.g.

   int n = 20;
   double x[n], y[n];
   for (int i=0; i<n; i++) {
      x[i] = i*0.1;
      y[i] = 10*sin(x[i]+0.2);
   }
   auto gr = new TGraph (n, x, y);

也支持使用AddPoint()函数添加点:

auto gr = new TGraph();
for (int i=0; i<20; i++) gr->AddPoint(i*0.1, 10*sin(i*0.1+0.2));

使用TGraph::Draw()绘制图形,且有多种绘图选项可选:

   auto gr = new TGraph();
   for (int i=0; i<20; i++) gr->AddPoint(i*0.1, 10*sin(i*0.1+0.2));
   gr->Draw();

从文件中读取数据

数据的保存格式有很多,常见的是文本格式和 root 格式:

  • 文本格式数据绘制 Graph

这里要求文件中的坐标中间是空格或者制表符,不可以是逗号。E.g.

int directdata(){
    TGraph *gr = new TGraph("mydata.txt");
    gr->Draw("AC*");    // 绘出 axis,坐标点以 curve 链接,坐标点形状为 * 型
}

从图表中读取数据

  • 数组模式

double *px = gr->GetX(); 将gr1图像中点数据以数组形式输出。

  • 指针模式

ToggleEventStatus()是 canvas 的成员函数。用于展示指针处的数据状态,打开后,指针所在位置的数据信息会被呈现在面板下方。

  • 高亮模式

高亮模式适用于TGraph(和TH1)类。 当高亮模式打开时,鼠标在点上的移动将以图形表示。 点将突出显示为“点圆”(由标记对象表示)。 此外,任何高亮显示(点变化)都会发出信号TCanvas::Highlighted(),允许用户做出反应并调用自己的函数。 为了更好地理解,请参阅教程$ROOTSYS/tutorials/graphs/hlGraph*.C 文件。

属性设置

图表的轴、标题、颜色均可以进行设置,参考章节:

绘图选项

使用以下选项绘制图表,在Draw()命令中它们不区分大小写,可不间隔的使用多个参数如Draw("APL")Draw("A p l"),均表示绘制包涵坐标轴和坐标点的图,并用直线相连:

E.g. X轴在上Y轴反转和自动取色
void graphpalettecolor () {
 
   gStyle->SetOptTitle(kFALSE);
   gStyle->SetPalette(kSolar);
 
   double x[5]  = {1,2,3,4,5};
   double y1[5] = {1.0,2.0,1.0,2.5,3.0};
   double y2[5] = {1.1,2.1,1.1,2.6,3.1};
   double y3[5] = {1.2,2.2,1.2,2.7,3.2};
   double y4[5] = {1.3,2.3,1.3,2.8,3.3};
   double y5[5] = {1.4,2.4,1.4,2.9,3.4};
 
   TGraph *g1 = new TGraph(5,x,y1); g1->SetTitle("Graph with a red star");
   TGraph *g2 = new TGraph(5,x,y2); g2->SetTitle("Graph with a circular marker");
   TGraph *g3 = new TGraph(5,x,y3); g3->SetTitle("Graph with an open square marker");
   TGraph *g4 = new TGraph(5,x,y4); g4->SetTitle("Graph with a blue star");
   TGraph *g5 = new TGraph(5,x,y5); g5->SetTitle("Graph with a full square marker");
 
   g1->SetLineWidth(3); g1->SetMarkerColor(kRed);
   g2->SetLineWidth(3); g2->SetMarkerStyle(kCircle);
   g3->SetLineWidth(3); g3->SetMarkerStyle(kOpenSquare);
   g4->SetLineWidth(3); g4->SetMarkerColor(kBlue);
   g5->SetLineWidth(3); g5->SetMarkerStyle(kFullSquare);
 
   g1->Draw("CA*x+ry PLC PFC");
   g2->Draw("PCx+ry  PLC PFC");
   g3->Draw("PC  PLC PFC");
   g4->Draw("*C  PLC PFC");
   g5->Draw("PC  PLC PFC");
 
   gPad->BuildLegend();
}

成果保存

将分析成果保存并反复展示。root 格式支持保存数据,也支持保存分析图片,而且图片保存为 root 格式后还可以反复打开并进行进一步的美化工作,十分便捷。

Save()

SaveAs()函数,支持

Write()函数

Print()

E.g. 将多个画布与图片连续保存到一个 PDF 文件中
{
   TCanvas* canvas = new TCanvas("canvas");
   TH1F* histo = new TH1F("histo","test 1",10,0.,10.);
   histo->SetFillColor(2);
   histo->Fill(2.);
   histo->Draw();
   canvas->Print("plots.pdf(","Title:One bin filled");
   histo->Fill(4.);
   histo->Draw();
   canvas->Print("plots.pdf","Title:Two bins filled");
   histo->Fill(6.);
   histo->Draw();
   canvas->Print("plots.pdf","Title:Three bins filled");
   histo->Fill(8.);
   histo->Draw();
   canvas->Print("plots.pdf","Title:Four bins filled");
   histo->Fill(8.);
   histo->Draw();
   canvas->Print("plots.pdf)","Title:The fourth bin content is 2");
}

误差与拟合

二维图表

使用符合标准的数据可以绘制二维图表。E.g.

{
   auto c = new TCanvas("c","Graph2D example",0,0,700,600);   // 画布距离左上角的距离(0,0)
   double x, y, z, P = 6.;
   int np = 200;
   auto dt = new TGraph2D();
   auto r  = new TRandom();
   for (int N=0; N<np; N++) {
      x = 2*P*(r->Rndm(N))-P;
      y = 2*P*(r->Rndm(N))-P;
      z = (sin(x)/x)*(sin(y)/y)+0.2;
      dt->SetPoint(N,x,y,z);
   }
   dt->Draw("tri1 p0");
}

绘图选项

极坐标 TGraphPolar

极坐标TGraphPolar()的绘图选项有:

E.g. 极坐标例子
{
   auto c46 = new TCanvas("c46","c46",500,500);
   auto grP1 = new TGraphPolar();
   grP1->SetTitle("TGraphPolar example");
 
   grP1->SetPoint(0, (1*TMath::Pi())/4., 0.05);
   grP1->SetPoint(1, (2*TMath::Pi())/4., 0.10);
   grP1->SetPoint(2, (3*TMath::Pi())/4., 0.15);
   grP1->SetPoint(3, (4*TMath::Pi())/4., 0.20);
   grP1->SetPoint(4, (5*TMath::Pi())/4., 0.25);
   grP1->SetPoint(5, (6*TMath::Pi())/4., 0.30);
   grP1->SetPoint(6, (7*TMath::Pi())/4., 0.35);
   grP1->SetPoint(7, (8*TMath::Pi())/4., 0.40);
 
   grP1->SetMarkerStyle(20);
   grP1->SetMarkerSize(1.);
   grP1->SetMarkerColor(4);
   grP1->SetLineColor(4);
   grP1->Draw("ALP");
 
   // Update, otherwise GetPolargram returns 0
   c46->Update();
   grP1->GetPolargram()->SetToRadian();
}

饼状图 TPie

多图绘法

root 支持在一张 canvas 上绘制多幅图表或者直方图。

独立绘制

使用TCanvas::Divide()函数将 Canvas 分割为不同的 Pad,例如将名为 c1 的 canvas 分为 2 列 3 行写作:c1->Divide(2,3),然后使用c1->cd()分别控制不同的 pad,pad 的名称从左向右,从上至下分别是1,2,……,例如可以在 pad1 上绘制 histogram,在 pad2 上绘制 graph。

共轴绘制

最简单的共轴画法是在TCanvas::Divide()函数中添加参数,例如c1->Divide(2,3,0),但当要进行一些美化工作的时候,就会发现它们的标题大小,marker 大小不再能通过统一的数值控制,这非常影响美观。

所以这里有一个稍微复杂的解决方法,能够使它们的大小保持一致,仅供参考:

CanvasPartition https://root.cern.ch/doc/master/canvas2_8C.html
 
void CanvasPartition(TCanvas *C,const Int_t Nx = 2,const Int_t Ny = 2,
                     Float_t lMargin = 0.15, Float_t rMargin = 0.05,
                     Float_t bMargin = 0.15, Float_t tMargin = 0.05);
double XtoPad(double x);
double YtoPad(double x);
 
void canvas2()
{
   gStyle->SetOptStat(0);
 
   auto C = (TCanvas*) gROOT->FindObject("C");
   if (C) delete C;
   C = new TCanvas("C","canvas",1024,640);
   C->SetFillStyle(4000);
 
   // Number of PADS
   const Int_t Nx = 5;
   const Int_t Ny = 5;
 
   // Margins
   Float_t lMargin = 0.12;
   Float_t rMargin = 0.05;
   Float_t bMargin = 0.15;
   Float_t tMargin = 0.05;
 
   // Canvas setup
   CanvasPartition(C,Nx,Ny,lMargin,rMargin,bMargin,tMargin);
 
   // Dummy histogram.
   auto h = (TH1F*) gROOT->FindObject("histo");
   if (h) delete h;
   h = new TH1F("histo","",100,-5.0,5.0);
   h->FillRandom("gaus",10000);
   h->GetXaxis()->SetTitle("x axis");
   h->GetYaxis()->SetTitle("y axis");
 
   TPad *pad[Nx][Ny];
 
   for (Int_t i = 0; i < Nx; i++) {
      for (Int_t j = 0; j < Ny; j++) {
         C->cd(0);
 
         // Get the pads previously created.
         pad[i][j] = (TPad*) C->FindObject(TString::Format("pad_%d_%d",i,j).Data());
         pad[i][j]->Draw();
         pad[i][j]->SetFillStyle(4000);
         pad[i][j]->SetFrameFillStyle(4000);
         pad[i][j]->cd();
 
         // Size factors
         Float_t xFactor = pad[0][0]->GetAbsWNDC()/pad[i][j]->GetAbsWNDC();
         Float_t yFactor = pad[0][0]->GetAbsHNDC()/pad[i][j]->GetAbsHNDC();
 
         TH1F *hFrame = (TH1F*) h->Clone(TString::Format("h_%d_%d",i,j).Data());
 
         // y axis range
         hFrame->SetMinimum(0.0001); // do not show 0
         hFrame->SetMaximum(1.2*h->GetMaximum());
 
         // Format for y axis
         hFrame->GetYaxis()->SetLabelFont(43);
         hFrame->GetYaxis()->SetLabelSize(16);
         hFrame->GetYaxis()->SetLabelOffset(0.02);
         hFrame->GetYaxis()->SetTitleFont(43);
         hFrame->GetYaxis()->SetTitleSize(16);
         hFrame->GetYaxis()->SetTitleOffset(2);
 
         hFrame->GetYaxis()->CenterTitle();
         hFrame->GetYaxis()->SetNdivisions(505);
 
         // TICKS Y Axis
         hFrame->GetYaxis()->SetTickLength(xFactor*0.04/yFactor);
 
         // Format for x axis
         hFrame->GetXaxis()->SetLabelFont(43);
         hFrame->GetXaxis()->SetLabelSize(16);
         hFrame->GetXaxis()->SetLabelOffset(0.02);
         hFrame->GetXaxis()->SetTitleFont(43);
         hFrame->GetXaxis()->SetTitleSize(16);
         hFrame->GetXaxis()->SetTitleOffset(1);
         hFrame->GetXaxis()->CenterTitle();
         hFrame->GetXaxis()->SetNdivisions(505);
 
         // TICKS X Axis
         hFrame->GetXaxis()->SetTickLength(yFactor*0.06/xFactor);
 
         // Draw cloned histogram with individual settings
         hFrame->Draw();
 
         TText text;
         text.SetTextAlign(31);
         text.SetTextFont(43);
         text.SetTextSize(10);
         text.DrawTextNDC(XtoPad(0.9), YtoPad(0.8), gPad->GetName());
      }
   }
   C->cd();
}
 
 
 
void CanvasPartition(TCanvas *C,const Int_t Nx,const Int_t Ny,
                     Float_t lMargin, Float_t rMargin,
                     Float_t bMargin, Float_t tMargin)
{
   if (!C) return;
 
   // Setup Pad layout:
   Float_t vSpacing = 0.0;
   Float_t vStep  = (1.- bMargin - tMargin - (Ny-1) * vSpacing) / Ny;
 
   Float_t hSpacing = 0.0;
   Float_t hStep  = (1.- lMargin - rMargin - (Nx-1) * hSpacing) / Nx;
 
   Float_t vposd,vposu,vmard,vmaru,vfactor;
   Float_t hposl,hposr,hmarl,hmarr,hfactor;
 
   for (Int_t i=0;i<Nx;i++) {
 
      if (i==0) {
         hposl = 0.0;
         hposr = lMargin + hStep;
         hfactor = hposr-hposl;
         hmarl = lMargin / hfactor;
         hmarr = 0.0;
      } else if (i == Nx-1) {
         hposl = hposr + hSpacing;
         hposr = hposl + hStep + rMargin;
         hfactor = hposr-hposl;
         hmarl = 0.0;
         hmarr = rMargin / (hposr-hposl);
      } else {
         hposl = hposr + hSpacing;
         hposr = hposl + hStep;
         hfactor = hposr-hposl;
         hmarl = 0.0;
         hmarr = 0.0;
      }
 
      for (Int_t j=0;j<Ny;j++) {
 
         if (j==0) {
            vposd = 0.0;
            vposu = bMargin + vStep;
            vfactor = vposu-vposd;
            vmard = bMargin / vfactor;
            vmaru = 0.0;
         } else if (j == Ny-1) {
            vposd = vposu + vSpacing;
            vposu = vposd + vStep + tMargin;
            vfactor = vposu-vposd;
            vmard = 0.0;
            vmaru = tMargin / (vposu-vposd);
         } else {
            vposd = vposu + vSpacing;
            vposu = vposd + vStep;
            vfactor = vposu-vposd;
            vmard = 0.0;
            vmaru = 0.0;
         }
 
         C->cd(0);
 
         auto name = TString::Format("pad_%d_%d",i,j);
         auto pad = (TPad*) C->FindObject(name.Data());
         if (pad) delete pad;
         pad = new TPad(name.Data(),"",hposl,vposd,hposr,vposu);
         pad->SetLeftMargin(hmarl);
         pad->SetRightMargin(hmarr);
         pad->SetBottomMargin(vmard);
         pad->SetTopMargin(vmaru);
 
         pad->SetFrameBorderMode(0);
         pad->SetBorderMode(0);
         pad->SetBorderSize(0);
 
         pad->Draw();
      }
   }
}
 
double XtoPad(double x)
{
   double xl,yl,xu,yu;
   gPad->GetPadPar(xl,yl,xu,yu);
   double pw = xu-xl;
   double lm = gPad->GetLeftMargin();
   double rm = gPad->GetRightMargin();
   double fw = pw-pw*lm-pw*rm;
   return (x*fw+pw*lm)/pw;
}
 
double YtoPad(double y)
{
   double xl,yl,xu,yu;
   gPad->GetPadPar(xl,yl,xu,yu);
   double ph = yu-yl;
   double tm = gPad->GetTopMargin();
   double bm = gPad->GetBottomMargin();
   double fh = ph-ph*bm-ph*tm;
   return (y*fh+bm*ph)/ph;
}

重叠绘制

将多个 graph 绘制在一张 pad 上,只需要在TGraph::Draw()函数中使用same参数即可。

合并绘制

TMultiGraph::TMultiGraph(),函数支持将一组图作为单个实体进行操作。且绘制时 X 轴和 Y 轴范围会自动计算,因此所有图形都将可见。TMultiGraph::Add()用于将新图表添加到列表中。E.g.

TGraph *gr1 = new TGraph(...
TGraphErrors *gr2 = new TGraphErrors(...
TMultiGraph *mg = new TMultiGraph();
mg->Add(gr1,"lp");
mg->Add(gr2,"cp");
mg->Draw("a");

标题、颜色、统计信息均可使用TMultiGraph类中的成员函数,用法与 graph 一致。

单个 graph 通过mg->GetListOfGraphs()->GetEntries();方式检索。

多页绘制

将graph保存到多页PDF中。

{
    TCanvas* canvas = new TCanvas ("canvas") ;
    TH1F* histo = new THIF("histo"c, "test 1", 10, 0., 10.) ;
    histo->SetFillColor (2); histo->Fil1(2.); histo->Draw();
    canvas->Print("plots.pdf(","Title:One bin filled"); histo->Fi11(4.); histo->Draw();
    canvas->Print "plots.pdf", "Title:Two bins filled"); histo->Fi11(6.);
    histo->Draw();
    canvas->Print ("plots.pdf", "Title: Three bins filled");
    histo->Fill (8.);
    histo->Draw();
    canvas->Print("plots.pdf", "Title:Four bins filled");
    histo->Fi11(8.);
    histo->Draw():
    canvas->Print ("plots.pdf)", "Title:The fourth bin content is 2");
}

图例

TLegend


参考

https://root.cern/doc/master/classTGaxis.html

https://root.cern/doc/master/classTGraphPainter.html

https://root.cern.ch/doc/master/classTHistPainter.html

最后更新于