Автоматическое масштабирование коллекций (scatter создает PathCollection
) - все еще нерешенная проблема , хотя есть идеи для обходных путей.
Странное хакерское решение в приведенном выше примере заключается в добавлении пустого графика plt.plot()
к осям перед созданием разброса.
import numpy as np
import matplotlib.pyplot as plt
mu1, sigma1 = 0, 1
x1 = mu1 + sigma1 * np.random.randn(10000)
hist1, bins1 = np.histogram(x1, bins='auto', density=True)
center1 = (bins1[:-1] + bins1[1:]) / 2
mu2, sigma2 = 100, 15
x2 = mu2 + sigma2 * np.random.randn(10000)
hist2, bins2 = np.histogram(x2, bins='auto', density=True)
center2 = (bins2[:-1] + bins2[1:]) / 2
plt.subplot(2, 2, 1)
plt.plot(center1, hist1)
plt.text(2, 0.27, 'plot\n$\\mu$ = 0 \n$\\sigma$ = 1')
plt.subplot(2, 2, 2)
plt.plot() ## <== empty plot
plt.scatter(center1, hist1)
plt.text(2, 0.27, 'scatter\n$\\mu$ = 0 \n$\\sigma$ = 1')
plt.subplot(2, 2, 3)
plt.plot(center2, hist2)
plt.text(127, 0.02, 'plot\n$\\mu$ = 100 \n$\\sigma$ = 15')
plt.subplot(2, 2, 4)
plt.plot() ## <== empty plot
plt.scatter(center2, hist2)
plt.text(127, 0.02, 'scatter\n$\\mu$ = 100 \n$\\sigma$ = 15')
plt.show()
Вышесказанное - скорее шутка, хотя в данном конкретном случае это работает. Более серьезным решением было бы создать график реальных данных и сразу же удалить их. Этого достаточно, чтобы позволить автомасштабированию работать, как и ожидалось, для диапазона данных разброса.
import numpy as np
import matplotlib.pyplot as plt
mu1, sigma1 = 0, 1
x1 = mu1 + sigma1 * np.random.randn(10000)
hist1, bins1 = np.histogram(x1, bins='auto', density=True)
center1 = (bins1[:-1] + bins1[1:]) / 2
mu2, sigma2 = 100, 15
x2 = mu2 + sigma2 * np.random.randn(10000)
hist2, bins2 = np.histogram(x2, bins='auto', density=True)
center2 = (bins2[:-1] + bins2[1:]) / 2
plt.subplot(2, 2, 1)
plt.plot(center1, hist1)
plt.text(2, 0.27, 'plot\n$\\mu$ = 0 \n$\\sigma$ = 1')
plt.subplot(2, 2, 2)
sentinel, = plt.plot(center1, hist1) ## <== sentinel plot
sentinel.remove()
plt.scatter(center1, hist1)
plt.text(2, 0.27, 'scatter\n$\\mu$ = 0 \n$\\sigma$ = 1')
plt.subplot(2, 2, 3)
plt.plot(center2, hist2)
plt.text(127, 0.02, 'plot\n$\\mu$ = 100 \n$\\sigma$ = 15')
plt.subplot(2, 2, 4)
sentinel, = plt.plot(center2, hist2) ## <== sentinel plot
sentinel.remove()
plt.scatter(center2, hist2)
plt.text(127, 0.02, 'scatter\n$\\mu$ = 100 \n$\\sigma$ = 15')
plt.show()
Наконец, учтите, что в случае большой сетки графиков вам в любом случае необходимо вручную отрегулировать положение текста. Таким образом, реальным решением здесь было бы создать функцию, которая вызывается для каждой оси, и позволить этому делать все автоматически.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import AnchoredText
def plot_my_hist(mu, sigma, ax=None):
ax = ax or plt.gca()
x = mu + sigma * np.random.randn(10000)
hist, bins = np.histogram(x, bins='auto', density=True)
center = (bins[:-1] + bins[1:]) / 2
# Plot
sentinel, = ax.plot(center, hist) ## <== sentinel plot
sentinel.remove()
ax.scatter(center, hist)
# Annotation
at = AnchoredText(f'scatter\n$\\mu$ = {mu} \n$\\sigma$ = {sigma}',
loc='upper right')
ax.add_artist(at)
mus = [0, 0, 12, 12, 100, 100]
sigmas = [1, 15, 1, 15, 1, 15]
fig, axes = plt.subplots(ncols=3, nrows=2, figsize=(10,6))
for ax, mu, sigma in zip(axes.T.flat, mus, sigmas):
plot_my_hist(mu, sigma, ax=ax)
fig.tight_layout()
plt.show()