Successive TCanvas Print() time increases?

Hello ROOT expers,

I am trying to generate a GIF from a series of images of a TCanvas. I’ve been following the modified version of hsum.C (root.cern.ch/root/html/tutorial … nim.C.html) to save my TCanvas snapshots as a GIF, and it appears to be working.

However, as the frame of the gif increases (each successive TCanvas->Print() ), the time it takes to Print() the TCanvas increases. I re-wrote the code to write single images out of the TCanvas rather than saving it as a GIF in case that was the problem, but the increase in Print() time with the image number still occurs.

I’ve written my code so the complexity of the histograms shown on the TCanvas shouldn’t increase for later images (only 3 bins of 1D histograms displayed on TCanvas pads at a time), but still see the time to Print() each the TCanvas still increases. Note that I see similar behavior with the modified hsum code.

I’m attaching a simplified version of the main loop of my code below. Thank you for your help!

[code]

for (ULong64_t timeBin=1; timeBin < detectorReadHistArray[0]->GetSize()-1; timeBin++) {

globalBinNumber=detectorReadHistArray[0]->GetBin(timeBin);
tempBinStorage=detectorReadHistArray[0]->GetBinContent(globalBinNumber);

if ( (tempBinStorage > 0) && (tempBinStorage < 10000) ) {
	for (UInt_t detector=0; detector < 24; detector++) {
		value=arrayOfHistogramValues[detector][timeBin-1];
		Hist->SetBinContent(detectorXLocs[detector],detectorYLocs[detector],value);
		detectorWriteHistArray[detector]->SetBinContent(timeBin,value);
	}

	//Plot 2D histogram
	pad1->cd();
	Hist->Draw("colz");
	baselineCanvas->Modified();
	baselineCanvas->Update();

	//Plot 1D histograms
	pad2->cd();
	minTimeBin = timeBin > 3 ? timeBin-3 : 0;
	detectorWriteHistArray[0]->GetXaxis()->SetRange(minTimeBin,timeBin);
	if (timeBin==1) {
		detectorWriteHistArray[0]->Draw("L");
	}
	else {
		detectorWriteHistArray[0]->Draw("Lsame");
	}
	detectorWriteHistArray[1]->Draw("Lsame");
	detectorWriteHistArray[2]->Draw("Lsame");
	detectorWriteHistArray[3]->Draw("Lsame");
	detectorWriteHistArray[4]->Draw("Lsame");
	detectorWriteHistArray[5]->Draw("Lsame");

	pad3->cd();
	detectorWriteHistArray[6]->GetXaxis()->SetRange(minTimeBin,timeBin);
	if (timeBin==1) {
		detectorWriteHistArray[6]->Draw("L");
	}
	else {
		detectorWriteHistArray[6]->Draw("Lsame");
	}
	detectorWriteHistArray[7]->Draw("Lsame");
	detectorWriteHistArray[8]->Draw("Lsame");
	detectorWriteHistArray[9]->Draw("Lsame");
	detectorWriteHistArray[10]->Draw("Lsame");
	detectorWriteHistArray[11]->Draw("Lsame");

	pad4->cd();
	detectorWriteHistArray[12]->GetXaxis()->SetRange(minTimeBin,timeBin);
	if (timeBin==1) {
		detectorWriteHistArray[12]->Draw("L");
	}
	else {
		detectorWriteHistArray[12]->Draw("Lsame");
	}
	detectorWriteHistArray[13]->Draw("Lsame");
	detectorWriteHistArray[14]->Draw("Lsame");
	detectorWriteHistArray[15]->Draw("Lsame");
	detectorWriteHistArray[16]->Draw("Lsame");
	detectorWriteHistArray[17]->Draw("Lsame");

	pad5->cd();
	detectorWriteHistArray[18]->GetXaxis()->SetRange(minTimeBin,timeBin);
	if (timeBin==1) {
		detectorWriteHistArray[18]->Draw("L");
	}
	else {
		detectorWriteHistArray[18]->Draw("Lsame");
	}
	detectorWriteHistArray[19]->Draw("Lsame");
	detectorWriteHistArray[20]->Draw("Lsame");
	detectorWriteHistArray[21]->Draw("Lsame");
	detectorWriteHistArray[22]->Draw("Lsame");
	detectorWriteHistArray[23]->Draw("Lsame");
	
	baselineCanvas->Modified();
	baselineCanvas->Update();

	if (timeBin==1) {
		baselineLegend1 = pad2->BuildLegend(0.92,0.45,1,0.9);
		baselineLegend1->SetTextSize(0.07);
		baselineLegend2 = pad3->BuildLegend(0.92,0.45,1,0.9);
		baselineLegend2->SetTextSize(0.07);
		baselineLegend3 = pad4->BuildLegend(0.92,0.45,1,0.9);
		baselineLegend3->SetTextSize(0.07);
		baselineLegend4 = pad5->BuildLegend(0.92,0.45,1,0.9);
		baselineLegend4->SetTextSize(0.07);
	}
	
	saveName="baseline";
	saveName.Append(to_string(timeBin));
	saveName.Append(".gif");
	baselineCanvas->SaveAs(saveName);
	//baselineCanvas->Print("baselines.gif+20");
}


if (timeBin >= 7) {
	//baselineCanvas->Print("baselines.gif++");
	gSystem->Exec("convert baseline*.gif anim.gif");
	exit(0);
}

if ( timeBin%1 == 0) {
	cout<<"On bin "<<timeBin<<" of "<<detectorReadHistArray[0]->GetSize()-1<<endl;
}

}[/code]

