Matplotlib stores .svg different than what is show on screen - python

Here is an example. The next is what get's stored as a .png and this is how it displays on the screen and it is correct
and the next is the .svg which is using interpolation for the heatmap
They are both stored using the next line of code respectively
plt.savefig(filename,format='png')
plt.savefig(filename,format='svg')
And the next is the code that generates the actual plot
def heatmapText(data,xlabels=[],ylabels=[],cmap='jet',fontsize=7):
'''
Heatmap with text on each of the cells
'''
plt.imshow(data,interpolation='none',cmap=cmap)
for y in range(data.shape[0]):
for x in range(data.shape[1]):
plt.text(x , y , '%.1f' % data[y, x],
horizontalalignment='center',
verticalalignment='center',
fontsize=fontsize
)
plt.gca()
if ylabels!=[]:
plt.yticks(range(ylabels.size),ylabels.tolist(),rotation='horizontal')
if xlabels!=[]:
plt.xticks(range(xlabels.size),xlabels.tolist(),rotation='vertical')
For both plots I used exactly the same function but stored it in different formats. Last, in screen appears correctly (like in the .png).
Any ideas on how to have the .svg to store the file correctly?

Based on http://matplotlib.org/examples/images_contours_and_fields/interpolation_none_vs_nearest.html
What does matplotlib `imshow(interpolation='nearest')` do?
and
matplotlib shows different figure than saves from the show() window
I'm going to recommend trying this with interpolation=nearest
The following code gives me identical displayed and saved as svg plots:
import matplotlib.pyplot as plt
import numpy as np
A = np.random.rand(5, 5)
plt.figure(1)
plt.imshow(A, interpolation='nearest')
plt.savefig('fig',format='svg')
plt.show()

Related

Rightmost part of axes disappears in Matplotlib PostScript figure

I'm creating a Matplotlib figure, which I need to be quite wide (174 mm) and in .eps format. I also need it to be created with LaTeX for consistency with other figures. The problem is that the rightmost parts of the axes do not appear in the output figure, and the legend's box and handles also disappear.
The problem appears only if the figure if very wide, when I use LaTeX to produce it, and when I save it in .eps. The figure is as expected if it is thinner, if I save it in .pdf or .png, or if I just replace plt.savefig(...) with plt.show() and use Matplotlib's default viewer.
To be clearer, consider the following code.
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
x = np.linspace(-1, 1, 100)
y = np.exp(x)
mpl.rcParams['text.usetex'] = True
mm = 1/25.4
fig = plt.figure(figsize=(174*mm, 44*mm))
plt.plot(x, y, label='exponential')
plt.legend(loc='lower right')
plt.tight_layout()
plt.savefig('test.eps')
This outputs the following figure, where the legend handle and the rightmost part of the axes do not appear.
If it can help, the .eps file output by the above code is available here.

Why does the siunitx LaTeX package add a vertical offset to some text elements in matplotlib figures?

I'm using LaTeX to render text in my matplotlib figures. When I add the package siunitx to my LaTeX preamble, some text elements are no longer vertically aligned correctly.
I've only encountered this problem recently: figures which were previously rendered correctly are now broken. It affects multiple python environments, so I believe it may be due to a recent version of siunitx?
Here is my minimum working example:
import numpy as np
import matplotlib.pyplot as plt
# Test data
x = np.linspace(0, 2*np.pi, 64)
y = np.sin(x)
# Use latex for text
plt.rcdefaults()
plt.rcParams['text.usetex'] = True
# Correctly behaving text
fig0, ax0 = plt.subplots()
ax0.plot(x, y, label='some string')
ax0.legend()
fig0.tight_layout()
fig0.savefig('without_siunitx.png')
plt.show()
# Use siunitx
plt.rcParams['text.latex.preamble'] = '\n'.join([
r'\usepackage{siunitx}',
])
# Now some text has incorrect y position
fig1, ax1 = plt.subplots()
ax1.plot(x, y, label='some string')
ax1.legend()
fig1.tight_layout()
fig1.savefig('with_siunitx.png')
plt.show()
For the minimum working example I'm using python 3.8.12, matplotlib 3.3.2 and siunitx 3.0.32 (installed via MiKTeX) on Windows 10.
The two png images generated are linked below:
You can see that the legend text and the y-axis tick labels are misaligned after using siunitx.
I'll be really grateful to anybody who can help me solve this issue, as it affects most of the figures for my thesis. Thanks very much!
If it worked correctly before, you can rollback to version 2 of siunitx with the following syntax:
\usepackage{siunitx}[=v2]

pyplot order of magnitude fontsize modification when using scientific ticks python [duplicate]

