Matplotlib line width when saving a PDF file

I have a figure with some pretty delicate features that are sensitive to line width. I want to save this figure as a PDF, which can be easily printed (i.e. do not scale on the receiver side, just Command + P and go). Unfortunately, when I set figsize = (8.5, 11) to correctly print the PDF for printing, matplotlib selects the very thick line width and text size that ruined the graph (the legend is too large and the lines in the overlap histogram). If I set figsize = (17,22), I get a very effective line width and text after scaling the PDF to 50% for printing. This is what I used, but this solution became unworkable due to the policy, and I really do not want to scale the PDF in Illustrator every time I make changes.

If I could work with bitmap images, I could achieve the desired result by setting figsize = (17,22) and setting dpi to half the target dpi, but this does not work for PDF files, since the dpi parameter seems to be ignored. I need a pdf which

  • looks like box_good.png (bitmap with distorted size with thin lines, small text).
  • measures 8.5x11in (or prints like it)
  • can be edited in illustrator (this is not a bitmap wrapped in pdf)

I cannot help but suspect that when saving to PDF, there is an easy way to pull out the “double size, half-inch” trick, but I refused it to work, and started trying to directly manipulate the line widths and texts. I managed to change the text, but not the line width. Here is a record of what I tried:

# Tried: # fig.set_size_inches(17,22) # fig.savefig('boxes.pdf', dpi=100,150,300) # dpi parameter has no effect on linewidth, text size, or the PDF dimensions # 'markerscale=.5' on plt.legend and pax.legend # no effect # mp.rcParams['font.size']=8 # worked! made text smaller, now for linewidth... # mp.rcParams['lines.linewidth']=5 # no effect # fig.set_linewidth(5) # no effect # pax.axhline(linewidth=5) # only changes x axis not box surrounding subplot # fig.set_size_inches(8.5,11) immediately before plt.savefig('boxes.pdf') # identical results to calling plt.figure(figsize=(8.5,11)) in the first place # I tried passing plt.figure(figsize=(17,22)) and swapping it to 8.5x11 using # fig.set_size_inches right before saving, but the lines were thick and the text # was large in the PDF, exactly as if I had set figsize=(8.5,11) to begin with 

Here is the source file (I shortened the schedule to the necessary items, so the obvious style workarounds are probably not workable solutions)

 import numpy as np import matplotlib as mp import matplotlib.pyplot as plt x = np.arange(200) bottom_red_bar = -np.random.random(200) bottom_black_bar = np.random.random(200) * bottom_red_bar fig = plt.figure() for subplotnum in [1,2,3]: pax = plt.subplot(310+subplotnum) pax.set_ylim([-1,1]) bot_rb = pax.bar(x, bottom_red_bar,1,color='r') bot_bb = pax.bar(x+(1-.3)/2,bottom_black_bar,.3,color='k') pax.legend([bot_rb,bot_bb],['Filler Text 1','Filler Text 2'],loc=4) fig.set_size_inches(8.5,11) fig.savefig('boxes_bad.png',dpi=300) # Lines are too thick fig.set_size_inches(17,22) fig.savefig('boxes_good.png',dpi=150) # Lines are just right fig.set_size_inches(8.5,11) plt.savefig('boxes.pdf') # Lines are too thick fig.set_size_inches(17,22) # Lines are just right plt.savefig('boxes.pdf') # but the PDF needs scaling before printing 

Thus, I get the opportunity to adjust the line width for the whole figure or the way to have matplotlib to save pdf with dimension metadata other than figsize. Any suggestions?

+6
source share
2 answers

Thanks Marius, I’ll fix it as soon as I get 15 reputation to do this. Although your rcParams didn't exactly match what I wanted to do, rcParams itself was the right place to look, so I listed rcParams containing the "line width" via rcParams.keys ():

 >>> [s for s in mp.rcParams.keys() if 'linewidth' in s] ['axes.linewidth', 'grid.linewidth', 'lines.linewidth', 'patch.linewidth'] 

After some experiments, I picked up what each pair controlled:
mp.rcParams ['axes.linewidth']: the square surrounding the entire section (not ticks, not the line y = 0)
mp.rcParams ['grid.linewidth']: not tested, presumably grid width
mp.rcParams ['lines.linewidth']: width of lines drawn using pyplot.plot
mp.rcParams ['patch.linewidth']: the width of the rectangle strokes, including the pyplot.bar graph stripes, legends, and bar legend labels
mp.rcParams ['xtick.minor.width']: line width of small keys (similar so)
mp.rcParams ['xtick.major.width']: line width of large keys (similar to yticks)

The specific solution that I used was

 mp.rcParams['axes.linewidth'] = .5 mp.rcParams['lines.linewidth'] = .5 mp.rcParams['patch.linewidth'] = .5 
+7
source

I would suggest setting parameters, such as line width, via rcParams (or your matplotlibrc file):

 # mp.rcParams['figure.figsize'] = fig_size # set figure size mp.rcParams['font.size'] = font_size mp.rcParams['axes.labelsize'] = font_size mp.rcParams['axes.linewidth'] = font_size / 12. mp.rcParams['axes.titlesize'] = font_size mp.rcParams['legend.fontsize'] = font_size mp.rcParams['xtick.labelsize'] = font_size mp.rcParams['ytick.labelsize'] = font_size 

I usually use the standard figure.figsize , which is (8,6) , and the line width in the axis object smaller than 1/12 (for example, font_size = 16 when I include graphics in two-column paper).

Remember that vector graphics do not mean that all lines and letters always have the same size when scaling. This means that you can scale without losing quality or sharpness (roughly).

+4
source

All Articles