Pixelated fonts when plot is saved as jpeg - python

When I save a matplotlib figure as a jpeg the tick fonts are pixelated. I'm not sure what is going on or if there is any hack to fix this. Does anyone have any insight?
%matplotlib nbagg
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(-1.2,1.2,1000,endpoint=True)
y = np.copy(x)
x,y = np.meshgrid(x,y)
z = -x**2 + y**2 - y**3
fig = plt.figure()
ax = fig.add_subplot(111)
CS = plt.contour(x,y,z, [0,-0.1,0.1], colors=['black','blue', 'gray'])
plt.clabel(CS, fontsize=14, inline=1, fmt='%1.1f', manual=[(-0.15,0), (-0.4,0), (0.25,0.5)])
plt.savefig('plot.png', format='png')
plt.savefig('plot.jpg', format='jpg')
plt.savefig('plot.tiff', format='tiff')
Here is plot.png:
Here is plot.jpg:
Here is the plot.tiff:
I believe this is related to a previous question I had: Anti-aliased Fonts in Animations

As noted above, this situation appears is dependent on the backend used. You can avoid the issue by using:
import matplotlib
matplotlib.use('webagg')
as opposed to:
%matplotlib nbagg
I believe the issue has to do with PIL trying to save a jpeg of a figure with transparency. If you insist on using nbagg, it appears that if you set:
matplotlib.rcParams['nbagg.transparent'] = False
Your jpeg image fonts won't be pixelated and will look nearly identical to the png and tiff files shown in the question. Unfortunately using the rcParams:
matplotlib.rcParams['savefig.transparent'] = False
is not sufficient. It appears that the 'savefig.transparent' rcParam will control the transparency of the plot inside the figure and the 'nbagg.transparent' will control the transparency outside of the figure (ie: axis, ticks, titles, etc..). There is probably an easy work by ensuring the backend forces transparency = False for when saving to file formats that don't support transparency.
Some of the other backends may not support transparency which is why it appears to fix the problem when you change backends.
I will report this to github as a bug.

Related

Save an image (only content, without axes or anything else) to a file using Matloptlib

I'd like to obtain a spectrogram out of a wav file and then save it to a png, but I need just the content of the image (not axes or anything else). I came across these questions
Matplotlib plots: removing axis, legends and white spaces
scipy: savefig without frames, axes, only content
I've also read the Matplotlib documentation but it seems useless and so either answers to questions above are outdated or I'm doing something wrong because simple
plt.savefig('out.png', bbox_inches='tight', pad_inches=0)
does not do what I want to achieve. Initially I tried to follow this guide but the code crashes. Then I tried this approach, but since it's outdated I modified it a little:
import matplotlib.pyplot as plt
from scipy.io import wavfile
import numpy as np
def graph_spectrogram(wav_file):
rate, data = wavfile.read(wav_file)
pxx, freqs, bins, im = plt.specgram(x=data, Fs=rate, noverlap=384, NFFT=512)
plt.axis('off')
plt.savefig('sp_xyz.png', bbox_inches='tight', dpi=300, frameon='false')
if __name__ == '__main__': # Main function
graph_spectrogram('...')
This is what I got:
Maybe it's not visible, but there's a white border around the content (from the biggest to the smallest): left, bottom, top, right. I want the same image but just the content without anything else. How can I achieve that? I use python 3.6 and Matplotlib 2.0.2.
I think you want subplots_adjust:
fig,ax = plt.subplots(1)
fig.subplots_adjust(left=0,right=1,bottom=0,top=1)
ax.axis('tight')
ax.axis('off')
In this case:
import matplotlib.pyplot as plt
from scipy.io import wavfile
import numpy as np
def graph_spectrogram(wav_file):
rate, data = wavfile.read(wav_file)
fig,ax = plt.subplots(1)
fig.subplots_adjust(left=0,right=1,bottom=0,top=1)
ax.axis('off')
pxx, freqs, bins, im = ax.specgram(x=data, Fs=rate, noverlap=384, NFFT=512)
ax.axis('off')
fig.savefig('sp_xyz.png', dpi=300, frameon='false')
if __name__ == '__main__': # Main function
graph_spectrogram('...')
May be helpful for someone who use librosa latest versions.
You can add transparent=True to the plt.savefig() function to set transparent background. But the problem is still x and y axis information are visible. Hens, you need to remove axis details using ax.set_axis_off()
You can remove right side color-bar by commenting out plt.colorbar()
plt.figure(figsize=(12, 4))
ax = plt.axes()
ax.set_axis_off()
plt.set_cmap('hot')
librosa.display.specshow(librosa.amplitude_to_db(S_full[:, idx], ref=np.max), y_axis='log', x_axis='time',sr=sr)
plt.colorbar()
plt.savefig(f'{args["output"]}/{name}_{i}.png', bbox_inches='tight', transparent=True, pad_inches=0.0 )
Please click images to check differences
When nothing is changed(Default)
When the axis informations are off Using ax.set_axis_off()
Here, this image doesn't have axis info but white background is there.
When enabling transparent using transparent= True
Here, this image doesn't have white background but axis info is there.
With axis info are off and enabling transparent
This image doesn't have either white background or axis info
You may not see the exact differences since images might be changed when uploading.

