Matplotlib手绘曲线

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







image-20210325221531635.png

手绘图数据

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,589评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,615评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,933评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,976评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,999评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,775评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,474评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,359评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,854评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,007评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,146评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,826评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,484评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,029评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,153评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,420评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,107评论 2 356

推荐阅读更多精彩内容