Package: plot-ann
RequirementsPython >= 3.6 (There are f strings)matpltolibnumpyMotivationThere are other libs that can plot ANNs, why writing your own?This implementation is completely based on matplotlib, and doesn't require any additional library like Viz or PyGraph.This also means that is natively compatible with jupyter noteboksFurthermore you can also create animations that work natively in HTML pages (can't be demonstrated here since github doesn't allow script tags execution)%%capturefrommatplotlibimportanimation,rcfromIPython.displayimportHTMLfromitertoolsimportchainfig,ax=plt.subplots()ax,nodes,edges=ann([3,5,2],ax=ax)ax.set_aspect('equal')lines=list(chain.from_iterable(chain.from_iterable(edges)))defanimate(i,lw):lw=np.roll(lw,i)forw,lineinzip(lw,lines):line.set_linewidth(w)returnlineslw=np.random.rand(len(lines))anim=animation.FuncAnimation(fig,animate,fargs=(lw,),frames=100,interval=60,repeat=True,blit=True)# HTML(anim.to_jshtml())UsageThe only import you need is theann()function from theplot_annmodule (which is the only module)fromplot_annimportannTo draw a network with default settings just pass the dimensionality of layers as aList[int]ax,*_=ann([3,5,2])ax.set_aspect('equal')Theann()function returnsax, nodes, edges. Whereaxis an instance ofmatplotlib.axes;nodesis a structured List ofmatplotlib.patches.Circleandedgesis a structured list ofmatplotlib.lines.Line2D.ann([1,1])(<AxesSubplot:>,
 [[<matplotlib.patches.Circle at 0x7f1f261929a0>],
  [<matplotlib.patches.Circle at 0x7f1f261929d0>]],
 [[[<matplotlib.lines.Line2D at 0x7f1f26147130>]]])Figure customizationSubplottingIf noaxinstance is passed, a new figure and axis will be instantiatied (fig, ax = plt.subplots()) and theaxis returned.Alternatively, one can pass anax:importmatplotlib.pyplotaspltfig,[_,ax]=plt.subplots(1,2,figsize=(8,4))ann([3,5,2],ax=ax);Plot sizeThe plot proportions can be changed using thewidthandheightparamtersfig,axes=plt.subplots(1,2,figsize=(8,8))ax1,ax2=axesann([3,5,2],ax=ax1,height=2)ann([3,5,2],ax=ax2,width=3)foraxinaxes:ax.set_aspect('equal')If you want to preserve the aspect of the axis, remember to either setax.set_aspect('equal')or manually set the rightfigsize. For example, defaultpltparamters will produce a non-square plot and affect the aspect of the network.ann([3,5,2]);Since inplttext is not affected by this distorsion, you can play with this to produce elliptical nodes with enough space to write long text inside of themfig,ax=plt.subplots(figsize=(12,5))ax,nodes,_=ann([3,5,2],ax=ax,radius=2)ax.text(*nodes[0][0].center,'I\'m long text',zorder=10,va='center',ha='center');Network CustomizationThe network is fairly customizableLayersSet thelayer_labelslayer_labels=Truewill set layer labels automaticallylayer_labels=Listwill set layer labels from the list from left to rightfig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1,layer_labels=True)ann([3,5,2],ax=ax2,layer_labels=['Input','meow']);foraxinaxes:ax.set_aspect('equal')NodesChange theradiusparameter to customize the radius of nodes:fig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1)ann([3,5,2],ax=ax2,radius=3);foraxinaxes:ax.set_aspect('equal')Change thenode_lw(linewidth) of nodes:fig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1)ann([3,5,2],ax=ax2,node_lw=3);foraxinaxes:ax.set_aspect('equal')Change thenode_color:node_colors=Truewill set colors automatically (C0 for input layer and C1 for everything else)node_colors=Listwill set colors specified in the list starting from top-most input the first layer and proceeding towards the bottom and then towards the right (if the list is shorter than the number of nodes default color is applied)importmatplotlib.pyplotaspltfig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1,node_colors=True,node_lw=2)ann([3,5,2],ax=ax2,node_colors=['C0','C1','C2','C3','C4'],node_lw=2);foraxinaxes:ax.set_aspect('equal')Setnode_labels:node_labels=Truewill set labels automaticallynode_labels=Listwill set labels specified in the list starting from top-most input the first layer and prociding towards the bottom and then towards the right (if the list is shorter than the number of nodes no label is applied)fig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesarchitecture=[3,5,2]ann(architecture,ax=ax1,radius=2,node_labels=True)ann(architecture,ax=ax2,radius=2,node_labels=range(sum(architecture)-3));foraxinaxes:ax.set_aspect('equal')EdgesDraw edges from the center of the node withedge_from_center=Trueor from the edge of the node withedge_from_center=Falsefig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1,radius=3)ann([3,5,2],ax=ax2,edge_from_center=False,radius=3);foraxinaxes:ax.set_aspect('equal')Change theedge_lw(linewidth)fig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1)ann([3,5,2],ax=ax2,edge_lw=2);foraxinaxes:ax.set_aspect('equal')Change theedge_colors:edge_colors=Truewill set colors automatically (C0 for input layer and C1 for everything else)edge_colors=Listwill set colors specified in the list starting from top-most input the first layer and proceeding towards the bottom and then towards the right (if the list is shorter than the number of edges default color is applied)importmatplotlib.pyplotaspltfig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1,edge_colors=True,edge_lw=1)ann([3,5,2],ax=ax2,edge_colors=['C0','C1','C2','C3','C4'],edge_lw=1);foraxinaxes:ax.set_aspect('equal')Setedge_labels:edge_labels=Truewill set labels automaticallyedge_labels=Listwill set labels specified in the list starting from top-most input the first layer and proceeding towards the bottom and then towards the right (if the list is shorter than the number of edges no label is applied)importnumpyasnpfig,axes=plt.subplots(1,2,figsize=(12.5,5))ax1,ax2=axesarchitecture=[3,5,2]ann(architecture,ax=ax1,edge_labels=True)ann(architecture,ax=ax2,edge_labels=range(np.prod(architecture)-10));foraxinaxes:ax.set_aspect('equal')Changeedge_label_spacing:edge_label_spacing=0will have all edge labels of a layer in the center of the edge (if all labels are drawn some of them will overlap)edge_label_spacing>0will displace a label left if its rotation angle is > 0 else rightimportnumpyasnpfig,axes=plt.subplots(1,2,figsize=(12.5,5))ax1,ax2=axesarchitecture=[3,5,2]ann(architecture,ax=ax1,edge_labels=True,edge_label_spacing=0)ann(architecture,ax=ax2,edge_labels=True,edge_label_spacing=1);foraxinaxes:ax.set_aspect('equal')bias=Truewill assume that the topmost input inarchitectureis the bias for each layer (no edges reaching them from the previous layer) and will change the indexing fornode_labels=Trueandedge_labels=Truefig,axes=plt.subplots(1,2,figsize=(8,4))ax1,ax2=axesann([3,5,2],ax=ax1,radius=2,bias=False,node_labels=True)ann([3,5,2],ax=ax2,radius=2,bias=True,node_labels=True)foraxinaxes:ax.set_aspect('equal')