pythonmatplotlibeps

Cannot open eps file after saving figure


Normally, opening an eps file is no problem but with this current code in Python that I am working on, the exported eps file is loading when opened but never appearing. I have tried exporting the same figure as a png and that works fine. Also I have tried exporting a really simple figure as eps and that opens without any flaws. I have included some of the relevant code concerning the plot/figure. Any help would be much appreciated.

    #%% plot section

    plt.close('all')

    plt.figure()

    plt.errorbar(r,omega,yerr=omega_err,fmt='mo')
    plt.xlabel('xlabel')
    plt.ylabel('ylabel')
    plt.title('profile averaged from {} ms to {} ms \n shot {}'.format(tidsinterval[0],tidsinterval[1],skud_numre[0]),y=1.05)
    plt.grid()
    plt.axhline(y=2.45,color='Red')
    plt.text(39,2.43,'txt block for horizontal line',backgroundcolor='white')
    plt.axvline(x=37.5,color='Purple')
    plt.text(37.5,1.2,'txt block for vertical line',ha='center',va="center",rotation='vertical',backgroundcolor='white')
    plt.savefig('directory/plot.eps', format='eps')
    plt.show()

The variables r, omega, omega_err are vectors of float of small sizes (6 perhaps).

Update: The program I use for opening eps-files is Evince, furthermore, one can download the eps file here https://filedropper.com/d/s/z7lxUCtANeox7tDMQ6dI6HZUpcTfHn. As far as I can see, it is fine sharing files over filedropper via community guidelines, but if I'm wrong please say so. Found out that it is possible to open the file as long as there is no text contained in the plot (for example x-label,y-label, title and so on), so the problem has to be related to the text.


Solution

  • The short answer is it's your font. The /e glyph is throwing an error on setcachedevice (your PostScript interpreter should have told you this).

    The actual problem is that the font program is careless (at least) about it's use of function name. The program contains this:

    /mpldict 11 dict def
    mpldict begin
    /d { bind def } bind def
    

    That creates a new dictionary called mpldict, begins that dictionary (makes it the topmost entry in the dictionary stack) and defines a function called 'd' in that dictionary

    We then move on to the font definition, there's a lot of boiler plate in here, but each character shape is defined by an entry in the font's CharStrings dictionary, we'll pick that up with the definition of the function called 'd' in the font's CharStrings dictionary.

    /d{1300 0 113 -29 1114 1556 sc
    930 950 m
    930 1556 l
    ce} d
    (2.60) == flush
    /e{1260 0 113 -29 1151 1147 sc
    1151 606 m
    1151 516 l
    305 516 l
    313 389 351 293 419 226 c
    488 160 583 127 705 127 c
    776 127 844 136 910 153 c
    977 170 1043 196 1108 231 c
    1108 57 l
    1042 29 974 8 905 -7 c
    836 -22 765 -29 694 -29 c
    515 -29 374 23 269 127 c
    165 231 113 372 113 549 c
    113 732 162 878 261 985 c
    360 1093 494 1147 662 1147 c
    813 1147 932 1098 1019 1001 c
    1107 904 1151 773 1151 606 c
    
    967 660 m
    966 761 937 841 882 901 c
    827 961 755 991 664 991 c
    561 991 479 962 417 904 c
    356 846 320 764 311 659 c
    967 660 l
    
    ce} d
    

    Notice that what this does is create a new definition of a function named 'd' in the current dictionary. That's not a problem in itself. We now have two functions named 'd'; one in the current dictionary (the font's CharStrings dictionary) and one in 'mpldict'.

    Then we define the next character:

    /e{1260 0 113 -29 1151 1147 sc
    1151 606 m
    1151 516 l
    305 516 l
    313 389 351 293 419 226 c
    488 160 583 127 705 127 c
    776 127 844 136 910 153 c
    977 170 1043 196 1108 231 c
    1108 57 l
    1042 29 974 8 905 -7 c
    836 -22 765 -29 694 -29 c
    515 -29 374 23 269 127 c
    165 231 113 372 113 549 c
    113 732 162 878 261 985 c
    360 1093 494 1147 662 1147 c
    813 1147 932 1098 1019 1001 c
    1107 904 1151 773 1151 606 c
    
    967 660 m
    966 761 937 841 882 901 c
    827 961 755 991 664 991 c
    561 991 479 962 417 904 c
    356 846 320 764 311 659 c
    967 660 l
    
    ce} d
    

    Now, the last thing we do at the end of defining that character shape (for the character named 'e') is call a function named 'd'. But there are two, which one do we call ? The answer is that we work backwards down the dictionary stack looking in each dictionary to see if it has a function called 'd' and we use the first one we find. The current dictionary is the font's CharStrings dictionary, and it has a function called 'd' (which defines the 'd' character) so we call that.

    And that function then tries to use setcachedevice. That operator is not legal except when executing a character description, which we are not doing, so it throws an undefined error.

    Now your PostScript interpreter should tell you there is an error (Ghostscript, for example, does so). Because there is an error the interpreter stops and doesn't draw anything further, which is why you get a blank page.

    What can you do about this ? Well you could raise a bug report with the creating application (apparently Matplotlib created the font too). This is not a good way to define a font!

    Other than that, well frankly the only thing you can do is search and replace through the file. If you look for occurrences of ce} d and replace them with ce}bind def it'll probably work. This time.