matplotlib place axes within figure box

This is my code (I am running it in a jupyter notebook on OS X )
% matplotlib inline
import matplotlib.pyplot as plt
fig = plt.figure()
fig.set_facecolor('gray')
ax = fig.add_axes([0.2, 0.2, 0.2, 0.2])
print fig.get_figwidth()
I was expecting to see a large gray figure box with a small white axes box in the bottom left hand corner. What I get is a small white axes box with a small gray box surrounding it.
I am obviously missing some setting or other. How do I get what I was expecting?
After some more experimentation and digging I found the answer in the matplotlib magic documentation referenced from here.
The ipython magics are enforcing bbox_inches='tight' by default. which causes the figure bbox to shrink to fit the axes.
The trick is to add the magic line
% config InlineBackend.print_figure_kwargs = {'bbox_inches':None}

Combining mayavi and matplotlib in the same figure

I will be making animations. In each frame I want to contain both a mayavi plot obtained with
mlab.pipeline.iso_surface(source, some other superfluous args)
and a matplotlib plot obtained using simply
pylab.plot(args)
I have scripts to do both separately, but have no idea how to go about combining them into one figure. I want the end product to be one script which contains the code from both the scripts that I currently have.
AFAIK, there is no direct way because the backends used are so different. It does not seem possible to add matplotlib axes to mayavi.figure or vice versa.
However, there is a "kind of a way" by using the the mlab.screenshot.
import mayavi.mlab as mlab
import matplotlib.pyplot as plt
# create and capture a mlab object
mlab.test_plot3d()
img = mlab.screenshot()
mlab.close()
# create a pyplot
fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.plot([0,1], [1,0], 'r')
# add the screen capture
ax2 = fig.add_subplot(122)
ax2.imshow(img)
ax2.set_axis_off()
This is not necessarily the nicest possible way of doing things, and you may bump into resolution problems, as well (check the size of the mayavi window). However, it gets the job done in most cases.
Adding to the answer by DrV which helped me a great deal, you can work with the mlab figure to set resolution before screenshot such as with batch plotting:
mfig = mlab.figure(size=(1024, 1024))
src = mlab.pipeline.scalar_field(field_3d_numpy_array)
mlab.pipeline.iso_surface(src)
iso_surface_plot = mlab.screenshot(figure=mfig, mode='rgba', antialiased=True)
mlab.clf(mfig)
mlab.close()
# Then later in a matplotlib fig:
plt.imshow(iso_surface_plot)

How to make savefig() save image for 'maximized' window instead of default size

