Custom xticks labels in loglog plot - matplotlib

A simple example is as follows:
import numpy as np
import numpy.random as npr
import matplotlib.pyplot as plt
N = 1000
x = np.linspace(1, 5, N)
y = npr.randint(1e16, size = N) / 1e16
y = np.sort(y)
fig, ax = plt.subplots()
ax.loglog(x, y, '.')
ax.grid(True, 'both')
Where I want to replace the xticks. So far everything I tried, failed to work:
ax.set_xticks([2, 3, 4], ['a', 'b', 'c'])
ax.xaxis.set_ticks_position('none')
ax.set_xticks([])
None of the above showed any effect. My goal is to replace the ticks with custom defined ticks (strings or integers). So instead of 2 x 10⁰ it should only be 2. Similar for other xticks.

Probably this is what you're after:
import numpy as np
import matplotlib.pyplot as plt
N = 1000
x = np.linspace(1, 5, N)
y = np.random.rand(N)
y = np.sort(y)
fig, ax = plt.subplots()
ax.loglog(x, y, '.')
ax.grid(True, 'both')
ax.set_xticks([2, 3, 4])
ax.set_xticklabels(['a', 'b', 'c'])
ax.minorticks_off()
plt.show()

Related

getting only the last plot

when plotting by below code I am getting c,d,e plots but I am getting only the last plot for plt.plot
def normalize(x):
return (x - x.min(0)) / x.ptp(0)
c=sns.distplot(mk[0]['mass'], hist=True, label='p', rug=True)
d=sns.distplot(mk[1]['mass'], hist=True, label='q', rug=True)
e=sns.distplot(mk[2]['mass'], hist=True, label='r', rug=True)
datadist=[c,d,e]
xd=dict()
yd2=dict()
for i in datadist:
line = i.get_lines()[0]
xd[i] = line.get_xdata()
yd = line.get_ydata()
yd2[i] = normalize(yd)
plt.plot(xd[c], yd2[c],color='black')
plt.plot(xd[d], yd2[d],color='yellow')
plt.plot(xd[e], yd2[e],color='green')
sns.distplot() returns the ax (the subplot) on which the histogram was drawn. All 3 are drawn on the same subplot, so the return value is the same three times.
The array lines = ax1.get_lines() contains exactly 3 elements: one for each of the kde curves, so you can extract them as follows:
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
def normalize(x):
return (x - x.min(0)) / x.ptp(0)
fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(14, 4))
sns.distplot(np.random.randn(30) + 10, hist=True, label='p', rug=True, ax=ax1, color='black')
sns.distplot(np.random.randn(30) + 15, hist=True, label='q', rug=True, ax=ax1, color='gold')
sns.distplot(np.random.randn(30) + 20, hist=True, label='r', rug=True, ax=ax1, color='green')
for line in ax1.get_lines():
ax2.plot(line.get_xdata(), normalize(line.get_ydata()), color=line.get_color())
plt.show()
Now, if you just want the kde-curves and "normalize" them, you could use scipy.stats import gaussian_kde:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import gaussian_kde
def normalize(x):
return (x - x.min(0)) / x.ptp(0)
fig, ax = plt.subplots(figsize=(12, 4))
mk0mass = np.random.randn(30) + 10
mk1mass = np.random.randn(30) + 15
mk2mass = np.random.randn(30) + 20
all_mkmass = [mk0mass, mk1mass, mk2mass]
x = np.linspace(min([mki.min() for mki in all_mkmass]) - 2,
max([mki.max() for mki in all_mkmass]) + 2, 1000)
for mki, color in zip(all_mkmass, ['black', 'gold', 'green']):
kde = gaussian_kde(mki)
yd = normalize(kde(x))
ax.plot(x, yd, color=color)
ax.fill_between(x, 0, yd, color=color, alpha=0.3)
plt.show()

Matplotlib Interpolate empty pixels

