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 相关文章推荐
Linux环境下MySQL-python安装过程分享
Feb 02 Python
Python实现简单的代理服务器
Jul 25 Python
Python中pow()和math.pow()函数用法示例
Feb 11 Python
Python利用pandas计算多个CSV文件数据值的实例
Apr 19 Python
Python把对应格式的csv文件转换成字典类型存储脚本的方法
Feb 12 Python
Python之NumPy(axis=0 与axis=1)区分详解
May 27 Python
树莓派极简安装OpenCv的方法步骤
Oct 10 Python
浅谈tensorflow 中tf.concat()的使用
Feb 07 Python
Python3.9 beta2版本发布了,看看这7个新的PEP都是什么
Jun 10 Python
Python接收手机短信的代码整理
Aug 02 Python
Python调用ffmpeg开源视频处理库,批量处理视频
Nov 16 Python
2020年10款优秀的Python第三方库,看看有你中意的吗?
Jan 12 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
解析PHP正则提取或替换img标记属性
2013/06/26 PHP
smarty中post用法实例
2014/11/28 PHP
php正则去除网页中所有的html,js,css,注释的实现方法
2016/11/03 PHP
laravel excel 上传文件保存到本地服务器功能
2019/11/14 PHP
html中使用javascript调用本地程序(exe、doc等)实现代码
2013/04/26 Javascript
jquery中的事件处理详细介绍
2013/06/24 Javascript
使用EVAL处理jqchart jquery 折线图返回数据无效的解决办法
2015/11/26 Javascript
纯JavaScript基于notie.js插件实现消息提示特效
2016/01/18 Javascript
javascript显示上周、上个月日期的处理方法
2016/02/03 Javascript
JavaScript中判断数据类型的方法总结
2016/05/24 Javascript
JS中使用apply方法通过不同数量的参数调用函数的方法
2016/05/31 Javascript
学习Node.js模块机制
2016/10/17 Javascript
vuejs如何配置less
2017/04/25 Javascript
Swiper自定义分页器使用详解
2017/12/28 Javascript
React 组件间的通信示例
2018/06/14 Javascript
基于ts的动态接口数据配置的详解
2019/12/18 Javascript
微信小程序基于ColorUI构建皮皮虾短视频去水印组件
2020/11/04 Javascript
[36:19]2018DOTA2亚洲邀请赛 小组赛 A组加赛 Newbee vs LGD
2018/04/03 DOTA
详解Django中间件的5种自定义方法
2018/07/26 Python
Python实现Event回调机制的方法
2019/02/13 Python
使用Python自动化破解自定义字体混淆信息的方法实例
2019/02/13 Python
基于wxPython的GUI实现输入对话框(2)
2019/02/27 Python
Python argparse模块使用方法解析
2020/02/20 Python
3分钟看懂Python后端必须知道的Django的信号机制
2020/07/26 Python
利用Bootstrap实现漂亮简洁的CSS3价格表实例源码
2017/03/02 HTML / CSS
什么是Deployment descriptors;都有什么类型的部署描述符
2015/07/28 面试题
五星级酒店餐饮部总监的标准岗位职责
2014/02/17 职场文书
安全生产承诺书
2014/03/26 职场文书
医院领导班子查摆问题对照检查材料思想汇报
2014/10/08 职场文书
2014年党支部工作总结
2014/11/13 职场文书
小学班主任评语
2014/12/29 职场文书
教师工作能力自我评价
2015/03/04 职场文书
小学国庆节活动总结
2015/03/23 职场文书
红色经典观后感
2015/06/18 职场文书
课改心得体会范文
2016/01/25 职场文书
oracle通过存储过程上传list保存功能
2021/05/12 Oracle