Rightmost part of axes disappears in Matplotlib PostScript figure - python

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.

Related

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.

Changing the default seaborn heatmap plots

I have exported a large Matrix from Matlab to a data.dat file, which is tab delimited. I am importing this data into a iPython script to use seaborn to create a heatmap of the matrix using the following MWE:
import numpy as np
import seaborn as sns
import matplotlib.pylab as plt
uniform_data = np.loadtxt("data.dat", delimiter="\t")
ax = sns.heatmap(uniform_data, linewidth=0.0)
plt.show()
This code runs fine and outputs a correct heatmap, generating the following output:
How can I change the style of this output? Specifically, I would like to change the colour scheme and also have the fonts in LaTeX form. This is since I would like to export this output as a .pdf file and import into a LaTeX document.
You can control the color scheme with the cmap key of sns.heatmap(). See here for what color maps are available.
Generally to make all fonts in a plot look like latex fonts you can do
sns.set(rc={'text.usetex': True})
What it does is adding a $ around each text object in the plot to allow the underlying tex environment to "tex-ify" it. This works fine for the colorbar but, as you can see here, there seems to be a (to me still unresolved bug) making it not working for axes ticklabels. As a workaround you can manually add $ around all tick labels to allow the tex interpreter recognize it as tex again à la
# Collecting all xtick locations and labels and wrapping the labels in two '$'
plt.xticks(plt.xticks()[0], ['$' + label._text + '$' for label in plt.xticks()[1]])
So for demonstrating your example
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
# Use tex for all labels globally in the plot
sns.set(rc={'text.usetex': True})
uniform_data = np.random.rand(30, 30)
# Adjust colormap with the cmap key (here 'cubehelix')
ax = sns.heatmap(uniform_data, linewidth=0.0, cmap='cubehelix')
# workaround wrap '$' around tick labels for x and y axis
# commenting the following two lines makes only the colorbar in latex font
plt.xticks(plt.xticks()[0], ['$' + label._text + '$' for label in plt.xticks()[1]])
plt.yticks(plt.yticks()[0], ['$' + label._text + '$' for label in plt.yticks()[1]])
plt.show()
leads to

Matplotlib stores .svg different than what is show on screen

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()

Seaborn plot saved to eps does not show grid

I have played around a bit and can't get saving a plot rendered with seaborn correctly. When using plt.savefig I lose the grid. However, using plt.show and then saving the figure manually works. This happens with eps and png as well. I need to render large amount of plots so this is a problem.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style = 'darkgrid', font_scale=2)
t = np.arange(100)
y = np.random.rand(len(t))
plt.plot(t,y)
plt.title('Test title')
plt.xlabel('Test xlab')
plt.ylabel('Tex $y_i = w_i x_i$')
plt.tight_layout()
#plt.show()
plt.savefig('test_plot.eps', format='eps')
Automatic save
Manual save
The solution was I had "savefig.transparent : True" in my matplotlibrc that I for some reason needed before. Changing this to False solved the problem in my case.

Plotting dot plot with enough space of ticks in Python/matplotlib?

In the following code snippet:
import numpy as np
import pandas as pd
import pandas.rpy.common as com
import matplotlib.pyplot as plt
mtcars = com.load_data("mtcars")
df = mtcars.groupby(["cyl"]).apply(lambda x: pd.Series([x["cyl"].count(), np.mean(x["wt"])], index=["n", "wt"])).reset_index()
plt.plot(df["n"], range(len(df["cyl"])), "o")
plt.yticks(range(len(df["cyl"])), df["cyl"])
plt.show()
This code outputs the dot plot graph, but the result looks quite awful, since both the xticks and yticks don't have enough space, that it's quite difficult to notice both 4 and 8 of the cyl variable output its values in the graph.
So how can I plot it with enough space in advance, much like you can do it without any hassles in R/ggplot2?
For your information, both of this code and this doesn't work in my case. Anyone knows the reason? And do I have to bother to creating such subplots in the first place? Is it impossible to automatically adjust the ticks with response to the input values?
I can't quite tell what you're asking...
Are you asking why the ticks aren't automatically positioned or are you asking how to add "padding" around the inside edges of the plot?
If it's the former, it's because you've manually set the tick locations with yticks. This overrides the automatic tick locator.
If it's the latter, use ax.margins(some_percentage) (where some_percentage is between 0 and 1, e.g. 0.05 is 5%) to add "padding" to the data limits before they're autoscaled.
As an example of the latter, by default, the data limits can be autoscaled such that a point can lie on the boundaries of the plot. E.g.:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(10), 'ro')
plt.show()
If you want to avoid this, use ax.margins (or equivalently, plt.margins) to specify a percentage of padding to be added to the data limits before autoscaling takes place.
E.g.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(range(10), 'ro')
ax.margins(0.04) # 4% padding, similar to R.
plt.show()

Categories

Resources