Предотвратить растяжение цветовой шкалы по ширине оси графика в matplotlib - PullRequest
0 голосов
/ 31 октября 2018

enter image description here

График выше был создан с использованием mpl_toolkits и matplotlib.colorbar.ColorbarBase, потому что мне нужно было настроить цветовую карту и цветовую панель для моего набора дискретных данных, как показано ниже:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colorbar
from matplotlib.collections import LineCollection
from matplotlib.colors import BoundaryNorm, ListedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
import random

x = np.arange(1, 1142)
y = np.zeros(len(x))
z = []
for _ in range(len(x)):
    z.append(random.randint(-1, 5))
z = np.array(z)

cmap = ListedColormap(['#FF0000', '#D52B00', '#AA5500', '#808000', '#55AA00', '#2BD500', '#00FF00'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5], cmap.N)

points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)

lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(10)

plt.gca().add_collection(lc)

plt.xlim(x.min() - (x.max() * 0.05), x.max() + (x.max() * 0.05))
plt.ylim(-1.1, 1.1)

plt.tick_params(axis='both', which='both', bottom=False, labelbottom=False, left=False, labelleft=False)

divider = make_axes_locatable(plt.gca())
ax_cb = divider.append_axes('bottom', size="2%", pad=-0.5)
cb = colorbar.ColorbarBase(ax_cb, cmap=cmap, norm=norm, orientation='horizontal', ticks=[-1, 0, 1, 2, 3, 4, 5])
cb.ax.set_yticklabels(['-1', '0', '1', '2', '3', '4', '5'])
plt.gcf().add_axes(ax_cb)

plt.show()

Это решение основано на примере здесь .

Мой вопрос, как я могу сделать цветовую полосу короче, чтобы она не растягивалась по всей ширине оси графика?

Ответы [ 2 ]

0 голосов
/ 01 ноября 2018

Проблема в том, что разделитель, созданный с помощью make_axes_locatable, гарантирует, что новые оси точно такие же, как и те, из которых он вырезан. Это главная цель этой функции; но здесь это как-то ортогонально желанию иметь другой размер.

Решение состоит в том, чтобы не использовать этот тип делителя и создать цветную полосу обычным способом с помощью plt.colorbar или fig.colorbar. Это позволяет использовать аргументы shrink и aspect. Поскольку с каждой стороны данных имеется 5% -ый запас, вы можете уменьшить цветовую полосу до 90%.

plt.colorbar(sm, orientation='horizontal', pad=-0.2,  shrink=0.9, aspect=30,
             ticks=[-1, 0, 1, 2, 3, 4, 5])

Полный код:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
from matplotlib.colors import BoundaryNorm, ListedColormap
from matplotlib.cm import ScalarMappable

x = np.arange(1, 1142)
y = np.zeros(len(x))
z = np.random.randint(-1, 5, size=x.shape)

cmap = ListedColormap(['#FF0000', '#D52B00', '#AA5500', '#808000', '#55AA00', '#2BD500', '#00FF00'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5], cmap.N)

points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)

lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(10)

plt.gca().add_collection(lc)

plt.xlim(x.min() - (x.max() * 0.05), x.max() + (x.max() * 0.05))
plt.ylim(-1.1, 1.1)

plt.tick_params(axis='both', which='both', bottom=False, labelbottom=False, 
                left=False, labelleft=False)

sm = ScalarMappable(norm=norm, cmap=cmap)
sm.set_array([])

plt.colorbar(sm, orientation='horizontal', pad=-0.2,  shrink=0.9, aspect=30,
             ticks=[-1, 0, 1, 2, 3, 4, 5])

plt.show()

enter image description here

0 голосов
/ 31 октября 2018

Это может быть так же просто, как изменить отступ на оси цветовой шкалы,

ax_cb = divider.append_axes('bottom', size="2%", pad=0.5)

, который уже выглядит лучше,

enter image description here

Более гибкий подход - добавить subplots_adjust и add_axes. Обратите внимание, что для этого необходимо установить цифру fig с осью ax. Итак, ваш пример,

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import colorbar
from matplotlib.collections import LineCollection
from matplotlib.colors import BoundaryNorm, ListedColormap
from mpl_toolkits.axes_grid1 import make_axes_locatable
import random

x = np.arange(1, 1142)
y = np.zeros(len(x))
z = []
for _ in range(len(x)):
    z.append(random.randint(-1, 5))
z = np.array(z)

cmap = ListedColormap(['#FF0000', '#D52B00', '#AA5500', '#808000', '#55AA00', '#2BD500', '#00FF00'])
norm = BoundaryNorm([-1.5, -0.5, 0.5, 1.5, 2.5, 3.5, 4.5, 5.5], cmap.N)

points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)

lc = LineCollection(segments, cmap=cmap, norm=norm)
lc.set_array(z)
lc.set_linewidth(10)

fig, ax = plt.subplots(1,1)

ax.add_collection(lc)

plt.xlim(x.min() - (x.max() * 0.05), x.max() + (x.max() * 0.05))
plt.ylim(-1.1, 1.1)
plt.tick_params(axis='both', which='both', bottom=False, labelbottom=False, left=False, labelleft=False)

fig.subplots_adjust(bottom=0.2)
ax_cb = fig.add_axes([0.15, 0.11, 0.7, 0.05])

cb = colorbar.ColorbarBase(ax_cb, cmap=cmap, norm=norm, orientation='horizontal', ticks=[-1, 0, 1, 2, 3, 4, 5])
cb.ax.set_yticklabels(['-1', '0', '1', '2', '3', '4', '5'])
plt.gcf().add_axes(ax_cb)

plt.show()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...