各位小表贝,你们的画图小老弟又来咯~
上一次我们聊到了如何画离散图,这一次我们来点复杂的,准备好了么,系好安全带,准备发车咯~滴滴~
我们先来点比较简单,那种易于上手的。
如果现在我知道了两个点的坐标,那么如何画出一条线呢?听起来有点简单过头。
首先,我们翻开了官网教程的相关页面。
matplotlib.lines.Line2D - Matplotlib 3.1.0 documentationmatplotlib.org光是看看参数的数量已经相当复杂了,我想申请撤退。
别急,其实绝大多是辅助性的作用,最为重要的是两个参数xdata和ydata
matplotlib.lines.Line2D
(xdata,ydata,……)
从我们一般的理解上来说,确定两个点的坐标,就可以画出一条直线,比如现在我想画出(0,0)到(1,5)的直线,那么是不是我们把这两个点的坐标放进去就OK了呢?
此刻请允许我东北人上身,能动手,就憋叨叨。
import matplotlib.pyplot as plt
from matplotlib.pyplot import Line2Dfig=plt.figure()
ax=fig.add_subplot(111)
ax.set_xlim(0,5)
ax.set_ylim(0,5)
line=Line2D((0,0),(1,5))
ax.add_line(line)
plt.show()
等一下!一定是我的开启方式有问题,为什么没有画出一根直线?从一个资深码农的角度来说,这时候应该是系统出现了问题,我需要,重启计算机。。
先别。注意看上面对于Line2D的官方解释,这里的xdata和ydata,并不是我们常规理解下的两个点的坐标。而是,将两个点的x坐标和y坐标分别写成一个数组。
import matplotlib.pyplot as plt
from matplotlib.pyplot import Line2Dfig=plt.figure()
ax=fig.add_subplot(111)
ax.set_xlim(0,5)
ax.set_ylim(0,5)
line=Line2D((0,1),(0,5))
ax.add_line(line)
plt.show()
其实啥都没变,只是把Line2D((0,0),(1,5))变成了Line2D((0,1),(0,5)),为了显得专业一些,我把代码重新贴了一份而已。
来,再试一次。
棒!想给自己鼓掌!(怎么着,我自己写文章还不能给自己加戏了??)
接下来,我们再来看看如何画一个圆。
还是从常规理解来说,一个圆最重要的也就是圆心以及半径。matplotlib的官方团队一定是窃取了我的想法,竟然和我的认知不谋而合。
https://matplotlib.org/3.1.0/api/_as_gen/matplotlib.patches.Circle.htmlmatplotlib.org虽然依然有着肥肠多的参数,但是我并不关心,注意看
matplotlib.patches.Circle
(xy,radius=5,**kwargs)
这里的xy比较明显的代表了,应该用一个tuple来表示一个圆心的坐标。(tuple是啥?还不先去把python的基础课程补一补?)
来,我们继续动手画起来。
import matplotlib.pyplot as plt
from matplotlib.patches import Circlefig=plt.figure()
ax=fig.add_subplot(111)
cir=Circle((3,3),radius=2)
ax.add_patch(cir)
plt.show()
这是在和我开玩笑么?这TM也敢自称是个圆?我一个漂亮的回旋踢应该也比这个圆吧。
当然究其原因。
- x轴和y轴的范围不同,一个是0到5,一个是0到10
- 这整个坐标系看起来就像是一个长方形,即使画出来的是一个正圆,也会被压缩成椭圆。
咱们一一解决。
首先,对于x,y轴范围的问题,可以去设置axis的范围(axis是啥?去看上一篇)。
fig=plt.figure()
ax=fig.add_subplot(111)
ax.set_xlim(0,10)
ax.set_ylim(0,10)
而如何将一个axis设置为一个正方形的显示区间,就需要去网上找答案了。
最终千辛万苦,会发现对于axis而言,有一个方法可以设置它的aspect
ax.set_aspect(num)
这里的num则是x,y轴的长宽比,如果我们想得到一个正儿八经的正方形,num填写1,修改一下代码再跑一次试试。
棒!仔细对比上下两张图,你会发现之前椭圆的那张图,确实不是一个正方形。而且可以负责任的说,matplotlib直接拿来画图而不去调整aspect的画,你一定画不出一个正圆。(好像说的有点满。)
目前来说,我相信你已经知道了如何绘制圆以及直线了,那咱们玩点有难度的。
我们用仅有的一些知识,来画出一幅人工智能中神经网络的连接图。那是个啥?我们先看看结果。
就是它了。简单来说,我们把这些圆分为了3层,第一层3个,第二层5个,第三层6个。然后每一层与每一层之间有一个全连接的关系。
全连接是啥?嗯。。比如下图这样,就是一个点对于下一层的全连接。
是不是已经兴奋的搓手手了?来,咱们先考虑考虑,这么一个看起来比较复杂的东西,该怎么画。(是不是想起了数学书上的课后练习?学会了1+1立马就得会做8239+44121。)
首先来说,这套图形,充满了各种重复劳动,而一切的重复劳动在代码面前都是纸老虎。编码的意义是什么?就是懒人给自己找到了一个偷懒的方法啊。
从一个编码人员的角度来说,现在是3层的网络,但是我希望用一套代码,可以解决3层,10层,甚至30层,并且只需要改动一个参数就行了,其他的我都不想改,因为,懒!
安排!
经过首轮简单分析,你可以很轻松的发现,对于圆以及直线而言,他们共用了所有的点。也就是说,两个直线连接的就是两个圆心,所以如果我们可以直接把所有圆心的位置都找到,并且储存成一个数组,那不就万事大吉了么?
对,就是这么简单。
就拿我们现在这个3层分布来说,那么一张画布,就可以被三等分为三个部分。
这么看起来,现在每一个圆心的x轴坐标,可以确定下来了。
但是现在x轴范围是0到10,我希望如果是0到100也不会影响到我的算法。话句话来说,现在第一层的x轴坐标应该是1.66(怎么算的?自己动动脑子。)如果这时候x的范围是0到100,那么第一层的x轴坐标就应该是16.6。
所以我需要去动态的进行计算,不应该把这个10当做一个固定值进行计算。
比较幸运的是,我们可以通过调用ax.get_xlim()和ax.get_ylim()来获取到x轴与y轴的范围,比如以当前情况而言,会返回一个(0,10)的tuple。
所以这么看起来,如果我按照x轴的长度,除以层数,就可以获取每一层应该有多宽了。完美!当然圆心和直线的一端就是在每一层x数值的中心咯。
那么对于y轴该如何分呢?以当前的[3,5,6]而言,那我们必然想让他的排布好看一些,如果office用的多都应该知道啥叫居中排布。
这么看来,每一个圆所在格子的高度,应该以圆的个数最多的那一层为准。比如这时候是第三层的6个,如果其他层有更多呢,比如我们再画一个。
那这时候就会以9作为基准。所以目前的第一目标就是找出,哪一层的圆比较多。
如果你要用冒泡算法或者其他的一些排序算法去找,也不是说不可以,不过numpy中有一个方法,用起来比较方便。比如。
import numpy as npa=[1,3,5,2,56,4]
b=np.amax(a)
Out[]: 56
那么好了,现在好像难题都已经被解决了,剩下的就是用各种循环去画图了。当然这一次我会先给出部分代码,我更希望你可以自己动手画一画。完整版的代码会在下一篇文章中以彩蛋的形式发布。(剧透了还能叫彩蛋么?)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib.pyplot import Line2Ddef draw_level(each_level):ylim=ax1.get_ylim()[1]xlim=ax1.get_xlim()[1]each_level=np.array(each_level)each_col=xlim/((len(each_level)))each_row=ylim/np.amax(each_level)radius=0.4*each_rowfor i,item in enumerate(each_level):# your code heredef draw_line(each_level):ylim = ax1.get_ylim()[1]xlim = ax1.get_xlim()[1]each_level = np.array(each_level)each_col = xlim / ((len(each_level)) )each_row = ylim / np.amax(each_level)result=list()for i, item in enumerate(each_level):# your code herefor i in range(len(each_level)-1):for item in result[i]:for i_next in result[i+1]:# your code here fig=plt.figure()
ax1=fig.add_subplot(111)
ax1.set_xlim(0,10)
ax1.set_ylim(0,10)
ax1.set_aspect(1)
each_level=[3,5,9,6]
draw_line(each_level)
draw_level(each_level)
plt.show()
如果喜欢请记得点赞收藏加关注哦~么么哒~(有一小段代码我懒得抽离出方法了,哈哈,反正懒就对了。)