В настоящее время я заканчиваю большой проект, и последняя часть - добавить простую легенду к сюжету многоцветной линии. Строка содержит только два разных цвета.
На следующем рисунке показан график при создании. 
На следующем изображении показан тот же график с более высоким разрешением. 
График отображает расстояние между Землей и Марсом во времени. Для месяцев с марта по август линия оранжевая, для других месяцев - синяя. Легенда должна появиться в простом поле в верхнем правом углу графика, на котором должна быть метка для каждого используемого цвета. Что-то вроде , это было бы неплохо.
Данные для графика взяты из огромной матрицы, которую я назвал master_array
. Он содержит намного больше информации, которая необходима для некоторых задач, прежде чем показывать сюжет, к которому относится этот вопрос.
Для сюжета, с которым я борюсь, важны столбцы 0, 1 и 6, которые содержат дату, расстояние между планетами на соответствующую дату, а в столбце 6 я установил флаг, чтобы определить, принадлежит ли данная точка «март-август». 'установлено или нет (0
для сентября-февраля / "зима", 1
для марта-августа / "лето"). master_array
является массивом numpy, dtype - float64
. Содержит около 45 тыс. Точек данных.
Похоже:
In [3]: master_array
Out[3]:
array([[ 1.89301010e+07, 1.23451036e+00, -8.10000000e+00, ...,
1.00000000e+00, 1.00000000e+00, 1.89300000e+03],
[ 1.89301020e+07, 1.24314818e+00, -8.50000000e+00, ...,
2.00000000e+00, 1.00000000e+00, 1.89300000e+03],
[ 1.89301030e+07, 1.25179997e+00, -9.70000000e+00, ...,
3.00000000e+00, 1.00000000e+00, 1.89300000e+03],
...,
[ 2.01903100e+07, 1.84236878e+00, 7.90000000e+00, ...,
1.00000000e+01, 3.00000000e+00, 2.01900000e+03],
[ 2.01903110e+07, 1.85066892e+00, 5.50000000e+00, ...,
1.10000000e+01, 3.00000000e+00, 2.01900000e+03],
[ 2.01903120e+07, 1.85894904e+00, 9.40000000e+00, ...,
1.20000000e+01, 3.00000000e+00, 2.01900000e+03]])
Это функция для получения графика, который я описал в начале:
def md_plot3(dt64=np.array, md=np.array, swFilter=np.array):
""" noch nicht fertig """
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
cmap = ListedColormap(['b','darkorange'])
plt.figure('zeitlich-global betrachtet')
plt.title("Marsdistanz unter Berücksichtigung der Halbjahre der steigenden und sinkenden Temperaturen",
loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
# plt.legend(loc='upper right', frameon=True) # worked formerly
ax=plt.gca()
plt.style.use('seaborn-whitegrid')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, cmap=cmap, linewidth=3)
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
В большем сценарии есть еще одна функция (точечная диаграмма), чтобы пометить минимумы и максимумы кривой, но я думаю, что здесь это не так важно.
Я уже попробовал это , в результате чего появилась легенда, показывающая вертикальную цветную полосу и только одну метку, а также оба варианта, описанные в ответах на этот вопрос , потому что это больше похоже на то, что Я стремлюсь, но не могу заставить это работать для моего случая.
Может быть, я должен добавить, что я только начинающий в Python, это мой первый проект, поэтому я не знаком с более глубокой функциональностью matplotlib
, что, вероятно, является причиной, почему я не могу настроить упомянутые ответы на заставить его работать в моем случае.
UPDATE
Благодаря помощи пользователя ImportanceOfBeingErnest я сделал несколько улучшений:

