I'm plotting a bar graph without axes. I'd like to only show bars with non-zero values. If it is zero, I want no bar at all. Currently it will show a tiny line at the zero axis, I want that to disappear. How can I do that?
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
data = (0, 1890,865, 236, 6, 1, 2, 0 , 0, 0, 0 ,0 ,0 ,0, 0, 0)
ind = range(len(data))
width = 0.9 # the width of the bars: can also be len(x) sequence
p1 = plt.bar(ind, data, width)
plt.xlabel('Duration 2^x')
plt.ylabel('Count')
plt.title('DBFSwrite')
plt.axis([0, len(data), -1, max(data)])
ax = plt.gca()
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
plt.savefig('myfig')
See the very thin lines at x=0 and x=7-16? I'd like to eliminate those.
You can make use of numpy's arrays, and create a mask which you can use to filter out the indices where data has value 0.
import numpy as np
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
data = np.array([0, 1890,865, 236, 6, 1, 2, 0 , 0, 0, 0 ,0 ,0 ,0, 0, 0])
ind = np.arange(len(data))
width = 0.9 # the width of the bars: can also be len(x) sequence
mask = data.nonzero()
p1 = plt.bar(ind[mask], data[mask], width)
plt.xlabel('Duration 2^x')
plt.ylabel('Count')
plt.title('DBFSwrite')
plt.axis([0, len(data), -1, max(data)])
ax = plt.gca()
ax.spines['right'].set_visible(False)
ax.spines['top'].set_visible(False)
ax.spines['left'].set_visible(False)
ax.spines['bottom'].set_visible(False)
plt.savefig('myfig')
Related
I am new to python programming. I was trying to make two subplots using matplotlib containing a line plot (panel-a) and 2-D color plot using imshow() (panel-b). I want the colorbar to be shown on the right side with same size as the color plot and it should not be within the subplot box limit.
`
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime as dt
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Panel (a)
x1 = np.linspace(2, -2, 5)
y1 = np.linspace(-2, 2, 5)
# Panel (b)
N = 10
arr = np.random.random((N, N))
x_lims = list(map(dt.datetime.fromtimestamp, [982376726, 982377321]))
x_lims = mdates.date2num(x_lims)
y_lims = [0, 40]
fig, ax = plt.subplots(2, 1, figsize=(14, 10))
ax[0].plot(x1, y1)
ax[0].set_ylim(-2, 2)
ax[0].set_xlim(2, -2)
ax[0].set_xticks([2, 1, 0, -1, -2])
ax[0].set_yticks([-2, -1, 0, 1, 2])
im = ax[1].imshow(arr, extent=[x_lims[0], x_lims[1], y_lims[0],
y_lims[1]],
aspect='auto')
divider = make_axes_locatable(ax[1])
cax = divider.append_axes("right", size="5%", pad=0.05)
plt.colorbar(im, cax=cax, label="diff. en. flux")
ax[1].xaxis_date()
date_format = mdates.DateFormatter('%H:%M:%S')
ax[1].xaxis.set_major_formatter(date_format)
I have a dataframe and I want to plot the seaborn heatmap:
import seaborn as sns
res = sns.heatmap(df, cmap='flare',xticklabels=1, yticklabels=1,linecolor='white',linewidths=0.5,
cbar=True,mask=df.isnull(),cbar_kws={'shrink': 0.6},vmin=vmin, vmax=vmax)
I have applied a mask for NaN cells. Now, I want to change the color of few cells by a customized color which is not in the colormap, for example blue, to show that those cells belong to another category.
My question is:
Is it possible to apply 2 masks or more with different colors to a seaborn heatmap or manually change the color of a cell to totally another color?
It is unclear how the blue squares are represented. The following solution supposes they are represented as ones in a second matrix. The first heatmap is drawn as before. Then the second heatmap uses a special colormap (in this case with one color, but also a full range is possible), masking out all places where nothing should be drawn.
Note that masks can be combined via the logical or (symbol: |).
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
import seaborn as sns
import pandas as pd
import numpy as np
N = 10
data = np.random.uniform(0, 45, size=(N, N))
for x, y in np.random.randint(0, N, 50).reshape(-1, 2):
data[x, y] = np.nan # fill in some nans at random places
df = pd.DataFrame(data)
up_triang = np.triu(np.ones_like(data)).astype(bool)
ax = sns.heatmap(df, cmap='flare', xticklabels=True, yticklabels=True, square=True,
linecolor='white', linewidths=0.5,
cbar=True, mask=df.isnull() | up_triang, cbar_kws={'shrink': 0.6, 'pad': 0}, vmin=0, vmax=45)
data_special = np.random.randint(0, 5, size=(N, N)) // 4
sns.heatmap(data_special, cmap=ListedColormap(['cornflowerblue']), linecolor='white', linewidths=0.5,
square=True, cbar=False, mask=(data_special != 1) | up_triang, ax=ax)
ax.plot([0, N, 0, 0], [0, N, N, 0], clip_on=False, color='black', lw=2)
ax.tick_params(left=False, bottom=False)
plt.show()
An alternative approach, when there is only one color for the special cells, is to use an "under" color for the colormap, and give these cells negative values. An additional benefit is that the color can be shown in the colorbar. Here is some sample code:
N = 10
data = np.random.uniform(0, 45, size=(N, N))
for x, y in np.random.randint(0, N, 50).reshape(-1, 2):
data[x, y] = np.nan
data_special = np.random.randint(0, 5, size=(N, N)) // 4
data[data_special == 1] = -1
df = pd.DataFrame(data)
up_triang = np.triu(np.ones_like(data)).astype(bool)
cmap = sns.color_palette('mako', as_cmap=True).copy()
cmap.set_under('crimson ')
ax = sns.heatmap(df, cmap=cmap, xticklabels=True, yticklabels=True, square=True,
linecolor='white', linewidths=0.5, cbar=True, mask=df.isnull() | up_triang,
cbar_kws={'shrink': 0.6, 'pad': 0, 'extend': 'min', 'extendrect': True}, vmin=0, vmax=45)
ax.plot([0, N, 0, 0], [0, N, N, 0], clip_on=False, color='black', lw=2)
ax.tick_params(left=False, bottom=False)
plt.show()
A test code is in the following. When I add the length=10, the tick length does not change at all. Anyone can help?
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pyplot as plt
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter((0, 0, 1), (0, 1, 0), (1, 0, 0))
ax.w_xaxis.line.set_color('red')
ax.w_yaxis.line.set_color('red')
ax.w_zaxis.line.set_color('red')
ax.w_zaxis.line.set_color('red')
ax.xaxis.label.set_color('red')
ax.yaxis.label.set_color('red')
ax.zaxis.label.set_color('red')
ax.tick_params(axis='x', colors='red')
ax.tick_params(axis='y', colors='red')
ax.tick_params(axis='z', colors='red') # add length = 10 does not change the length of ticks, why?
plt.show()
I have a subplot and its tick labels overlap with the data. I would like to set the x-tick labels to have a background colour (e.g. white). Currently I have only been able to find how to change the label's colour, but not the background. I know how to get the effect using a text object as shown below. (NB - I don't want the whole subplot's margin to be coloured, but just the tick label).
MWE
import matplotlib as mpl
rc_fonts = {
"text.usetex": True,
'text.latex.preview': True,
"font.size": 50,
'mathtext.default': 'regular',
'axes.titlesize': 55,
"axes.labelsize": 55,
"legend.fontsize": 50,
"xtick.labelsize": 50,
"ytick.labelsize": 50,
'figure.titlesize': 55,
'figure.figsize': (10, 6.5), # 15, 9.3
'text.latex.preamble': [
r"""\usepackage{lmodern,amsmath,amssymb,bm,physics,mathtools,nicefrac,letltxmacro,fixcmex}
"""],
"font.family": "serif",
"font.serif": "computer modern roman",
}
mpl.rcParams.update(rc_fonts)
import matplotlib.pylab as plt
from mpl_toolkits.axes_grid1.inset_locator import inset_axes, InsetPosition, mark_inset
from numpy import linspace, sin
x = linspace(0, 1, 100)
plt.clf()
ax1 = plt.gca()
ax2 = plt.axes([0, 0, 1, 1], label=str(2))
ip = InsetPosition(ax1, [0.08, 0.63, 0.45, 0.3])
ax2.set_axes_locator(ip)
ax1.plot(x, x)
ax1.plot(x, x + 0.3)
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
ax2.xaxis.set_tick_params(labelcolor='r')
ax1.text(0.3, 0.3, '$1$', transform=ax1.transAxes, horizontalalignment='center', verticalalignment='center', color='black', backgroundcolor='white')
To set a label's background color you may use the same property as for a text, essentially because a label is a text.
plt.setp(ax2.get_xticklabels(), backgroundcolor="limegreen")
For more sophisticated backgrounds, you could also use the bbox property.
bbox = dict(boxstyle="round", ec="limegreen", fc="limegreen", alpha=0.5)
plt.setp(ax2.get_xticklabels(), bbox=bbox)
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
ax.plot(np.linspace(0, 1, 5), np.random.rand(5))
# set xticklabels
xtl = []
for x in ax.get_xticks():
xtl += ['lbl: {:.1f}'.format(x)]
ax.set_xticklabels(xtl)
# modify labels
for tl in ax.get_xticklabels():
txt = tl.get_text()
if txt == 'lbl: 1.0':
txt += ' (!)'
tl.set_backgroundcolor('C3')
tl.set_text(txt)
I am plotting 3d bar plots using mplot3d:
import numpy as np
import matplotlib
matplotlib.use("Qt4Agg")
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
from matplotlib import cm
result=[[0, 0, 5, 5, 14,40,50],
[0, 1, 8, 9, 20,50,70],
[0, 2, 8, 10, 25,60,80],
[0, 5, 10, 20, 40,75,100]]
result = np.array(result, dtype=np.int)
fig=plt.figure()
fig.set_size_inches(6, 4)
ax1=fig.add_subplot(111, projection='3d')
ax1.view_init(25, 280)
matplotlib.rcParams.update({'font.size': 12})
matplotlib.rcParams['font.weight']='normal'
xlabels = np.array(["Count1", "Count3","Count5", "Count6","Count7","Count8","Count9"])
xpos = np.arange(xlabels.shape[0])
ylabels = np.array(["5%","10%","20%","100%"])
ypos = np.arange(ylabels.shape[0])
xposM, yposM = np.meshgrid(xpos, ypos, copy=False)
zpos=result
zpos = zpos.ravel()
dx=0.75
dy=0.5
dz=zpos
ax1.w_xaxis.set_ticks(xpos + dx/2.)
ax1.w_xaxis.set_ticklabels(xlabels)
ax1.w_yaxis.set_ticks(ypos + dy/2)
ax1.set_yticklabels(ylabels)
ax1.w_zaxis.set_ticklabels(["","20%","40%","60%","80%","100%"])
colors = ['b','b','b','b','b','b','b','r','r','r','r','r','r','r','y','y','y','y','y','y','y','g','g','g','g','g','g','g']
ax1.bar3d(xposM.ravel(), yposM.ravel(), dz*0, dx, dy, dz, color=colors)
fig.savefig('tmp.tiff', dpi=300)
plt.close()
and here is what i got:
There are two problems here actually:
1) the y tick labels do not display correctly, they are supposed to be in the middle of the ticks but instead below the ticks. z tick labels are too close to the z ticks.
2) I suppose to use the font size 12 and the dpi should be higher than 300. I could not scale x axis such that the x tick labels fit nicely and do not overlap. I have tried multiply the xpos by 2. However the tick labels still overlap.