If it would be helpful to have code that actually runs that shows this oddity, the code I linked to (root.cern.ch/root/html/tutorial … nim.C.html) does this as well. Increase the iterations of the loop, and the time it takes to print each canvas to the GIF increases with the loop iteration.

Yes this is well know with animated gif. The time to create them as soon as you add more picture. Animated gif are meant to produce animations of a few seconds surely not a full movie.

Thanks for the reply. I assumed as much, however I see the same slowdown when I print each TCanvas update as a separate image, rather than as a GIF (with the intention of forming a gif from the images with external software).

I think there’s most likely an issue with my code, but I am having difficulty finding the source of this slowdown.

I have timed my code, and the major slowdown comes from the Print() line. I doubt there is a problem with Print(), but am wondering what I could be doing in my loop to cause this slowdown.

Which ROOT version are you using ?

6.08/02

Can you provide a small script reproducing the issue ? … with separated images I do not see why it should slow down …

Hi couet,

I modified the code to make it self-contained, and have attached it below. It has the same issue I described.

I can provide a make file if necessary, just let me know.

Note that this will create 70 .gif files in whatever folder the code is executed in.

//C++ include files
#include <iostream>
#include <string>
#include <cstdlib>
#include <list>
#include <time.h>
#include <TStyle.h>
#include "stdio.h"

//Root include files
#include "TFile.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TSystem.h"
#include "TCanvas.h"
#include "TPad.h"
#include "TLegend.h"
#include "TArray.h"
#include "TROOT.h"

using namespace std;

