Skip to content

Instantly share code, notes, and snippets.

@alisterburt
Created June 27, 2025 18:18
Show Gist options
  • Save alisterburt/1e97af09ef440d3965dcbd0e8f6eaaae to your computer and use it in GitHub Desktop.
Save alisterburt/1e97af09ef440d3965dcbd0e8f6eaaae to your computer and use it in GitHub Desktop.
transformations
Display the source blob
Display the rendered blob
Raw
{
"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