Escaping Characters when Saving Plots

Hi,

I’ve been trying lots of things to try and escape ‘(’ and ‘)’ when saving a TCanvas to pdf, but none seem to work.

The filename gets cut off just before the characters above.
I’m using a SaveAs() from TCanvas to save the plots to pdf.

I’ve tried \(, \\(, \\\\(, #(, @(, !(, ~(, ^(, %(, to escape parenthesis, nothing seems to work.

How can a save a plot to a filename which includes parenthesis ()?

Thanks

can you post a example showing what are doing ?

a filename which includes parenthesis ()?

it is not a good idea to have a filename with ( and ) inside …

nothing special, just something like this:

the resulting saved filename is: “/local_data/Plots/Device_Name_” and I can’t figure out how to escape ( and ) so that the filename is properly saved.

Not a good idea to have normal ASCII characters in the filename? Sorry, but now I have to question what kind of a rotten structure ROOT is based on, since it doesn’t appear to have a way to escape offensive characters or even if it does, the documentation is acutely lacking its details.

( should be fine.

Ahhhhhh, grrrr.

How stupid is this? “(” needs to be escaped, but “)” does not. ?!?!?!

So, to make it work, this is how it would look like: (char*)"/tmp/hello_world(abc).pdf"

Thanks

So I’m continuing to have a bit of trouble.

charReplaceAll function is:

void charReplaceAll(char* cstr, const string& from, const string& to) { string str = cstr; if(from.empty()) {return;} string wsRet; wsRet.reserve(str.length()); size_t start_pos = 0, pos; while((pos = str.find(from, start_pos)) != string::npos) { wsRet += str.substr(start_pos, pos - start_pos); wsRet += to; pos += from.length(); start_pos = pos; } wsRet += str.substr(start_pos); str.swap(wsRet); // faster than str = wsRet; strcpy(cstr, str.c_str()); }

Using this code:

Output:

Result:
name is cut off after using (


Using code:

sprintf(savePlotFilename, "/local_data0/Data/GAIN/%s_%iC_%.1fV/%s_%iC_Template-%.1fV_%.1fV_%s_maxamp.pdf", deviceNameExtendedU.c_str(), temperature, HVTemplate, deviceNameExtendedU.c_str(), temperature, HVTemplate, HV, todaysDate); cout<<savePlotFilename<<endl; charReplaceAll(savePlotFilename, "(", "\("); cout<<savePlotFilename<<endl; cMaxAmpDistribution->SaveAs(savePlotFilename);

Output:

/local_data0/Data/GAIN/test_with_Shaper(47pF)_5C_71.0V/test_with_Shaper(47pF)_5C_Template-71.0V_70.6V_Jul242013_maxamp.pdf /local_data0/Data/GAIN/test_with_Shaper(47pF)_5C_71.0V/test_with_Shaper(47pF)_5C_Template-71.0V_70.6V_Jul242013_maxamp.pdf Info in <TCanvas::Print>: Current canvas added to pdf file /local_data0/Data/GAIN/test_with_Shaper

Result:
Seems like there’s a weird conversion that gets eaten up, resulting in failure to save file. ( seems to be eaten up by the compiler. So I would need to use “\(” in order to get “(” in the filename.


Using code:

sprintf(savePlotFilename, "/local_data0/Data/GAIN/%s_%iC_%.1fV/%s_%iC_Template-%.1fV_%.1fV_%s_maxamp.pdf", deviceNameExtendedU.c_str(), temperature, HVTemplate, deviceNameExtendedU.c_str(), temperature, HVTemplate, HV, todaysDate); cout<<savePlotFilename<<endl; charReplaceAll(savePlotFilename, "(", "\\\("); cout<<savePlotFilename<<endl; cMaxAmpDistribution->SaveAs(savePlotFilename);

Output:

/local_data0/Data/GAIN/test_with_Shaper(47pF)_5C_71.0V/test_with_Shaper(47pF)_5C_Template-71.0V_70.6V_Jul242013_maxamp.pdf /local_data0/Data/GAIN/test_with_Shaper\(47pF)_5C_71.0V/test_with_Shaper\(47pF)_5C_Template-71.0V_70.6V_Jul242013_maxamp.pdf Info in <TCanvas::Print>: Current canvas added to pdf file /local_data0/Data/GAIN/test_with_Shaper\

Result:
The cout after replacing ( with ( looks good, but SaveAs still does not work, still gets cut off at (.

Input:

Output:


Input:

Output:


Input:

Output:

I don’t understand, in one script “(” works, but in another it doesn’t.


Input:

Output:


WHYYYYY!!! :imp: :imp: :imp:

Ah, here we go, a BUGGGGGG! :smiling_imp:

PDF saving routine does not handle “(” the same way as PNG does, hence PDF fails when it encounters a “(”.

As explained in the documentation () and [} are control characters for PDF and PS files. They allow to leave a file open and pile up several pictures in the same file. Png (and others) do not have this possibility. That’s why it behaves differently. Please avoid this specials characters for PDF and PS. That’s not a big deal. There is many other characters you can use.

[quote=“kandrey89”]Input:

cMaxAmpDistribution->SaveAs((char*)"/tmp/hello_world .... \( ..... abc).pdf");

Output:

Info in <TCanvas::Print>: Current canvas added to pdf file /tmp/hello_world

WHYYYYY!!! :imp: :imp: :imp:

Ah, here we go, a BUGGGGGG! :smiling_imp:
[/quote]

Well, bug or not, but C++ does not have an escape sequence ‘(’ or ‘)’, so you’d better do not use them in string literals (there can be ‘conditionally supported’ escape sequences, but they are compiler-dependent and I do not think any compiler has ‘(’). For example, try to compile this with -pedantic (if you have a g++ compiler):

[code]#include

int main()
{
std::cout<<“lalala(lalalala”<<std::endl;
}[/code]

Without -pedantic g++ (and e.g. clang) simply remove this stray ''.

So be sure you provide a valid C++ code before saying "what kind of a rotten structure ROOT is based on " or “… BUGGGGG”, otherwise … yeah, buggg, in YOUR CODE, and this " rotten structure " … is the C++ programming language.

P.S. And Olivier has already explained you about some special symbols in some file names.

As a workaround, could you perhaps create the file in temp path that is clear of chars that ROOT can’t handle and then simply move the file to desired path using file system functions that will work for sure?

I think this bug is a bigger issue than what it’s being treated as here:
If you’re creating a simple script where you can decide the output path, then likely not that big a deal.
But say you’re creating a GUI where user chooses the output path where some canvas is to be saved. Since it naturally should be perfectly valid to save files to valid paths in OS, the parenthesis handling inconsistency means that the GUI code must manually check the paths and handle them in some way. Not handling them may lead to confusion as demonstrated by this thread.

PLease read what I already said ! PS and PDF use () and as control !!

2couet

I read and understood what you wrote, but I suspect that you did not quite got what I wrote and I couldn’t find confirmation to your quote from documentation. Even if it worked the way you described the functionality would be bad because SaveAs should save file to given path without obscure failures on certain combinations of path and format. This is especially so as this is not documented well: for example TPad::SaveAs says “Save Pad contents in a file in one of various formats.” Yes it ultimately leads to TPad::Print that says:

Note “file name finishes with”.
As far as I see this documentation does not explain the behaviour reported by OP as his paths does not end with parenthesis so I see no reason why your quote applies to this case; could you provide a link to related documentation? Or perhaps this is related to [url=ROOT and paths with parentheses profound problem in ROOT[/url]?

And while I have obvious shortcomings what comes to reading and understanding text, I would appreciate if you did not find it necessary to emphasize you posts with excessive exclamation marks.

I think, the documentation is ok but the implementation is kind of sloppy, if you look into the TPad::Print it simply does:

// The parenthesis mechanism is only valid for PS and PDF files. copen = (char*)strstr(psname.Data(),"("); if (copen) *copen = 0; cclose = (char*)strstr(psname.Data(),")"); if (cclose) *cclose = 0;

Brrrr … obviously this is not what the documentation says :slight_smile:
So indeed there is a bug. Or documentation should say “the first occurence of ‘(’”.

The OP, I’m afraid, has to read about escape sequences first, while Olivier is fixing strstr :slight_smile:

[quote=“couet”]PLease read what I already said ! PS and PDF use () and [] as control !!

[quote]
As explained in the documentation () and [} are control characters for PDF and PS files. They allow to leave a file open and pile up several pictures in the same file. Png (and others) do not have this possibility. That’s why it behaves differently. Please avoid this specials characters for PDF and PS. That’s not a big deal. There is many other characters you can use.
[/quote][/quote]

Next, you’re going to say I can’t use “x” because it’s so and so control character.
Oh… it’s OK, you have 25+ other characters available.

That’s just stupid! :imp:
I hate ROOT for exactly this kind of crap. It uses archaic and seemingly backward ways to accomplish the simplest of things, and in the process managed to pile up exceptions, rules and conditions that have no business being there had it been properly created in the 1st place.

[quote=“kandrey89”]
I hate ROOT for exactly this kind of crap. It uses archaic and seemingly backward ways to accomplish the simplest of things, and in the process managed to pile up exceptions, rules and conditions that have no business being there had it been properly created in the 1st place.[/quote]

I’m pretty sure the software you are developing is much better than ROOT and does not have any flaws/bugs/etc. (apart from the fact that you do not know about escape sequences in C++). It’s a pity ROOT was not designed/written by you.

[quote=“tpochep”][quote=“tc3t”]
This is especially so as this is not documented well: for example TPad::SaveAs says “Save Pad contents in a file in one of various formats.” Yes it ultimately leads to TPad::Print that says:

Note “file name finishes with”.
[/quote]

I think, documentation is ok but the implementation is kind of sloppy, if you look into the TPad::Print it simply does:

// The parenthesis mechanism is only valid for PS and PDF files. copen = (char*)strstr(psname.Data(),"("); if (copen) *copen = 0; cclose = (char*)strstr(psname.Data(),")"); if (cclose) *cclose = 0;

Brrrr … obviously this is not what documentation says :slight_smile:
So indeed there is a bug. Or documentation should say “the first occurence of ‘(’”.

The OP, I’m afraid, has to read about escape sequences first, while Olivier is fixing strstr :slight_smile:[/quote]

The only reason I’m hopping around with escape sequences is because I’m dealing with shell(BASH) in my script, so it requires escaping, and what drove me insane was ROOT implementation of SaveAs and “(”.

It’s not that I don’t know about escape sequences, it’s that it went out the window when I had to figure out wtf ROOT was doing.

Oh and by the way, instead of using control characters, why not code a proper class that handles PDF saving, with all the page adding, and etc features via actual functions, instead of control characters. What is this 1970’s?

pdfClassVar->open(“path”); pdfClassVar->setOptions(…); pdfClassVar->addPage(tCanvasName); pdfClassVar->write; pdfClassVar->Close();
something like that…

Ok. Now we know what’s the reason, I hope Olivier will fix these strstrs in a couple of hours and you’ll be able to use file names you want to without any problems (and without and slashes).

This I can not discuss since I’m not responsible for these classes/interfaces/design :slight_smile:
There are a lot of things I do not like in one or another C++ library/framework but as I’m not going to “re-write the whole world” I simply tend to use them without telling their developers what I’m thinking about their intellectual level. After all, everything has a reason at some point, especially this is true for a 15-20 year old library. The bug (or incorrect implementation) indeed exists and as we can see it has nothing to do with escape characters.

And by the way, I think you will not care about ‘(’ or ‘)’ if it’s REALLY THE LAST character in a file name, right? You do not need blabla.pdf(, right? So … you can work/live even with this “1970-s” :slight_smile:

Luckily so.

No “first occurence”, please :wink:

The first example by OP did not have any escapes so it’s not about that. But it didn’t have pdf or ps either so perhaps this is worse than that.

[quote=“kandrey89”]Next, you’re going to say I can’t use “x” because it’s so and so control character.
Oh… it’s OK, you have 25+ other characters available.

That’s just stupid! :imp: [/quote]
Note though that if the behaviour was as documented (which is different from what couet said), it should work fine.

[quote=“tpochep”][quote=“kandrey89”]
I hate ROOT for exactly this kind of crap. It uses archaic and seemingly backward ways to accomplish the simplest of things, and in the process managed to pile up exceptions, rules and conditions that have no business being there had it been properly created in the 1st place.[/quote]

I’m pretty sure the software you are developing is much better than ROOT and does not have any flaws/bugs/etc. (apart from the fact that you do not know about escape sequences in C++). It’s a pity ROOT was not designed/written by you.[/quote]
And it’s a pity for everyone that many parts of ROOT has been written so badly.

Have you checked if TPDF has that functionality? Don’t be disappointed, though, if it doesn’t :slight_smile:

Well, “there are two way this can end and in both of them y”…. :slight_smile:) I mean if it says “the last”, this fragment with strstr must be re-written
(BTW all logic has to be re-checked and cleared in this TPad::Print, it’s quite a messy function of ~300 LOC).

Well, in this case it’s not clear why he named the topic this way, WHY he decided he has to escape parenthesis, why he decided they have to be escaped this way
etc.

Exactly, since nobody needs name.pdf( or name.pdf)

As ROOT is an open-source project, I think everybody welcome to improve it if he really can do this and have some stable solution
which works everywhere and does not break everything else in ROOT and ROOT-related projects.

In our concrete case, TPad::Print must be obviously FIXED.

So do I need to create a bug report? I don’t see it.
If it’s fixed soon, if I’m not running head, or developer’s release, when can I expect the next version of ROOT?