I am using pylab in matplotlib to create a plot and save the plot to an image file. However, when I save the image using pylab.savefig( image_name ), I find that the SIZE image saved is the same as the image that is shown when I use pylab.show().
As it happens, I have a lot of data in the plot and when I am using pylab.show(), I have to maximize the window before I can see all of the plot correctly, and the xlabel tickers don't superimpose on each other.
Is there anyway that I can programmatically 'maximize' the window before saving the image to file? - at the moment, I am only getting the 'default' window size image, which results in the x axis labels being superimposed on one another.
There are two major options in matplotlib (pylab) to control the image size:
You can set the size of the resulting image in inches
You can define the DPI (dots per inch) for output file (basically, it is a resolution)
Normally, you would like to do both, because this way you will have full control over the resulting image size in pixels. For example, if you want to render exactly 800x600 image, you can use DPI=100, and set the size as 8 x 6 in inches:
import matplotlib.pyplot as plt
# plot whatever you need...
# now, before saving to file:
figure = plt.gcf() # get current figure
figure.set_size_inches(8, 6)
# when saving, specify the DPI
plt.savefig("myplot.png", dpi = 100)
One can use any DPI. In fact, you might want to play with various DPI and size values to get the result you like the most. Beware, however, that using very small DPI is not a good idea, because matplotlib may not find a good font to render legend and other text. For example, you cannot set the DPI=1, because there are no fonts with characters rendered with 1 pixel :)
From other comments I understood that other issue you have is proper text rendering. For this, you can also change the font size. For example, you may use 6 pixels per character, instead of 12 pixels per character used by default (effectively, making all text twice smaller).
import matplotlib
#...
matplotlib.rc('font', size=6)
Finally, some references to the original documentation:
http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.savefig, http://matplotlib.sourceforge.net/api/pyplot_api.html#matplotlib.pyplot.gcf, http://matplotlib.sourceforge.net/api/figure_api.html#matplotlib.figure.Figure.set_size_inches, http://matplotlib.sourceforge.net/users/customizing.html#dynamic-rc-settings
P.S. Sorry, I didn't use pylab, but as far as I'm aware, all the code above will work same way in pylab - just replace plt in my code with the pylab (or whatever name you assigned when importing pylab). Same for matplotlib - use pylab instead.
You set the size on initialization:
fig2 = matplotlib.pyplot.figure(figsize=(8.0, 5.0)) # in inches!
Edit:
If the problem is with x-axis ticks - You can set them "manually":
fig2.add_subplot(111).set_xticks(arange(1,3,0.5)) # You can actually compute the interval You need - and substitute here
And so on with other aspects of Your plot. You can configure it all. Here's an example:
from numpy import arange
import matplotlib
# import matplotlib as mpl
import matplotlib.pyplot
# import matplotlib.pyplot as plt
x1 = [1,2,3]
y1 = [4,5,6]
x2 = [1,2,3]
y2 = [5,5,5]
# initialization
fig2 = matplotlib.pyplot.figure(figsize=(8.0, 5.0)) # The size of the figure is specified as (width, height) in inches
# lines:
l1 = fig2.add_subplot(111).plot(x1,y1, label=r"Text $formula$", "r-", lw=2)
l2 = fig2.add_subplot(111).plot(x2,y2, label=r"$legend2$" ,"g--", lw=3)
fig2.add_subplot(111).legend((l1,l2), loc=0)
# axes:
fig2.add_subplot(111).grid(True)
fig2.add_subplot(111).set_xticks(arange(1,3,0.5))
fig2.add_subplot(111).axis(xmin=3, xmax=6) # there're also ymin, ymax
fig2.add_subplot(111).axis([0,4,3,6]) # all!
fig2.add_subplot(111).set_xlim([0,4])
fig2.add_subplot(111).set_ylim([3,6])
# labels:
fig2.add_subplot(111).set_xlabel(r"x $2^2$", fontsize=15, color = "r")
fig2.add_subplot(111).set_ylabel(r"y $2^2$")
fig2.add_subplot(111).set_title(r"title $6^4$")
fig2.add_subplot(111).text(2, 5.5, r"an equation: $E=mc^2$", fontsize=15, color = "y")
fig2.add_subplot(111).text(3, 2, unicode('f\374r', 'latin-1'))
# saving:
fig2.savefig("fig2.png")
So - what exactly do You want to be configured?
I think you need to specify a different resolution when saving the figure to a file:
fig = matplotlib.pyplot.figure()
# generate your plot
fig.savefig("myfig.png",dpi=600)
Specifying a large dpi value should have a similar effect as maximizing the GUI window.
Check this:
How to maximize a plt.show() window using Python
The command is different depending on which backend you use. I find that this is the best way to make sure the saved pictures have the same scaling as what I view on my screen.
Since I use Canopy with the QT backend:
pylab.get_current_fig_manager().window.showMaximized()
I then call savefig() as required with an increased DPI per silvado's answer.
You can look in a saved figure it's size, like 1920x983 px (size when i saved a maximized window), then I set the dpi as 100 and the size as 19.20x9.83 and it worked fine. Saved exactly equal to the maximized figure.
import numpy as np
import matplotlib.pyplot as plt
x, y = np.genfromtxt('fname.dat', usecols=(0,1), unpack=True)
a = plt.figure(figsize=(19.20,9.83))
a = plt.plot(x, y, '-')
plt.savefig('file.png',format='png',dpi=100)
I had this exact problem and this worked:
plt.savefig(output_dir + '/xyz.png', bbox_inches='tight')
Here is the documentation:
[https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.savefig.html][1]
I did the same search time ago, it seems that he exact solution depends on the backend.
I have read a bunch of sources and probably the most useful was the answer by Pythonio here How to maximize a plt.show() window using Python
I adjusted the code and ended up with the function below.
It works decently for me on windows, I mostly use Qt, where I use it quite often, while it is minimally tested with other backends.
Basically it consists in identifying the backend and calling the appropriate function. Note that I added a pause afterwards because I was having issues with some windows getting maximized and others not, it seems this solved for me.
def maximize(backend=None,fullscreen=False):
"""Maximize window independently on backend.
Fullscreen sets fullscreen mode, that is same as maximized, but it doesn't have title bar (press key F to toggle full screen mode)."""
if backend is None:
backend=matplotlib.get_backend()
mng = plt.get_current_fig_manager()
if fullscreen:
mng.full_screen_toggle()
else:
if backend == 'wxAgg':
mng.frame.Maximize(True)
elif backend == 'Qt4Agg' or backend == 'Qt5Agg':
mng.window.showMaximized()
elif backend == 'TkAgg':
mng.window.state('zoomed') #works fine on Windows!
else:
print ("Unrecognized backend: ",backend) #not tested on different backends (only Qt)
plt.show()
plt.pause(0.1) #this is needed to make sure following processing gets applied (e.g. tight_layout)
Old question but to anyone in need, Here's what had worked for me a while ago:
You have to have a general idea of the aspect ratio that would maximise your plot fitting. This will take some trial and error to get right, but generally 1920x1080 would be a good aspect ratio for most modern monitors. I would still suggest playing around with the aspect ratios to best suit your plot.
Steps:
Before initiating the plot, set the size for the plot, use:
plt.figure(19.20, 10.80)
**notice how I have multiplied my aspect ratio by '0.01'.
At the end of the plot, when using plt.savefig, save it as follows:
plt.savefig('name.jpg', bbox_inches='tight', dpi=1000)
If I understand correctly what you want to do, you can create your figure and set the size of the window. Afterwards, you can save your graph with the matplotlib toolbox button. Here an example:
from pylab import get_current_fig_manager,show,plt,imshow
plt.Figure()
thismanager = get_current_fig_manager()
thismanager.window.wm_geometry("500x500+0+0")
#in this case 500 is the size (in pixel) of the figure window. In your case you want to maximise to the size of your screen or whatever
imshow(your_data)
show()

