Matplotlib多色标题(文字) - 在实践中

时间:2016-03-28 14:23:24

标签: python-3.x matplotlib title

有一个示例here,用于创建多色文本标题。

但是,我想将它应用于已有数字的情节。

例如,如果我将它应用于此(与示例相同的代码减去一些额外内容和另一个数字)...:

from itertools import groupby

l = [('Monkey', 71), ('Monkey', 78), ('Ostrich', 80), ('Ostrich', 96), ('Ant', 98)]
                # Key is the animal, value is a list of the available integers obtained by
d = OrderedDict((animal, [i for _, i in vals])
                for (animal, vals) in
                # Grouping your list by the first value inside animalAndInt, which is the animal
                groupby(l, lambda animalAndInt: animalAndInt[0]))
# If you want a tuple, instead of [i for _, i in vals] use tuple(i for _, i in vals)
print(d)
>>> OrderedDict([('Monkey', [71, 78]), ('Ostrich', [80, 96]), ('Ant', [98])])

...结果是2个图,标题放大了。 这对我来说很有意义,因为我正在使用plt。两次。 但是我如何整合它以便它只引用plt的第一个实例。在创建标题?

另外,关于这一行:

plt.rcdefaults()
import matplotlib.pyplot as plt
%matplotlib inline
from matplotlib import transforms

fig = plt.figure(figsize=(4,3), dpi=300)

def rainbow_text(x,y,ls,lc,**kw):

    t = plt.gca().transData
    fig = plt.gcf()
    plt.show()

    #horizontal version
    for s,c in zip(ls,lc):
        text = plt.text(x,y," "+s+" ",color=c, transform=t, **kw)
        text.draw(fig.canvas.get_renderer())
        ex = text.get_window_extent()
        t = transforms.offset_copy(text._transform, x=ex.width, units='dots')

plt.figure()
rainbow_text(0.5,0.5,"all unicorns poop rainbows ! ! !".split(), 
        ['red', 'orange', 'brown', 'green', 'blue', 'purple', 'black'],
        size=40)

我注意到它可以改变单词之间的间距,但是当我使用x的值时,结果是不可预测的(单词之间的间距不一致)。 我怎样才能有意义地调整这个价值?

最后,在说“units ='dots'”的地方,还有其他选择吗? “点”是1/72英寸(这是Matplotlib的默认值吗?)?

如何将单位从点转换为英寸?

提前致谢!

3 个答案:

答案 0 :(得分:2)

实际上,文本的边界框的单位与使用的单位不同,例如,在散点图中。文本是一种不同类型的对象,如果您调整窗口大小或更改比率,它会以某种方式重绘。通过设置稳定的窗口,您可以在绘图单元中询问边界框的坐标,并以这种方式构建彩色文本:

a = "all unicorns poop rainbows ! ! !".split()
c = ['red', 'orange', 'brown', 'green', 'blue', 'purple', 'black']

f = plt.figure(figsize=(4,3), dpi=120)
ax = f.add_subplot(111)

r = f.canvas.get_renderer()
space = 0.1
w = 0.5
counter = 0
for i in a:
    t = ax.text(w, 1.2, a[counter],color=c[counter],fontsize=12,ha='left')
    transf = ax.transData.inverted()
    bb = t.get_window_extent(renderer=f.canvas.renderer)
    bb = bb.transformed(transf)
    w = w + bb.xmax-bb.xmin + space
    counter = counter + 1
plt.ylim(0.5,2.5)
plt.xlim(0.6,1.6)
plt.show()

,结果是:

Matplotlib colored text

然而,这仍然不理想,因为您需要继续控制绘图轴的大小以获得单词之间的正确空格。这有点武断,但如果你设法使用这样的控制来完成你的程序,那么使用绘图单元来实现你的预期目的是可行的。

原始邮件:

plt.只是对图书馆的调用。实际上,您正在全局范围内创建plt.figure的实例(因此可以在函数的本地中看到它)。因此,您将覆盖figure,因为您对变量使用相同的名称(因此它最终只是一个实例)。要解决此问题,请尝试控制图形实例的名称。例如:

import matplotlib.pyplot as plt
#%matplotlib inline
from matplotlib import transforms

fig = plt.figure(figsize=(4,3), dpi=300)
#plt.show(fig)

def rainbow_text(x,y,ls,lc,**kw):

    t = plt.gca().transData
    figlocal = plt.gcf()

    #horizontal version
    for s,c in zip(ls,lc):
        text = plt.text(x,y," "+s+" ",color=c, transform=t, **kw)
        text.draw(figlocal.canvas.get_renderer())
        ex = text.get_window_extent()
        t = transforms.offset_copy(text._transform, x=ex.width, units='dots')

    plt.show(figlocal) #plt.show((figlocal,fig))

#plt.figure()
rainbow_text(0.5,0.5,"all unicorns poop rainbows ! ! !".split(), 
        ['red', 'orange', 'brown', 'green', 'blue', 'purple', 'black'],
        size=40,)

