Matplotlib手绘曲线
代码:
from matplotlib import pyplot as plt
# 支持中文
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
class LineDrawer(object):
def __init__(self, line, axis, figure): # 将line(Line2D(matplotlib.artist.Artist)作为该类的一个属性,该类只做好数据处理与传递工作
self.line = line
self.axis = axis
self.figure = figure
# 用于拖拽坐标(AxesSubplot(SubplotBase, matplotlib.axes._axes.Axes))
self.press = None
self.cur_xlim = None
self.cur_ylim = None
self.x0 = None
self.y0 = None
self.x1 = None
self.y1 = None
self.xpress = None
self.ypress = None
# 用于将坐标点的存储
self.lines_x_list = [] # 各分段的总数据
self.lines_y_list = [] # 各分段的总数据
# 撤回的回收线段
self.undo_lines_x_list = []
self.undo_lines_y_list = []
#self.xs = list(line.get_xdata()) # xs属于自定义变量名
#self.ys = list(line.get_ydata())
self.cid_press = self.line.figure.canvas.mpl_connect('button_press_event', self.onPress) # 按下鼠标三键
self.cid_release = self.line.figure.canvas.mpl_connect('button_release_event', self.onRelease) # 释放鼠标三键
#self.cid_release = self.line.figure.canvas.mpl_connect('scroll_event', self.zoom_factory) # 滚轮
def Get_lines_xy_show_From_lines_xy_list(self):
#print(len(self.lines_x_list), len(self.lines_y_list))
self.lines_x_show = [] # 取出已经画好的n段曲线
self.lines_y_show = [] # 取出已经画好的n段曲线
for l in self.lines_x_list:
for x in l:
self.lines_x_show.append(x)
for l in self.lines_y_list:
for y in l:
self.lines_y_show.append(y)
def onPress(self, event):
if event.button == 3: # 鼠标右键 手绘图
self.cid_motion = self.figure.canvas.mpl_connect("motion_notify_event", self.mouse_move)
self.xdata_this_move = []
self.ydata_this_move = []
self.Get_lines_xy_show_From_lines_xy_list()
elif event.button == 2: # 鼠标中键
if not event.dblclick: #单击鼠标中键 撤回(撤销最后一段)
try:
#print(len(self.lines_x_list), len(self.lines_y_list))
self.undo_lines_x_list.append(self.lines_x_list.pop(-1)) # 回收
self.undo_lines_y_list.append(self.lines_y_list.pop(-1)) # 回收
except IndexError:
return
else:#双击鼠标中键 取消撤回
'''
try:
#print(len(self.lines_x_list), len(self.lines_y_list))
self.lines_x_list.append(self.undo_lines_x_list.pop(-1)) # 取消撤回
self.lines_y_list.append(self.undo_lines_y_list.pop(-1)) # 取消撤回
except IndexError:
return
'''
pass
self.Get_lines_xy_show_From_lines_xy_list()
#print(len(self.lines_x_show), len(self.lines_y_show))
self.line.set_data(self.lines_x_show, self.lines_y_show) # 连接各段,全部画出来
#self.line.figure.canvas.get_renderer(cleared=True)
self.line.figure.canvas.draw_idle()
def mouse_move(self, event):
self.xdata_this_move.append(event.xdata)
self.ydata_this_move.append(event.ydata)
self.lines_x_show.append(event.xdata)
self.lines_y_show.append(event.ydata)
self.line.set_data(self.lines_x_show, self.lines_y_show) # 连接各段,全部画出来
self.line.figure.canvas.draw_idle() # 数据重画
def onRelease(self, event):
if event.button == 3: # 鼠标右键 手绘图
self.cid_release = self.figure.canvas.mpl_disconnect(self.cid_motion)
self.lines_x_list.append(self.xdata_this_move) # 释放后添加本次运动的x点
self.lines_y_list.append(self.ydata_this_move) # 释放后添加本次运动的y点
#print(self.xdata_this_move, self.ydata_this_move, '\n==================\n\n')
# 缩放
def zoom_factory(self, base_scale=1.1):
# ax (AxesSubplot(SubplotBase, matplotlib.axes._axes.Axes))
def zoom(event):
cur_xlim = self.axis.get_xlim()
cur_ylim = self.axis.get_ylim()
xdata = event.xdata # get event x location
ydata = event.ydata # get event y location
if event.button == 'down':
# deal with zoom in
scale_factor = 1 / base_scale
elif event.button == 'up':
# deal with zoom out
scale_factor = base_scale
else:
# deal with something that should never happen
scale_factor = 1
#print(event.button)
new_width = (cur_xlim[1] - cur_xlim[0]) * scale_factor
new_height = (cur_ylim[1] - cur_ylim[0]) * scale_factor
relx = (cur_xlim[1] - xdata)/(cur_xlim[1] - cur_xlim[0])
rely = (cur_ylim[1] - ydata)/(cur_ylim[1] - cur_ylim[0])
self.axis.set_xlim([xdata - new_width * (1-relx), xdata + new_width * (relx)])
self.axis.set_ylim([ydata - new_height * (1-rely), ydata + new_height * (rely)])
self.axis.figure.canvas.draw() # 数据重画
#fig = self.axis.get_figure() # get the figure of interest
self.figure.canvas.mpl_connect('scroll_event', zoom)
return zoom
# 左键拖动
def pan_factory(self):
def onPress(event):
if event.button == 1:
if event.inaxes != self.axis: return
self.cur_xlim = self.axis.get_xlim()
self.cur_ylim = self.axis.get_ylim()
self.press = self.x0, self.y0, event.xdata, event.ydata
self.x0, self.y0, self.xpress, self.ypress = self.press
def onRelease(event):
self.press = None
self.axis.figure.canvas.draw() # 数据重画
def onMotion(event):
if self.press is None: return
if event.inaxes != self.axis: return
dx = event.xdata - self.xpress
dy = event.ydata - self.ypress
self.cur_xlim -= dx
self.cur_ylim -= dy
self.axis.set_xlim(self.cur_xlim)
self.axis.set_ylim(self.cur_ylim)
self.axis.figure.canvas.draw() # 数据重画
#fig = self.axis.get_figure() # get the figure of interest
# attach the call back
self.figure.canvas.mpl_connect('button_press_event',onPress)
self.figure.canvas.mpl_connect('button_release_event',onRelease)
self.figure.canvas.mpl_connect('motion_notify_event',onMotion)
#return the function
return onMotion
def main():
l = [500, 657, 814, 971, 1128, 1285, 1442, 1599, 1756, 1913, 2070, 1913, 1756, 1599, 1442, 1285, 1128, 971, 814, 657, 500, 1518, 575, 1725, 500]
X = []
Y = []
n = 0
for i in l:
for j in range(120):
n += 1
X.append(n)
Y.append(i)
fig = plt.figure()
ax = fig.add_subplot(111) # class AxesSubplot(SubplotBase, matplotlib.axes._axes.Axes)
ax.set_title('Matplotlib手绘曲线')
line_fix, = ax.plot(X, Y, lw='0.5')
line_draw_by_hand, = ax.plot([], [], lw=1)
linebuilder = LineDrawer(line=line_draw_by_hand, axis=ax, figure=fig)
figZoom = linebuilder.zoom_factory(base_scale = 1.1)
figPan = linebuilder.pan_factory()
plt.show()
# 关闭图像后, 再执行以下代码
X_line_draw = []
Y_line_draw = []
for l in linebuilder.lines_x_list:
for i in l:
X_line_draw.append(i)
for l in linebuilder.lines_y_list:
for i in l:
Y_line_draw.append(i)
out = open('手绘数据.txt', 'w', encoding='utf8')
for i in range(len(X_line_draw)):
x = X_line_draw[i]
y = Y_line_draw[i]
out.write(f'{x}\t{y}\n')
out.close()
if __name__ == '__main__':
main()
手绘图数据
25.638961693548367 546.1584093872231
36.72397513440853 557.8551871856957
50.580241935483855 563.7035760849321
50.580241935483855 560.7793816353139
50.580241935483855 554.9309927360775
64.43650873655906 563.7035760849321
147.57410954301065 657.2777984727138
216.85544354838703 762.5487986589683
214.084190188172 762.5487986589683
208.5416834677419 756.7004097597319
214.084190188172 791.79074315515
244.56797715053756 891.2133544421681
261.1954973118279 917.5311044887317
261.1954973118279 891.2133544421681
297.2217909946236 867.8197988452226
336.01933803763427 929.2278822872045
358.1893649193547 1025.7262991246043
363.7318716397848 1034.498882473459
380.35939180107505 1008.1811324268953
408.0719254032257 1014.0295213261317
424.69944556451594 1028.6504935742225
546.6345934139782 1163.1634382566588
627.0009408602149 1300.6005773887132
657.4847278225806 1326.9183274352768
660.2559811827956 1312.297355187186
665.7984879032257 1312.297355187186
693.5110215053761 1411.719966474204
723.9948084677418 1502.3699944123675
746.1648353494621 1458.5070776680948
779.4198756720428 1402.9473831253495
796.0473958333331 1423.4167442726766
832.0736895161289 1522.8393555596947
895.812516801075 1654.428105792513
912.4400369623653 1669.0490780406037
915.2112903225803 1651.5039113428948
948.4663306451611 1677.8216613894583
1017.7476646505373 1753.850717079531
1120.2840389784942 1873.7426895138763
1167.3953461021501 1914.6814118085308
1178.4803595430103 1879.5910784131127
1192.3366263440857 1870.818495064258
1220.0491599462362 1917.605606258149
1231.1341733870963 1929.3023840566216
1239.4479334677417 1926.3781896070034
1727.1885248655913 1505.2941888619857
1724.417271505376 1484.8248277146586
1724.417271505376 1478.9764388154222
1735.5022849462362 1473.1280499161858
1763.2148185483866 1493.597411063513
1782.613592069892 1443.886105420004
1824.182392473118 1297.676382939095
1838.0386592741934 1318.1457440864224
1879.6074596774188 1373.7054386291677
1907.3199932795696 1332.7667163345131
1943.3462869623654 1291.8279940398586
1932.2612735215048 1280.131216241386
2084.6802083333328 970.1666045818589
2106.8502352150535 920.4552989383499
2112.3927419354836 917.5311044887317
2156.7327956989243 926.3036878375863
2167.8178091397845 926.3036878375863
2228.785383064516 911.6827155894954
2298.066717069892 891.2133544421681
2300.837970430107 894.1375488917863
主页:https://www.zhihu.com/people/caviar126