I have some color plots that I need to be saved in grayscale. Is there an easy way to do this without changing the plotting formats?
-
4There were some discussion around that, see [convert figure from color to BW/grayscale](http://old.nabble.com/convert-figure-from-color-to-BW-grayscale-td29756144.html). Don't know whether the `set_gray` attribute is available or not in the latest release of matplotlib. – chl May 16 '11 at 18:29
-
You could use imagemagick afterward: `convert -type Grayscale old.png new.png` I think there is already something on SO cf [link](http://stackoverflow.com/questions/3823752/display-image-as-grayscale-using-matplotlib) – Pierre Guilbert May 17 '11 at 20:53
6 Answers
It's currently awkward to do directly from matplotlib, but in "the future" they plan to support a set_gray(True)
call on the figure (see the mailing list thread here).
Your best options will be to save it in color and convert it, either in python with PIL:
import Image
Image.open('color.png').convert('L').save('bw.png')
or from the command line with imagemagick:
convert -type Grayscale color.png bw.png

- 10,935
- 4
- 38
- 69
-
1Like the other answers, this answer is not very satisfactory because it rasterizes the plot. – Ian Goodfellow Apr 25 '15 at 05:11
Actually, this was asked before. Here is a pretty good answer, which comes 2nd on google (as of today):
Display image as grayscale using matplotlib
And the solution is VERY similar to Suki's...
Oh, well, I am bored, so I post here also a full blown code:
import numpy as np
import pylab as p
xv=np.ones(4)*.5
yv=np.arange(0,4,1)
xv1=np.ones(4)*-.5
yv1=np.arange(0,4,1)
#red vertical line on the right
yv2=np.arange(0,1.5,0.1)
xv2=np.ones_like(yv2)*.7
#red vertical line on the left
yv3=np.arange(0,2,0.01)
xv3=np.ones_like(yv3)*-0.7
###
xc=np.arange(-1.4,2,0.05)
yc=np.ones_like(xc)*1
fig = p.figure()
ax1 = fig.add_subplot(111)
#adjustprops = dict(left=0.12, bottom=0.2, right=0.965, top=0.96, wspace=0.13, hspace=0.37)
#fig.subplots_adjust(**adjustprops)
ax1.plot(xv,yv, color='blue', lw=1, linestyle='dashed')
ax1.plot(xv1,yv1, 'green', linestyle='dashed')
ax1.plot(np.r_[-1:1:0.2],np.r_[-1:1:0.2],'red')
ax1.plot(xc,yc, 'k.', markersize=3)
p.savefig('colored_image.png')
import matplotlib.image as mpimg
import matplotlib.cm as cm
import Image
figprops = dict(figsize=(10,10), dpi=100)
fig1 = p.figure(**figprops)
#fig1 = p.figure()
#ax1 = fig.add_subplot(111)
adjustprops = dict()
image=Image.open('colored_image.png').convert("L")
arr=np.asarray(image)
p.figimage(arr,cmap=cm.Greys_r)
p.savefig('grayed.png')
p.savefig('grayed.pdf',papertype='a4',orientation='portrait')
This will produce a graph in color, than read it, convert it to gray scale, and will save a png and pdf.
-
3This answer is not very good because it requires rasterizing the plot and any fonts in it. The rasterization occurs when you convert to .png. It would be better to write a pdf to the filesystem and then convert that to grayscale, perhaps using ghostscript. – Ian Goodfellow Apr 25 '15 at 05:10
-
I am struggling with this issue too. As far as I can tell, matplotlib doesn't support direct conversion to grayscale, but you can save a color pdf and then convert it to grayscale with ghostscript:
gs -sOutputFile=gray.pdf -sDEVICE=pdfwrite -sColorConversionStrategy=Gray -dProcessColorModel=/DeviceGray -dNOPAUSE -dBATCH -dAutoRotatePages=/None color.pdf

- 14,867
- 5
- 37
- 64

- 2,584
- 2
- 19
- 20
-
why not just use the grayscale style sheet? http://matplotlib.org/examples/style_sheets/plot_grayscale.html – Paul H Apr 25 '15 at 05:16
-
That doesn't actually convert a color plot to grayscale. It just makes some elements gray by default. I have plots that I want to export as both color for a web page and convert to gray for printing. – Ian Goodfellow Apr 25 '15 at 05:48
-
You can use the style sheets within a context manager. Wrap your calls to a non-data processing plotting function with those. – Paul H Apr 25 '15 at 05:58
-
I don't understand this suggestion. Why does a context manager help? How is data processing relevant? – Ian Goodfellow Apr 25 '15 at 06:25
-
if you plotting function does a lot of data processing, making multiple calls to it will slow down the flow of your program. But pre-processing the data and then calling a simpler plotting function within a colorful then grayscale style context manager should be pretty manageable. – Paul H Apr 25 '15 at 14:29
And to add to Mu Mind's solution
If for whatever reason you want to avoid writing it to a file you can use StringIO like a file:
import Image
import pylab
from StringIO import StringIO
pylab.plot(range(10),[x**2 for x in range(10)])
IO = StringIO()
pylab.savefig(IO,format='png')
IO.seek(0)
#this, I stole from Mu Mind solution
Image.open(IO).convert('L').show()

- 139
- 1
- 2
-
Like the other answers, this answer is not very satisfactory because it rasterizes the plot. – Ian Goodfellow Apr 25 '15 at 05:12
Developed from Ian Goodfellow's answer, here is a python script that generates and runs a ghostscript command that converts a PDF into grayscale. It is preferable to the answers that rasterise to PNG as it retains the vector representation of the plot.
import subprocess
import sys
def pdf_to_grayscale(input_pdf, output_pdf):
try:
# Ghostscript command to convert PDF to grayscale
ghostscript_cmd = [
"gs",
"-sDEVICE=pdfwrite",
"-sColorConversionStrategy=Gray",
"-sProcessColorModel=DeviceGray",
"-dCompatibilityLevel=1.4",
"-dNOPAUSE",
"-dQUIET",
"-dBATCH",
f"-sOutputFile={output_pdf}",
input_pdf
]
# Execute Ghostscript command using subprocess
subprocess.run(ghostscript_cmd, check=True)
print("PDF converted to grayscale successfully.")
except subprocess.CalledProcessError:
print("Error occurred during PDF conversion to grayscale.")
if __name__ == "__main__":
assert len(sys.argv) == 3, "Two args: input pdf and output pdf"
pdf_to_grayscale(sys.argv[1], sys.argv[2])
Save it as to_gray.py and run it like this:
python to_gray.py test.pdf gray.pdf

- 958
- 8
- 11