I have a file 'mydata.tmp' which contains 3 colums like this:
3.81107 0.624698 0.000331622
3.86505 0.624698 0.000131237
3.91903 0.624698 5.15136e-05
3.97301 0.624698 1.93627e-05
1.32802 0.874721 1.59245
1.382 0.874721 1.542
1.43598 0.874721 1.572
1.48996 0.874721 4.27933
etc.
Then I want to make a heatmap color plot where the first two columns are coordinates, and the third column are the values of that coordinates.
Also, I would like to set the third column in log scale.
I have done this
import pandas as pd
import matplotlib.pyplot as plt
import scipy.interpolate
import numpy as np
import matplotlib.colors as colors
# import data
df = pd.read_csv('mydata.tmp', delim_whitespace=True,
comment='#',header=None,
names=['1','2','3'])
x = df['1']
y = df['2']
z = df['3']
spacing = 500
xi, yi = np.linspace(x.min(), x.max(), spacing), np.linspace(y.min(),
y.max(), spacing)
XI, YI = np.meshgrid(xi, yi)
rbf = scipy.interpolate.Rbf(x, y, z, function='linear')
ZI = rbf(XI, YI)
fig, ax = plt.subplots()
sc = ax.imshow(ZI, vmin=z.min(), vmax=z.max(), origin='lower',
extent=[x.min(), x.max(), y.min(),
y.max()], cmap="GnBu", norm=colors.LogNorm(vmin=ZI.min(),
vmax=ZI.max()))
fig.colorbar(sc, ax=ax, fraction=0.05, pad=0.01)
plt.show()
And I get this Image
which has all these empty pixels.
I am looking for something like this instead (I have done this other picture with GNUplot):
How can I do it?
You could use cmap.set_bad to define a color for the NaN values:
import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import griddata
import matplotlib.colors as colors
from matplotlib import cm
import copy
# Some data
x = np.array([0, 1, 3, 0, 2, 4])
y = np.array([0, 0, 0, 1, 1, 1])
z = np.array([2, 2, 3, 2, 3, 4])
# Interpolation on a grid:
nrb_points = 101
xi = np.linspace(-.5, 4.5, nrb_points)
yi = np.linspace(-.5, 1.5, nrb_points)
XI, YI = np.meshgrid(xi, yi)
xy = np.vstack((x, y)).T
XY = (XI.ravel(), YI.ravel())
ZI = griddata(points, z, XY,
method='linear',
fill_value=np.nan) # Value used [for] points
# outside of the convex hull
# of the input points.
ZI = ZI.reshape(XI.shape)
# Color map:
cmap = copy.copy(cm.jet)
cmap.set_bad('grey', 1.)
# Graph:
plt.pcolormesh(xi, yi, ZI,
#norm=colors.LogNorm(),
cmap=cmap);
plt.colorbar(label='z');
plt.plot(x, y, 'ko');
plt.xlabel('x'); plt.ylabel('y');
the result is:
I would also use griddata instead of RBF method for the interpolation. Then, point outside the input data area (i.e. the convex hull) can be set to NaN.

matlibplot: How to add space between some subplots

How can I adjust the whitespace between some subplots? In the example below, let's say I want to eliminate all whitespace between the 1st and 2nd subplots as well as between the 3rd and 4th and increase the space between the 2nd and 3rd?
import matplotlib.pyplot as plt
import numpy as np
# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
f, ax = plt.subplots(4,figsize=(10,10),sharex=True)
ax[0].plot(x, y)
ax[0].set_title('Panel: A')
ax[1].plot(x, y**2)
ax[2].plot(x, y**3)
ax[2].set_title('Panel: B')
ax[3].plot(x, y**4)
plt.tight_layout()
To keep the solution close to your code you may use create 5 subplots with the middle one being one forth in height of the others and remove that middle plot.
import matplotlib.pyplot as plt
import numpy as np
# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
f, ax = plt.subplots(5,figsize=(7,7),sharex=True,
gridspec_kw=dict(height_ratios=[4,4,1,4,4], hspace=0))
ax[0].plot(x, y)
ax[0].set_title('Panel: A')
ax[1].plot(x, y**2)
ax[2].remove()
ax[3].plot(x, y**3)
ax[3].set_title('Panel: B')
ax[4].plot(x, y**4)
plt.tight_layout()
plt.show()
You would need to use GridSpec to have different spaces between plots:
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import numpy as np
# Simple data to display in various forms
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
f = plt.figure(figsize=(10,10))
gs0 = gridspec.GridSpec(2, 1)
gs00 = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=gs0[0], hspace=0)
ax0 = f.add_subplot(gs00[0])
ax0.plot(x, y)
ax0.set_title('Panel: A')
ax1 = f.add_subplot(gs00[1], sharex=ax0)
ax1.plot(x, y**2)
gs01 = gridspec.GridSpecFromSubplotSpec(2, 1, subplot_spec=gs0[1], hspace=0)
ax2 = f.add_subplot(gs01[0])
ax2.plot(x, y**3)
ax2.set_title('Panel: B')
ax3 = f.add_subplot(gs01[1], sharex=ax0)
ax3.plot(x, y**4)
plt.show()

Matplotlib: Don't show errorbars in legend