I am attempting to plot differential cross-sections of nuclear decays and so the magnitudes of the y-axis are around 10^-38 (m^2) pylab as default plots the axis as 0.0,0.2,0.4... etc and has a '1e-38' at the top of the y-axis.
I need to increase the font size of just this little bit, I have tried adjusting the label size
py.tick_params(axis='y', labelsize=20)
but this only adjusts the labels 0.0,0.2,0.4....
Many thanks for all help
You can access the text object using the ax.yaxis.get_offset_text().
import numpy as np
import matplotlib.pyplot as plt
# Generate some data
N = 10
x = np.arange(N)
y = np.array([i*(10**-38) for i in x])
fig, ax = plt.subplots()
# Plot the data
ax.plot(x,y)
# Get the text object
text = ax.yaxis.get_offset_text()
# Set the size.
text.set_size(30) # Overkill!
plt.show()
I've written the solution above using matplotlib.pyplot rather than pylab though if you absolutely have to use pylab then it can be changed (though I'd recommend you use matplotlib.pyplot in any case as they are pretty much identical you can just do a lot more with pyplot easier).
Edit
If you were to use pylab then the code would be:
pylab.plot(x, y)
ax = pylab.gca() # Gets the current axis object
text = ax.yaxis.get_offset_text() # Get the text object
text.set_size(30) # # Set the size.
pylab.show()
An example plot with an (overkill!) offset text.

an empty pdf created when a figure with subplots was saved as pdf from matpolotlib in python3.2

I need to save a figure (with 8 subplots on it) generated from matpolotlib in python3.2. I need to same save the figure on one pdf page.
Each subplot nmay have 240k to 400k data points.
My code:
from matplotlib.backends.backend_pdf import PdfPages
plt.show(block=False)
pp = PdfPages('multipage.pdf')
fig = plt.figure()
fig.savefig('figure_1.pdf', dpi = fig.dpi)
pp.close()
But, only an empty pdf file was created and no figures on it.
Any help would be appreciated.
UPDATE
This is a demo code:
def plot_pdf_example():
fig = plt.figure()
# I create subplots here
#x = np.random.rand(50)
#y = np.random.rand(50)
plt.plot(x, y, '.')
fig.savefig('figure_b.pdf')
if __name__ == '__main__':
r = plot_pdf_example()
# the return value of r is not 0 for my case
print("donne")
If I used plt.show() to get the figure in pop-up window, there are some titles and legends overlaps between subplots. How to adjuse the pop-up figure so that I can get all subplots without any overlaps and also keep all subplots as square. keeping them as square uis very important for me.
Your code does save the single and empty figure fig to the file figure_1.pdf, without making any use of PdfPages. It is also normal that the pdf file is empty, since you are not plotting anything in fig. Below is a MWE that shows how to save only one figure to a single pdf file. I've removed all the stuff with PdfPages that was not necessary.
Update (2015-07-27): When there is some problem saving a fig to pdf because there is too much data to render or in the cases of complex and detailed colormaps, it may be a good idea to rasterize some of the elements of the plot that are problematic. The MWE below has been updated to reflect that.
import matplotlib.pyplot as plt
import numpy as np
import time
plt.close("all")
fig = plt.figure()
N = 400000
x = np.random.rand(400000)
y = np.random.rand(400000)
colors = np.random.rand(400000)
area = 3
ax0 = fig.add_axes([0.1, 0.1, 0.85, 0.85])
scater = ax0.scatter(x, y, s=area, c=colors)
scater.set_rasterized(True)
plt.show(block=False)
ts = time.clock()
fig.savefig('figure_1.pdf')
te = time.clock()
print('t = %f sec' % (te-ts))
On my machine, the code above took about 6.5 sec to save the pdf when rasterized was set to true for scater, while it took 61.5 sec when it was set to False.
By default, when saving in pdf, the figure is saved in vectorial format. This means that every point is saved as a set of parameters (colors, size, position, etc). This is a lot of information to store when there is a lot of data (8 * 400k in the case of the OP). When converting some elements of the plot to a raster format, the number of points plotted does not matter because the image is saved as a fixed number of pixels instead (like in a png). By only rasterizing the scater, the rest of the figure (axes, labels, text, legend, etc.) still remains in vectorial format. So overall, the loss in quality is not that much noticeable for some type of graph (like colormaps or scatter plots), but it will be for graphs with sharp lines.

matplotlib imshow how to plot points instead of image?

Here is the code:
plots=imshow(Z,extent=extent,origin,cmap=cmap,aspect='auto',vmin=vmin,vmax=vmax)
plots.plot(Response,component,vrange)
It plots an image based on data list Z, how can I let it print data points instead of an image?
Looks like needs to change to scatter(x, y,...) to plot data points, how difficult it is to change array Z to x, y?
As #jdj081 said, you want to produce a scatter plot.
import os.path
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
# get an image from the sample data directory
fname = os.path.join(matplotlib.get_data_path(), 'sample_data', 'lena.png')
im = plt.imread(fname)
# Reduce the data by a factor of 4 (so that we can see the points)
im = im[::4, ::4]
# generate coordinates for the image. Note that the image is "top down", so the y coordinate goes from high to low.
ys, xs = np.mgrid[im.shape[0]:0:-1, 0:im.shape[1]]
# Scatter plots take 1d arrays of xs and ys, and the colour takes a 2d array,
# with the second dimension being RGB
plt.scatter(xs.flatten(), ys.flatten(), s=4,
c=im.flatten().reshape(-1, 3), edgecolor='face')
plt.show()
You didn't provide much information to go on, but it sounds like you really want to create a scatter plot.
There are many options here depending on what you are plotting and what you want to see, but I have found the following helpful:
Fixing color in scatter plots in matplotlib
import pylab
pylab.figure(1)
pylab.plot([1,2,3,4],[1,7,3,5]) # draw on figure one
pylab.show() # show figure on screen

Categories

Resources