2016-03-28 87 views
0

有一个示例here用于创建多色文本标题。Matplotlib多色标题(文本) - 实际中

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

例如,如果我把它应用到这个(相同的代码与例子减去一些额外和另一个数字)...:

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) 

...结果是2个地块与标题放大。 这种情况对我来说很合理,因为我使用的是plt。两次。 但是,我如何整合它,以便它只涉及plt的第一个实例。在创建标题?

此外,关于这条线:

t = transforms.offset_copy(text._transform, x=ex.width, units='dots') 

我注意到它可以改变字之间的间距,但是当我随着x的值发挥,结果是不可预测的(间距是单词之间不一致)。 我该如何有意义地调整这个值?

最后,它说“units ='dots'”,其他选项是什么? '点'是1/72英寸(并且是Matplotlib的默认值?)?

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

在此先感谢!

回答

1

实际上,文本的边框与单位不同,例如散点图。如果调整窗口大小或更改比率,则文本是一种不同类型的对象,可以重新绘制。由于具有稳定的窗口,你可以问边界框的坐标情节单位,建立自己的彩色文本方式:

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

+0

谢谢,@armatita但如何控制(真,正规化)对于给定的单元的宽度?我问,因为这些例子会产生不一致的单词间距,这正是我最终想要解决的问题(关于我的问题的第二部分)。 –

+1

@舞会派对2如果这种变换没有做正确的方式,那么就忘记变换。定义您的字体,对齐并使用坐标绘制每个单词。注意你已经获得了文本的边界框(text.get_window_extent()),所以你可以声明一个空格,例如0.2表示word2应该放在word1_width + 0.2中(对于word3也是如此)将会自己建立一种转变。事情是我不确定你正在使用的是什么变化实际上在做。另外:http://stackoverflow.com/questions/5320205/matplotlib-text-dimensions – armatita

+0

是的!非常感谢!这将节省我几个小时的时间。如果你想发布这个答案,我会很乐意接受它。 –

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(),因为它在我尝试时不起作用。无论如何,如果我可以在所有图表中实现这一点,它将为我节省无数个小时。非常感谢!

+1

不客气。您可能已经注意到,当您调整matplolib图的大小时,轴将重绘。这种转换并不适用于文本(或者它对你没有用处)。所以当你做一个情节时(无论你为什么定制),并试图调整大小,它会失去你试图维护的那些宝贵的平等空间。这就是为什么我认为这不是一个理想的解决方案的原因,但是如果对你的情节的大小有绝对控制权,那么它应该会有诀窍。 – armatita

+0

没关系。我想我明白你的意思。当我使宽度为10英寸而不是4时,间距(我设置为0.1)增加。对于具有给定宽度的给定情节,在我得到可行的东西之前,调整该值并不会太大。 –

+0

我发现如果我用这样的逗号分割一个字符串,我不必担心间距,因为我可以只包含分隔符之间的空格:a = str(“Group 1,vs。,Group 2(,sub1, )和(,sub2,)“)。split(',')... colors:c = ['black','red','black','green','black','blue','black '] –

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()