int main(int argc, char** argv) {

//Code reads histograms from root file, plots values in real time as they change, saves canvas they are plotted to as a gif

//Creating fake data to show the issue
TH1D* detectorDataHistArray[24];
TString histNames[24];
for (UInt_t detector=0; detector < 24; detector++) {
	histNames[detector]="test";
	histNames[detector].Append(to_string(detector));
	detectorDataHistArray[detector] = new TH1D(histNames[detector],histNames[detector],20000,0,100000);
	detectorDataHistArray[detector]->FillRandom("gaus",100000);
}

//Set up canvas that will be saved as images
TCanvas* c1 = new TCanvas("c1","",200,10,1900,900);
//Create pads
TPad *pad1 = new TPad("pad1","2D Array",0.0,0.0,0.4,1.0);
TPad *pad2 = new TPad("pad2","Ch0-5",0.4,0.76,1.0,1.0);
TPad *pad3 = new TPad("pad2","Ch6-11",0.4,0.52,1.0,0.76);
TPad *pad4 = new TPad("pad2","Ch12-17",0.4,0.28,1.0,0.52);
TPad *pad5 = new TPad("pad2","Ch18-23",0.4,0.04,1.0,0.28);
pad1->Draw();
pad2->Draw();
pad3->Draw();
pad4->Draw();
pad5->Draw();
//Set Pad Margins
pad1->SetRightMargin(0.15);
pad1->SetLeftMargin(0.05);
pad2->SetRightMargin(0.0);
pad3->SetRightMargin(0.0);
pad4->SetRightMargin(0.0);
pad5->SetRightMargin(0.0);
pad2->SetLeftMargin(0.07);
pad3->SetLeftMargin(0.07);
pad4->SetLeftMargin(0.07);
pad5->SetLeftMargin(0.07);
//Create grid for 2D array
pad1->cd();
c1->SetGridx();
c1->SetGridy();
//Set color palette of z-axis
gStyle->SetPalette(51);

//Create 1D histograms
TH1D* detectorReadHistArray[24]; //Stores histograms that are read from root files
TH1D* detectorWriteHistArray[24]; //Histograms that will be displayed on the plot
//Will store bin limits from read-in histograms
Double_t minBin;
Double_t maxBin;
Double_t nBins;
for (UInt_t detector=0; detector < 24; detector++) {
	//The commented lines read detector this the name histNames[detector] from the root file, store in detectorReadHistArray[detector]
	//histNames[detector] = "histName_ch";
	//histNames[detector].Append(to_string(detector));
	//detectorReadHistArray[detector] = (TH1D*)rootFile->Get(histNames[detector]);
	detectorReadHistArray[detector] = detectorDataHistArray[detector];

	//Get bin limits
	minBin = detectorReadHistArray[detector]->GetXaxis()->GetXmin();
	maxBin = detectorReadHistArray[detector]->GetXaxis()->GetXmax();
	nBins = detectorReadHistArray[detector]->GetSize();

	//Create histograms
	histNames[detector] = "chan: ";
	histNames[detector].Append(to_string(detector));
	detectorWriteHistArray[detector] = new TH1D(histNames[detector],"",nBins,minBin,maxBin);
	detectorWriteHistArray[detector]->SetMarkerColor(detector%6+1);
	detectorWriteHistArray[detector]->SetLineColor(detector%6+1);
}

//Tried to speed up code by loading detectorReadHistArray values into an array and reading from that rather than using GetBinContent
Double_t *arrayOfHistogramValues[24];
for (UInt_t detector=0; detector < 24; detector++) {
	arrayOfHistogramValues[detector]=detectorReadHistArray[detector]->GetArray();
}

//Create a 2D histogram
TH2D* TwoDimHist = new TH2D("TwoDimHist","Example 2D histogram",6,0,6,4,0,4);
//These specify the locations of the detectors on the 2D plot
UInt_t detectorXLocations[24] = { 5, 6, 3, 4, 5, 4, 1, 1, 5, 3, 5,  1,  3,  2,  1,  4,  6,  4,  3,  6,  2,  2,  2,  6 };
UInt_t detectorYLocations[24] = { 2, 3, 1, 4, 4, 3, 4, 2, 3, 2, 1,  3,  4,  3,  1,  2,  1,  1,  3,  2,  4,  2,  1,  4 };

//Variables needed for loop code
UInt_t numberOfBinsToPlot=70; //number of bins to plot total
Double_t valueToPlot;
Int_t globalBinNumber;
UInt_t numberOfBinsToDisplay=3; //number of bins to display at once
UInt_t minTimeBin; //Lower limit of displayed bins
TString saveName;

for (ULong64_t timeBin=1; timeBin < detectorReadHistArray[0]->GetSize()-1; timeBin++) {

	//Get the global bin number corresponding to the first bin on the 0th detector 1D histogram
	globalBinNumber=detectorReadHistArray[0]->GetBin(timeBin);

	//Fill histograms
	for (UInt_t detector=0; detector < 24; detector++) { 
		valueToPlot=arrayOfHistogramValues[detector][timeBin-1];
		TwoDimHist->SetBinContent(detectorXLocations[detector],detectorYLocations[detector],valueToPlot);
		detectorWriteHistArray[detector]->SetBinContent(timeBin,valueToPlot);
	}

	//Plot 2D histogram
	pad1->cd();
	TwoDimHist->Draw("colz");
	c1->Modified();
	c1->Update();

	//Updated code to only display numberOfBinsToDisplay bins of data
	minTimeBin = timeBin > numberOfBinsToDisplay ? timeBin-numberOfBinsToDisplay : 0;

	//Set the display range
	detectorWriteHistArray[0]->GetXaxis()->SetRange(minTimeBin,timeBin);
	detectorWriteHistArray[6]->GetXaxis()->SetRange(minTimeBin,timeBin);
	detectorWriteHistArray[12]->GetXaxis()->SetRange(minTimeBin,timeBin);
	detectorWriteHistArray[18]->GetXaxis()->SetRange(minTimeBin,timeBin);

	//Plot 1D histograms
	pad2->cd();
	if (timeBin==1) {
		detectorWriteHistArray[0]->Draw("L");
	}
	else {
		detectorWriteHistArray[0]->Draw("Lsame");
	}
	detectorWriteHistArray[1]->Draw("Lsame");
	detectorWriteHistArray[2]->Draw("Lsame");
	detectorWriteHistArray[3]->Draw("Lsame");
	detectorWriteHistArray[4]->Draw("Lsame");
	detectorWriteHistArray[5]->Draw("Lsame");

	pad3->cd();
	if (timeBin==1) {
		detectorWriteHistArray[6]->Draw("L");
	}
	else {
		detectorWriteHistArray[6]->Draw("Lsame");
	}
	detectorWriteHistArray[7]->Draw("Lsame");
	detectorWriteHistArray[8]->Draw("Lsame");
	detectorWriteHistArray[9]->Draw("Lsame");
	detectorWriteHistArray[10]->Draw("Lsame");
	detectorWriteHistArray[11]->Draw("Lsame");

	pad4->cd();
	if (timeBin==1) {
		detectorWriteHistArray[12]->Draw("L");
	}
	else {
		detectorWriteHistArray[12]->Draw("Lsame");
	}
	detectorWriteHistArray[13]->Draw("Lsame");
	detectorWriteHistArray[14]->Draw("Lsame");
	detectorWriteHistArray[15]->Draw("Lsame");
	detectorWriteHistArray[16]->Draw("Lsame");
	detectorWriteHistArray[17]->Draw("Lsame");

	pad5->cd();
	if (timeBin==1) {
		detectorWriteHistArray[18]->Draw("L");
	}
		else {
	detectorWriteHistArray[18]->Draw("Lsame");
	}
	detectorWriteHistArray[19]->Draw("Lsame");
	detectorWriteHistArray[20]->Draw("Lsame");
	detectorWriteHistArray[21]->Draw("Lsame");
	detectorWriteHistArray[22]->Draw("Lsame");
	detectorWriteHistArray[23]->Draw("Lsame");

	c1->Modified();
	c1->Update();

	saveName="image";
	saveName.Append(to_string(timeBin));
	saveName.Append(".gif");
	c1->SaveAs(saveName);

	if (timeBin >= numberOfBinsToPlot) {
		gSystem->Exec("convert image*.gif anim.gif");
		exit(0);
	}

	if ( timeBin%1 == 0) {
		cout<<"On bin "<<timeBin<<" of "<<detectorReadHistArray[0]->GetSize()-1<<endl;
	}
}

}

