python画弯曲的线_python – matplotlib中的弯曲文本呈现

以下是我对这个问题的看法:

为了使图形在绘制后对图形调整具有鲁棒性,我从matplotlib.text派生了一个子类CurvedText. CurvedText对象采用x和y值数组形式的字符串和曲线.要显示的文本本身被剪切成单独的字符,每个字符都被添加到适当位置的图中.由于如果字符串为空,matplotlib.text不会绘制任何内容,而是用不可见的’a’替换所有空格.在调整数字时,重载的draw()调用update_positions()函数,该函数注意字符位置和方向保持正确.为了确保调用顺序(每个字符的draw()函数也将被调用),CurvedText对象还要注意每个字符的zorder高于它自己的zorder.按照我的示例

here,文本可以进行任何对齐.如果文本无法适应当前分辨率的曲线,则其余部分将被隐藏,但会在调整大小时显示.下面是带有应用程序示例的代码.

from matplotlib import pyplot as plt

from matplotlib import patches

from matplotlib import text as mtext

import numpy as np

import math

class CurvedText(mtext.Text):

"""

A text object that follows an arbitrary curve.

"""

def __init__(self, x, y, text, axes, **kwargs):

super(CurvedText, self).__init__(x[0],y[0],' ', **kwargs)

axes.add_artist(self)

##saving the curve:

self.__x = x

self.__y = y

self.__zorder = self.get_zorder()

##creating the text objects

self.__Characters = []

for c in text:

if c == ' ':

##make this an invisible 'a':

t = mtext.Text(0,0,'a')

t.set_alpha(0.0)

else:

t = mtext.Text(0,0,c, **kwargs)

#resetting unnecessary arguments

t.set_ha('center')

t.set_rotation(0)

t.set_zorder(self.__zorder +1)

self.__Characters.append((c,t))

axes.add_artist(t)

##overloading some member functions, to assure correct functionality

##on update

def set_zorder(self, zorder):

super(CurvedText, self).set_zorder(zorder)

self.__zorder = self.get_zorder()

for c,t in self.__Characters:

t.set_zorder(self.__zorder+1)

def draw(self, renderer, *args, **kwargs):

"""

Overload of the Text.draw() function. Do not do

do any drawing, but update the positions and rotation

angles of self.__Characters.

"""

self.update_positions(renderer)

def update_positions(self,renderer):

"""

Update positions and rotations of the individual text elements.

"""

#preparations

##determining the aspect ratio:

##from https://stackoverflow.com/a/42014041/2454357

##data limits

xlim = self.axes.get_xlim()

ylim = self.axes.get_ylim()

## Axis size on figure

figW, figH = self.axes.get_figure().get_size_inches()

## Ratio of display units

_, _, w, h = self.axes.get_position().bounds

##final aspect ratio

aspect = ((figW * w)/(figH * h))*(ylim[1]-ylim[0])/(xlim[1]-xlim[0])

#points of the curve in figure coordinates:

x_fig,y_fig = (

np.array(l) for l in zip(*self.axes.transData.transform([

(i,j) for i,j in zip(self.__x,self.__y)

]))

)

#point distances in figure coordinates

x_fig_dist = (x_fig[1:]-x_fig[:-1])

y_fig_dist = (y_fig[1:]-y_fig[:-1])

r_fig_dist = np.sqrt(x_fig_dist**2+y_fig_dist**2)

#arc length in figure coordinates

l_fig = np.insert(np.cumsum(r_fig_dist),0,0)

#angles in figure coordinates

rads = np.arctan2((y_fig[1:] - y_fig[:-1]),(x_fig[1:] - x_fig[:-1]))

degs = np.rad2deg(rads)

rel_pos = 10

for c,t in self.__Characters:

#finding the width of c:

t.set_rotation(0)

t.set_va('center')

bbox1 = t.get_window_extent(renderer=renderer)

w = bbox1.width

h = bbox1.height

#ignore all letters that don't fit:

if rel_pos+w/2 > l_fig[-1]:

t.set_alpha(0.0)

rel_pos += w

continue

elif c != ' ':

t.set_alpha(1.0)

#finding the two data points between which the horizontal

#center point of the character will be situated

#left and right indices:

il = np.where(rel_pos+w/2 >= l_fig)[0][-1]

ir = np.where(rel_pos+w/2 <= l_fig)[0][0]

#if we exactly hit a data point:

if ir == il:

ir += 1

#how much of the letter width was needed to find il:

used = l_fig[il]-rel_pos

rel_pos = l_fig[il]

#relative distance between il and ir where the center

#of the character will be

fraction = (w/2-used)/r_fig_dist[il]

##setting the character position in data coordinates:

##interpolate between the two points:

x = self.__x[il]+fraction*(self.__x[ir]-self.__x[il])

y = self.__y[il]+fraction*(self.__y[ir]-self.__y[il])

#getting the offset when setting correct vertical alignment

#in data coordinates

t.set_va(self.get_va())

bbox2 = t.get_window_extent(renderer=renderer)

bbox1d = self.axes.transData.inverted().transform(bbox1)

bbox2d = self.axes.transData.inverted().transform(bbox2)

dr = np.array(bbox2d[0]-bbox1d[0])

#the rotation/stretch matrix

rad = rads[il]

rot_mat = np.array([

[math.cos(rad), math.sin(rad)*aspect],

[-math.sin(rad)/aspect, math.cos(rad)]

])

##computing the offset vector of the rotated character

drp = np.dot(dr,rot_mat)

#setting final position and rotation:

t.set_position(np.array([x,y])+drp)

t.set_rotation(degs[il])

t.set_va('center')

t.set_ha('center')

#updating rel_pos to right edge of character

rel_pos += w-used

if __name__ == '__main__':

Figure, Axes = plt.subplots(2,2, figsize=(7,7), dpi=100)

N = 100

curves = [

[

np.linspace(0,1,N),

np.linspace(0,1,N),

],

[

np.linspace(0,2*np.pi,N),

np.sin(np.linspace(0,2*np.pi,N)),

],

[

-np.cos(np.linspace(0,2*np.pi,N)),

np.sin(np.linspace(0,2*np.pi,N)),

],

[

np.cos(np.linspace(0,2*np.pi,N)),

np.sin(np.linspace(0,2*np.pi,N)),

],

]

texts = [

'straight lines work the same as rotated text',

'wavy curves work well on the convex side',

'you even can annotate parametric curves',

'changing the plotting direction also changes text orientation',

]

for ax, curve, text in zip(Axes.reshape(-1), curves, texts):

#plotting the curve

ax.plot(*curve, color='b')

#adjusting plot limits

stretch = 0.2

xlim = ax.get_xlim()

w = xlim[1] - xlim[0]

ax.set_xlim([xlim[0]-stretch*w, xlim[1]+stretch*w])

ylim = ax.get_ylim()

h = ylim[1] - ylim[0]

ax.set_ylim([ylim[0]-stretch*h, ylim[1]+stretch*h])

#adding the text

text = CurvedText(

x = curve[0],

y = curve[1],

text=text,#'this this is a very, very long text',

va = 'bottom',

axes = ax, ##calls ax.add_artist in __init__

)

plt.show()

结果如下:

当文本遵循急剧弯曲曲线的凹面时,仍然存在一些问题.这是因为字符沿曲线“拼接”在一起而不考虑重叠.如果我有时间,我会尽力改进.任何评论都非常欢迎.

在python 3.5和2.7上测试过

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值