Python如何生成树形图案


Posted in Python onJanuary 03, 2018

本文实例为大家分享了Python生成树形图案的具体代码,供大家参考,具体内容如下

先看一下效果,见下图。

Python如何生成树形图案

上面这颗大树是使用Python + Tkinter绘制的,主要原理为使用分形画树干、树枝,最终叶节点上画上绿色圆圈代表树叶。当然,为了看起来更真实,绘制过程中也加入了一些随机变化,比如树枝会稍微有些扭曲而不是一条直线,分叉的角度、长短等都会随机地作一些偏移等。

以下是完整源代码:

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

因为每次生成的树都是随机的,所以你生成的树和上图会不太一样,可能会更为枝繁叶茂,也可能会看起来才刚刚发芽。程序中绑定了若干快捷键,比如“n”是随机产生一颗新的树,“q”是退出程序。另外还有一些不太常用的快捷键,如“+”/“-”是增加/减少树的深度,“b”/“c”分别代表更多/更少的分叉,需要注意的是,增加深度或分叉可能需要更多的计算时间。

从这次树形图案的绘制过程中,我也有一些有趣的发现,比如,树枝上某一处的横截面宽度与它与树根之间的距离似乎呈一种指数函数的关系。如用H表示树的总高度,h表示树枝上某一点的高度,w表示这一点横截面的宽度,那么w与h之间似乎存在这样一种关系:w = a * b ^ (H - h) + c,这儿a、b、c都是常数。当然,这只是一个猜测,因为绘制的过程中我发现当w与h满足这样关系时画出来的图案看起来最“自然”,这个问题或许下次可以再深入研究一下。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中为feedparser设置超时时间避免堵塞
Sep 28 Python
python查找目录下指定扩展名的文件实例
Apr 01 Python
Python的Flask框架中使用Flask-Migrate扩展迁移数据库的教程
Jun 14 Python
python实现各种插值法(数值分析)
Jul 30 Python
Python利用WMI实现ping命令的例子
Aug 14 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
Sep 10 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
Feb 11 Python
pytorch实现CNN卷积神经网络
Feb 19 Python
Python面向对象魔法方法和单例模块代码实例
Mar 25 Python
Python实现一个简单的毕业生信息管理系统的示例代码
Jun 08 Python
python cv2.resize函数high和width注意事项说明
Jul 05 Python
python给视频添加背景音乐并改变音量的具体方法
Jul 19 Python
Python爬取十篇新闻统计TF-IDF
Jan 03 #Python
Python制作词云的方法
Jan 03 #Python
Python读取Json字典写入Excel表格的方法
Jan 03 #Python
python基于ID3思想的决策树
Jan 03 #Python
python遍历文件夹下所有excel文件
Jan 03 #Python
Python将多份excel表格整理成一份表格
Jan 03 #Python
Python将多个excel文件合并为一个文件
Jan 03 #Python
You might like
一个查看session内容的函数
2006/10/09 PHP
使用sockets:从新闻组中获取文章(二)
2006/10/09 PHP
php侧拉菜单 漂亮,可以向右或者向左展开,支持FF,IE
2009/10/15 PHP
一个PHP分页类的代码
2011/05/18 PHP
php实现的PDO异常处理操作分析
2018/12/27 PHP
PHP htmlspecialchars_decode()函数用法讲解
2019/03/01 PHP
JQuery 小练习(实例代码)
2009/08/07 Javascript
JavaScript 学习笔记一些小技巧
2010/03/28 Javascript
jQuery Ajax提交表单查询获得数据实例代码
2012/09/19 Javascript
JQuery给元素绑定click事件多次执行的解决方法
2014/05/29 Javascript
javascript实现限制上传文件大小
2015/02/06 Javascript
javaScript实现可缩放的显示区效果代码
2015/10/26 Javascript
jQuery实现放大镜效果实例代码
2016/03/17 Javascript
Javascript中浏览器窗口的基本操作总结
2016/08/18 Javascript
vue-dialog的弹出层组件
2020/05/25 Javascript
js学习总结之DOM2兼容处理重复问题的解决方法
2017/07/27 Javascript
原生JavaScrpit中异步请求Ajax实现方法
2017/11/03 Javascript
微信小程序中使用 async/await的方法实例分析
2020/05/06 Javascript
Element MessageBox弹框的具体使用
2020/07/27 Javascript
将Python代码嵌入C++程序进行编写的实例
2015/07/31 Python
使用tensorflow实现AlexNet
2017/11/20 Python
python format 格式化输出方法
2018/07/16 Python
Pyqt5实现英文学习词典
2019/06/24 Python
python模拟键盘输入 切换键盘布局过程解析
2019/08/15 Python
Tensorflow全局设置可见GPU编号操作
2020/06/30 Python
python 实现数据库中数据添加、查询与更新的示例代码
2020/12/07 Python
西班牙在线宠物食品和配件商店:bitiba
2019/10/11 全球购物
什么时候需要进行强制类型转换
2016/09/03 面试题
关键字throw与throws的用法差异
2016/11/22 面试题
财务会计实习报告体会
2013/12/20 职场文书
冰淇淋店的创业计划书
2014/02/07 职场文书
经典婚礼主持词
2014/03/13 职场文书
户外宣传策划方案
2014/05/25 职场文书
沙滩主题婚礼活动策划方案
2014/09/15 职场文书
企业法人代表证明书
2015/06/18 职场文书
签字仪式主持词
2015/07/03 职场文书