
各位小表貝,你們的畫圖小老弟又來咯~

上一次我們聊到了如何畫離散圖,這一次我們來點復雜的,準備好了么,系好安全帶,準備發車咯~滴滴~

我們先來點比較簡單,那種易于上手的。
如果現在我知道了兩個點的坐標,那么如何畫出一條線呢?聽起來有點簡單過頭。
首先,我們翻開了官網教程的相關頁面。
matplotlib.lines.Line2D - Matplotlib 3.1.0 documentation?matplotlib.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的官方團隊一定是竊取了我的想法,竟然和我的認知不謀而合。

雖然依然有著肥腸多的參數,但是我并不關心,注意看
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()
如果喜歡請記得點贊收藏加關注哦~么么噠~(有一小段代碼我懶得抽離出方法了,哈哈,反正懶就對了。)
