2015-10-15 9 views
3

Мне было интересно, какой лучший способ сделать y-метку, где каждое слово на этикетке может быть другого цвета.Matplotlib: метка оси y с несколькими цветами

Причина, по которой я хочу, это потому, что я буду делать графики, которые будут содержать кривые (электрические поля и векторные потенциальные поля). Эти кривые будут разных цветов, и я хотел бы показать это в ярлыках. Ниже приведен упрощенный пример, используя предыдущий пост (Matplotlib multiple colours in tick labels), чтобы приблизиться. Это сообщение хорошо подходит для оси x, однако оно не занимает/не упорядочивает ось y правильно.

У другого поста был аналогичный вопрос (Partial coloring of text in matplotlib), но первый ответ больше не работал, и второй ответ заставляет сохранить файл как файл .ps.

Мой пример кода

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, HPacker, VPacker 

ax = plt.subplot(111) 

x = np.linspace(0,10,10) 
y1 = x 
y2 = x**2 

ax.plot(x,y1,color='r',label='data1') 
ax.plot(x,y2,color='b',label='data2') 
ax.set_xticks([]) # empty xticklabels 
ax.set_yticks([]) # empty xticklabels 

# x-axis label 
xbox1 = TextArea("Data1-x ", textprops=dict(color="r", size=15)) 
xbox2 = TextArea("and ", textprops=dict(color="k", size=15)) 
xbox3 = TextArea("Data2-x ", textprops=dict(color="b", size=15)) 

xbox = HPacker(children=[xbox1, xbox2, xbox3], 
        align="center", pad=0, sep=5) 

anchored_xbox = AnchoredOffsetbox(loc=3, child=xbox, pad=0., frameon=False, 
             bbox_to_anchor=(0.3, -0.07), 
             bbox_transform=ax.transAxes, borderpad=0.) 

# y-axis label 
ybox1 = TextArea("Data1-y ", textprops=dict(color="r", size=15,rotation='vertical')) 
ybox2 = TextArea("and ", textprops=dict(color="k", size=15,rotation='vertical')) 
ybox3 = TextArea("Data2-y ", textprops=dict(color="b", size=15,rotation='vertical')) 

ybox = VPacker(children=[ybox1, ybox2, ybox3], 
        align="center", pad=0, sep=5) 

anchored_ybox = AnchoredOffsetbox(loc=8, child=ybox, pad=0., frameon=False, 
             bbox_to_anchor=(-0.08, 0.4), 
             bbox_transform=ax.transAxes, borderpad=0.) 


ax.add_artist(anchored_xbox) 
ax.add_artist(anchored_ybox) 
plt.legend() 
plt.show() 

Example image

Спасибо за помощь!

+0

Вы думали об использовании 'TwinX()'? Я обычно рисую второй набор данных на второй оси y и меняю цвет соответственно – Moritz

ответ

5

Вы были почти там. Вам просто нужно указать выравнивание текста, используя ha = 'left', va = 'bottom'. (И переверните порядок объектов TextArea, переданных в VPacker).

import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, HPacker, VPacker 

ax = plt.subplot(111) 

x = np.linspace(0,10,10) 
y1 = x 
y2 = x**2 

ax.plot(x,y1,color='r',label='data1') 
ax.plot(x,y2,color='b',label='data2') 

ybox1 = TextArea("Data2-y ", textprops=dict(color="r", size=15,rotation=90,ha='left',va='bottom')) 
ybox2 = TextArea("and ",  textprops=dict(color="k", size=15,rotation=90,ha='left',va='bottom')) 
ybox3 = TextArea("Data1-y ", textprops=dict(color="b", size=15,rotation=90,ha='left',va='bottom')) 

ybox = VPacker(children=[ybox1, ybox2, ybox3],align="bottom", pad=0, sep=5) 

anchored_ybox = AnchoredOffsetbox(loc=8, child=ybox, pad=0., frameon=False, bbox_to_anchor=(-0.08, 0.4), 
            bbox_transform=ax.transAxes, borderpad=0.) 

ax.add_artist(anchored_ybox) 
plt.legend() 
plt.show() 

enter image description here

еще лучше, здесь есть функция, которая делает метки с использованием произвольного списка строк и цветов:

import numpy as np 
import matplotlib.pyplot as plt 

def multicolor_ylabel(ax,list_of_strings,list_of_colors,axis='x',anchorpad=0,**kw): 
    """this function creates axes labels with multiple colors 
    ax specifies the axes object where the labels should be drawn 
    list_of_strings is a list of all of the text items 
    list_if_colors is a corresponding list of colors for the strings 
    axis='x', 'y', or 'both' and specifies which label(s) should be drawn""" 
    from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, HPacker, VPacker 

    # x-axis label 
    if axis=='x' or axis=='both': 
     boxes = [TextArea(text, textprops=dict(color=color, ha='left',va='bottom',**kw)) 
        for text,color in zip(list_of_strings,list_of_colors) ] 
     xbox = HPacker(children=boxes,align="center",pad=0, sep=5) 
     anchored_xbox = AnchoredOffsetbox(loc=3, child=xbox, pad=anchorpad,frameon=False,bbox_to_anchor=(0.2, -0.09), 
              bbox_transform=ax.transAxes, borderpad=0.) 
     ax.add_artist(anchored_xbox) 

    # y-axis label 
    if axis=='y' or axis=='both': 
     boxes = [TextArea(text, textprops=dict(color=color, ha='left',va='bottom',rotation=90,**kw)) 
        for text,color in zip(list_of_strings[::-1],list_of_colors) ] 
     ybox = VPacker(children=boxes,align="center", pad=0, sep=5) 
     anchored_ybox = AnchoredOffsetbox(loc=3, child=ybox, pad=anchorpad, frameon=False, bbox_to_anchor=(-0.10, 0.2), 
              bbox_transform=ax.transAxes, borderpad=0.) 
     ax.add_artist(anchored_ybox) 


ax = plt.subplot(111) 

x = np.linspace(0,10,1000) 
y1 = np.sin(x) 
y2 = np.sin(2*x) 

ax.plot(x,y1,color='r') 
ax.plot(x,y2,color='b') 

multicolor_ylabel(ax,('Line1','and','Line2','with','extra','colors!'),('r','k','b','k','m','g'),axis='both',size=15,weight='bold') 

plt.show() 

Он по-прежнему занимает некоторое возился с позициями в " bbox_to_anchor ".

enter image description here

+0

Отлично! Спасибо за быстрый ответ!!! –

+0

Это очень приятное решение, но почему вы инвертировали список строк (но не цвета) в случае 'y'? –

+0

Я перевернул список строк, чтобы слова находились в том же порядке по оси y (которая упорядочивает сверху вниз, напротив того, как мы читаем). Я не перелистал список цветов, потому что забыл :) – DanHickstein