Render equation to .png file using Python

I want to render equations to PNG files and embed them in the HTML documentation of my library. I am already using pylab (matplotlib) in other projects.
I have not found any clues in http://matplotlib.sourceforge.net/users/usetex.html and http://matplotlib.sourceforge.net/users/mathtext.html
When I do
plt.title(r'$\alpha > \beta$')
plt.show()
I get a titled empty figure with axes.
Update:
After doing some research I found, that the easiest way of rendering LaTeX to png is using mathext ( http://code.google.com/p/mathtex/ ).
Suprisingly, I had all requiered libraries to build it from source.
Anyway, thanks to everyone for replies.
Update 2:
I did some testing of mathtex and found it does not support matrices (\begin{pmatrix}) and some other things I need.
So, I'm going to install LaTex (MikTeX).
Update 3:
I installed proTeXt. It's huge, but easy-to-use and fast. IMHO, for now it's the only way of rendering equations.
This worked for me:
# https://gist.github.com/tonyseek/95c90638cf43a87e723b
from cStringIO import StringIO
import matplotlib.pyplot as plt
def render_latex(formula, fontsize=12, dpi=300, format_='svg'):
"""Renders LaTeX formula into image.
"""
fig = plt.figure(figsize=(0.01, 0.01))
fig.text(0, 0, u'${}$'.format(formula), fontsize=fontsize)
buffer_ = StringIO()
fig.savefig(buffer_, dpi=dpi, transparent=True, format=format_, bbox_inches='tight', pad_inches=0.0)
plt.close(fig)
return buffer_.getvalue()
if __name__ == '__main__':
image_bytes = render_latex(
r'\theta=\theta+C(1+\theta-\beta)\sqrt{1-\theta}succ_mul',
fontsize=10, dpi=200, format_='png')
with open('formula.png', 'wb') as image_file:
image_file.write(image_bytes)
(source) If you are using IPython interpreter, it renders all single matplotlib step into a figure window by default.
Thus, plt.title(r'$\alpha > \beta$') in IPython would immediately create a figure even before calling .show(). On the other hand, using terminal/cmd/IDLE won't.
plt.show() would create a figure window whether you're using IPython or not, you want to change that line to:
plt.savefig('filename.png')
Edit:
Okay, I misunderstood your question. As #Li-aung Yip said, you may want to use Sympy for pure equation image. We can still do some trick in matplotlib to achieve what you want though (you may need to readjust or resize accordingly):
import matplotlib.pyplot as plt
#add text
plt.text(0.01, 0.8, r'$\alpha > \beta$',fontsize=50)
#hide axes
fig = plt.gca()
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.draw() #or savefig
This is done by hiding axes ticks and adding text inside the plot figure.
But...this doesn't really "not drawing" a figure :\ Though you can post-process such as cropping the image with PIL.
It sounds like you want to render LaTeX equations to images. See linked question for a variety of ways of doing this with minimal dependencies. (Some even involve matplotlib, I believe.)
Alternately, if you can install LaTeX or rely on LaTeX being installed, you can just use LaTeX itself to render the equation to postscript and thence into an image format.
I fiddled with #warvariuc's answer for a long time in Python 3 and came up with the following solution. It is very similar but has a couple of key differences. First, StringIO and cStringIO are not modules in Py3. Secondly, the equivalent class io.StringIO does not work with at least some versions of MatPlotLib. See this thread: http://matplotlib.1069221.n5.nabble.com/savefig-and-StringIO-error-on-Python3-td44241.html. Basically, the image is binary, so you need to use io.BytesIO. The getvalue() method works just as with StringIO. I took the liberty of using savefig to do the file opening, since it can decide whether you passed in a file name or not for itself:
from io import BytesIO
import matplotlib.pyplot as plt
def renderLatex(formula, fontsize=12, dpi=300, format='svg', file=None):
"""Renders LaTeX formula into image or prints to file.
"""
fig = plt.figure(figsize=(0.01, 0.01))
fig.text(0, 0, u'${}$'.format(formula), fontsize=fontsize)
output = BytesIO() if file is None else file
with warnings.catch_warnings():
warnings.filterwarnings('ignore', category=MathTextWarning)
fig.savefig(output, dpi=dpi, transparent=True, format=format,
bbox_inches='tight', pad_inches=0.0, frameon=False)
plt.close(fig)
if file is None:
output.seek(0)
return output
The warning was something that I am pretty sure is related to the figure size. You can remove the enclosing with entirely if you would like. The reason for the seek is to make the "file" readable (best explained here: https://stackoverflow.com/a/8598881/2988730).

Categories

Resources