Thanks for your help!

I have no problem running your macro and it does not seem to slow down to much. But i use that the memory usage because tiger and bigger. I have a site large memory so it is fine for me … may be in your case it is an issue and root starts to paginate on disk,

Hi Couet,

Thanks for trying the code. I forgot an optimization line

gStyle->SetCanvasPreferGL(kTRUE);

That speeds up the drawing time, without it the drawing steps take as long as the saving step. I also added timing information to show that it is the canvas print that is the issue, and that each one takes successively longer. Also, the problem is worse if there are more bins in each histogram–I increased bins to 2,000,000 in the code and the slowdown was more significant, which supports the idea that it is a memory issue.

I don’t know why the memory usage gets worse every time through causing the canvas print to take longer. There are no new histograms histograms or objects being created.

I also removed the canvas print line and noticed that without it the code was taking 1.7GB in memory with the number of bins to plot increased to 700,000 (so 700,000 images would be saved if the save lines were uncommented). This code executed very quickly. With the print lines in the slowdown becomes pretty insane when trying to plot 20 bins, and here the memory usage is 800MB.

Here is new code that better demonstrates the problem

//C++ include files
#include <iostream>
#include <string>
#include <cstdlib>
#include <list>
#include <time.h>
#include <TStyle.h>
#include "stdio.h"

//Root include files
#include "TFile.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TSystem.h"
#include "TCanvas.h"
#include "TPad.h"
#include "TLegend.h"
#include "TArray.h"
#include "TROOT.h"

using namespace std;