import matplotlib.dates as mdates
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap
from matplotlib.lines import Line2D
def md_plot4(dt64=np.array, md=np.array, swFilter=np.array):
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
z = np.unique(swFilter)
cmap = ListedColormap(['b','darkorange'])
fig = plt.figure('Test')
plt.title("Test", loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
# plt.legend(loc='upper right', frameon=True) # worked formerly
ax=plt.gca()
plt.style.use('seaborn-whitegrid')
#plt.style.use('classic')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, array=z, cmap=plt.cm.get_cmap(cmap),
linewidth=3)
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
fig.colorbar(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
def make_proxy(zvalue, scalar_mappable, **kwargs):
color = scalar_mappable.cmap(scalar_mappable.norm(zvalue))
return Line2D([0, 1], [0, 1], color=color, **kwargs)
proxies = [make_proxy(item, lc, linewidth=2) for item in z]
ax.legend(proxies, ['Winter', 'Summer'])
plt.show()
md_plot4(dt64, md, swFilter)
+ Что в этом хорошего:
Ну, это показывает легенду и показывает правильные цвета в соответствии с ярлыками.
-Что еще нужно оптимизировать:
1) Легенда не находится в рамке, и «линии» легенды мешают нижним слоям сюжета. Как заявил пользователь ImportanceOfBeingErnest, это вызвано использованием plt.style.use('seaborn-whitegrid')
. Так что, если есть способ использовать plt.style.use('seaborn-whitegrid')
вместе со стилем легенды plt.style.use('classic')
, это может помочь.
2) Большим вопросом является цветовая полоса. Я добавил строку fig.colorbar(lc)
к исходному коду, чтобы добиться того, что искал, согласно этого ответа .
Итак, я попробовал некоторые другие изменения:
Я использовал plt.style.use('classic')
, чтобы получить легенду так, как мне нужно, но это стоило мне хорошего стиля plt.style.use('seaborn-whitegrid')
, как упоминалось ранее. Более того, я отключил добавленную ранее строку colorbar
в соответствии с упомянутым ответом .
Вот что я получил:

import matplotlib.dates as mdates
from matplotlib.collections import LineCollection
from matplotlib.colors import ListedColormap
from matplotlib.lines import Line2D
def md_plot4(dt64=np.array, md=np.array, swFilter=np.array):
y, m, d = dt64.astype(int) // np.c_[[10000, 100, 1]] % np.c_[[10000, 100, 100]]
dt64 = y.astype('U4').astype('M8') + (m-1).astype('m8[M]') + (d-1).astype('m8[D]')
z = np.unique(swFilter)
cmap = ListedColormap(['b','darkorange'])
#fig =
plt.figure('Test')
plt.title("Test", loc='left', wrap=True)
plt.xlabel("Zeit in Jahren\n")
plt.xticks(rotation = 45)
plt.ylabel("Marsdistanz in AE\n(1 AE = 149.597.870,7 km)")
# plt.legend(loc='upper right', frameon=True) # worked formerly
ax=plt.gca()
#plt.style.use('seaborn-whitegrid')
plt.style.use('classic')
#convert dates to numbers first
inxval = mdates.date2num(dt64)
points = np.array([inxval, md]).T.reshape(-1,1,2)
segments = np.concatenate([points[:-1],points[1:]], axis=1)
lc = LineCollection(segments, array=z, cmap=plt.cm.get_cmap(cmap),
linewidth=3)
# set color to s/w values
lc.set_array(swFilter)
ax.add_collection(lc)
#fig.colorbar(lc)
loc = mdates.AutoDateLocator()
ax.xaxis.set_major_locator(loc)
ax.xaxis.set_major_formatter(mdates.AutoDateFormatter(loc))
ax.autoscale_view()
def make_proxy(zvalue, scalar_mappable, **kwargs):
color = scalar_mappable.cmap(scalar_mappable.norm(zvalue))
return Line2D([0, 1], [0, 1], color=color, **kwargs)
proxies = [make_proxy(item, lc, linewidth=2) for item in z]
ax.legend(proxies, ['Winter', 'Summer'])
plt.show()
md_plot4(dt64, md, swFilter)
+ Что в этом хорошего:
Показывает легенду так, как мне нужно.
Цветная полоса больше не отображается.
-Что стоит оптимизировать:
Сюжет больше не разноцветный.
Ни одна из легенд не существует.
Стиль classic
- это не то, что я искал, как я объяснял ранее ...
Так что, если у кого-то есть хороший совет, пожалуйста, дайте мне знать!
Я использую numpy версию 1.16.2 и matplotlib версию 3.0.3