Skip to content

Commit

Permalink
Added example notebook
Browse files Browse the repository at this point in the history
  • Loading branch information
xoltar committed Aug 15, 2018
1 parent e9dfb47 commit 0e2d1d0
Show file tree
Hide file tree
Showing 3 changed files with 428 additions and 0 deletions.
375 changes: 375 additions & 0 deletions example/RIVET Python API Tour.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,375 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# RIVET Python API (pyrivet)"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from pyrivet import rivet\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's start with some warmups. We can run RIVET on an existing data file:"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['circle_data_240pts_codensity.txt',\n",
" 'circle_data_60pts_codensity.txt.H0_x0_y0.rivet',\n",
" 'circle_data_600pts_codensity.txt',\n",
" 'circle_data_60pts_codensity.txt',\n",
" 'circle_data_60pts.png',\n",
" 'circle_data_240pts.png',\n",
" 'points1.txt',\n",
" 'points2.txt',\n",
" 'points3.txt',\n",
" 'circle_data_60pts_codensity.txt.H1_x20_y20.rivet',\n",
" 'points6.txt',\n",
" 'points4.txt',\n",
" 'points5.txt']"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# The RIVET distribution comes with some test data files\n",
"import os\n",
"\n",
"rivet_location = '../../rivet' #Might be in a different location for you\n",
"os.listdir(rivet_location + '/data/Test_Point_Clouds')\n"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'../../rivet/data/Test_Point_Clouds/circle_data_60pts_codensity.txt.H1_x20_y20.rivet'"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"computed_file_path = rivet.compute_file(\n",
" rivet_location + '/data/Test_Point_Clouds/circle_data_60pts_codensity.txt',\n",
" homology=1,\n",
" x=20,\n",
" y=20)\n",
"computed_file_path"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output when used this way is a path to a file generated by RIVET. We can load the contents of that computed file into memory and run other RIVET commands on it, like computing barcodes."
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[((45.0, 0.0), Barcode([Bar(6.98695, 7.68564, 1), Bar(5.65685, 6.28825, 1)])),\n",
" ((45.0, 1.0), Barcode([Bar(5.65685, 5.68564, 1)]))]"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"with open(computed_file_path, 'rb') as f:\n",
" computed_data = f.read()\n",
"\n",
"codes = rivet.barcodes(computed_data, [\n",
" (45, 0), # 45 degrees, offset 0\n",
" (45, 1), # 45 degrees, offset 1\n",
"])\n",
"codes"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's look at one barcode in the list. The format for each bar is Bar(birth, death, multiplicity)"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Barcode([Bar(6.98695, 7.68564, 1), Bar(5.65685, 6.28825, 1)])"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"barcode1 = codes[0][1]\n",
"barcode1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A barcode can also be easily converted to a Numpy array:"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[6.98695, 7.68564, 1. ],\n",
" [5.65685, 6.28825, 1. ]])"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"barcode1.to_array()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can also load data directly from memory."
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"MultiBetti(dimensions=Dimensions([Fraction(0, 1)], [Fraction(0, 1), Fraction(1838477, 1000000), Fraction(2012461, 1000000), Fraction(512957, 250000), Fraction(1159741, 500000), Fraction(3041381, 1000000), Fraction(3125699, 1000000), Fraction(388973, 100000)]), graded_rank=[[5.]\n",
" [4.]\n",
" [3.]\n",
" [2.]\n",
" [2.]\n",
" [1.]\n",
" [1.]\n",
" [1.]], xi_0=[(0, 0, 5)], xi_1=[(0, 1, 1), (0, 2, 1), (0, 3, 1), (0, 5, 1)], xi_2=[])"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"#Equivalent to the 'points1.txt' sample data file in the RIVET distribution\n",
"points = rivet.PointCloud(\n",
" rivet.points(\n",
" (0.3, 1.5),\n",
" (4.2, 3.8),\n",
" (5.6, 2.3),\n",
" (2.9, 5.1),\n",
" (3.3, 2.0)\n",
" ),\n",
" second_param_name='birth',\n",
" max_dist=4.1\n",
")\n",
"\n",
"# Now let's take the Betti information\n",
"betti = rivet.betti(points)\n",
"betti"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's look at two persistence modules for molecules.\n",
"\n",
"First, let's see how to compute L2 distance on Hilbert functions of the persistence modules."
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Distance with Hilbert functions: 3442399.7063080464\n"
]
}
],
"source": [
"# Let's look at H0, binned into 10x10.\n",
"aspirin_h0_betti = rivet.betti_file('aspirin-ZINC000000000053.sdf.txt', homology=0, x=10, y=10)\n",
"tylenol_h0_betti = rivet.betti_file('tylenol-ZINC000013550868.sdf.txt', homology=0, x=10, y=10)\n",
"\n",
"# We can compute distance between these using Hilbert functions\n",
"from pyrivet import hilbert_distance\n",
"print(\"Distance with Hilbert functions:\", \n",
" hilbert_distance.distance(\n",
" aspirin_h0_betti, \n",
" tylenol_h0_betti\n",
" )\n",
" )\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And now let's look at the matching distance."
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Distance with matching distance: 1.2909725839903918e-06\n"
]
}
],
"source": [
"# We can also compute the matching distance, if we have the full precomputed arrangement\n",
"aspirin_h0 = open(rivet.compute_file('aspirin-ZINC000000000053.sdf.txt', homology=0, x=10, y=10), 'rb').read()\n",
"tylenol_h0 = open(rivet.compute_file('tylenol-ZINC000013550868.sdf.txt', homology=0, x=10, y=10), 'rb').read()\n",
"\n",
"from pyrivet import matching_distance\n",
"print(\"Distance with matching distance:\",\n",
" matching_distance.matching_distance(aspirin_h0, tylenol_h0, grid_size=10, normalize=True)\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"While the RIVET GUI does many things that would be tricky to duplicate in a notebook, we can at least visualize the Hilbert\n",
"functions!"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.image.AxesImage at 0x10d768208>"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 864x576 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib inline\n",
"from matplotlib import pyplot as plt\n",
"\n",
"fig = plt.figure(figsize=(12,8))\n",
"plots = fig.subplots(1, 2, sharex=True, sharey=True)\n",
"\n",
"plots[0].imshow(aspirin_h0_betti.graded_rank, origin='lower', aspect='auto', cmap='coolwarm')\n",
"plots[1].imshow(tylenol_h0_betti.graded_rank, origin='lower', aspect='auto', cmap='coolwarm')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.6.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Loading

0 comments on commit 0e2d1d0

Please sign in to comment.