int main(int argc, char** argv) {

time_t startTime, endTime, lapTime;


//Code reads histograms from root file, plots values in real time as they change, saves canvas they are plotted to as a gif

//Creating fake data to show the issue
TH1D* detectorDataHistArray[24];
TString histNames[24];
for (UInt_t detector=0; detector < 24; detector++) {
	histNames[detector]="test";
	histNames[detector].Append(to_string(detector));
	detectorDataHistArray[detector] = new TH1D(histNames[detector],histNames[detector],2000000,0,1000000);
	detectorDataHistArray[detector]->FillRandom("gaus",1000000);
}

//Speeds up draw speed
gStyle->SetCanvasPreferGL(kTRUE);

//Set up canvas that will be saved as images
TCanvas* c1 = new TCanvas("c1","",200,10,1900,900);
//Create pads
TPad *pad1 = new TPad("pad1","2D Array",0.0,0.0,0.4,1.0);
TPad *pad2 = new TPad("pad2","Ch0-5",0.4,0.76,1.0,1.0);
TPad *pad3 = new TPad("pad2","Ch6-11",0.4,0.52,1.0,0.76);
TPad *pad4 = new TPad("pad2","Ch12-17",0.4,0.28,1.0,0.52);
TPad *pad5 = new TPad("pad2","Ch18-23",0.4,0.04,1.0,0.28);
pad1->Draw();
pad2->Draw();
pad3->Draw();
pad4->Draw();
pad5->Draw();
//Set Pad Margins
pad1->SetRightMargin(0.15);
pad1->SetLeftMargin(0.05);
pad2->SetRightMargin(0.0);
pad3->SetRightMargin(0.0);
pad4->SetRightMargin(0.0);
pad5->SetRightMargin(0.0);
pad2->SetLeftMargin(0.07);
pad3->SetLeftMargin(0.07);
pad4->SetLeftMargin(0.07);
pad5->SetLeftMargin(0.07);
//Create grid for 2D array
pad1->cd();
c1->SetGridx();
c1->SetGridy();
//Set color palette of z-axis
gStyle->SetPalette(51);

//Create 1D histograms
TH1D* detectorReadHistArray[24]; //Stores histograms that are read from root files
TH1D* detectorWriteHistArray[24]; //Histograms that will be displayed on the plot
//Will store bin limits from read-in histograms
Double_t minBin;
Double_t maxBin;
Double_t nBins;
for (UInt_t detector=0; detector < 24; detector++) {
	//The commented lines read detector this the name histNames[detector] from the root file, store in detectorReadHistArray[detector]
	//histNames[detector] = "histName_ch";
	//histNames[detector].Append(to_string(detector));
	//detectorReadHistArray[detector] = (TH1D*)rootFile->Get(histNames[detector]);
	detectorReadHistArray[detector] = detectorDataHistArray[detector];

	//Get bin limits
	minBin = detectorReadHistArray[detector]->GetXaxis()->GetXmin();
	maxBin = detectorReadHistArray[detector]->GetXaxis()->GetXmax();
	nBins = detectorReadHistArray[detector]->GetSize();

	//Create histograms
	histNames[detector] = "chan: ";
	histNames[detector].Append(to_string(detector));
	detectorWriteHistArray[detector] = new TH1D(histNames[detector],"",nBins,minBin,maxBin);
	detectorWriteHistArray[detector]->SetMarkerColor(detector%6+1);
	detectorWriteHistArray[detector]->SetLineColor(detector%6+1);
}

//Tried to speed up code by loading detectorReadHistArray values into an array and reading from that rather than using GetBinContent
Double_t *arrayOfHistogramValues[24];
for (UInt_t detector=0; detector < 24; detector++) {
	arrayOfHistogramValues[detector]=detectorReadHistArray[detector]->GetArray();
}

//Create a 2D histogram
TH2D* TwoDimHist = new TH2D("TwoDimHist","Example 2D histogram",6,0,6,4,0,4);
//These specify the locations of the detectors on the 2D plot
UInt_t detectorXLocations[24] = { 5, 6, 3, 4, 5, 4, 1, 1, 5, 3, 5,  1,  3,  2,  1,  4,  6,  4,  3,  6,  2,  2,  2,  6 };
UInt_t detectorYLocations[24] = { 2, 3, 1, 4, 4, 3, 4, 2, 3, 2, 1,  3,  4,  3,  1,  2,  1,  1,  3,  2,  4,  2,  1,  4 };

//Variables needed for loop code
UInt_t numberOfBinsToPlot=70; //number of bins to plot total
Double_t valueToPlot;
Int_t globalBinNumber;
UInt_t numberOfBinsToDisplay=3; //number of bins to display at once
UInt_t minTimeBin; //Lower limit of displayed bins
TString saveName;

time(&startTime);

for (ULong64_t timeBin=1; timeBin < detectorReadHistArray[0]->GetSize()-1; timeBin++) {

	//Get the global bin number corresponding to the first bin on the 0th detector 1D histogram
	globalBinNumber=detectorReadHistArray[0]->GetBin(timeBin);

	//Fill histograms
	for (UInt_t detector=0; detector < 24; detector++) { 
		valueToPlot=arrayOfHistogramValues[detector][timeBin-1];
		TwoDimHist->SetBinContent(detectorXLocations[detector],detectorYLocations[detector],valueToPlot);
		detectorWriteHistArray[detector]->SetBinContent(timeBin,valueToPlot);
	}

	//Plot 2D histogram
	pad1->cd();
	TwoDimHist->Draw("colz");
	c1->Modified();
	c1->Update();

	//Updated code to only display numberOfBinsToDisplay bins of data
	minTimeBin = timeBin > numberOfBinsToDisplay ? timeBin-numberOfBinsToDisplay : 0;

	//Set the display range
	detectorWriteHistArray[0]->GetXaxis()->SetRange(minTimeBin,timeBin);
	detectorWriteHistArray[6]->GetXaxis()->SetRange(minTimeBin,timeBin);
	detectorWriteHistArray[12]->GetXaxis()->SetRange(minTimeBin,timeBin);
	detectorWriteHistArray[18]->GetXaxis()->SetRange(minTimeBin,timeBin);

	//Plot 1D histograms
	pad2->cd();
	if (timeBin==1) {
		detectorWriteHistArray[0]->Draw("L");
	}
	else {
		detectorWriteHistArray[0]->Draw("Lsame");
	}
	detectorWriteHistArray[1]->Draw("Lsame");
	detectorWriteHistArray[2]->Draw("Lsame");
	detectorWriteHistArray[3]->Draw("Lsame");
	detectorWriteHistArray[4]->Draw("Lsame");
	detectorWriteHistArray[5]->Draw("Lsame");

	pad3->cd();
	if (timeBin==1) {
		detectorWriteHistArray[6]->Draw("L");
	}
	else {
		detectorWriteHistArray[6]->Draw("Lsame");
	}
	detectorWriteHistArray[7]->Draw("Lsame");
	detectorWriteHistArray[8]->Draw("Lsame");
	detectorWriteHistArray[9]->Draw("Lsame");
	detectorWriteHistArray[10]->Draw("Lsame");
	detectorWriteHistArray[11]->Draw("Lsame");

	pad4->cd();
	if (timeBin==1) {
		detectorWriteHistArray[12]->Draw("L");
	}
	else {
		detectorWriteHistArray[12]->Draw("Lsame");
	}
	detectorWriteHistArray[13]->Draw("Lsame");
	detectorWriteHistArray[14]->Draw("Lsame");
	detectorWriteHistArray[15]->Draw("Lsame");
	detectorWriteHistArray[16]->Draw("Lsame");
	detectorWriteHistArray[17]->Draw("Lsame");

	pad5->cd();
	if (timeBin==1) {
		detectorWriteHistArray[18]->Draw("L");
	}
		else {
	detectorWriteHistArray[18]->Draw("Lsame");
	}
	detectorWriteHistArray[19]->Draw("Lsame");
	detectorWriteHistArray[20]->Draw("Lsame");
	detectorWriteHistArray[21]->Draw("Lsame");
	detectorWriteHistArray[22]->Draw("Lsame");
	detectorWriteHistArray[23]->Draw("Lsame");

	c1->Modified();
	c1->Update();

	saveName="image";
	saveName.Append(to_string(timeBin));
	saveName.Append(".gif");

	//Timing
	time(&lapTime);
	cout<<"Time for rest of loop: "<<difftime(lapTime,startTime)<<endl;
	time(&startTime);

	c1->SaveAs(saveName);

	//Timing
	time(&lapTime);
	cout<<"Time to print: "<<difftime(lapTime,startTime)<<endl;
	time(&startTime);

	if (timeBin >= numberOfBinsToPlot) {
		gSystem->Exec("convert image*.gif anim.gif");
		exit(0);
	}

	if ( timeBin%1 == 0) {
		cout<<"On bin "<<timeBin<<" of "<<detectorReadHistArray[0]->GetSize()-1<<endl;
	}
}

}

Yes I see 'Time to print" increases. I will check.

I noticed that it slows down even if you do not print the images.

Hi Couet,

I have not measured the time down to sub-second resolution, but when I disable the c1->SaveAs(saveName) line the loop never executes in longer than a second. The total time the loop takes to execute with 2,000,000 iterations (with data histogram sizes increased) is 49 seconds. In comparison it takes 25 seconds to do 1,000,000 iterations, and 12 seconds to do 500,000.

This is with the line

gStyle->SetCanvasPreferGL(kTRUE);

which was an optimization to speed up the drawing process I had read about. Without it, I noticed the same slowdown in the draw part of the loop as with the save part. This is from running my compiled code, and in this case I do not see the canvas or plots on my screen.

I just tried loading this code into a ROOT session and executing it, and noticed that I do see the canvas, and the loop time increases with the iteration even with canvas saving disabled and that optimization line included. I am now suspecting that maybe the plots weren’t getting drawn in my compiled code with that optimization line, so maybe the slowdown is unavoidable.

I have a couple ideas to re-write to code to try to make it more memory friendly and faster, so if the slowdown is unavoidable the way I have written it I will move on to another approach. I ultimately wanted to turn a few thousand of these images into a gif, and this may be impossible the way I have written it.

If you have any other suggestions please let me know. If not, thank you for your help.

[code]//C++ include files
#include
#include
#include
#include
#include <time.h>
#include <TStyle.h>
#include “stdio.h”

//Root include files
#include “TFile.h”
#include “TH1D.h”
#include “TH2D.h”
#include “TSystem.h”
#include “TCanvas.h”
#include “TPad.h”
#include “TLegend.h”
#include “TArray.h”
#include “TROOT.h”

using namespace std;

int main(int argc, char** argv) {

time_t startTime, endTime, lapTime, firstTime;

//Code reads histograms from root file, plots values in real time as they change, saves canvas they are plotted to as a gif

//Creating fake data to show the issue
TH1D* detectorDataHistArray[24];
TString histNames[24];
for (UInt_t detector=0; detector < 24; detector++) {
histNames[detector]=“test”;
histNames[detector].Append(to_string(detector));
detectorDataHistArray[detector] = new TH1D(histNames[detector],histNames[detector],2000000,0,2000000);
detectorDataHistArray[detector]->FillRandom(“gaus”,2000000);
}

//Speeds up draw speed
gStyle->SetCanvasPreferGL(kTRUE);

//Set up canvas that will be saved as images
TCanvas* c1 = new TCanvas(“c1”,"",200,10,1900,900);
//Create pads
TPad *pad1 = new TPad(“pad1”,“2D Array”,0.0,0.0,0.4,1.0);
TPad *pad2 = new TPad(“pad2”,“Ch0-5”,0.4,0.76,1.0,1.0);
TPad *pad3 = new TPad(“pad2”,“Ch6-11”,0.4,0.52,1.0,0.76);
TPad *pad4 = new TPad(“pad2”,“Ch12-17”,0.4,0.28,1.0,0.52);
TPad *pad5 = new TPad(“pad2”,“Ch18-23”,0.4,0.04,1.0,0.28);
pad1->Draw();
pad2->Draw();
pad3->Draw();
pad4->Draw();
pad5->Draw();
//Set Pad Margins
pad1->SetRightMargin(0.15);
pad1->SetLeftMargin(0.05);
pad2->SetRightMargin(0.0);
pad3->SetRightMargin(0.0);
pad4->SetRightMargin(0.0);
pad5->SetRightMargin(0.0);
pad2->SetLeftMargin(0.07);
pad3->SetLeftMargin(0.07);
pad4->SetLeftMargin(0.07);
pad5->SetLeftMargin(0.07);
//Create grid for 2D array
pad1->cd();
c1->SetGridx();
c1->SetGridy();
//Set color palette of z-axis
gStyle->SetPalette(51);

//Create 1D histograms
TH1D* detectorReadHistArray[24]; //Stores histograms that are read from root files
TH1D* detectorWriteHistArray[24]; //Histograms that will be displayed on the plot
//Will store bin limits from read-in histograms
Double_t minBin;
Double_t maxBin;
Double_t nBins;
for (UInt_t detector=0; detector < 24; detector++) {
//The commented lines read detector this the name histNames[detector] from the root file, store in detectorReadHistArray[detector]
//histNames[detector] = “histName_ch”;
//histNames[detector].Append(to_string(detector));
//detectorReadHistArray[detector] = (TH1D*)rootFile->Get(histNames[detector]);
detectorReadHistArray[detector] = detectorDataHistArray[detector];

//Get bin limits
minBin = detectorReadHistArray[detector]->GetXaxis()->GetXmin();
maxBin = detectorReadHistArray[detector]->GetXaxis()->GetXmax();
nBins = detectorReadHistArray[detector]->GetSize();

//Create histograms
histNames[detector] = "chan: ";
histNames[detector].Append(to_string(detector));
detectorWriteHistArray[detector] = new TH1D(histNames[detector],"",nBins,minBin,maxBin);
detectorWriteHistArray[detector]->SetMarkerColor(detector%6+1);
detectorWriteHistArray[detector]->SetLineColor(detector%6+1);

}

//Tried to speed up code by loading detectorReadHistArray values into an array and reading from that rather than using GetBinContent
Double_t *arrayOfHistogramValues[24];
for (UInt_t detector=0; detector < 24; detector++) {
arrayOfHistogramValues[detector]=detectorReadHistArray[detector]->GetArray();
}

//Create a 2D histogram
TH2D* TwoDimHist = new TH2D(“TwoDimHist”,“Example 2D histogram”,6,0,6,4,0,4);
//These specify the locations of the detectors on the 2D plot
UInt_t detectorXLocations[24] = { 5, 6, 3, 4, 5, 4, 1, 1, 5, 3, 5, 1, 3, 2, 1, 4, 6, 4, 3, 6, 2, 2, 2, 6 };
UInt_t detectorYLocations[24] = { 2, 3, 1, 4, 4, 3, 4, 2, 3, 2, 1, 3, 4, 3, 1, 2, 1, 1, 3, 2, 4, 2, 1, 4 };

//Variables needed for loop code
UInt_t numberOfBinsToPlot=500000; //number of bins to plot total
Double_t valueToPlot;
Int_t globalBinNumber;
UInt_t numberOfBinsToDisplay=3; //number of bins to display at once
UInt_t minTimeBin; //Lower limit of displayed bins
TString saveName;

time(&startTime);
time(&firstTime);

for (ULong64_t timeBin=1; timeBin < detectorReadHistArray[0]->GetSize()-1; timeBin++) {

//Get the global bin number corresponding to the first bin on the 0th detector 1D histogram
globalBinNumber=detectorReadHistArray[0]->GetBin(timeBin);

//Fill histograms
for (UInt_t detector=0; detector < 24; detector++) { 
	valueToPlot=arrayOfHistogramValues[detector][timeBin-1];
	TwoDimHist->SetBinContent(detectorXLocations[detector],detectorYLocations[detector],valueToPlot);
	detectorWriteHistArray[detector]->SetBinContent(timeBin,valueToPlot);
}

//Plot 2D histogram
pad1->cd();
TwoDimHist->Draw("colz");
c1->Modified();
c1->Update();

//Updated code to only display numberOfBinsToDisplay bins of data
minTimeBin = timeBin > numberOfBinsToDisplay ? timeBin-numberOfBinsToDisplay : 0;

//Set the display range
detectorWriteHistArray[0]->GetXaxis()->SetRange(minTimeBin,timeBin);
detectorWriteHistArray[6]->GetXaxis()->SetRange(minTimeBin,timeBin);
detectorWriteHistArray[12]->GetXaxis()->SetRange(minTimeBin,timeBin);
detectorWriteHistArray[18]->GetXaxis()->SetRange(minTimeBin,timeBin);

//Plot 1D histograms
pad2->cd();
if (timeBin==1) {
	detectorWriteHistArray[0]->Draw("L");
}
else {
	detectorWriteHistArray[0]->Draw("Lsame");
}
detectorWriteHistArray[1]->Draw("Lsame");
detectorWriteHistArray[2]->Draw("Lsame");
detectorWriteHistArray[3]->Draw("Lsame");
detectorWriteHistArray[4]->Draw("Lsame");
detectorWriteHistArray[5]->Draw("Lsame");

pad3->cd();
if (timeBin==1) {
	detectorWriteHistArray[6]->Draw("L");
}
else {
	detectorWriteHistArray[6]->Draw("Lsame");
}
detectorWriteHistArray[7]->Draw("Lsame");
detectorWriteHistArray[8]->Draw("Lsame");
detectorWriteHistArray[9]->Draw("Lsame");
detectorWriteHistArray[10]->Draw("Lsame");
detectorWriteHistArray[11]->Draw("Lsame");

pad4->cd();
if (timeBin==1) {
	detectorWriteHistArray[12]->Draw("L");
}
else {
	detectorWriteHistArray[12]->Draw("Lsame");
}
detectorWriteHistArray[13]->Draw("Lsame");
detectorWriteHistArray[14]->Draw("Lsame");
detectorWriteHistArray[15]->Draw("Lsame");
detectorWriteHistArray[16]->Draw("Lsame");
detectorWriteHistArray[17]->Draw("Lsame");

pad5->cd();
if (timeBin==1) {
	detectorWriteHistArray[18]->Draw("L");
}
	else {
detectorWriteHistArray[18]->Draw("Lsame");
}
detectorWriteHistArray[19]->Draw("Lsame");
detectorWriteHistArray[20]->Draw("Lsame");
detectorWriteHistArray[21]->Draw("Lsame");
detectorWriteHistArray[22]->Draw("Lsame");
detectorWriteHistArray[23]->Draw("Lsame");

c1->Modified();
c1->Update();

saveName="image";
saveName.Append(to_string(timeBin));
saveName.Append(".gif");

//Timing
time(&lapTime);
cout<<"Time for rest of loop: "<<difftime(lapTime,startTime)<<endl;
time(&startTime);

// c1->SaveAs(saveName);

//Timing
time(&lapTime);
cout<<"Time to print: "<<difftime(lapTime,startTime)<<endl;
time(&startTime);

if (timeBin >= numberOfBinsToPlot) {
		//Timing
		time(&endTime);
		cout<<"Time for loop: "<<difftime(endTime,firstTime)<<endl;
		exit(0);
}

if ( timeBin%1 == 0) {
	cout<<"On bin "<<timeBin<<" of "<<detectorReadHistArray[0]->GetSize()-1<<endl;
}

}

}
[/code]