Python如何生成樹形圖案
本文實(shí)例為大家分享了Python生成樹形圖案的具體代碼,供大家參考,具體內(nèi)容如下
先看一下效果,見下圖。
上面這顆大樹是使用Python + Tkinter繪制的,主要原理為使用分形畫樹干、樹枝,最終葉節(jié)點(diǎn)上畫上綠色圓圈代表樹葉。當(dāng)然,為了看起來更真實(shí),繪制過程中也加入了一些隨機(jī)變化,比如樹枝會(huì)稍微有些扭曲而不是一條直線,分叉的角度、長短等都會(huì)隨機(jī)地作一些偏移等。
以下是完整源代碼:
# -*- coding: utf-8 -*- import Tkinter import sys, random, math class Point(object): def __init__(self, x, y): self.x = x self.y = y def __str__(self): return "<Point>: (%f, %f)" % (self.x, self.y) class Branch(object): def __init__(self, bottom, top, branches, level = 0): self.bottom = bottom self.top = top self.level = level self.branches = branches self.children = [] def __str__(self): s = "Top: %s, Bottom: %s, Children Count: %d" % / (self.top, self.bottom, len(self.children)) return s def nextGen(self, n = -1, rnd = 1): if n <= 0: n = self.branches if rnd == 1: n = random.randint(n / 2, n * 2) if n <= 0: n = 1 dx = self.top.x - self.bottom.x dy = self.top.y - self.bottom.y r = 0.20 + random.random() * 0.2 if self.top.x == self.bottom.x: # 如果是一條豎線 x = self.top.x y = dy * r + self.bottom.y elif self.top.y == self.bottom.y: # 如果是一條橫線 x = dx * r + self.bottom.x y = self.top.y else: x = dx * r y = x * dy / dx x += self.bottom.x y += self.bottom.y oldTop = self.top self.top = Point(x, y) a = math.pi / (2 * n) for i in range(n): a2 = -a * (n - 1) / 2 + a * i - math.pi a2 *= 0.9 + random.random() * 0.2 self.children.append(self.mkNewBranch(self.top, oldTop, a2)) def mkNewBranch(self, bottom, top, a): dx1 = top.x - bottom.x dy1 = top.y - bottom.y r = 0.9 + random.random() * 0.2 c = math.sqrt(dx1 ** 2 + dy1 ** 2) * r if dx1 == 0: a2 = math.pi / 2 else: a2 = math.atan(dy1 / dx1) if (a2 < 0 and bottom.y > top.y) / or (a2 > 0 and bottom.y < top.y) / : a2 += math.pi b = a2 - a dx2 = c * math.cos(b) dy2 = c * math.sin(b) newTop = Point(dx2 + bottom.x, dy2 + bottom.y) return Branch(bottom, newTop, self.branches, self.level + 1) class Tree(object): def __init__(self, root, canvas, bottom, top, branches = 3, depth = 3): self.root = root self.canvas = canvas self.bottom = bottom self.top = top self.branches = branches self.depth = depth self.new() def gen(self, n = 1): for i in range(n): self.getLeaves() for node in self.leaves: node.nextGen() self.show() def new(self): self.leavesCount = 0 self.branch = Branch(self.bottom, self.top, self.branches) self.gen(self.depth) print "leaves count: %d" % self.leavesCount def chgDepth(self, d): self.depth += d if self.depth < 0: self.depth = 0 if self.depth > 10: self.depth = 10 self.new() def chgBranch(self, d): self.branches += d if self.branches < 1: self.branches = 1 if self.branches > 10: self.branches = 10 self.new() def getLeaves(self): self.leaves = [] self.map(self.findLeaf) def findLeaf(self, node): if len(node.children) == 0: self.leaves.append(node) def show(self): for i in self.canvas.find_all(): self.canvas.delete(i) self.map(self.drawNode) self.canvas.tag_raise("leaf") def exit(self, evt): sys.exit(0) def map(self, func = lambda node: node): # 遍歷樹 children = [self.branch] while len(children) != 0: newChildren = [] for node in children: func(node) newChildren.extend(node.children) children = newChildren def drawNode(self, node): self.line2( # self.canvas.create_line( node.bottom.x, node.bottom.y, node.top.x, node.top.y, fill = "#100", width = 1.5 ** (self.depth - node.level), tags = "branch level_%d" % node.level, ) if len(node.children) == 0: # 畫葉子 self.leavesCount += 1 self.canvas.create_oval( node.top.x - 3, node.top.y - 3, node.top.x + 3, node.top.y + 3, fill = "#090", tag = "leaf", ) self.canvas.update() def line2(self, x0, y0, x1, y1, width = 1, fill = "#000", minDist = 10, tags = ""): dots = midDots(x0, y0, x1, y1, minDist) dots2 = [] for i in range(len(dots) - 1): dots2.extend([dots[i].x, dots[i].y, dots[i + 1].x, dots[i + 1].y]) self.canvas.create_line( dots2, fill = fill, width = width, smooth = True, tags = tags, ) def midDots(x0, y0, x1, y1, d): dots = [] dx, dy, r = x1 - x0, y1 - y0, 0 if dx != 0: r = float(dy) / dx c = math.sqrt(dx ** 2 + dy ** 2) n = int(c / d) + 1 for i in range(n): if dx != 0: x = dx * i / n y = x * r else: x = dx y = dy * i / n if i > 0: x += d * (0.5 - random.random()) * 0.25 y += d * (0.5 - random.random()) * 0.25 x += x0 y += y0 dots.append(Point(x, y)) dots.append(Point(x1, y1)) return dots if __name__ == "__main__": root = Tkinter.Tk() root.title("Tree") gw, gh = 800, 600 canvas = Tkinter.Canvas(root, width = gw, height = gh, ) canvas.pack() tree = Tree(root, canvas, Point(gw / 2, gh - 20), Point(gw / 2, gh * 0.2), / branches = 2, depth = 8) root.bind("n", lambda evt: tree.new()) root.bind("=", lambda evt: tree.chgDepth(1)) root.bind("+", lambda evt: tree.chgDepth(1)) root.bind("-", lambda evt: tree.chgDepth(-1)) root.bind("b", lambda evt: tree.chgBranch(1)) root.bind("c", lambda evt: tree.chgBranch(-1)) root.bind("q", tree.exit) root.mainloop()
因?yàn)槊看紊傻臉涠际请S機(jī)的,所以你生成的樹和上圖會(huì)不太一樣,可能會(huì)更為枝繁葉茂,也可能會(huì)看起來才剛剛發(fā)芽。程序中綁定了若干快捷鍵,比如“n”是隨機(jī)產(chǎn)生一顆新的樹,“q”是退出程序。另外還有一些不太常用的快捷鍵,如“+”/“-”是增加/減少樹的深度,“b”/“c”分別代表更多/更少的分叉,需要注意的是,增加深度或分叉可能需要更多的計(jì)算時(shí)間。
從這次樹形圖案的繪制過程中,我也有一些有趣的發(fā)現(xiàn),比如,樹枝上某一處的橫截面寬度與它與樹根之間的距離似乎呈一種指數(shù)函數(shù)的關(guān)系。如用H表示樹的總高度,h表示樹枝上某一點(diǎn)的高度,w表示這一點(diǎn)橫截面的寬度,那么w與h之間似乎存在這樣一種關(guān)系:w = a * b ^ (H - h) + c,這兒a、b、c都是常數(shù)。當(dāng)然,這只是一個(gè)猜測,因?yàn)槔L制的過程中我發(fā)現(xiàn)當(dāng)w與h滿足這樣關(guān)系時(shí)畫出來的圖案看起來最“自然”,這個(gè)問題或許下次可以再深入研究一下。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
python基礎(chǔ)教程之popen函數(shù)操作其它程序的輸入和輸出示例
popen函數(shù)允許一個(gè)程序?qū)⒘硪粋€(gè)程序作為新進(jìn)程啟動(dòng),并可以傳遞數(shù)據(jù)給它或者通過它接收數(shù)據(jù),下面使用示例學(xué)習(xí)一下他的使用方法2014-02-02使用Python3中的gettext模塊翻譯Python源碼以支持多語言
這篇文章主要介紹了使用Python3中的gettext模塊翻譯Python源碼以支持多語言,其中翻譯Python源碼只是作為示例以展示gettext的功能和用法,需要的朋友可以參考下2015-03-03langchain使用自定義example?selector示例解析
這篇文章主要為大家介紹了langchain使用自定義example?selector示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08將string類型的數(shù)據(jù)類型轉(zhuǎn)換為spark rdd時(shí)報(bào)錯(cuò)的解決方法
今天小編就為大家分享一篇關(guān)于將string類型的數(shù)據(jù)類型轉(zhuǎn)換為spark rdd時(shí)報(bào)錯(cuò)的解決方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-02-02Python搭建自己IP代理池的方法實(shí)現(xiàn)
本文主要介紹了Python搭建自己IP代理池的方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-02-02Django用戶登錄與注冊系統(tǒng)的實(shí)現(xiàn)示例
這篇文章主要介紹了Django用戶登錄與注冊系統(tǒng)的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06python安裝包出現(xiàn)Retrying?(Retry(total=4,?connect=None,?read=No
這篇文章主要給大家介紹了關(guān)于python安裝包出現(xiàn)Retrying?(Retry(total=4,?connect=None,?read=None,?redirect=None,?status=None))問題的解決方法,需要的朋友可以參考下2022-09-09