Setting mean and median manually in violin plot

Dear ROOTers,
I want to plot some data using a violin plot. In the documentation of the THistPainter class, it is written, that the properties like mean and median are calculated from the binned data stored in the TH2 and might therefore deviate from the true values. In the documentation of the class TCandle, I found the functions TCandle::SetMean(Double_t mean), TCandle::SetMedian(Double_t median), TCandle::SetQ1(Double_t q1) and TCandle::SetQ2(Double_t q2). So I thought about calculating the corresponding quantities from the unbinned data and setting them manually. The question now is: How do I access the single candles in order to call these functions? I am looking for something like

TCandle *candle1=(TCandle*)myth2->GetCandle(1); //or something equivalent
candle1->SetMedian(median1);

Is there such a function?
I am using root version 6.18-04.

Best,
Timo

Hi Timo,

it looks like this requires the help of @couet, who is on vacation this week. Can you get in touch again if you don’t hear back lets say Tuesday or Wednesday next week?

Hi Stephan,

thanks for your reply. Yes, I can wait until next week. But I just found some alternative that with some additional help might lead to a solution of my problem.
I had a look into the code of the THistPainter:: PaintCandlePlot(Option_t *option) function and tried similar to this, to create single TCandles and then to paint them. I tried

Double_t a[5]={1,2,3,4,4};
TCandle* c=new TCandle(0.5,1,5,a); //this line seems to do all the calculation of mean and median on the unbinned data in a
TH2D* h2=new TH2D(“hist”,“hist”,4,0,4,100,0,10); //empty histogram in order to get axis
TCanvas* c1= new TCanvas(“mycanvas”,“mycanvas”);
h2->Draw();
//set some drawing options for the candle
c->SetLineColor(kBlack);
c->SetLineWidth(1);
c->SetFillColor(kBlue);
c->SetMarkerStyle(1);
c->SetCandleWidth(1);
c->SetHistoWidth(1);
char* opt=strdup(“VIOLINX(00002320), same”); //draw only whiskers, mean and median
c->ParseOption(opt);
c->Paint(“same”);
c1->Update();

this code runs without any error, but no candle is drawn. A call of
c->GetMedian() returns 3.0, so it seems like additional computation on the raw data is not necessary. If this would work, I could create all candles on after another and paint them. So the only thing missing actually seems to make the candle appear in the canvas. Any idea how to proceed from here?

Of course, simply drawing the entire th2 with the option “VIOLINX(00002320), same” and then modifying Mean, median, Q1 and Q3 as intended in my initial post would still be an option, that might be faster.

Best,
Timo

I really don’t know the details, but I think you have to tell the candle where to paint, i.e., you cannot leave out the SetHistogram() part. The histogram presumably sets the coordinate system.
Also, try to remove the "same" from Paint().

I emailed the author of this code. Let’s wait his answer.

Hi,
…it’s quite a long time ago I wrote this code (I guess almost 5 years)…

TCandle is a painter class only which shouldn’t be used to draw something manually.

It’s still in my pipeline to implement a “raw-data-candle” which can be accessed from TTree directly, unfortunately it’s not ready - sorry, time is very limited at the moment. This raw-data-candle would solve your problem

Because of this I would suggest a workaround:
in 99% of all cases I know, it is suffucient to increase the number of bins in your histogram. With an increased number of bins the deviation between the raw-data calculation of median, mean, etc and the binned calculation will be reduced. Usually this is sufficient as the deviations are not visible in the chart anymore

If this is still not sufficient for you, there might be another cheat: If you draw a candle or violin chart from a histogram based of only 5 points this will be used as definition of the candle (this is a logical consequence from the implemented routine. It used the GetQuantiles-Method from TH1).

Be aware that there are different definitions for the anchors (candle1 and candle2). When I remember correctly there were some static variable, too, so that one could influence the IQR (the box-size) - Please check TCandle::SetBoxRange() - this is a general setting for all Candle charts.

Cheers
George

Hi George,
thanks for your answer. For plotting you’re right, small enough bin sizes do the job. So my workaround would be to create two histograms:

  1. a histogram with a bin size chosen to get a nice looking histogram for the violin plot. Here, drawing options are selected, such that only the histogram, but no candle or whiskers are drawn.
  2. a histogram with very small bins. For this one, drawing options are selected, such that no histogram, but, the candle is plotted. This histogram is added to the canvas with the option “same”

For tabulated values, the median and quantiles are calculated from the raw data stored in arrays using the corresponding TMath functions (or from TTree) or even the TCandle functions with the constructur using an array can be used.

For future implementation of candles based on unbinned data, I would propose to make it accessible from a class similar to TMultiGraph. I see that it’s a bit complicated as it means that one has data that is binned in one dimension and unbinned in the second. An implementation based on TTree would have been rather unhandy for me as the groups in my violin plot have different numbers of entries.

Best,
Timo