我已经评论了几条说明,但请注意我为函数figure提供了一个不同的名称(figlocal)。另请注意,在我的演示示例中,我直接控制应显示哪个figure

关于您的其他问题,请注意您可以使用其他单位,如功能文档中所示:

Return a new transform with an added offset.
      args:
        trans is any transform
      kwargs:
        fig is the current figure; it can be None if units are 'dots'
        x, y give the offset
        units is 'inches', 'points' or 'dots'

编辑:显然,文本边界框的范围存在某种问题,这些问题没有给出正确的单词宽度,因此单词之间的空间不稳定。我的建议是使用Matplotlib的乳胶功能在同一个字符串中写入颜色(所以只能调用一次plt.text)。你可以这样做:

import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('pgf')
from matplotlib import rc

rc('text',usetex=True)
rc('text.latex', preamble=r'\usepackage{color}')

a = "all unicorns poop rainbows ! ! !".split()
c = ['red', 'orange', 'brown', 'green', 'blue', 'purple', 'black']
st = ''
for i in range(len(a)):
    st = st + r'\textcolor{'+c[i]+'}{'+a[i]+'}'
plt.text(0.5,0.5,st)
plt.show()

然而,这不是一个理想的解决方案。原因是你需要安装Latex,包括必要的包(注意我正在使用颜色包)。在这个问题中看一下Yann的回答:Partial coloring of text in matplotlib

答案 1 :(得分:0)

@armatita:我认为你的答案确实能满足我的需要。我认为我需要显示坐标,但看起来我只能使用轴1坐标,如果这是什么(我计划通过subplot2grid使用多个轴)。这是一个例子:

import matplotlib.pyplot as plt
%matplotlib inline
dpi=300
f_width=4
f_height=3
f = plt.figure(figsize=(f_width,f_height), dpi=dpi)

ax1 = plt.subplot2grid((100,115), (0,0), rowspan=95, colspan=25)
ax2 = plt.subplot2grid((100,115), (0,30), rowspan=95, colspan=20)
ax3 = plt.subplot2grid((100,115), (0,55), rowspan=95, colspan=35)
ax4 = plt.subplot2grid((100,115), (0,95), rowspan=95, colspan=20)
r = f.canvas.get_renderer()
t = ax1.text(.5, 1.1, 'a lot of text here',fontsize=12,ha='left')
space=0.1
w=.5

transf = ax1.transData.inverted()
bb = t.get_window_extent(renderer=f.canvas.renderer)
bb = bb.transformed(transf)

e = ax1.text(.5+bb.width+space, 1.1, 'text',fontsize=12,ha='left')

print(bb)
plt.show()
但是,我不确定你控制轴尺寸的意思。您是指在不同环境中使用代码还是导出不同大小的图像?我计划在相同的环境和相同的大小(使用这种方法的每个实例)中使用图像,所以我认为它会没问题。我的逻辑是否有意义?我对实际情况的了解很少,所以我希望如此。我会像你一样使用函数(通过拆分文本),但有些情况下我需要拆分其他字符(即括号中的单词应该是彩色的,而不是括号)。也许我可以在那里放一个分隔符,如','?我想我需要一种不同形式的.split(),因为当我尝试它时它没有用。 无论如何,如果我可以在我的所有图表中实现这一点,它将为我节省无数个小时。非常感谢你!

答案 2 :(得分:0)

这是一个示例,其中有2个图和2个使用该后代函数的实例:

import matplotlib.pyplot as plt
%matplotlib inline
dpi=300
f_width=4
f_height=3
f = plt.figure(figsize=(f_width,f_height), dpi=dpi)

ax1 = plt.subplot2grid((100,60), (0,0), rowspan=95, colspan=30)
ax2 = plt.subplot2grid((100,60), (0,30), rowspan=95, colspan=30)

f=f #Name for figure
string = str("Group 1 ,vs. ,Group 2 (,sub1,) and (,sub2,)").split(',')
color = ['black','red','black','green','black','blue','black']
xpos = .5
ypos = 1.2
axis=ax1
#No need to include space if incuded between delimiters above
#space = 0.1 
def colortext(f,string,color,xpos,ypos,axis):
#f=figure object name (i.e. fig, f, figure)
    r = f.canvas.get_renderer()
    counter = 0
    for i in string:
        t = axis.text(xpos, ypos, string[counter],color=color[counter],fontsize=12,ha='left')
        transf = axis.transData.inverted()
        bb = t.get_window_extent(renderer=f.canvas.renderer)
        bb = bb.transformed(transf)
        xpos = xpos + bb.xmax-bb.xmin
        counter = counter + 1
colortext(f,string,color,xpos,ypos,axis)

string2 = str("Group 1 part 2 ,vs. ,Group 2 (,sub1,) and (,sub2,)").split(',')
ypos2=1.1
colortext(f,string2,color,xpos,ypos2,axis)

plt.show()