Matplotlib Multi-colored Title (Text) - 在实践中
Matplotlib Multi-colored Title (Text) - in practice
有一个示例 here 说明如何创建 multi-colored 文本标题。
但是,我想将其应用于已经有人物的情节。
例如,如果我将它应用到这个(与示例相同的代码减去一些额外内容和另一个数字)...:[=14=]
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'",还有哪些其他选项? 'dots' 是 1/72 英寸(这是 Matplotlib 的默认值吗?)?
如何将单位从点转换为英寸?
提前致谢!
事实上,文本的边界框采用的单位与散点图中使用的单位不同。文本是一种不同类型的对象,如果您调整 window 的大小或更改比例,它会以某种方式重绘。通过稳定 window,您可以以绘图单位询问边界框的坐标,并以此方式构建彩色文本:
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()
,结果为:
然而,这仍然不理想,因为您需要不断控制绘图轴的大小以获得单词之间的正确 spaces。这有点武断,但如果你设法用这样的控件来编写你的程序,那么使用绘图单位来实现你的预期目的是可行的。
原版POST:
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
)。另请注意,在我的 show 示例中,我直接控制应该显示哪个 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'
编辑:显然文本边界框的范围存在某种问题,没有给出正确的单词宽度,因此单词之间的 space 不稳定。我的建议是使用 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
@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 个图和 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()
有一个示例 here 说明如何创建 multi-colored 文本标题。
但是,我想将其应用于已经有人物的情节。
例如,如果我将它应用到这个(与示例相同的代码减去一些额外内容和另一个数字)...:[=14=]
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'",还有哪些其他选项? 'dots' 是 1/72 英寸(这是 Matplotlib 的默认值吗?)?
如何将单位从点转换为英寸?
提前致谢!
事实上,文本的边界框采用的单位与散点图中使用的单位不同。文本是一种不同类型的对象,如果您调整 window 的大小或更改比例,它会以某种方式重绘。通过稳定 window,您可以以绘图单位询问边界框的坐标,并以此方式构建彩色文本:
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()
,结果为:
然而,这仍然不理想,因为您需要不断控制绘图轴的大小以获得单词之间的正确 spaces。这有点武断,但如果你设法用这样的控件来编写你的程序,那么使用绘图单位来实现你的预期目的是可行的。
原版POST:
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
)。另请注意,在我的 show 示例中,我直接控制应该显示哪个 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'
编辑:显然文本边界框的范围存在某种问题,没有给出正确的单词宽度,因此单词之间的 space 不稳定。我的建议是使用 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
@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 个图和 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()