Created
June 27, 2025 18:18
-
-
Save alisterburt/1e97af09ef440d3965dcbd0e8f6eaaae to your computer and use it in GitHub Desktop.
transformations
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"metadata": {}, | |
"cell_type": "markdown", | |
"source": [ | |
"# transformations\n", | |
"\n", | |
"this page is great\n", | |
"https://www.labri.fr/perso/nrougier/python-opengl/#transformationsb" | |
], | |
"id": "f5862be824d9c6c4" | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T17:52:48.575038Z", | |
"start_time": "2025-06-27T17:52:48.565156Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"import sympy as sp\n", | |
"\n", | |
"# first, let's set up our transformation as a 4x4 matrix A\n", | |
"# this matrix encodes our rotation and translation for transforming structures/maps\n", | |
"a11, a12, a13, a14 = sp.symbols('a11 a12 a13 a14')\n", | |
"a21, a22, a23, a24 = sp.symbols('a21 a22 a23 a24')\n", | |
"a31, a32, a33, a34 = sp.symbols('a31 a32 a33 a34')\n", | |
"a41, a42, a43, a44 = sp.symbols('a41 a42 a43 a44')\n", | |
"\n", | |
"A = sp.Matrix([\n", | |
" [a11, a12, a13, a14],\n", | |
" [a21, a22, a23, a24],\n", | |
" [a31, a32, a33, a34],\n", | |
" [a41, a42, a43, a44]\n", | |
"])\n", | |
"A" | |
], | |
"id": "d32d3e1f0183f948", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[a11, a12, a13, a14],\n", | |
"[a21, a22, a23, a24],\n", | |
"[a31, a32, a33, a34],\n", | |
"[a41, a42, a43, a44]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}a_{11} & a_{12} & a_{13} & a_{14}\\\\a_{21} & a_{22} & a_{23} & a_{24}\\\\a_{31} & a_{32} & a_{33} & a_{34}\\\\a_{41} & a_{42} & a_{43} & a_{44}\\end{matrix}\\right]$" | |
}, | |
"execution_count": 4, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 4 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T17:57:54.551406Z", | |
"start_time": "2025-06-27T17:57:54.537967Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# now, let's set up a 3D vector representing an arbitrary point in our structure\n", | |
"# (in homogenous coordinates)\n", | |
"px, py, pz = sp.symbols('p_x p_y p_z')\n", | |
"vector = sp.Matrix([\n", | |
" [px],\n", | |
" [py],\n", | |
" [pz],\n", | |
" [1]]\n", | |
")\n", | |
"vector" | |
], | |
"id": "88274056a8d4eb3f", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[p_x],\n", | |
"[p_y],\n", | |
"[p_z],\n", | |
"[ 1]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}p_{x}\\\\p_{y}\\\\p_{z}\\\\1\\end{matrix}\\right]$" | |
}, | |
"execution_count": 12, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 12 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T17:59:12.788424Z", | |
"start_time": "2025-06-27T17:59:12.775669Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# we transform the vector by left-multiplying it\n", | |
"# this is what pymol is doing with the matrix internally\n", | |
"# to transform atoms/voxels in map\n", | |
"transformed_vector = A @ vector\n", | |
"transformed_vector" | |
], | |
"id": "9deaed022c969590", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[a11*p_x + a12*p_y + a13*p_z + a14],\n", | |
"[a21*p_x + a22*p_y + a23*p_z + a24],\n", | |
"[a31*p_x + a32*p_y + a33*p_z + a34],\n", | |
"[a41*p_x + a42*p_y + a43*p_z + a44]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}a_{11} p_{x} + a_{12} p_{y} + a_{13} p_{z} + a_{14}\\\\a_{21} p_{x} + a_{22} p_{y} + a_{23} p_{z} + a_{24}\\\\a_{31} p_{x} + a_{32} p_{y} + a_{33} p_{z} + a_{34}\\\\a_{41} p_{x} + a_{42} p_{y} + a_{43} p_{z} + a_{44}\\end{matrix}\\right]$" | |
}, | |
"execution_count": 15, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 15 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T18:00:57.915502Z", | |
"start_time": "2025-06-27T18:00:57.906498Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# now, this is what the matrix in our uncropped MRC file looks like\n", | |
"uncropped_matrix = sp.eye(4)\n", | |
"uncropped_matrix" | |
], | |
"id": "481c10860bba1d12", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[1, 0, 0, 0],\n", | |
"[0, 1, 0, 0],\n", | |
"[0, 0, 1, 0],\n", | |
"[0, 0, 0, 1]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}1 & 0 & 0 & 0\\\\0 & 1 & 0 & 0\\\\0 & 0 & 1 & 0\\\\0 & 0 & 0 & 1\\end{matrix}\\right]$" | |
}, | |
"execution_count": 16, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 16 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T18:08:28.748643Z", | |
"start_time": "2025-06-27T18:08:28.701398Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# the identity matrix above represents no transformation\n", | |
"# let's verify this by transforming it with our transformation matrix\n", | |
"# notice that the result is the same as A\n", | |
"#\n", | |
"# this is why replacing the matrix on the uncropped map works\n", | |
"# the existing transformation on the uncropped map was a no-op\n", | |
"result = A @ uncropped_matrix\n", | |
"result" | |
], | |
"id": "8cd22199a23bf281", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[a11, a12, a13, a14],\n", | |
"[a21, a22, a23, a24],\n", | |
"[a31, a32, a33, a34],\n", | |
"[a41, a42, a43, a44]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}a_{11} & a_{12} & a_{13} & a_{14}\\\\a_{21} & a_{22} & a_{23} & a_{24}\\\\a_{31} & a_{32} & a_{33} & a_{34}\\\\a_{41} & a_{42} & a_{43} & a_{44}\\end{matrix}\\right]$" | |
}, | |
"execution_count": 20, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 20 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T18:08:33.397652Z", | |
"start_time": "2025-06-27T18:08:33.392598Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# this is what the cropped MRC file matrix looks like\n", | |
"tx, ty, tz = sp.symbols('t_x t_y t_z')\n", | |
"cropped_matrix = sp.Matrix(\n", | |
" [[1, 0, 0, tx],\n", | |
" [0, 1, 0, ty],\n", | |
" [0, 0, 1, tz],\n", | |
" [0, 0, 0, 1]]\n", | |
")\n", | |
"cropped_matrix" | |
], | |
"id": "157ab8ac452bcea7", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[1, 0, 0, t_x],\n", | |
"[0, 1, 0, t_y],\n", | |
"[0, 0, 1, t_z],\n", | |
"[0, 0, 0, 1]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}1 & 0 & 0 & t_{x}\\\\0 & 1 & 0 & t_{y}\\\\0 & 0 & 1 & t_{z}\\\\0 & 0 & 0 & 1\\end{matrix}\\right]$" | |
}, | |
"execution_count": 21, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 21 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T18:11:22.802344Z", | |
"start_time": "2025-06-27T18:11:22.779397Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# if we apply the transformation correctly to the\n", | |
"# cropped map matrix we will see that the result is not the same as\n", | |
"# the initial transformation\n", | |
"#\n", | |
"# setting the matrix on the cropped map to your transformation matrix doesn't work\n", | |
"# because this result != your initial transformation\n", | |
"result = A @ cropped_matrix\n", | |
"result" | |
], | |
"id": "9ed05d2a7c50e0d6", | |
"outputs": [ | |
{ | |
"data": { | |
"text/plain": [ | |
"Matrix([\n", | |
"[a11, a12, a13, a11*t_x + a12*t_y + a13*t_z + a14],\n", | |
"[a21, a22, a23, a21*t_x + a22*t_y + a23*t_z + a24],\n", | |
"[a31, a32, a33, a31*t_x + a32*t_y + a33*t_z + a34],\n", | |
"[a41, a42, a43, a41*t_x + a42*t_y + a43*t_z + a44]])" | |
], | |
"text/latex": "$\\displaystyle \\left[\\begin{matrix}a_{11} & a_{12} & a_{13} & a_{11} t_{x} + a_{12} t_{y} + a_{13} t_{z} + a_{14}\\\\a_{21} & a_{22} & a_{23} & a_{21} t_{x} + a_{22} t_{y} + a_{23} t_{z} + a_{24}\\\\a_{31} & a_{32} & a_{33} & a_{31} t_{x} + a_{32} t_{y} + a_{33} t_{z} + a_{34}\\\\a_{41} & a_{42} & a_{43} & a_{41} t_{x} + a_{42} t_{y} + a_{43} t_{z} + a_{44}\\end{matrix}\\right]$" | |
}, | |
"execution_count": 23, | |
"metadata": {}, | |
"output_type": "execute_result" | |
} | |
], | |
"execution_count": 23 | |
}, | |
{ | |
"metadata": { | |
"ExecuteTime": { | |
"end_time": "2025-06-27T18:16:45.603128Z", | |
"start_time": "2025-06-27T18:16:45.598112Z" | |
} | |
}, | |
"cell_type": "code", | |
"source": [ | |
"# so, how do we solve your problem?\n", | |
"#\n", | |
"# you need to\n", | |
"# - calculate the correct transformation for the cropped map as above (A @ cropped_matrix)\n", | |
"# - set this correct transform on the cropped map\n", | |
"#\n", | |
"# this chains the transformation with the existing one rather than replacing it" | |
], | |
"id": "d13302d7b0bdc06a", | |
"outputs": [], | |
"execution_count": 26 | |
} | |
], | |
"metadata": { | |
"kernelspec": { | |
"display_name": "Python 3", | |
"language": "python", | |
"name": "python3" | |
}, | |
"language_info": { | |
"codemirror_mode": { | |
"name": "ipython", | |
"version": 2 | |
}, | |
"file_extension": ".py", | |
"mimetype": "text/x-python", | |
"name": "python", | |
"nbconvert_exporter": "python", | |
"pygments_lexer": "ipython2", | |
"version": "2.7.6" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 5 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment