How to make marker thicker?

Dear all,

MacOS: Sonoma 14.4.1
ROOT: 6.32.08

Sorry to ask such a basic question.
Attached is candleplot.cpp (ROOT: tutorials/hist/candleplot.C File Reference).

I’d like to make markers (represent average values) thicker in boxplot.
According to the website (ROOT: TAttMarker Class Reference), markers with markerstyle over 50 can be used. However, Line 29 in the attached file does not work.

Could you tell me how to do that?

Best, KS.

candleplot.cpp (1.1 KB)

It doesn’t seem you can control these markers attributes. Even if you change the marker shape the X doesn’t change. Candle plot are special, it looks like the markers are built in. @Georg_T , the author of this code, might confirm ?

Dear @couet

Thank you for your answer.
But, h0.SetMarkerSize() works. I don’t know why h0.SetMarkerStyle() does not work.

I’m looking forward to @Georg_T reply.

Best, KS.

I think it the way candle plots should be represented: Circle in the middle and X on the errors. Anyway that’s how its is coded:

Dear @couet

Thank you.
I think it is OK that the circles represent averages. When I change the line thickness, the circle is too thin. I mean that I’d like to change the circle thickness (e.g., MarkerStyle = 71, 89, 107) to match the thickness of the line.

Best, KS.

I understand that, but the line thickness is not an attribute of the markers. As you noticed, you need to change the marker style to get thicker markers. And, as you see, the marker style is hard coded. So, with the current code, there is no way to do what you are looking for. Some changes are needed in the code. I need to look how to do it.

We can imagine two new attributes:

gStyle->SetCandleCircleLineWidth(w);
gStyle->SetCandleCrossLineWidth(w);

where 1 <= w <= 5

Would that be a possibility ?

Dear @couet

Thank you for the suggestion. I’d love to use them if these attributes are implemented.

Best, KS.

I made a PR implementing this: Allow the set the line width of candle markers by couet · Pull Request #17128 · root-project/root · GitHub

Dear @couet

Thank you.

Best, KS.

Hi, it’s a while ago I implemented this…

TCandle is a painter-class, so you cannot access the properties of the candles immediately (TCandle is only used by THistPainter directly), we did something in the past, by using these global variables, as suggested by @couet

Today you can represent the mean of the candle by using a dashed line (please refer to THistPainter-Doc). The candle enforces the line to be dashed in order to give a consistent candle behaviour inside root. By doing so one can always differentiate between the median (non-dashed) and the mean (dashed, or circle).

Nevertheless, I have a cheat (or two) for you. I already mentioned this in post before, you can tell root to create an individual candle by createing histoslides with exact 5 values, due to the calculation method (basically it is the GetQuantiles-Function of TH1) these will represent, mean, the box-ranges and the anchors. I just tested this new cheat for you

void candleplot() {
 
   gStyle->SetTimeOffset(0);
   TDatime dateBegin(2010,1,1,0,0,0);
   TDatime dateEnd(2011,1,1,0,0,0);
 
   auto h1 = new TH2I("h1","Machine A + B",12,dateBegin.Convert(),dateEnd.Convert(),1000,0,1000);
   auto h1mean = new TH2I("h1mean","Mean of Machine A + B",12,dateBegin.Convert(),dateEnd.Convert(),1000,0,1000);
   auto h2 = new TH2I("h2","Machine B",12,dateBegin.Convert(),dateEnd.Convert(),1000,0,1000);
   auto h2mean = new TH2I("h2mean","Mean of Machine B",12,dateBegin.Convert(),dateEnd.Convert(),1000,0,1000);
 
   h1->GetXaxis()->SetTimeDisplay(1);
   h1->GetXaxis()->SetTimeFormat("%m/%y");
   h1->GetXaxis()->SetTitle("Date [month/year]");
 
   float Rand;
   for (int i = dateBegin.Convert(); i < dateEnd.Convert(); i+=86400*30) {
      for (int j = 0; j < 1000; j++) {
         Rand = gRandom->Gaus(500+sin(i/10000000.)*100,50); h1->Fill(i,Rand);
         Rand = gRandom->Gaus(500+sin(i/11000000.)*100,70); h2->Fill(i,Rand);
      }
   }
   
   for (int i = 1; i <= h2->GetXaxis()->GetNbins(); i++) {
	   TH1D *hSlice = h1->ProjectionY("_py",i,i+1);
	   float meanOfSlice = hSlice->GetMean();
	   h1mean->Fill(h2->GetXaxis()->GetBinCenter(i), meanOfSlice);
	   hSlice = h2->ProjectionY("_py",i,i+1);
	   meanOfSlice = hSlice->GetMean();
	   h2mean->Fill(h2->GetXaxis()->GetBinCenter(i), meanOfSlice);
   }
 
   h1->SetBarWidth(0.4);
   h1->SetBarOffset(-0.25);
   h1->SetFillColor(kYellow);
   h1->SetFillStyle(1001);
   
   h1mean->SetBarWidth(0.4);
   h1mean->SetBarOffset(-0.25);
 
   h2->SetBarWidth(0.4);
   h2->SetBarOffset(0.25);
   h2->SetMarkerStyle(106);
   h2->SetLineColor(kRed);
   h2->SetFillColor(kGreen);
   
   h2mean->SetBarWidth(0.4);
   h2mean->SetBarOffset(0.25);
   h2mean->SetLineColor(kRed);
   h2mean->SetLineWidth(5);
 
   auto c1 = new TCanvas();
 
   h1->Draw("candle(112001)"); //1=outliers, 1=anchor, 2=whisker at 1.5iqr, 0=no mean, 0=no median, 1=box 
   h1mean->Draw("candle(200000) same"); //draw all values as cross
   h2->Draw("candle(112001) same"); //1=outliers, 1=anchor, 2=whisker at 1.5iqr, 0=no mean, 0=no median, 1=box 
   h2mean->Draw("candle(10000) same"); //drawing only the anchors
 
   gPad->BuildLegend(0.78,0.695,0.980,0.935,"","f");
   
   
   
}

I’m creating two new histos h1mean and h2mean which only contain the mean values per candle-slice.
I changed the drawing method for h1, so that the candle will not draw the mean anymore, instead of this we are drawing the mean by using h1mean on top of this. h1mean uses the “draw all values”, as only mean is inside, it will be drawn. Unluckily, TCandle enforces us that the values are drawn as crosses (that would be a nice improvement).
In the second case, h2mean is drawn on top of h2, and here we are drawing only the anchors. As there is only one value inside, the anchor will have the value of the mean.

There is a pretty good documentiation about the candle-options in THistPainter-Doc,

Hope this helps :slight_smile:

@couet:
Instead of the original change-request I would rather recommend a global variable containing the markeroption for the outliers (in case you want to draw all datapoints)

Georg

@Georg_T : Is the PR I provided valid ? (see the macro I provede as example, it is simple)

@couet:
Of course you can do this change!

Please make this option available too - for me this increases the flexibility much more:

int drawallusingcandle() {
	TH2I *h1 = new TH2I("h1","Setup A",5,0,5,100,0,100);
	TH2I *h2 = new TH2I("h2","Setup B",5,0,5,100,0,100);
	
	float Rand;
   for (int i = 0; i < 5; i++) {
      for (int j = 0; j < 5; j++) {
         Rand = gRandom->Gaus(40, 10); h1->Fill(i,Rand);
         Rand = gRandom->Gaus(60, 10); h2->Fill(i,Rand);
      }
   }
 
 h1->SetLineColor(kRed);
 h2->SetLineColor(kBlue);
 
 
 THStack *hs = new THStack();
 hs->Add(h1);
 hs->Add(h2);

 hs->Draw("candle(200000)");
  hs->GetXaxis()->SetNdivisions(509,true);
gPad->Update();

 //gStyle->SetCandleMarkerAllPoints(55); //That would be nice :-)
 gPad->SetGrid(1,0);
 gPad->BuildLegend(0.75,0.75,0.95,0.95,"");
	
return 0;

}

this marker needs to be linked into this inside TCandle:

if (GetCandleOption(5) > 0) { //Draw outliers
      if (IsOption(kPointsAllScat)) { //Draw outliers and "all" values scattered
         SetMarkerStyle(0);
      } else {
         SetMarkerStyle(5); /// <----Link HERE
      }
      TAttMarker::Modify();
      gPad->PaintPolyMarker(fNDrawPoints,fDrawPointsX, fDrawPointsY);

Yes see my PR…