Source code for ensembler.visualisation.plotConveyorBelt

import matplotlib.patches as patches
import matplotlib.patheffects as path_effects
import matplotlib.pyplot as plt
import numpy as np


[docs]def calc_lam(CapLam, i=0, numsys=8, w=0.1): ome = (CapLam + i * np.pi * 2.0 / numsys) % (2. * np.pi) if ome > np.pi: ome = 2.0 * np.pi - ome return ome / np.pi
[docs]def drawCirc(ax, radius, centX, centY, angle_, theta2_, lineWidth=3, color_='black'): # ========Line arc = patches.Arc([centX, centY], radius, radius, angle=angle_, theta1=0, theta2=theta2_, capstyle='round', linestyle='-', lw=lineWidth, color=color_) ax.add_patch(arc) # ========Create the arrow head # endX=centX+(radius/2)*np.cos((theta2_+angle_)/180*np.pi) #Do trig to determine end position # endY=centY+(radius/2)*np.sin((theta2_+angle_)/180*np.pi) # ax.add_patch( #Create triangle as arrow head # patches.RegularPolygon( # (endX, endY), # (x,y) # 3, # number of vertices # radius/10, # radius # (angle_+theta2_)/180*np.pi, # orientation # color=color_ # ) # ) # ========Create the arrow head begX = centX + (radius / 2) * np.cos((angle_) / 180 * np.pi) # Do trig to determine end position begY = centY + (radius / 2) * np.sin((angle_) / 180 * np.pi) ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (begX, begY), # (x,y) 3, # number of vertices radius / 20, # radius (180 + angle_) / 180 * np.pi, # orientation color=color_ ) ) ax.set_xlim([centX - radius, centY + radius]) and ax.set_ylim([centY - radius, centY + radius])
[docs]def drawFunicular(x, y, CapLam=0.1, M=2, drawArrows=False): pSize = 2.009 goldRat = 1.618 lineWidth = 1 [path_effects.SimpleLineShadow(), path_effects.Normal()] fig = plt.figure(figsize=(pSize * goldRat, pSize)) ax = fig.gca() fig.subplots_adjust(left=0.1, right=1.0-0.1, bottom=0.24, top=0.99) rx=0.05 ry=rx shifty=0.75/goldRat cvb_bot=np.zeros((90,2)) cvb_bot[:,0]=np.linspace(calc_lam(CapLam, 1, numsys=2), 1.0-rx, 90) cvb_bot[:,1]=np.ones(90)*shifty cvb_top=np.zeros((90,2)) cvb_top[:,0]=np.linspace(calc_lam(CapLam, 0, numsys=2), 1.0-rx, 90) cvb_top[:,1]=np.ones(90)*(shifty+2.0*ry) lamVals=x-x.min() lamVals/=lamVals.max() gVals=y-y.min() if gVals.max() != 0.0: gVals/=(2.0*gVals.max()*goldRat) else: gVals+=1/(2.0*goldRat) ax.plot(lamVals[2:], gVals[2:], 'k', lw=lineWidth) l = CapLam numsys = M rotation = [] y = [] for i in range(M): if calc_lam(CapLam, i, numsys=M) > rx and calc_lam(CapLam, i, numsys=M) < (1.0 - rx): rotation.append(45) y.append(1.0) elif calc_lam(CapLam, i, numsys=M) < rx: alpha = np.arcsin((rx - calc_lam(CapLam, i, numsys=M)) / rx) rotation.append(45 - alpha / np.pi * 180.0) y.append(np.cos(alpha)) else: alpha = np.arcsin((rx - (1 - calc_lam(CapLam, i, numsys=M))) / rx) rotation.append(45 - alpha / np.pi * 180.0) y.append(np.cos(alpha)) shiftMarker = 0.02 * np.sqrt(2) ax.plot(cvb_bot[:, 0], cvb_bot[:, 1], 'k', lw=lineWidth, zorder=1) ax.plot(cvb_top[:, 0], cvb_top[:, 1], 'k', lw=lineWidth, zorder=1) # ax.add_artist(patches.Arc((rx,shifty+ry), 2*rx, 2*ry, theta1=90, theta2=270, lw=lineWidth)) ax.add_artist(patches.Arc((1.0 - rx, shifty + ry), 2 * rx, 2 * ry, theta1=270, theta2=90, lw=lineWidth)) # ax.add_artist(patches.Arc((rx,shifty+ry), 1.4*rx, 1.4*ry, lw=lineWidth)) ax.add_artist(patches.Arc((1.0 - rx, shifty + ry), 1.4 * rx, 1.4 * ry, lw=lineWidth)) # ax.annotate(r'$\Lambda=0$', xy=(-0.01, shifty+ry), xytext=(-0.05, shifty+ry), va='center', ha='right', arrowprops=dict(arrowstyle='-')) # ax.annotate(r'$\Lambda=\frac{\pi}{2}$', xy=(0.5, shifty+2*ry+0.01), xytext=(0.5, shifty+2*ry+0.05), va='bottom', ha='center', arrowprops=dict(arrowstyle='-')) # ax.annotate(r'$\Lambda=\frac{3\pi}{2}$', xy=(0.5, shifty-0.01), xytext=(0.5, shifty-0.05), va='top', ha='center', arrowprops=dict(arrowstyle='-')) # ax.annotate(r'$\Lambda=\pi$', xy=(1.01, shifty+ry), xytext=(1.05, shifty+ry), va='center', ha='left', arrowprops=dict(arrowstyle='-')) # if np.fabs(rotation[0]-45)>0.0001: # print(alpha) # ax.annotate('Current state:\n$\Lambda={:.1f}$'.format(CapLam), xy=(calc_lam(CapLam, 0, numsys=M), shifty+ry+np.cos(alpha)*ry), # xytext=(calc_lam(CapLam, 0, numsys=M)-np.sin(alpha)*1.5*rx, shifty+(1+np.cos(alpha)*2.5)*ry), # arrowprops=dict(arrowstyle='<-', linewidth=3), va='center', ha='center', zorder=0) # else: # ax.annotate('Current state:\n$\Lambda={:.1f}$'.format(CapLam), xy=(calc_lam(CapLam, 0, numsys=M), shifty+2.0*ry+shiftMarker), # xytext=(calc_lam(CapLam, 0, numsys=M), shifty+3.5*ry), # arrowprops=dict(arrowstyle='<-', linewidth=3), va='center', ha='center', zorder=0) # arrows in the conveyor belt # drawCirc(ax,rx*0.8,rx,shifty+ry,45,270, color_='red') drawCirc(ax, rx * 0.8, 1.0 - rx, shifty + ry, 225, 270, lineWidth=lineWidth, color_='red') for i in range(int(M / 2)): x = calc_lam(CapLam, i, numsys=M) - np.sqrt(1 - y[i] ** 2) * shiftMarker ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (x, shifty + ry + y[i] * ry), # (x,y) 4, # number of vertices 0.02, # radius rotation[i] / 180.0 * np.pi, # orientation color='red', zorder=10 ) ) ax.scatter(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker, s=30, marker='o', edgecolors='face', color='r', zorder=10) if drawArrows: ax.annotate('', xy=(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker), xytext=(x + 0.1, gVals[np.abs(lamVals - x - 0.1).argmin()] + shiftMarker), arrowprops=dict(arrowstyle='<-', linewidth=lineWidth)) ax.plot([x, x], [gVals[np.abs(lamVals - x).argmin()], shifty + ry + y[i] * ry], color='0.8', lw=lineWidth, zorder=0) for i in range(int(M / 2)): x = calc_lam(CapLam, i + int(M / 2), numsys=M) - np.sqrt(1 - y[i] ** 2) * shiftMarker ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (x, shifty), # (x,y) 4, # number of vertices 0.02, # radius rotation[i] / 180.0 * np.pi, # orientation color='red', zorder=10 ) ) ax.plot([x, x], [gVals[np.abs(lamVals - x).argmin()], shifty + (1.0 - y[i]) * ry], color='0.8', lw=lineWidth, zorder=0) ax.scatter(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker, s=30, marker='o', edgecolors='face', color='r', zorder=10) if drawArrows: ax.annotate('', xy=(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker), xytext=(x - 0.1, gVals[np.abs(lamVals - x + 0.1).argmin()] + shiftMarker), arrowprops=dict(arrowstyle='<-', linewidth=lineWidth)) ax.set_xlim(-0.1, 1.1) ax.set_ylim(0, 1.2 / goldRat) ax.set_xticks([0.0, 0.5, 1.0]) ax.set_xticklabels(['0\n(A)', r'$\sfrac{1}{2}$', '1\n(B)']) # ax.text(lamVals[-1], gVals[-1]-0.05, 'Free energy profile', ha='right', va='top') ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') ax.set_yticks([]) ax.spines['left'].set_color('None') ax.spines['right'].set_color('None') ax.spines['top'].set_color('None') ax.annotate('', xy=(0, 0), xytext=(0, 0.5 / goldRat), ha='center', va='bottom', arrowprops=dict(arrowstyle='<|-', facecolor='k', linewidth=1.5)) ax.text(-0.025, 0.25 / goldRat, '$G(\lambda)$', ha='right', va='center', fontsize=14) ax.text(1.025, 0.0, '$\lambda$', ha='left', va='center', fontsize=14) return fig
[docs]def plotEnsembler(x, y, CapLam=0.1, M=8, drawArrows=False): pSize = 6.027 goldRat = 1.70 lineWidth = 1 [path_effects.SimpleLineShadow(), path_effects.Normal()] fig = plt.figure(figsize=(pSize * goldRat, pSize)) ax = fig.gca() fig.subplots_adjust(left=0.1, right=1.0-0.1, bottom=0.25, top=0.964) rx=0.05 ry=rx shifty=0.75/goldRat cvb_bot=np.zeros((90,2)) cvb_bot[:,0]=np.linspace(rx, 1.0-rx, 90) cvb_bot[:,1]=np.ones(90)*shifty cvb_top=np.zeros((90,2)) cvb_top[:,0]=np.linspace(rx, 1.0-rx, 90) cvb_top[:,1]=np.ones(90)*(shifty+2.0*ry) lamVals=x-x.min() lamVals/=lamVals.max() gVals=y-y.min() if gVals.max() != 0.0: gVals/=(2.0*gVals.max()*goldRat) else: gVals+=1/(2.0*goldRat) ax.plot(lamVals[2:], gVals[2:], 'k', lw=lineWidth) l = CapLam numsys = M rotation = [] y = [] # replicas boxes for i in range(M): if calc_lam(CapLam, i, numsys=M) > rx and calc_lam(CapLam, i, numsys=M) < (1.0 - rx): rotation.append(45) y.append(1.0) elif calc_lam(CapLam, i, numsys=M) < rx: alpha = np.arcsin((rx - calc_lam(CapLam, i, numsys=M)) / rx) if (CapLam + i * 2 * np.pi / float(M)) % (2. * np.pi) < np.pi: rotation.append(45 + alpha / np.pi * 180.0) else: rotation.append(45 - alpha / np.pi * 180.0) y.append(np.cos(alpha)) else: alpha = np.arcsin((rx - (1 - calc_lam(CapLam, i, numsys=M))) / rx) if (CapLam + i * 2 * np.pi / float(M)) % (2. * np.pi) < np.pi: rotation.append(45 - alpha / np.pi * 180.0) else: rotation.append(45 + alpha / np.pi * 180.0) y.append(np.cos(alpha)) shiftMarker = 0.02 * np.sqrt(2) # funicular ax.plot(cvb_bot[:, 0], cvb_bot[:, 1], 'k', lw=lineWidth) ax.plot(cvb_top[:, 0], cvb_top[:, 1], 'k', lw=lineWidth) ax.add_artist(patches.Arc((rx, shifty + ry), 2 * rx, 2 * ry, theta1=90, theta2=270, lw=lineWidth)) ax.add_artist(patches.Arc((1.0 - rx, shifty + ry), 2 * rx, 2 * ry, theta1=270, theta2=90, lw=lineWidth)) ax.add_artist(patches.Arc((rx, shifty + ry), 1.4 * rx, 1.4 * ry, lw=lineWidth)) ax.add_artist(patches.Arc((1.0 - rx, shifty + ry), 1.4 * rx, 1.4 * ry, lw=lineWidth)) ax.annotate(r'$\Lambda=0$', xy=(0.01, shifty + ry), xytext=(-0.05, shifty + ry), va='center', ha='right', fontsize='small', arrowprops=dict(arrowstyle='-', linewidth=lineWidth)) ax.annotate(r'$\Lambda=\frac{\pi}{2}$', xy=(0.5, shifty + 2 * ry + 0.01), xytext=(0.5, shifty + 2 * ry + 0.05), va='bottom', ha='center', fontsize='small', arrowprops=dict(arrowstyle='-', linewidth=lineWidth)) ax.annotate(r'$\Lambda=\frac{3\pi}{2}$', xy=(0.5, shifty - 0.01), xytext=(0.5, shifty - 0.05), va='top', ha='center', fontsize='small', arrowprops=dict(arrowstyle='-', linewidth=lineWidth)) ax.annotate(r'$\Lambda=\pi$', xy=(.99, shifty + ry), xytext=(1.05, shifty + ry), va='center', ha='left', fontsize='small', arrowprops=dict(arrowstyle='-', linewidth=lineWidth)) if drawArrows: if np.fabs(rotation[0] - 45) > 0.0001: ax.annotate('Current state:\n$\Lambda={:.1f}$'.format(CapLam), xy=(calc_lam(CapLam, 0, numsys=M), shifty + ry + np.cos(alpha) * (ry + shiftMarker)), xytext=( calc_lam(CapLam, 0, numsys=M) - np.sin(alpha) * 2 * rx, shifty + (1 + np.cos(alpha) * 5) * ry), fontsize='small', arrowprops=dict(arrowstyle='<-', linewidth=1.0, shrinkA=0.0), va='top', ha='center', zorder=0, bbox=dict(pad=-.1, lw=0.0, color='None')) else: ax.annotate('Current state:\n$\Lambda={:.1f}$'.format(CapLam), xy=(calc_lam(CapLam, 0, numsys=M), shifty + 2.0 * ry + shiftMarker), xytext=(calc_lam(CapLam, 0, numsys=M), shifty + 6 * ry), arrowprops=dict(arrowstyle='<-', linewidth=1.0, shrinkA=0.0), fontsize='small', va='top', ha='center', zorder=0, bbox=dict(pad=-.1, lw=0.0, color='None')) # arrows in the conveyor belt drawCirc(ax, rx * 0.8, rx, shifty + ry, 45, 270, lineWidth=1.0, color_='red') drawCirc(ax, rx * 0.8, 1.0 - rx, shifty + ry, 225, 270, lineWidth=1.0, color_='red') # lines and markers for Epot for i in range(M): x = calc_lam(CapLam, i, numsys=M) if x < rx: rx -= np.sqrt(1 - y[i] ** 2) * shiftMarker elif x > 1 - rx: rx += np.sqrt(1 - y[i] ** 2) * shiftMarker if (CapLam + i * 2 * np.pi / float(M)) % (2. * np.pi) < np.pi: ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (x, shifty + ry + y[i] * ry + y[i] * shiftMarker), # (x,y) 4, # number of vertices 0.02, # radius rotation[i] / 180.0 * np.pi, # orientation color='red', zorder=10 ) ) ax.scatter(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker, s=30, marker='o', edgecolors='face', color='r', zorder=10) if drawArrows: ax.annotate('', xy=(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker), xytext=(x + 0.1, gVals[np.abs(lamVals - x - 0.1).argmin()] + shiftMarker), arrowprops=dict(arrowstyle='<-', linewidth=lineWidth)) ax.plot([x, x], [gVals[np.abs(lamVals - x).argmin()], shifty + ry + y[i] * ry + y[i] * shiftMarker], color='0.8', lw=lineWidth, zorder=0) else: ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (x, shifty - y[i] * shiftMarker), # (x,y) 4, # number of vertices 0.02, # radius rotation[i] / 180.0 * np.pi, # orientation color='red', zorder=10 ) ) ax.plot([x, x], [gVals[np.abs(lamVals - x).argmin()], shifty + (1.0 - y[i]) * ry - y[i] * shiftMarker], color='0.8', lw=lineWidth, zorder=0) ax.scatter(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker, s=30, marker='o', edgecolors='face', color='r', zorder=10) if drawArrows: ax.annotate('', xy=(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker), xytext=(x - 0.1, gVals[np.abs(lamVals - x + 0.1).argmin()] + shiftMarker), arrowprops=dict(arrowstyle='<-', linewidth=lineWidth)) # formatting ax.set_xlim(-0.1, 1.1) ax.set_ylim(0, 1.2 / goldRat) ax.set_xticks([0.0, 0.5, 1.0]) ax.set_xticklabels(['0\n(A)', r'$\sfrac{1}{2}$', '1\n(B)']) ax.xaxis.set_ticks_position('bottom') ax.yaxis.set_ticks_position('left') ax.set_yticks([]) ax.spines['left'].set_color('None') ax.spines['right'].set_color('None') ax.spines['top'].set_color('None') ax.set_title("Conveyor Belt over simulated Free Energy Landscape") ax.annotate('', xy=(0, 0), xytext=(0, 0.5 / goldRat), ha='center', va='bottom', arrowprops=dict(arrowstyle='<|-', facecolor='k', linewidth=1.5)) ax.text(-0.025, 0.25 / goldRat, '$G(\lambda)$', ha='right', va='center', fontsize=14) ax.text(1.025, 0.0, '$\lambda$', ha='left', va='center', fontsize=14) return fig, ax
[docs]def updateEnsembler(x, y, ax, CapLam=0.1, M=8, drawArrows=False): pSize = 6.027 goldRat = 1.70 lineWidth = 1 [path_effects.SimpleLineShadow(), path_effects.Normal()] rx=0.05 ry=rx shifty=0.75/goldRat cvb_bot=np.zeros((90,2)) cvb_bot[:,0]=np.linspace(rx, 1.0-rx, 90) cvb_bot[:,1]=np.ones(90)*shifty cvb_top=np.zeros((90,2)) cvb_top[:,0]=np.linspace(rx, 1.0-rx, 90) cvb_top[:,1]=np.ones(90)*(shifty+2.0*ry) lamVals=x-x.min() lamVals/=lamVals.max() gVals=y-y.min() if gVals.max() != 0.0: gVals/=(2.0*gVals.max()*goldRat) else: gVals+=1/(2.0*goldRat) ax.plot(lamVals[2:], gVals[2:], 'k', lw=lineWidth) rotation = [] y = [] # buildBox for i in range(M): if calc_lam(CapLam, i, numsys=M) > rx and calc_lam(CapLam, i, numsys=M) < (1.0 - rx): rotation.append(45) y.append(1.0) elif calc_lam(CapLam, i, numsys=M) < rx: alpha = np.arcsin((rx - calc_lam(CapLam, i, numsys=M)) / rx) if (CapLam + i * 2 * np.pi / float(M)) % (2. * np.pi) < np.pi: rotation.append(45 + alpha / np.pi * 180.0) else: rotation.append(45 - alpha / np.pi * 180.0) y.append(np.cos(alpha)) else: alpha = np.arcsin((rx - (1 - calc_lam(CapLam, i, numsys=M))) / rx) if (CapLam + i * 2 * np.pi / float(M)) % (2. * np.pi) < np.pi: rotation.append(45 - alpha / np.pi * 180.0) else: rotation.append(45 + alpha / np.pi * 180.0) y.append(np.cos(alpha)) shiftMarker = 0.02 * np.sqrt(2) # arrow if drawArrows: if np.fabs(rotation[0] - 45) > 0.0001: ax.annotate('Current state:\n$\Lambda={:.1f}$'.format(CapLam), xy=(calc_lam(CapLam, 0, numsys=M), shifty + ry + np.cos(alpha) * (ry + shiftMarker)), xytext=( calc_lam(CapLam, 0, numsys=M) - np.sin(alpha) * 2 * rx, shifty + (1 + np.cos(alpha) * 5) * ry), fontsize='small', arrowprops=dict(arrowstyle='<-', linewidth=1.0, shrinkA=0.0), va='top', ha='center', zorder=0, bbox=dict(pad=-.1, lw=0.0, color='None')) else: ax.annotate('Current state:\n$\Lambda={:.1f}$'.format(CapLam), xy=(calc_lam(CapLam, 0, numsys=M), shifty + 2.0 * ry + shiftMarker), xytext=(calc_lam(CapLam, 0, numsys=M), shifty + 6 * ry), arrowprops=dict(arrowstyle='<-', linewidth=1.0, shrinkA=0.0), fontsize='small', va='top', ha='center', zorder=0, bbox=dict(pad=-.1, lw=0.0, color='None')) # arrows in the conveyor belt drawCirc(ax, rx * 0.8, rx, shifty + ry, 45, 270, lineWidth=1.0, color_='red') drawCirc(ax, rx * 0.8, 1.0 - rx, shifty + ry, 225, 270, lineWidth=1.0, color_='red') # box arrow? for i in range(M): x = calc_lam(CapLam, i, numsys=M) if x < rx: rx -= np.sqrt(1 - y[i] ** 2) * shiftMarker elif x > 1 - rx: rx += np.sqrt(1 - y[i] ** 2) * shiftMarker if (CapLam + i * 2 * np.pi / float(M)) % (2. * np.pi) < np.pi: ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (x, shifty + ry + y[i] * ry + y[i] * shiftMarker), # (x,y) 4, # number of vertices 0.02, # radius rotation[i] / 180.0 * np.pi, # orientation color='red', zorder=10 ) ) ax.scatter(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker, s=30, marker='o', edgecolors='face', color='r', zorder=10) if drawArrows: ax.annotate('', xy=(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker), xytext=(x + 0.1, gVals[np.abs(lamVals - x - 0.1).argmin()] + shiftMarker), arrowprops=dict(arrowstyle='<-', linewidth=lineWidth)) ax.plot([x, x], [gVals[np.abs(lamVals - x).argmin()], shifty + ry + y[i] * ry + y[i] * shiftMarker], color='0.8', lw=lineWidth, zorder=0) else: ax.add_patch( # Create triangle as arrow head patches.RegularPolygon( (x, shifty - y[i] * shiftMarker), # (x,y) 4, # number of vertices 0.02, # radius rotation[i] / 180.0 * np.pi, # orientation color='red', zorder=10 ) ) ax.plot([x, x], [gVals[np.abs(lamVals - x).argmin()], shifty + (1.0 - y[i]) * ry - y[i] * shiftMarker], color='0.8', lw=lineWidth, zorder=0) ax.scatter(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker, s=30, marker='o', edgecolors='face', color='r', zorder=10) if drawArrows: ax.annotate('', xy=(x, gVals[np.abs(lamVals - x).argmin()] + shiftMarker), xytext=(x - 0.1, gVals[np.abs(lamVals - x + 0.1).argmin()] + shiftMarker), arrowprops=dict(arrowstyle='<-', linewidth=lineWidth))