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
Related
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.
By default, Matplotlib "clips" or "truncates" circles (or other symbols) displayed as hatch overlay, as illustrated in the example figure created with this code.
import numpy as np
from matplotlib import pyplot as plt
n = 20
sig = np.ma.masked_greater(np.random.rand(n,n), 0.25)
f, ax1 = plt.subplots(1,1, figsize=(4,4))
ax1.pcolor(sig, hatch="o", alpha=0)
I understand why this is so, but in some of my applications, I would like to solely display "untruncated" symbols. In the below example, I tried ax1.pcolor(sig, hatch="o", alpha=0, clip_on=False), but it has no effect.
How is this possible?
And: I there any option to control that "truncated" symbols are either (a) not shown at all or (b) as complete symbols?
Using Jupyter 4.4.0 and Python 3.6.5 (Anaconda), I am generating a heatmap as follows:
import seaborn as sns
import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
# generate a 9x4 matrix of random values and long labels
x,y = 9,4
plt.figure(figsize=(x,y))
scores = np.random.random((y, x))
cols = ['looooooooooong_label_x_%d' % i for i in range(x)]
rows = ['looooooooooong_label_y_%d' % i for i in reversed(range(y))]
# generate a heatmap using seaborn with rotated labels
ax = sns.heatmap(pd.DataFrame(scores, columns=cols, index=rows), annot=True, square=True, cbar=False, cmap='YlGnBu', xticklabels=True, yticklabels=True)
ax.set_yticklabels(ax.get_yticklabels(), rotation=0, fontsize=8)
ax.set_xticklabels(ax.get_xticklabels(), rotation=45, fontsize=8, rotation_mode='anchor', ha='right')
In the notebook, Jupyter automatically renders this image as shown:
This looks exactly as I want it to. However, when I take the next step and save the plot to file with:
ax.figure.savefig('hmx.png')
This file appears as:
Differences appear to be:
The saved image appears to be shifted down and to the left, cutting off the labels;
The Jupyter-rendered PNG has a transparent background, and the saved image does not (it has a white background).
I would like to know how to save the image generated by Jupyter to file, or better yet, what I am doing wrong when I try to save the PNG myself.
Fixed!
ax.figure.savefig('hmx.png', transparent=True, bbox_inches='tight')
The output now matches what Jupyter generated: transparent, and correctly aligned without any labels cut off:
I would like to change the fontweight of part of some text I give to matplotlib's text command on a plot using matplotlib. For example, I would like the first word to be bold. Also, I would like to change the font weight and font to Times New Roman without affecting the rest of the labels, i.e. x-axis and y-axis labels.
Browsing the stack exchange, I came across the rc('text', usetex=True) command. When I use this, these changes affect the entire plot (i.e., the x-axis and y-axis labels as well). I would just like to format the text given to matplotlib's text command. Is there a way to do this?
Here's an example:
import numpy as np
import matplotlib.pyplot as plt
randomNumber = []
for index in range(0, 1000):
np.random.seed()
randomNumber.append(np.random.normal(0, 1, 1)[0])
plt.figure()
ax = plt.gca()
ax.hist(randomNumber, 12)
#plt.figure()
#plt.plot()
plt.rc('text', usetex=True)
ax.text(-2, 150, '\\textbf{test} testing', fontsize=16, fontname='Times New Roman')
Using Matplotlib I'd like to remove the grid lines inside the plot, while keeping the frame (i.e. the axes lines). I've tried the code below and other options as well, but I can't get it to work. How do I simply keep the frame while removing the grid lines?
I'm doing this to reproduce a ggplot2 plot in matplotlib. I've created a MWE below. Be aware that you need a relatively new version of matplotlib to use the ggplot2 style.
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import pylab as P
import numpy as np
if __name__ == '__main__':
values = np.random.uniform(size=20)
plt.style.use('ggplot')
fig = plt.figure()
_, ax1 = P.subplots()
weights = np.ones_like(values)/len(values)
plt.hist(values, bins=20, weights=weights)
ax1.set_xlabel('Value')
ax1.set_ylabel('Probability')
ax1.grid(b=False)
#ax1.yaxis.grid(False)
#ax1.xaxis.grid(False)
ax1.set_axis_bgcolor('white')
ax1.set_xlim([0,1])
P.savefig('hist.pdf', bbox_inches='tight')
OK, I think this is what you are asking (but correct me if I misunderstood):
You need to change the colour of the spines. You need to do this for each spine individually, using the set_color method:
for spine in ['left','right','top','bottom']:
ax1.spines[spine].set_color('k')
You can see this example and this example for more about using spines.
However, if you have removed the grey background and the grid lines, and added the spines, this is not really in the ggplot style any more; is that really the style you want to use?
EDIT
To make the edge of the histogram bars touch the frame, you need to either:
Change your binning, so the bin edges go to 0 and 1
n,bins,patches = plt.hist(values, bins=np.linspace(0,1,21), weights=weights)
# Check, by printing bins:
print bins[0], bins[-1]
# 0.0, 1.0
If you really want to keep the bins to go between values.min() and values.max(), you would need to change your plot limits to no longer be 0 and 1:
n,bins,patches = plt.hist(values, bins=20, weights=weights)
ax.set_xlim(bins[0],bins[-1])