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满足这样关系时画出来的图案看起来最“自然”,这个问题或许下次可以再深入研究一下。

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

(0)

相关推荐

  • Python3计算三角形的面积代码

    关于Python语言,众说纷纭,但无外乎两种,强大,垃圾.大多数人还是对Python持肯定意见,认为它很强大.前些天和两个的大学同学聊天,一个是在做手机测试,一个是给银行系统做维护一类的工作,都在北京.都在一边工作一边学习,其中一个学的就是Python.我也不能落后啊,走上了Python的不归路.我个人觉得对广大编程爱好者来说,尤其是在校大学生,大家可以有时间学习一门语言,对以后是很有帮助的. 以下实例为通过用户输入三角形三边长度,并计算三角形的面积: # -*- coding: UTF-8 -

  • python绘制双柱形图代码实例

    图表是比干巴巴的表格更直观的表达,简洁.有力.工作中经常遇到的场景是,有一些数值需要定时的监控,比如服务器的连接数.活跃用户数.点击某个按钮的人数,并且通过邮件或者网页展示出来.当我们想关注比数值本身更多的信息(像数值的变化.对比或异常),图表就非常有用了.把数值转化为图片要依赖第三方库的帮忙,在Python之中最好的图表库叫matplotlib.(一直觉得,Python最大的优势就是丰富的第三方库,让你能轻易实现各种需求) matplotlib,顾名思义就是提供了一整套和matlab相似的AP

  • python绘制条形图方法代码详解

    1.首先要绘制一个简单的条形图 import numpy as np import matplotlib.pyplot as plt from matplotlib import mlab from matplotlib import rcParams fig1 = plt.figure(2) rects =plt.bar(left = (0.2,1),height = (1,0.5),width = 0.2,align="center",yerr=0.000001) plt.titl

  • 基于Python的Android图形解锁程序详解

    安卓手机的图形锁是3x3的点阵,按次序连接数个点从而达到锁定/解锁的功能.最少需要连接4个点,最多能连接9个点.网上也有暴力删除手机图形锁的方法,即直接干掉图形锁功能.但假如你想进入别人的手机,但又不想引起其警觉的话--你可以参考一下本文(前提条件:手机需要root,而且打开调试模式.一般来讲,如果用过诸如"豌豆荚手机助手"."360手机助手"一类的软件,都会被要求打开调试模式的.如果要删除手机内置软件,则需要将手机root). 首先科普一下,安卓手机是如何标记这9

  • Python如何生成树形图案

    本文实例为大家分享了Python生成树形图案的具体代码,供大家参考,具体内容如下 先看一下效果,见下图. 上面这颗大树是使用Python + Tkinter绘制的,主要原理为使用分形画树干.树枝,最终叶节点上画上绿色圆圈代表树叶.当然,为了看起来更真实,绘制过程中也加入了一些随机变化,比如树枝会稍微有些扭曲而不是一条直线,分叉的角度.长短等都会随机地作一些偏移等. 以下是完整源代码: # -*- coding: utf-8 -*- import Tkinter import sys, rando

  • python 生成器生成杨辉三角的方法(必看)

    用Python写趣味程序感觉屌屌的,停不下来 #生成器生成展示杨辉三角 #原理是在一个2维数组里展示杨辉三角,空的地方用0,输出时,转化为' ' def yang(line): n,leng=0,2*line - 1 f_list = list(range(leng+2)) #预先分配,insert初始胡会拖慢速度,最底下一行,左右也有1个空格 #全部初始化为0 for i,v in enumerate(f_list): f_list[v] = 0 ZEROLIST = f_list[:] #预

  • ASP.NET生成树形显示的GridView实现思路

    目的:生成树形结构的表格数据(EasyUI也有TreeGrid,此处只是提供一个思路),可以扩展单击展开/收缩节点 图例: 类代码: 复制代码 代码如下: using System; using System.Data; /// <summary> ///GridViewHelper 的摘要说明 /// </summary> public class GridViewHelper { private string gridline; //连接线 private DataTable

  • asp.net TreeView递归循环子节点生成树形菜单实例

    本文实例讲述了asp.net TreeView递归循环子节点生成树形菜单的方法.分享给大家供大家参考,具体如下: 这里主要用到递归循环获取子结点 /// <summary> /// 生成根节点 /// </summary> /// <param name="treeview"></param> protected void BindTreeView(long ID, TreeView treeview) { DataTable dt =

  • php从数据库查询结果生成树形列表的方法

    本文实例讲述了php从数据库查询结果生成树形列表的方法.分享给大家供大家参考.具体分析如下: 本代码可以从数据库读取数据生成一个类似于windows的资源管理器的树形列表 <?php /* Here are the database definitions (for Solid) that i use in this code. * It should not be hard to adapt it to another database. */ /* CREATE TABLE dirent_t

  • 利用Python批量生成任意尺寸的图片

    实现效果 通过源图片,在当前工作目录的/img目录下生成1000张,分别从1*1到1000*1000像素的图片. 效果如下: 目录结构 实现示例 # -*- coding: utf-8 -*- import threading from PIL import Image image_size = range(1, 1001) def start(): for size in image_size: t = threading.Thread(target=create_image, args=(s

  • Python随机生成彩票号码的方法

    本文实例讲述了Python随机生成彩票号码的方法.分享给大家供大家参考.具体如下: 前些日子在淘宝上买了一阵子彩票,每次都是使用淘宝的机选,每次一注.后来觉得不如自己写一个机选的程序有意思 1. xuanhao.py文件 import random def getResultStr(totalCount, resultCount): elements = [x + 1 for x in range(totalCount)] retStr = '' for i in range(resultCou

  • Python编程生成随机用户名及密码的方法示例

    本文实例讲述了Python编程生成随机用户名及密码的方法.分享给大家供大家参考,具体如下: 方案一: import random global userName,userPassword #为了便于使用,定义为全局变量 userName = '' userPassword = '' def get_userNameAndPassword(): global userName, userPassword usableName_char = "1234567890abcdefghijklmnopqr

  • Python中生成Epoch的方法

    在Python2中datetime对象没有timestamp方法,不能很方便的生成epoch,现有方法没有处理很容易导致错误.关于Epoch可以参见时区与Epoch 0 Python中生成Epoch from datetime import datetime # python3 datetime.now().timestamp() # python2 import time time.mktime(datetime.now().timetuple()) # 为了兼容python2和3,该用法使用

  • Python随机生成信用卡卡号的实现方法

    本文实例讲述了Python随机生成信用卡卡号的实现方法.分享给大家供大家参考.具体分析如下: 这段Python代码根据信用卡卡号产生规则随机生成信用卡卡号,是可以通过验证的,仅供学习参考,请不要用于非法用途,否则后果自负. #!/usr/bin/python """ gencc: A simple program to generate credit card numbers that pass the MOD 10 check (Luhn formula). Usefull

随机推荐