I'm plotting a series of data points with x and y error but do NOT want the errorbars to be included in the legend (only the marker). Is there a way to do so?
Example:
import matplotlib.pyplot as plt
import numpy as np
subs=['one','two','three']
x=[1,2,3]
y=[1,2,3]
yerr=[2,3,1]
xerr=[0.5,1,1]
fig,(ax1)=plt.subplots(1,1)
for i in np.arange(len(x)):
ax1.errorbar(x[i],y[i],yerr=yerr[i],xerr=xerr[i],label=subs[i],ecolor='black',marker='o',ls='')
ax1.legend(loc='upper left', numpoints=1)
fig.savefig('test.pdf', bbox_inches=0)
You can modify the legend handler. See the legend guide of matplotlib.
Adapting your example, this could read:
import matplotlib.pyplot as plt
import numpy as np
subs=['one','two','three']
x=[1,2,3]
y=[1,2,3]
yerr=[2,3,1]
xerr=[0.5,1,1]
fig,(ax1)=plt.subplots(1,1)
for i in np.arange(len(x)):
ax1.errorbar(x[i],y[i],yerr=yerr[i],xerr=xerr[i],label=subs[i],ecolor='black',marker='o',ls='')
# get handles
handles, labels = ax1.get_legend_handles_labels()
# remove the errorbars
handles = [h[0] for h in handles]
# use them in the legend
ax1.legend(handles, labels, loc='upper left',numpoints=1)
plt.show()
This produces
Here is an ugly patch:
pp = []
colors = ['r', 'b', 'g']
for i, (y, yerr) in enumerate(zip(ys, yerrs)):
p = plt.plot(x, y, '-', color='%s' % colors[i])
pp.append(p[0])
plt.errorbar(x, y, yerr, color='%s' % colors[i])
plt.legend(pp, labels, numpoints=1)
Here is a figure for example:
The accepted solution works in simple cases but not in general. In particular, it did not work in my own more complex situation.
I found a more robust solution, which tests for ErrorbarContainer, which did work for me. It was proposed by Stuart W D Grieve and I copy it here for completeness
import matplotlib.pyplot as plt
from matplotlib import container
label = ['one', 'two', 'three']
color = ['red', 'blue', 'green']
x = [1, 2, 3]
y = [1, 2, 3]
yerr = [2, 3, 1]
xerr = [0.5, 1, 1]
fig, (ax1) = plt.subplots(1, 1)
for i in range(len(x)):
ax1.errorbar(x[i], y[i], yerr=yerr[i], xerr=xerr[i], label=label[i], color=color[i], ecolor='black', marker='o', ls='')
handles, labels = ax1.get_legend_handles_labels()
handles = [h[0] if isinstance(h, container.ErrorbarContainer) else h for h in handles]
ax1.legend(handles, labels)
plt.show()
It produces the following plot (on Matplotlib 3.1)
I works for me if I set the label argument as a None type.
plt.errorbar(x, y, yerr, label=None)

Weird "zero ticks" on matplotlib subplot y-axis

I'm creating a plot consisting of several subplots in matplotlib, like this one:
But for some reason, I get weird Zeros on the y-axis (actually on both sides of the plot):
They don't seem to be ticks, since the ax1.get_yaxis().set_ticks([]) statement does not affect them.
Any ideas why I get these and how I can get rid of them?
import matplotlib.pyplot as plt
from pylab import *
import numpy as np
subplots_adjust(hspace=0.000)
groups = ['01', '03', '05', '07']
for i in range(len(groups)):
x = np.linspace(0, 2*np.pi,400)
y = np.sin(x**2)
ax1 = subplot(len(groups),1,i+1)
ax1.scatter(x, y, s=20, c='b', marker='o')
plt.xlim(xmin=0,xmax=1)
ax1.get_yaxis().set_ticks([])
plt.show()
plt.close()
Thank you for any help!
These are just leftovers from the x ticks at 0.0 and 1.0:
import matplotlib.pyplot as plt
#from pylab import * # don't do it, btw
import numpy as np
groups = ['01' , '03', '05', '07']
fig = plt.figure()
ax = []
for i in range(len(groups)):
ax.append( fig.add_subplot( len(groups), 1, i+1 ) )
fig.subplots_adjust(hspace=0.000)
for i in range(len(groups)):
x = np.linspace(0, 2*np.pi,400)
y = np.sin(x**2)
ax[i] = plt.subplot(len(groups),1,i+1)
ax[i].scatter(x, y, s=20, c='b', marker='o')
ax[i].get_yaxis().set_ticks([])
ax[i].set_xlim([0.001,0.9999]) # <<<<========== here
plt.show()