"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `subprocess` module replaces the following modules (so don't use them):"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"os.system\n",
"os.spawn*\n",
"os.popen*\n",
"popen2.*\n",
"commands.*"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.call"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"ARGS='ls'"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [],
"source": [
"!mkdir /tmp/empty"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/tmp/empty\n"
]
}
],
"source": [
"cd /tmp/empty"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import subprocess\n",
"subprocess.call(ARGS, stdin=None, stdout=None, stderr=None, shell=False)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Run the command described by `ARGS`. Wait for command to complete, then return the returncode attribute.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# ARGS"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`ARGS` specifies the command to call and its arguments. It can either be a **string** or a **list of strings**."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"subprocess.call('echo')"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"hello\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"subprocess.call(['echo','hello'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If `shell=False` (default) and `args` is a string, it must be only the name of the program (no arguments). If a list is provided, then the first element is the program name and the remaining elements are the arguments."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# shell"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If (and only if) `shell = True` then the string provided for `args` is parsed *exactly* as if you typed it on the commandline. This means you that:\n",
"\n",
"* you must escape special characters (e.g. spaces in file names)\n",
"* you can use the wildcard '*' character to expand file names\n",
"* you can add IO redirection\n",
"\n",
"If `shell=False` then list arguments must be use and they are passed literally to the program (e.g., it would get '*' for a file name).\n",
"\n",
"`shell` is `False` by default for security reasons. Consider:\n",
"\n",
" filename = input(\"What file would you like to display?\\n\")\n",
" What file would you like to display?\n",
" non_existent; rm -rf / #\n",
" subprocess.call(\"cat \" + filename, shell=True) # Uh-oh. This will end badly..."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Be default `/bin/sh` is used as the shell. You are probably using `bash`. You can specify what shell to use with the `executable` argument."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"/bin/sh\n",
"/bin/bash\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"subprocess.call('echo $0',shell=True) #prints out /bin/sh\n",
"subprocess.call('echo $0',executable='/bin/bash',shell=True) #prints out /bin/bash"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# shell Examples"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"ls: cannot access '*': No such file or directory\n"
]
},
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"subprocess.call(['ls','*']) # ls: *: No such file or directory"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"!touch file\\ with\\ spaces"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"file with spaces\n",
"0\n",
"2\n",
"file with spaces\n",
"0\n",
"file with spaces\n",
"0\n",
"2\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"ls: cannot access 'file': No such file or directory\n",
"ls: cannot access 'with': No such file or directory\n",
"ls: cannot access 'spaces': No such file or directory\n",
"ls: cannot access 'file\\ with\\ spaces': No such file or directory\n"
]
}
],
"source": [
"#note - ls returns nonzero exit code if can't list any files\n",
"print(subprocess.call('ls *',shell=True)) #shows all files\n",
"print(subprocess.call('ls file with spaces',shell=True)) #tries to ls three different files\n",
"print(subprocess.call('ls file\\ with\\ spaces',shell=True)) #shows single file with spaces in name\n",
"print(subprocess.call(['ls','file with spaces'])) #ditto\n",
"print(subprocess.call(['ls','file\\ with\\ spaces'])) #fails since it looks for file with backslashes in name"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"ename": "FileNotFoundError",
"evalue": "[Errno 2] No such file or directory: 'ls *'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[15], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43msubprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcall\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mls *\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m)\u001b[49m \u001b[38;5;66;03m#why is this FileNotFoundError?\u001b[39;00m\n",
"File \u001b[0;32m/usr/lib/python3.10/subprocess.py:345\u001b[0m, in \u001b[0;36mcall\u001b[0;34m(timeout, *popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 337\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mcall\u001b[39m(\u001b[38;5;241m*\u001b[39mpopenargs, timeout\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[1;32m 338\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Run command with arguments. Wait for command to complete or\u001b[39;00m\n\u001b[1;32m 339\u001b[0m \u001b[38;5;124;03m timeout, then return the returncode attribute.\u001b[39;00m\n\u001b[1;32m 340\u001b[0m \n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 343\u001b[0m \u001b[38;5;124;03m retcode = call([\"ls\", \"-l\"])\u001b[39;00m\n\u001b[1;32m 344\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[0;32m--> 345\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m \u001b[43mPopen\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mpopenargs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m \u001b[38;5;28;01mas\u001b[39;00m p:\n\u001b[1;32m 346\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 347\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m p\u001b[38;5;241m.\u001b[39mwait(timeout\u001b[38;5;241m=\u001b[39mtimeout)\n",
"File \u001b[0;32m/usr/lib/python3.10/subprocess.py:971\u001b[0m, in \u001b[0;36mPopen.__init__\u001b[0;34m(self, args, bufsize, executable, stdin, stdout, stderr, preexec_fn, close_fds, shell, cwd, env, universal_newlines, startupinfo, creationflags, restore_signals, start_new_session, pass_fds, user, group, extra_groups, encoding, errors, text, umask, pipesize)\u001b[0m\n\u001b[1;32m 967\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mtext_mode:\n\u001b[1;32m 968\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr \u001b[38;5;241m=\u001b[39m io\u001b[38;5;241m.\u001b[39mTextIOWrapper(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr,\n\u001b[1;32m 969\u001b[0m encoding\u001b[38;5;241m=\u001b[39mencoding, errors\u001b[38;5;241m=\u001b[39merrors)\n\u001b[0;32m--> 971\u001b[0m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_execute_child\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mexecutable\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpreexec_fn\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mclose_fds\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 972\u001b[0m \u001b[43m \u001b[49m\u001b[43mpass_fds\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcwd\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43menv\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 973\u001b[0m \u001b[43m \u001b[49m\u001b[43mstartupinfo\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mcreationflags\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshell\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 974\u001b[0m \u001b[43m \u001b[49m\u001b[43mp2cread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mp2cwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 975\u001b[0m \u001b[43m \u001b[49m\u001b[43mc2pread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mc2pwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 976\u001b[0m \u001b[43m \u001b[49m\u001b[43merrread\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43merrwrite\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 977\u001b[0m \u001b[43m \u001b[49m\u001b[43mrestore_signals\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 978\u001b[0m \u001b[43m \u001b[49m\u001b[43mgid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mgids\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43muid\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mumask\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 979\u001b[0m \u001b[43m \u001b[49m\u001b[43mstart_new_session\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 980\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m:\n\u001b[1;32m 981\u001b[0m \u001b[38;5;66;03m# Cleanup if the child failed starting.\u001b[39;00m\n\u001b[1;32m 982\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m f \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mfilter\u001b[39m(\u001b[38;5;28;01mNone\u001b[39;00m, (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdin, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstdout, \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstderr)):\n",
"File \u001b[0;32m/usr/lib/python3.10/subprocess.py:1863\u001b[0m, in \u001b[0;36mPopen._execute_child\u001b[0;34m(self, args, executable, preexec_fn, close_fds, pass_fds, cwd, env, startupinfo, creationflags, shell, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, restore_signals, gid, gids, uid, umask, start_new_session)\u001b[0m\n\u001b[1;32m 1861\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m errno_num \u001b[38;5;241m!=\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 1862\u001b[0m err_msg \u001b[38;5;241m=\u001b[39m os\u001b[38;5;241m.\u001b[39mstrerror(errno_num)\n\u001b[0;32m-> 1863\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m child_exception_type(errno_num, err_msg, err_filename)\n\u001b[1;32m 1864\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m child_exception_type(err_msg)\n",
"\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: 'ls *'"
]
}
],
"source": [
"subprocess.call('ls *') #why is this FileNotFoundError?"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Input/Output/Error"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Every process (program) has standard places to write output and read input. \n",
"\n",
"* stdin - standard input is usually from the keyboard\n",
"* stdout - standard output is usually buffered\n",
"* stderr - standard error is unbuffered (output immediately)\n",
"\n",
"On the commandline, you can changes these places with IO redirection (<,>,|). For example:\n",
"\n",
" grep Congress cnn.html > congress\n",
" wc < congress\n",
" grep Congress cnn.html | wc\n",
"
\n",
"When calling external programs from scripts we'll usually want to provide input to the programs and read their output, so we'll have to change these 'places' as well."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# stdin/stdout/stderr"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"stdin, stdout and stderr specify the executed program’s standard input, standard output and standard error file handles, respectively. Valid values are\n",
"\n",
"* `subprocess.PIPE` - this enables communication between your script and the program\n",
"* an existing file object - e.g. created with `open`\n",
"* None - the program will default to the existing stdin/stdout/stderr \n",
"\n",
"**Do no use `subprocess.PIPE` with subprocess.call**"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Redirecting to files"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'dump\\n'"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f = open('dump','w')\n",
"subprocess.call('ls',stdout=f)\n",
"f = open('dump','r') #this would be a very inefficient way to get the stdout of a program\n",
"f.readline()"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"f = open('dump','w')\n",
"subprocess.call(['ls','nonexistantfile'],stdout=f,stderr=subprocess.STDOUT) #you can redirect stderr to stdout"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"ls: cannot access 'nonexistantfile': No such file or directory\n",
"\n"
]
}
],
"source": [
"print(open('dump').read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.check_call"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`check_call` is identical to `call`, but throws an exception when the called program has a nonzero return value."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"ls: cannot access 'missingfile': No such file or directory\n"
]
},
{
"ename": "CalledProcessError",
"evalue": "Command '['ls', 'missingfile']' returned non-zero exit status 2.",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mCalledProcessError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[23], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43msubprocess\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcheck_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mls\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mmissingfile\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\u001b[43m)\u001b[49m\n",
"File \u001b[0;32m/usr/lib/python3.10/subprocess.py:369\u001b[0m, in \u001b[0;36mcheck_call\u001b[0;34m(*popenargs, **kwargs)\u001b[0m\n\u001b[1;32m 367\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m cmd \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 368\u001b[0m cmd \u001b[38;5;241m=\u001b[39m popenargs[\u001b[38;5;241m0\u001b[39m]\n\u001b[0;32m--> 369\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m CalledProcessError(retcode, cmd)\n\u001b[1;32m 370\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;241m0\u001b[39m\n",
"\u001b[0;31mCalledProcessError\u001b[0m: Command '['ls', 'missingfile']' returned non-zero exit status 2."
]
}
],
"source": [
"subprocess.check_call(['ls','missingfile'])"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.check_output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.check_output"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"b'dump\\nfile with spaces\\n'"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"subprocess.check_output(ARGS, stdin=None, stderr=None, shell=False)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Typically, you are calling a program because you want to parse its output. `check_output` provides the easiest way to do this. Its return value is what was written to `stdout`. \n",
"\n",
"Nonzero return values result in a `CalledProcessError` exception (like `check_call`)."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'file with spaces\\n'\n"
]
}
],
"source": [
"files = subprocess.check_output('ls file*',shell=True)\n",
"print(files)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.check_output"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Can redirect `stderr` to `STDOUT`"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"b\"ls: cannot access 'non_existent_file': No such file or directory\\n\""
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"subprocess.check_output(\"ls non_existent_file; exit 0\", stderr=subprocess.STDOUT, shell=True)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"source": [
"Why `exit 0`?"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"How can we communicate with the program we are launching?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Popen"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All the previous functions are just convenience wrappers around the Popen object."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
""
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"dump\n",
"file with spaces\n"
]
}
],
"source": [
"subprocess.Popen(ARGS, stdin=None, stdout=None, stderr=None, shell=False, cwd=None, env=None)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Popen has quite a few optional arguments. Shown are just the most common. \n",
"\n",
"`cwd` sets the working directory for the process (if `None` defaults to the current working directory of the python script).\n",
"\n",
"`env` is a dictionary that can be used to define a new set of environment variables.\n",
"\n",
"*`Popen` is a constructor and returns a `Popen` object.* "
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"subprocess.Popen"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"proc = subprocess.Popen('echo')\n",
"type(proc)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Popen"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The python script does **not** wait for the called process to finish before returning.\n",
"\n",
"We can finally use `PIPE`.\n",
"\n",
"
"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.PIPE"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If we set stdin/stdout/stderr to `subprocess.PIPE` then they are available to read/write to in the resulting Popen object."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
"proc = subprocess.Popen('ls',stdout=subprocess.PIPE)"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"_io.BufferedReader"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"type(proc.stdout)"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'dump\\n'\n"
]
}
],
"source": [
"print(proc.stdout.readline())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# subprocess.PIPE\n",
"\n",
"Pipes enable communication between your script and the called program. \n",
"\n",
"If `stdout/stdin/stderr` is set to `subprocess.PIPE` then that input/output stream of the process is accessible through a file object in the returned object."
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'Hello'\n"
]
}
],
"source": [
"proc = subprocess.Popen('cat',stdin=subprocess.PIPE,stdout=subprocess.PIPE)\n",
"proc.stdin.write(b\"Hello\")\n",
"proc.stdin.close()\n",
"print(proc.stdout.read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"python3 strings are unicode, but most programs need byte strings"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"ename": "TypeError",
"evalue": "a bytes-like object is required, not 'str'",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"Cell \u001b[0;32mIn[34], line 2\u001b[0m\n\u001b[1;32m 1\u001b[0m proc \u001b[38;5;241m=\u001b[39m subprocess\u001b[38;5;241m.\u001b[39mPopen(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcat\u001b[39m\u001b[38;5;124m'\u001b[39m,stdin\u001b[38;5;241m=\u001b[39msubprocess\u001b[38;5;241m.\u001b[39mPIPE,stdout\u001b[38;5;241m=\u001b[39msubprocess\u001b[38;5;241m.\u001b[39mPIPE)\n\u001b[0;32m----> 2\u001b[0m \u001b[43mproc\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstdin\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mwrite\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mHello\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[1;32m 3\u001b[0m proc\u001b[38;5;241m.\u001b[39mstdin\u001b[38;5;241m.\u001b[39mclose()\n\u001b[1;32m 4\u001b[0m \u001b[38;5;28mprint\u001b[39m(proc\u001b[38;5;241m.\u001b[39mstdout\u001b[38;5;241m.\u001b[39mread())\n",
"\u001b[0;31mTypeError\u001b[0m: a bytes-like object is required, not 'str'"
]
}
],
"source": [
"proc = subprocess.Popen('cat',stdin=subprocess.PIPE,stdout=subprocess.PIPE)\n",
"proc.stdin.write(\"Hello\")\n",
"proc.stdin.close()\n",
"print(proc.stdout.read())"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Unicode (aside)\n",
"\n",
"Bytes strings (which were the default kinds of string in python2) store each character using a single byte (ASCII, like in the Martian).\n",
"\n",
"Unicode uses 1 to 6 bytes per a character.\n",
"\n",
"This allows supports for other languages and the all important emoji."
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"🦄\n"
]
}
],
"source": [
"print('\\U0001F984')"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"Converting bytes to string"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'a byte str'"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"b'a byte str'.decode()"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"b'a unicode string'"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'a unicode string'.encode()"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"b'Hello'\n"
]
}
],
"source": [
"proc = subprocess.Popen('cat',stdin=subprocess.PIPE,stdout=subprocess.PIPE)\n",
"proc.stdin.write(b\"Hello\")\n",
"proc.stdin.close()\n",
"print(proc.stdout.read())"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n"
],
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%%html\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Warning!"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"source": [
"*Managing simultaneous input and output is tricky and can easily lead to deadlocks*. \n",
"\n",
"For example, your script may be blocked waiting for output from the process which is blocked waiting for input.\n",
"\n",
"
\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# `Popen.communicate(input=None)`"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.\n",
"\n",
"`input` is a string of data to be provided to stdin (which must be set to `PIPE`). \n",
"\n",
"Likewise, to receive stdout/stderr, they must be set to `PIPE`.\n",
"\n",
"This *will not deadlock*. \n",
"\n",
"99% of the time if you have to both provide input and read output of a subprocess, communicate will do what you need.\n"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"proc = subprocess.Popen(\"awk '{print $1}'\",stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)\n",
"(out, err) = proc.communicate(b\"x y z\\n1 2 3\\na b c\\n\") #returns tuple of output and error"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"x\n",
"1\n",
"a\n",
"\n"
]
}
],
"source": [
"print(out.decode()) # decode converts a bytes string to a regular unicode string"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Interacting with Popen"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* `Popen.poll()` - check to see if process has terminated\n",
"* `Popen.wait()` - wait for process to terminate **Do not use PIPE**\n",
"* `Popen.terminate()` - terminate the process (ask nicely)\n",
"* `Popen.kill()` - kill the process with extreme prejudice\n",
"\n",
"Note that if your are generating a large amount of data, `communicate`, which buffers all the data in memory, may not be an option (instead just read from `Popen.stdout`). \n",
"\n",
"If you need to `PIPE` both `stdin` and `stdout` and can't use `communicate`, be *very* careful about controlling how data is communicated."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Review\n",
"\n",
"* Just want to run a command?\n",
" * `subprocess.call`\n",
"* Want the output of the command?\n",
" * `subprocess.check_output`\n",
"* Don't want to wait for command to finish? \n",
" * `subprocess.Popen`\n",
"* Need to provide data through stdin?\n",
" * `subprocess.Popen`, `stdin=subprocess.PIPE`, `communicate`"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Exercise"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We want to predict the binding affinity of a small molecule to a protein using the program `gnina`. \n",
"\n",
"For simplicity, run your code starting from this colab:\n",
"https://colab.research.google.com/drive/1QYo5QLUE80N_G28PlpYs6OKGddhhd931?usp=sharing"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--2023-11-08 16:58:28-- http://mscbio2025.csb.pitt.edu/files/rec.pdb\n",
"Resolving mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)... 136.142.4.139\n",
"Connecting to mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)|136.142.4.139|:80... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 489908 (478K) [chemical/x-pdb]\n",
"Saving to: ‘rec.pdb’\n",
"\n",
"rec.pdb 100%[===================>] 478.43K --.-KB/s in 0.009s \n",
"\n",
"2023-11-08 16:58:28 (52.6 MB/s) - ‘rec.pdb’ saved [489908/489908]\n",
"\n",
"--2023-11-08 16:58:28-- http://mscbio2025.csb.pitt.edu/files/lig.pdb\n",
"Resolving mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)... 136.142.4.139\n",
"Connecting to mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)|136.142.4.139|:80... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 3536 (3.5K) [chemical/x-pdb]\n",
"Saving to: ‘lig.pdb’\n",
"\n",
"lig.pdb 100%[===================>] 3.45K --.-KB/s in 0s \n",
"\n",
"2023-11-08 16:58:28 (519 MB/s) - ‘lig.pdb’ saved [3536/3536]\n",
"\n",
"--2023-11-08 16:58:28-- http://mscbio2025.csb.pitt.edu/files/receptor.pdb\n",
"Resolving mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)... 136.142.4.139\n",
"Connecting to mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)|136.142.4.139|:80... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 143208 (140K) [chemical/x-pdb]\n",
"Saving to: ‘receptor.pdb’\n",
"\n",
"receptor.pdb 100%[===================>] 139.85K --.-KB/s in 0.003s \n",
"\n",
"2023-11-08 16:58:28 (46.2 MB/s) - ‘receptor.pdb’ saved [143208/143208]\n",
"\n",
"--2023-11-08 16:58:28-- http://mscbio2025.csb.pitt.edu/files/ligs.sdf\n",
"Resolving mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)... 136.142.4.139\n",
"Connecting to mscbio2025.csb.pitt.edu (mscbio2025.csb.pitt.edu)|136.142.4.139|:80... connected.\n",
"HTTP request sent, awaiting response... 200 OK\n",
"Length: 65619 (64K) [chemical/x-mdl-sdfile]\n",
"Saving to: ‘ligs.sdf’\n",
"\n",
"ligs.sdf 100%[===================>] 64.08K --.-KB/s in 0.001s \n",
"\n",
"2023-11-08 16:58:28 (44.5 MB/s) - ‘ligs.sdf’ saved [65619/65619]\n",
"\n"
]
}
],
"source": [
"!wget http://mscbio2025.csb.pitt.edu/files/rec.pdb\n",
"!wget http://mscbio2025.csb.pitt.edu/files/lig.pdb\n",
"!wget http://mscbio2025.csb.pitt.edu/files/receptor.pdb\n",
"!wget http://mscbio2025.csb.pitt.edu/files/ligs.sdf"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"# Project\n",
"\n",
"1. Run the command `smina -r rec.pdb -l lig.pdb --minimize` on these files.\n",
"Parse the affinity and RMSD and print them on one line.\n",
"2. Run the command `smina -r receptor.pdb -l ligs.sdf --minimize`. Parse the affinities and RMSDS.\n",
" 1. Plot histograms of both\n",
" 2. Plot a scatter plot "
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"slideshow": {
"slide_type": "notes"
}
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/dkoes/.local/lib/python3.10/site-packages/matplotlib/projections/__init__.py:63: UserWarning: Unable to import Axes3D. This may be due to multiple versions of Matplotlib being installed (e.g. as a system package and as a pip package). As a result, the 3D projection is not available.\n",
" warnings.warn(\"Unable to import Axes3D. This may be due to multiple versions of \"\n",
"==============================\n",
"*** Open Babel Warning in PerceiveBondOrders\n",
" Failed to kekulize aromatic bonds in OBMol::PerceiveBondOrders\n",
"\n"
]
}
],
"source": [
"import subprocess, re\n",
"import matplotlib.pyplot as plt\n",
"import numpy as np\n",
"%matplotlib inline\n",
"\n",
"out = subprocess.check_output('gnina -r receptor.pdb -l ligs.sdf --minimize',shell=True).decode(\"utf-8\") \n",
"affinities = np.array(re.findall(r'Affinity: (\\S+)',out),dtype=float)\n",
"rmsds = np.array(re.findall(r'RMSD: (\\S+)',out),dtype=float)"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAWpElEQVR4nO3de4xU9fn48We5DVphFVhucq8tVo03tGStsVSpSoz1lraxJqIxJFpstWhrt4mXJamQmmLb1KhpLTYpVmOrtSlRU2jRRNEChihVqVAIqwK2GHYBZUE5vz++cX9dEdxZnlmY3dcrmT/mcM6eZ/04O++cnZ2pKYqiCACABL0O9gAAQPchLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANH26+oR79uyJt99+OwYMGBA1NTVdfXoAoBOKooht27bFyJEjo1evfV+X6PKwePvtt2P06NFdfVoAIEFTU1OMGjVqn//e5WExYMCAiPi/wQYOHNjVpwcAOqGlpSVGjx7d9jy+L10eFh/9+mPgwIHCAgCqzKe9jMGLNwGANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEhTVljccccdUVNT0+527LHHVmo2AKDKlP1ZIccff3wsWrTo/3+BPl3+cSMAwCGq7Cro06dPDB8+vBKzAABVruzXWLzxxhsxcuTImDBhQlxxxRWxYcOG/e7f2toaLS0t7W4AQPdUUxRF0dGdn3zyydi+fXtMnDgxNm7cGI2NjfHWW2/FqlWr9vn57HfccUc0Njbutb25udnHpsOnGPfDhQd7hLKtn3vBwR4BqICWlpaora391OfvssLi47Zu3Rpjx46NefPmxTXXXPOJ+7S2tkZra2u7wUaPHi0soAOEBXCo6GhYHNArL4888sj4/Oc/H2vWrNnnPqVSKUql0oGcBgCoEgf0Phbbt2+PtWvXxogRI7LmAQCqWFlhcfPNN8czzzwT69evj+effz4uueSS6N27d1x++eWVmg8AqCJl/SrkzTffjMsvvzy2bNkSdXV1ceaZZ8YLL7wQdXV1lZoPAKgiZYXFww8/XKk5AIBuwGeFAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkEZYAABphAUAkOaAwmLu3LlRU1MTN954Y9I4AEA163RYLFu2LO6///448cQTM+cBAKpYp8Ji+/btccUVV8SvfvWrOOqoo7JnAgCqVKfCYubMmXHBBRfE1KlTP3Xf1tbWaGlpaXcDALqnPuUe8PDDD8dLL70Uy5Yt69D+c+bMicbGxrIHg0zjfrjwYI/AIcz/H+zL+rkXHOwRqk5ZVyyamprihhtuiAULFkT//v07dExDQ0M0Nze33Zqamjo1KABw6CvrisWKFSvinXfeiVNPPbVt24cffhjPPvts/PKXv4zW1tbo3bt3u2NKpVKUSqWcaQGAQ1pZYXHOOefEK6+80m7b1VdfHccee2zccsste0UFANCzlBUWAwYMiBNOOKHdts985jMxePDgvbYDAD2Pd94EANKU/VchH7dkyZKEMQCA7sAVCwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgjbAAANIICwAgTVlhce+998aJJ54YAwcOjIEDB0Z9fX08+eSTlZoNAKgyZYXFqFGjYu7cubFixYpYvnx5nH322XHRRRfFP//5z0rNBwBUkT7l7HzhhRe2u//jH/847r333njhhRfi+OOPTx0MAKg+ZYXF//rwww/j0UcfjR07dkR9ff0+92ttbY3W1ta2+y0tLZ09JQBwiCs7LF555ZWor6+PnTt3xhFHHBGPP/54HHfccfvcf86cOdHY2HhAQwLVY9wPFx7sEYCDqOy/Cpk4cWKsXLkyXnzxxbjuuuti+vTp8eqrr+5z/4aGhmhubm67NTU1HdDAAMChq+wrFv369YtjjjkmIiImTZoUy5Yti5///Odx//33f+L+pVIpSqXSgU0JAFSFA34fiz179rR7DQUA0HOVdcWioaEhpk2bFmPGjIlt27bFQw89FEuWLImnn366UvMBAFWkrLB455134sorr4yNGzdGbW1tnHjiifH000/HV7/61UrNBwBUkbLC4oEHHqjUHABAN+CzQgCANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANGWFxZw5c+L000+PAQMGxNChQ+Piiy+O1atXV2o2AKDKlBUWzzzzTMycOTNeeOGF+Otf/xq7d++Oc889N3bs2FGp+QCAKtKnnJ2feuqpdvcffPDBGDp0aKxYsSLOOuus1MEAgOpTVlh8XHNzc0REDBo0aJ/7tLa2Rmtra9v9lpaWAzklAHAI63RY7NmzJ2688cb40pe+FCeccMI+95szZ040NjZ29jRlGffDhV1ynkzr515wsEcoWzX+dwaga3T6r0JmzpwZq1atiocffni/+zU0NERzc3PbrampqbOnBAAOcZ26YnH99dfHX/7yl3j22Wdj1KhR+923VCpFqVTq1HAAQHUpKyyKoojvfOc78fjjj8eSJUti/PjxlZoLAKhCZYXFzJkz46GHHoonnngiBgwYEJs2bYqIiNra2jjssMMqMiAAUD3Keo3FvffeG83NzTFlypQYMWJE2+2RRx6p1HwAQBUp+1chAAD74rNCAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASCMsAIA0wgIASFN2WDz77LNx4YUXxsiRI6Ompib+9Kc/VWAsAKAalR0WO3bsiJNOOinuueeeSswDAFSxPuUeMG3atJg2bVolZgEAqlzZYVGu1tbWaG1tbbvf0tJS6VMCAAdJxcNizpw50djYWOnTVK1xP1x4sEcAYB+q8Wf0+rkXHNTzV/yvQhoaGqK5ubnt1tTUVOlTAgAHScWvWJRKpSiVSpU+DQBwCPA+FgBAmrKvWGzfvj3WrFnTdn/dunWxcuXKGDRoUIwZMyZ1OACgupQdFsuXL4+vfOUrbfdnzZoVERHTp0+PBx98MG0wAKD6lB0WU6ZMiaIoKjELAFDlvMYCAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEgjLACANMICAEjTqbC45557Yty4cdG/f/+YPHly/OMf/8ieCwCoQmWHxSOPPBKzZs2K22+/PV566aU46aST4rzzzot33nmnEvMBAFWk7LCYN29ezJgxI66++uo47rjj4r777ovDDz88fvOb31RiPgCgivQpZ+ddu3bFihUroqGhoW1br169YurUqbF06dJPPKa1tTVaW1vb7jc3N0dEREtLS2fm3a89re+lf00AqCaVeH79369bFMV+9ysrLP773//Ghx9+GMOGDWu3fdiwYfH6669/4jFz5syJxsbGvbaPHj26nFMDAB1Q+7PKfv1t27ZFbW3tPv+9rLDojIaGhpg1a1bb/T179sS7774bgwcPjpqamkqfvp2WlpYYPXp0NDU1xcCBA7v03Hw663Pos0aHNutzaKv29SmKIrZt2xYjR47c735lhcWQIUOid+/esXnz5nbbN2/eHMOHD//EY0qlUpRKpXbbjjzyyHJOm27gwIFVuag9hfU59FmjQ5v1ObRV8/rs70rFR8p68Wa/fv1i0qRJsXjx4rZte/bsicWLF0d9fX35EwIA3UrZvwqZNWtWTJ8+PU477bT44he/GD/72c9ix44dcfXVV1diPgCgipQdFt/85jfjP//5T9x2222xadOmOPnkk+Opp57a6wWdh6JSqRS33377Xr+a4dBgfQ591ujQZn0ObT1lfWqKT/u7EQCADvJZIQBAGmEBAKQRFgBAGmEBAKTptmGxZMmSqKmp+cTbsmXL9nnclClT9tr/2muv7cLJe47OrtHOnTtj5syZMXjw4DjiiCPisssu2+tN28izcOHCmDx5chx22GFx1FFHxcUXX7zf/a+66qq91vP888/vmmF7qHLXqCiKuO2222LEiBFx2GGHxdSpU+ONN97ommF7mHHjxu31eJg7d+5+j6n256GKv6X3wXLGGWfExo0b22279dZbY/HixXHaaaft99gZM2bE7Nmz2+4ffvjhFZmxp+vsGn3ve9+LhQsXxqOPPhq1tbVx/fXXx6WXXhrPPfdcpUfucf74xz/GjBkz4s4774yzzz47Pvjgg1i1atWnHnf++efH/Pnz2+539z+vO5g6s0Y/+clP4he/+EX89re/jfHjx8ett94a5513Xrz66qvRv3//Lpq855g9e3bMmDGj7f6AAQM+9Ziqfh4qeohdu3YVdXV1xezZs/e735e//OXihhtu6JqhaKcja7R169aib9++xaOPPtq27bXXXisioli6dGlXjNlj7N69uzj66KOLX//612UdN3369OKiiy6qzFC005k12rNnTzF8+PDirrvuatu2devWolQqFb///e8rMWaPNnbs2OLuu+8u65hqfx7qtr8K+bg///nPsWXLlg69Q+iCBQtiyJAhccIJJ0RDQ0O8956PY+8KHVmjFStWxO7du2Pq1Klt24499tgYM2ZMLF26tCvG7DFeeumleOutt6JXr15xyimnxIgRI2LatGkdumKxZMmSGDp0aEycODGuu+662LJlSxdM3PN0Zo3WrVsXmzZtavcYqq2tjcmTJ3sMVcjcuXNj8ODBccopp8Rdd90VH3zwwaceU83PQ932VyEf98ADD8R5550Xo0aN2u9+3/rWt2Ls2LExcuTIePnll+OWW26J1atXx2OPPdZFk/ZcHVmjTZs2Rb9+/fb6ILthw4bFpk2bKjxhz/Lvf/87IiLuuOOOmDdvXowbNy5++tOfxpQpU+Jf//pXDBo06BOPO//88+PSSy+N8ePHx9q1a+NHP/pRTJs2LZYuXRq9e/fuym+h2+vMGn30OPn4uyV7DFXGd7/73Tj11FNj0KBB8fzzz0dDQ0Ns3Lgx5s2bt89jqv556GBfMinXLbfcUkTEfm+vvfZau2OampqKXr16FX/4wx/KPt/ixYuLiCjWrFmT9S10e5VcowULFhT9+vXba/vpp59e/OAHP0j9Prqrjq7PggULiogo7r///rZjd+7cWQwZMqS47777Ony+tWvXFhFRLFq0qBLfTrdUyTV67rnniogo3n777Xbbv/71rxff+MY3Kvp9dRed+Rn3kQceeKDo06dPsXPnzg6fr9qeh6ruisVNN90UV1111X73mTBhQrv78+fPj8GDB8fXvva1ss83efLkiIhYs2ZNfPazny37+J6okms0fPjw2LVrV2zdurXdVYvNmzfH8OHDOztyj9LR9fnohbXHHXdc2/ZSqRQTJkyIDRs2dPh8EyZMiCFDhsSaNWvinHPO6dTMPU0l1+ijx8nmzZtjxIgRbds3b94cJ5988oEN3kN05mfcRyZPnhwffPBBrF+/PiZOnNih81Xb81DVhUVdXV3U1dV1eP+iKGL+/Plx5ZVXRt++fcs+38qVKyMi2j0A2b9KrtGkSZOib9++sXjx4rjssssiImL16tWxYcOGqK+vP6C5e4qOrs+kSZOiVCrF6tWr48wzz4yIiN27d8f69etj7NixHT7fm2++GVu2bPEYKkMl12j8+PExfPjwWLx4cVtItLS0xIsvvhjXXXdd2vfQnZX7M+5/rVy5Mnr16hVDhw4t65iIKnoeOtiXTCpt0aJF+7ws9eabbxYTJ04sXnzxxaIoimLNmjXF7Nmzi+XLlxfr1q0rnnjiiWLChAnFWWed1dVj9yjlrFFRFMW1115bjBkzpvjb3/5WLF++vKivry/q6+u7cuQe44YbbiiOPvro4umnny5ef/314pprrimGDh1avPvuu237TJw4sXjssceKoiiKbdu2FTfffHOxdOnSYt26dcWiRYuKU089tfjc5z5X1qVfOq7cNSqKopg7d25x5JFHFk888UTx8ssvFxdddFExfvz44v333z8Y30K39fzzzxd33313sXLlymLt2rXF7373u6Kurq648sor2/bpjs9D3T4sLr/88uKMM874xH9bt25dERHF3//+96IoimLDhg3FWWedVQwaNKgolUrFMcccU3z/+98vmpubu3DinqecNSqKonj//feLb3/728VRRx1VHH744cUll1xSbNy4sYum7Vl27dpV3HTTTcXQoUOLAQMGFFOnTi1WrVrVbp+IKObPn18URVG89957xbnnnlvU1dUVffv2LcaOHVvMmDGj2LRp00GYvmcod42K4v/+5PTWW28thg0bVpRKpeKcc84pVq9e3cWTd38rVqwoJk+eXNTW1hb9+/cvvvCFLxR33nlnu8jujs9DPjYdAEjTY97HAgCoPGEBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKQRFgBAGmEBAKT5f9xYxCQ1VNuKAAAAAElFTkSuQmCC",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.hist(affinities);"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAh8AAAGdCAYAAACyzRGfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/SrBM8AAAACXBIWXMAAA9hAAAPYQGoP6dpAAAdVElEQVR4nO3df5DU9X348dfJeQtxuFOw/LjmEKRRFA02ogxiEmiZEkTUdFptYynFNib1Eqp0jFCDJPXHoeM4NIZCY5tApypJW6FWLMYSCTVilF+trYoSUGnsQZ0md4B1Re7z/eM77vTkQPf47Ptuz8dj5vPHfva9+3nxzsE9s7vn1WRZlgUAQCIn9PQAAMCHi/gAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkant6gPfq6OiI119/PQYOHBg1NTU9PQ4A8AFkWRb79++PxsbGOOGEY7+20evi4/XXX4+mpqaeHgMA6IY9e/bERz/60WOu6XXxMXDgwIj4/8PX19f38DQAwAfR3t4eTU1Npe/jx9Lr4uPdt1rq6+vFBwBUmQ/ykQkfOAUAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJFXb0wOkNnL+2p4eoWyvLJ7R0yMAQG688gEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AIKmy42Pjxo0xc+bMaGxsjJqamlizZs0Ra1544YW47LLLoqGhIU466aS44IIL4rXXXstjXgCgypUdHwcPHoxx48bF0qVLu7z/Jz/5SVx88cUxZsyY2LBhQ/zbv/1bLFy4MPr373/cwwIA1a+23AdMnz49pk+fftT7b7755rjkkkvirrvuKp0bPXp096YDAPqcXD/z0dHREWvXro0zzjgjpk2bFkOGDIkJEyZ0+dbMu4rFYrS3t3c6AIC+K9f42LdvXxw4cCAWL14cn/nMZ+L73/9+fPazn41f//Vfjx/+8IddPqalpSUaGhpKR1NTU54jAQC9TO6vfEREXH755XHDDTfEeeedF/Pnz49LL700li9f3uVjFixYEG1tbaVjz549eY4EAPQyZX/m41hOPfXUqK2tjbPPPrvT+bPOOiuefPLJLh9TKBSiUCjkOQYA0Ivl+spHXV1dXHDBBbFjx45O51966aU47bTT8rwUAFClyn7l48CBA7Fz587S7d27d8f27dtj0KBBMWLEiLjxxhvjqquuik996lMxZcqUWLduXfzjP/5jbNiwIc+5AYAqVXZ8bN68OaZMmVK6PW/evIiImD17dqxYsSI++9nPxvLly6OlpSXmzp0bZ555Zvz93/99XHzxxflNDQBUrbLjY/LkyZFl2THXXHPNNXHNNdd0eygAoO/yu10AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASZUdHxs3boyZM2dGY2Nj1NTUxJo1a4669otf/GLU1NTEkiVLjmNEAKAvKTs+Dh48GOPGjYulS5cec93q1avj6aefjsbGxm4PBwD0PbXlPmD69Okxffr0Y6756U9/Gl/+8pfjscceixkzZnR7OACg7yk7Pt5PR0dHzJo1K2688cYYO3bs+64vFotRLBZLt9vb2/MeCQDoRXL/wOmdd94ZtbW1MXfu3A+0vqWlJRoaGkpHU1NT3iMBAL1IrvGxZcuW+LM/+7NYsWJF1NTUfKDHLFiwINra2krHnj178hwJAOhlco2Pf/mXf4l9+/bFiBEjora2Nmpra+PVV1+NP/7jP46RI0d2+ZhCoRD19fWdDgCg78r1Mx+zZs2KqVOndjo3bdq0mDVrVsyZMyfPSwEAVars+Dhw4EDs3LmzdHv37t2xffv2GDRoUIwYMSIGDx7caf2JJ54Yw4YNizPPPPP4pwUAql7Z8bF58+aYMmVK6fa8efMiImL27NmxYsWK3AYDAPqmsuNj8uTJkWXZB17/yiuvlHsJAKAP87tdAICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgqbLjY+PGjTFz5sxobGyMmpqaWLNmTem+Q4cOxU033RTnnntunHTSSdHY2Bi/+7u/G6+//nqeMwMAVazs+Dh48GCMGzculi5desR9b775ZmzdujUWLlwYW7dujYceeih27NgRl112WS7DAgDVr7bcB0yfPj2mT5/e5X0NDQ3x+OOPdzr3zW9+My688MJ47bXXYsSIEd2bEgDoM8qOj3K1tbVFTU1NnHzyyV3eXywWo1gslm63t7dXeiQAoAdV9AOnb731Vtx0003x27/921FfX9/lmpaWlmhoaCgdTU1NlRwJAOhhFYuPQ4cOxZVXXhlZlsWyZcuOum7BggXR1tZWOvbs2VOpkQCAXqAib7u8Gx6vvvpq/OAHPzjqqx4REYVCIQqFQiXGAAB6odzj493wePnll+OJJ56IwYMH530JAKCKlR0fBw4ciJ07d5Zu7969O7Zv3x6DBg2K4cOHx2/8xm/E1q1b45FHHonDhw9Ha2trREQMGjQo6urq8pscAKhKZcfH5s2bY8qUKaXb8+bNi4iI2bNnx9e+9rV4+OGHIyLivPPO6/S4J554IiZPntz9SQGAPqHs+Jg8eXJkWXbU+491HwCA3+0CACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASKrs+Ni4cWPMnDkzGhsbo6amJtasWdPp/izL4pZbbonhw4fHgAEDYurUqfHyyy/nNS8AUOXKjo+DBw/GuHHjYunSpV3ef9ddd8U3vvGNWL58efz4xz+Ok046KaZNmxZvvfXWcQ8LAFS/2nIfMH369Jg+fXqX92VZFkuWLImvfvWrcfnll0dExF//9V/H0KFDY82aNfFbv/VbxzctAFD1cv3Mx+7du6O1tTWmTp1aOtfQ0BATJkyITZs2dfmYYrEY7e3tnQ4AoO/KNT5aW1sjImLo0KGdzg8dOrR033u1tLREQ0ND6WhqaspzJACgl+nxn3ZZsGBBtLW1lY49e/b09EgAQAXlGh/Dhg2LiIi9e/d2Or93797Sfe9VKBSivr6+0wEA9F25xseoUaNi2LBhsX79+tK59vb2+PGPfxwTJ07M81IAQJUq+6ddDhw4EDt37izd3r17d2zfvj0GDRoUI0aMiOuvvz5uu+22+NjHPhajRo2KhQsXRmNjY1xxxRV5zg0AVKmy42Pz5s0xZcqU0u158+ZFRMTs2bNjxYoV8ZWvfCUOHjwY1157bfz85z+Piy++ONatWxf9+/fPb2oAoGrVZFmW9fQQ/1d7e3s0NDREW1tbRT7/MXL+2tyfs9JeWTyjp0cAgGMq5/t3j/+0CwDw4SI+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBIKvf4OHz4cCxcuDBGjRoVAwYMiNGjR8ett94aWZblfSkAoArV5v2Ed955ZyxbtixWrlwZY8eOjc2bN8ecOXOioaEh5s6dm/flAIAqk3t8PPXUU3H55ZfHjBkzIiJi5MiR8eCDD8YzzzyT96UAgCqU+9suF110Uaxfvz5eeumliIj413/913jyySdj+vTpeV8KAKhCub/yMX/+/Ghvb48xY8ZEv3794vDhw3H77bfH1Vdf3eX6YrEYxWKxdLu9vT3vkQCAXiT3Vz6+973vxf333x8PPPBAbN26NVauXBl33313rFy5ssv1LS0t0dDQUDqampryHgkA6EVqspx/DKWpqSnmz58fzc3NpXO33XZb/M3f/E28+OKLR6zv6pWPpqamaGtri/r6+jxHi4iIkfPX5v6clfbK4hk9PQIAHFN7e3s0NDR8oO/fub/t8uabb8YJJ3R+QaVfv37R0dHR5fpCoRCFQiHvMQCAXir3+Jg5c2bcfvvtMWLEiBg7dmxs27Yt7rnnnrjmmmvyvhQAUIVyj4977703Fi5cGNddd13s27cvGhsb4wtf+ELccssteV8KAKhCucfHwIEDY8mSJbFkyZK8nxoA6AP8bhcAICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFK1PT0A72/k/LU9PULZXlk8o6dHAKCX8soHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkKhIfP/3pT+N3fud3YvDgwTFgwIA499xzY/PmzZW4FABQZWrzfsKf/exnMWnSpJgyZUr80z/9U/zCL/xCvPzyy3HKKafkfSkAoArlHh933nlnNDU1xXe+853SuVGjRuV9GQCgSuX+tsvDDz8c48ePj9/8zd+MIUOGxC//8i/Hfffdd9T1xWIx2tvbOx0AQN+Ve3zs2rUrli1bFh/72Mfiscceiz/8wz+MuXPnxsqVK7tc39LSEg0NDaWjqakp75EAgF6kJsuyLM8nrKuri/Hjx8dTTz1VOjd37tx49tlnY9OmTUesLxaLUSwWS7fb29ujqakp2traor6+Ps/RIiJi5Py1uT8nR3pl8YyeHgGAhNrb26OhoeEDff/O/ZWP4cOHx9lnn93p3FlnnRWvvfZal+sLhULU19d3OgCAviv3+Jg0aVLs2LGj07mXXnopTjvttLwvBQBUodzj44Ybboinn3467rjjjti5c2c88MAD8a1vfSuam5vzvhQAUIVyj48LLrggVq9eHQ8++GCcc845ceutt8aSJUvi6quvzvtSAEAVyv2/8xERcemll8all15aiacGAKqc3+0CACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASEp8AABJiQ8AICnxAQAkJT4AgKTEBwCQlPgAAJISHwBAUuIDAEhKfAAASYkPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApMQHAJCU+AAAkhIfAEBS4gMASKri8bF48eKoqamJ66+/vtKXAgCqQEXj49lnn42/+Iu/iI9//OOVvAwAUEUqFh8HDhyIq6++Ou6777445ZRTKnUZAKDKVCw+mpubY8aMGTF16tRjrisWi9He3t7pAAD6rtpKPOmqVati69at8eyzz77v2paWlvj6179eiTEAgF4o91c+9uzZE3/0R38U999/f/Tv3/991y9YsCDa2tpKx549e/IeCQDoRXJ/5WPLli2xb9+++MQnPlE6d/jw4di4cWN885vfjGKxGP369SvdVygUolAo5D0GANBL5R4fv/qrvxrPPfdcp3Nz5syJMWPGxE033dQpPACAD5/c42PgwIFxzjnndDp30kknxeDBg484DwB8+PgvnAIASVXkp13ea8OGDSku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vHhxVldXl/3d3/1d9l//9V+lY//+/T31R6ha5e79e/lpl+4rd+9fe+21bODAgdmXvvSlbMeOHdkjjzySDRkyJLvtttt66o9Qlcrd90WLFmUDBw7MHnzwwWzXrl3Z97///Wz06NHZlVde2VN/hKq1f//+bNu2bdm2bduyiMjuueeebNu2bdmrr76aZVmWzZ8/P5s1a1Zp/bs/anvjjTdmL7zwQrZ06dK+96O2WZZl9957bzZixIisrq4uu/DCC7Onn366dN+nP/3pbPbs2Z3Wf+9738vOOOOMrK6uLhs7dmy2du3axBP3HeXs/WmnnZZFxBHHokWL0g/eB5T7df9/iY/jU+7eP/XUU9mECROyQqGQnX766dntt9+evfPOO4mnrn7l7PuhQ4eyr33ta9no0aOz/v37Z01NTdl1112X/exnP0s/eJV74oknuvy3+939nj17dvbpT3/6iMecd955WV1dXXb66adn3/nOd3KZpSbLvG4FAKTTKz7zAQB8eIgPACAp8QEAJCU+AICkxAcAkJT4AACSEh8AQFLiAwBISnwAAEmJDwAgKfEBACQlPgCApP4fG+GKkdz18MUAAAAASUVORK5CYII=",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.hist(rmsds);"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"data": {
"image/png": "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m5D2mzp1qnXjjTdGpigEdeT4BAIBy+v1Wg899FBw29GjRy2322397ne/i0SZce+8886zHn744ZD2ifXzEJeloujFF1/U4cOHNX369DO2feKJJ5SWlqbc3FwVFRXpxIkTUagQ7TlGW7du1ZdffqmCgoLgtosvvljnnnuuysrKolFm3Ni2bZv279+vhIQEDRo0SJmZmbr++uvb1XOzefNmpaenq1+/fpo9e7YOHz4chYrjS0eOT2VlpXw+X7O/H4/Ho7y8PP5+IuiBBx5Qr169NGjQID300EM6efLkGfeJ5fMQl6WiaO3atRo9erTOOeec07a7+eabdd5556lPnz76+9//rnnz5mnnzp167rnnolRp/GrPMfL5fEpKSlKPHj2abc/IyJDP54twhfFlz549kqT7779fy5cvV3Z2tpYtW6arr75aH3/8sVJTU1vdb8yYMfre976nnJwc7d69W/fee6+uv/56lZWVKTExMZpvwWgdOT5NfyMZGRnNtvP3Ezn/9V//pcGDBys1NVVbtmxRUVGRqqurtXz58jb3ifnzkN1dR7Fo3rx5lqTTPj788MNm+1RVVVkJCQnWs88+G/LrlZaWWpKsXbt2hestGC+Sx+iJJ56wkpKSWmwfNmyY9eMf/zis78NU7T0+TzzxhCXJevTRR4P71tfXW2lpadbq1avb/Xq7d++2JFmvv/56JN6OcSJ5fN555x1LkvXpp582237TTTdZ//mf/xnR92WSjnzGNVm7dq3VpUsXq76+vt2vF2vnIXpuOuAHP/iBpk2bdto2559/frPn69atU69evTRu3LiQXy8vL0+StGvXLl1wwQUh7x+PInmMvF6vGhsbdfTo0Wa9NzU1NfJ6vR0tOa609/g0Dfbu379/cLvb7db555+vffv2tfv1zj//fKWlpWnXrl267rrrOlRzPInk8Wn6G6mpqVFmZmZwe01NjQYOHNi5wuNIRz7jmuTl5enkyZPau3ev+vXr167Xi7XzEOGmA3r37q3evXu3u71lWVq3bp2mTJmirl27hvx6FRUVktTsgwCnF8ljNGTIEHXt2lWlpaWaMGGCJGnnzp3at2+f8vPzO1V3vGjv8RkyZIjcbrd27typkSNHSpK+/PJL7d27V+edd167X++TTz7R4cOH+Rtqp0gen5ycHHm9XpWWlgbDTF1dnf7yl79o9uzZYXsPpgv1M+6rKioqlJCQoPT09JD2kWLoPGR311E8eP3119vsIvzkk0+sfv36WX/5y18sy7KsXbt2WYsXL7bee+89q7Ky0nrhhRes888/37ryyiujXXZcCeUYWZZlzZo1yzr33HOtP/3pT9Z7771n5efnW/n5+dEsOW7cfffdVt++fa1XX33V+uijj6wZM2ZY6enp1pEjR4Jt+vXrZz333HOWZVnWsWPHrB/+8IdWWVmZVVlZab3++uvW4MGDrYsuuiikbni0T6jHx7Is64EHHrB69OhhvfDCC9bf//5368Ybb7RycnKsL774wo63YLQtW7ZYDz/8sFVRUWHt3r3b2rBhg9W7d29rypQpwTYmnocIN1EwadIka8SIEa3+rLKy0pJkvfHGG5ZlWda+ffusK6+80kpNTbXcbrd14YUXWj/60Y+s2traKFYcf0I5RpZlWV988YV1xx13WD179rTOOuss6z/+4z+s6urqKFUbXxobG60f/OAHVnp6upWSkmIVFBRY27dvb9ZGkrVu3TrLsizrxIkT1qhRo6zevXtbXbt2tc477zxr5syZls/ns6F684V6fCzr1HTwBQsWWBkZGZbb7bauu+46a+fOnVGuPD5s3brVysvLszwej5WcnGxdcskl1pIlS5oFfRPPQy7LsiwbO44AAADCinVuAACAUQg3AADAKIQbAABgFMINAAAwCuEGAAAYhXADAACMQrgBAABGIdwAAACjEG4AOI5lWbr99tuVmpoql8ulioqKVrddffXVuueee9r9e/fu3RvcF4C5WKEYgG3Kyso0cuRIjRkzRps2bQpu/7//+z/deOON2rx5c/CO3q+99lqLbXV1deratatSUlLa9Xp+v18HDx5UWlqaunTpos2bN+uaa67RZ5991uwO7wBiG3cFB2CbtWvXas6cOVq7dq0+/fRT9enTR5K0e/duZWZmasSIEcG2rW1LTU0N6fUSExPl9XrDUzwAx+KyFABbfP7559q4caNmz56t7373u3r88cclSdOmTdOcOXO0b98+uVwuZWdnt7pNUovLUtnZ2VqyZIluvfVWpaSk6Nxzz9Wvf/3r4M+/ellq7969uuaaayRJPXv2lMvl0rRp07R+/Xr16tVLDQ0NzeodP368brnlloj+mwAID8INAFs8/fTTuvjii9WvXz9NnjxZjz32mCzL0i9+8QstXrxY55xzjqqrq/XXv/611W1tWbZsmYYOHaq//e1vuuOOOzR79mzt3LmzRbusrCz9/ve/lyTt3LlT1dXV+sUvfqGbbrpJfr9fL774YrDtgQMHtGnTJt16663h/4cAEHaEGwC2WLt2rSZPnixJGjNmjGpra/XnP/9ZHo9HKSkpwUtIvXv3bnVbW2644QbdcccduvDCCzVv3jylpaXpjTfeaNEuMTExeFkrPT1dXq9XHo9H3bp1080336x169YF227YsEHnnnuurr766vD+IwCICMINgKjbuXOnysvLNWnSJElSly5dNHHiRK1du7bTv/uyyy4L/rfL5ZLX69WBAwdC+h0zZ87UH//4R+3fv1+S9Pjjj2vatGlyuVydrg9A5DGgGEDUrV27VidPngwOIJZOTf92u91auXJlp353165dmz13uVwKBAIh/Y5BgwZpwIABWr9+vUaNGqUPPvig2WwuAM5GuAEQVSdPntT69eu1bNkyjRo1qtnPxo8fr9/97ndRqyUpKUnSqSniX3fbbbdpxYoV2r9/vwoKCpSVlRW1ugB0DpelAETVyy+/rM8++0wzZsxQbm5us8eECRPCcmmqvc477zy5XC69/PLLOnjwoD7//PPgz26++WZ98sknWrNmDQOJgRhDuAEQVWvXrlVBQYE8Hk+Ln02YMEHvvfee6urqolJL3759tWjRIs2fP18ZGRm66667gj/zeDyaMGGCzj77bI0fPz4q9QAID1YoBoA2XHfddfrWt76lX/7yl3aXAiAEhBsA+JrPPvtMmzdv1ve//33t2LFD/fr1s7skACFgQDEAfM2gQYP02Wef6cEHHyTYADGInhsAAGAUBhQDAACjEG4AAIBRCDcAAMAohBsAAGAUwg0AADAK4QYAABiFcAMAAIxCuAEAAEb5/wDgajncci7VGwAAAABJRU5ErkJggg==",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.plot(affinities,rmsds,'o')\n",
"plt.xlabel(\"Affinity\")\n",
"plt.ylabel(\"RMSD\");"
]
}
],
"metadata": {
"celltoolbar": "Slideshow",
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
}
},
"nbformat": 4,
"nbformat_minor": 1
}