2016-03-28 33 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()