Consistent Absolute Font Sizing When Saving to SVG

Hello,

I am attempting to produce plots with consistent styling for use in a publication. My preferred workflow is to save my TCanvas to an SVG file so that I can annotate outside of ROOT and then export to a vector graphics file for the publication (e.g. eps or pdf).

I am having an issue where I cannot figure out how to specify an absolute font size that is respected when saving to SVG (independent of canvas size).

I am aware of the need to select a font with precision >2 to specify absolute font sizes, and indeed this works for getting consistent sizing in the ROOT canvas. However, this does not seem to apply to exported SVG files.

Here is an example:

{
	gStyle->SetLabelFont(43);
	gStyle->SetLabelSize(16);
	TH1F* h = new TH1F("h","",50,-10,10);
	h->FillRandom("gaus");

	TCanvas* c1 = new TCanvas("c1","Big Canvas",1200,1600);
	h->Draw();
	TCanvas* c2 = new TCanvas("c2","Small Canvas",150,200);
	h->Draw();
	c1->SaveAs("c1.svg");
	c2->SaveAs("c2.svg");
}

When I run this, c1.svg has a font size of 5.52 pt for the axis labels, according to Inkscape. c2.png has a font size of 42.55 pt. I would like them to be exactly the same (and better yet - easily specifiable in point size, e.g. 10 pt).

Is there any way to accomplish this?

This might be a question for @couet.

In the SVGs the graphics are saved as vectors, not raster (pixels), so pixels don’t have much meaning; thus, the plot elements are saved with the same proportions you see on the canvas when you run the macro (huge labels in the “small” canvas, tiny labels in the “big” canvas). So in this case, try the “normal” font types, which are proportional to the canvas and they may look “wrong” (too small in the small canvas; not actually wrong, but what you chose to do!) in the interactive canvas but “correct” in the SVG; these, for example, seem ok:

  gStyle->SetLabelFont(42);
  gStyle->SetLabelSize(.035);

Bonus info: since these font sizes are, as I mentioned, proportional to the canvas size, you should make sure your canvases have exactly the same aspect ratio, which is not the case in your example (*); so .035 looks ok but is not perfect.
(*) Note that to control the canvas sizes, use canvas->SetCanvasSize(w,h); the values you gave in the canvas constructor are for the window, meaning that the window decorations will use some of that size, effectively changing the aspect ratios in different ways for different sizes; try for example this:

{
  gStyle->SetLabelFont(42);
  gStyle->SetLabelSize(.035);
  TH1F* h = new TH1F("h","",50,-10,10);
  h->FillRandom("gaus");

  TCanvas* c1 = new TCanvas("c1","Big Canvas");
  c1->SetCanvasSize(1200,1600);
  h->Draw();
  TCanvas* c2 = new TCanvas("c2","Small Canvas");
  c2->SetCanvasSize(150,200);
  h->Draw();
  c1->SaveAs("c1.svg");
  c2->SaveAs("c2.svg");
}

Notice also that in the above, the window sizes are some default value (as I did not specify any values), therefore if you run in the interactive prompt one canvas seems to have white space around it and the other doesn’t fit and the window has scroll bars; but the canvas sizes are as expected both interactively (try resizing the canvas windows by hand to check) and in the saved SVGs.

Okay, thank you. That helps with getting the sizes consistent for sure. Still, if I want a specific point size in the SVG, is there any way to do that - aside from trying to calculate it based on the canvas size and/or guess & check with an output file?

It appears not, but maybe I am still missing something.

I hope, Olivier @couet will have solution for you.

The problem I see - ROOT produces SVG file with size which is differ from configured canvas size.
PNG images does not have such problem.

If you still want to use SVG - try root --web=chrome.
Web-based graphics creates SVG files with proper sizes.

I made a more direct test:

{
   auto t = new TText(.5, .5, "SVG test"); 
   t->SetTextFont(43);
   t->SetTextSize(16);
   TCanvas* c1 = new TCanvas("c1","Big Canvas",1200,1600);
   t->Draw();
   TCanvas* c2 = new TCanvas("c2","Small Canvas",150,200);
   t->Draw();
   c1->SaveAs("c1.svg");
   c2->SaveAs("c2.svg");
}

As you said, and as expected, this gives the same text size in the 2 canvases. But in the SVG files I see:

<text xml:space="preserve" x="283.965" y="218.632" fill="black" font-size="7.44649" font-family="Helvetica">SVG test</text>

and:

<text xml:space="preserve" x="283.965" y="335.178" fill="black" font-size="56.729" font-family="Helvetica">SVG test</text>

So clearly the the font-size parameter is different. It might simply be that "font precision = 3"is not implemented in the SVG case. I need to check.

Hi Olivier,

For me problem also that SVG sizes are wrong.
In c1.svg I see:

<svg width="562.521" height="737.508" viewBox="0 0 562.521 737.508" ...

And in c2.svg I see:

<svg width="567.429" height="655.533" viewBox="0 0 567.429 655.533"

Both are far away from configured canvas sizes.

Sergey

Did you use SetCanvasSize() for that? with my example above I get (checked now on Ubuntu + WSL2, but not on web, though, if that makes any difference) both SVGs with the same size:

<svg width="553.256" height="737.508" viewBox="0 0 553.256 737.508" xmlns="http://www.w3.org/2000/svg" shape-rendering="crispEdges">

Indeed that’s not specific to SVG (TSVG.cxx) it is same for PDF and PS: The text size “in pixel” is converted into vector graphics units and the low level backends are not even aware of such conversion. If you compare the SVG display, PDF display to the screen display then size of the text inside the drawing area is the same. So its correct. See the comparison as the “Small canvas” (SVG on the left, PDF in the middle and screen on the right):

No, I run code from Olivier.
But even if I provide SetCanvasSize - TSVG class does not set dimension for produced svg element.

One can see how TWebCanvas is working. It creates svg element like:

<svg width="1200" height="1600" ...

And inside it create text with font-family="Arial" font-size="16"

This that I expect when configuring:

   t->SetTextFont(43);
   t->SetTextSize(16);

See my example with red canvases in order to see better the size of the canvas. The text size in PDF and SVG is correct relatively to the red area. SVG viewer and PDF viewer enlarge the display compare to the display on screen but inside the drawing area (now in red) the size of the text is the same

{
   auto t = new TText(.5, .5, "SVG test"); 
   t->SetTextFont(43);
   t->SetTextSize(16);
   TCanvas* c1 = new TCanvas("c1","Big Canvas",1200,1600);
   c1->SetFillColor(2);
   t->Draw();
   
   TCanvas* c2 = new TCanvas("c2","Small Canvas",150,200);
   c2->SetFillColor(2);

   t->Draw();
   c1->SaveAs("c1.svg");
   c1->SaveAs("c1.pdf");
   c2->SaveAs("c2.svg");
   c2->SaveAs("c2.pdf");
}