博士家园

查看: 1735|回复: 7

Python 绘制的电场线

[复制链接]
发表于 2016-10-17 09:49:41 | 显示全部楼层 |阅读模式
这个项目来自 Github 的 Fogleman:




用一个底层的库和几十行代码作出这样的效果已经很不错了。

代码如下:
  1. from math import hypot, atan2, sin, cos, pi, radians
  2. import cairo
  3. import colorsys
  4. import random

  5. class Model(object):
  6.     def __init__(self):
  7.         self.particles = []
  8.     def add(self, x, y, m=1.0):
  9.         self.particles.append((x, y, m))
  10.     def test(self, x, y):
  11.         dx = 0
  12.         dy = 0
  13.         for px, py, pm in self.particles:
  14.             d = hypot(x - px, y - py)
  15.             angle = atan2(y - py, x - px)
  16.             dx += pm * cos(angle) / d
  17.             dy += pm * sin(angle) / d
  18.         angle = atan2(dy, dx) + pi / 2
  19.         dx = cos(angle)
  20.         dy = sin(angle)
  21.         return (dx, dy)

  22. def points(sides):
  23.     x = 0.5
  24.     y = 0.5
  25.     rotation = 0
  26.     angle = 2 * pi / sides
  27.     rotation = rotation - pi / 2
  28.     angles = [angle * i + rotation for i in range(sides)]
  29.     d = 0.35
  30.     return [(x + cos(a) * d, y + sin(a) * d) for a in angles]

  31. def draw_path(dc, model, scale, width, r, g, b):
  32.     n = 128
  33.     f = 1 / 1024.0
  34.     sx = random.random()
  35.     sy = random.random()
  36.     for m in [-1, 1]:
  37.         x, y = sx, sy
  38.         dc.move_to(x, y)
  39.         for j in range(n):
  40.             dx, dy = model.test(x, y)
  41.             dc.line_to(x, y)
  42.             p = 1.0 - (j / (n - 1.0)) ** 2
  43.             a = p * 0.3
  44.             dc.set_source_rgba(r, g, b, a)
  45.             dc.set_line_width(width * p / scale)
  46.             if j:
  47.                 dc.stroke()
  48.             dc.move_to(x, y)
  49.             x += dx * f * m
  50.             y += dy * f * m
  51.             if x < -0.1 or y < -0.1 or x > 1.1 or y > 1.1:
  52.                 break

  53. def main():
  54.     size = 4096
  55.     scale = size
  56.     surface = cairo.ImageSurface(cairo.FORMAT_RGB24, size, size)
  57.     dc = cairo.Context(surface)
  58.     dc.set_line_cap(cairo.LINE_CAP_ROUND)
  59.     dc.set_line_join(cairo.LINE_JOIN_ROUND)
  60.     dc.scale(scale, scale)
  61.     dc.set_source_rgb(0, 0, 0)
  62.     dc.paint()
  63.     model = Model()
  64.     for x, y in points(5):
  65.         model.add(x, y)
  66.     model.add(0.5, 0.5, 0.1)
  67.     for i in range(512):
  68.         h = random.random() * 0.06 + 0.04
  69.         s = random.random() * 0.8 + 0.2
  70.         v = random.random() * 0.2 + 0.8
  71.         r, g, b = colorsys.hsv_to_rgb(h, s, v)
  72.         w = random.random() * 48 + 16
  73.         draw_path(dc, model, scale, w, r, g, b)
  74.     surface.write_to_png('output.png')

  75. if __name__ == '__main__':
  76.     main()
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
发表于 2016-10-19 12:47:47 | 显示全部楼层
蛮好看的
发表于 2017-8-1 23:24:41 | 显示全部楼层
今天看到题主python code 想运行一下,发现自己的Mac python 没有cairo 库,在网上找了很多种方法都无法导入cairo都没有成功,求教!
 楼主| 发表于 2017-8-2 11:36:52 | 显示全部楼层
Aimee~math 发表于 2017-8-1 23:24
今天看到题主python code 想运行一下,发现自己的Mac python 没有cairo 库,在网上找了很多种方法都无法导 ...

cairo 本身是一个 C 语言写的 2d 绘图库,python 中的 cairo 库是对 C 语言库的一个封装。

据我所知,只要安装 matplotlib,就会自动安装 cairo 这个库 (Linux 下是这样的)。这可能是一个解决方法。

另一个解决方法是这样的:安装 cairocffi 这个库。它也是一个对 C 版本绘图库的封装,用法和 cairo 完全一样,只是你需要在程序开头的部分把

  1. import cairo
复制代码


改成

  1. import cairocffi as cairo
复制代码


其余的不用动。
发表于 2017-8-2 16:15:59 | 显示全部楼层
按照你的方法后,出现这个
if __name__ == '__main__':
main()
SyntaxError: expected an indented block
我实在是刚开始学python ,啥也不会。
发表于 2017-8-2 21:43:44 | 显示全部楼层
程序没问题,图形没有。。怎么办
发表于 2017-8-3 07:53:38 | 显示全部楼层
弄好了,谢谢你啦!
发表于 2017-8-7 04:58:02 | 显示全部楼层
图形确实不错,赞一个

关于我们|手机版|博士家园 ( 沪ICP备15045866号 )(沪公网安备沪公网安备 31011702001868号) 

GMT+8, 2018-11-14 12:30 , Processed in 1.062500 second(s), 16 queries , Gzip On.

Powered by Discuz! X3.2

© 2004-2018 Comsenz Inc.

快速回复 返回顶部 返回列表