From e12688b210019933cc1f353eadb26003d044b1df Mon Sep 17 00:00:00 2001 From: Neil Shephard Date: Fri, 10 Nov 2023 16:12:51 +0000 Subject: [PATCH] Apply linting and formatting to codebase --- LICENSE.md => COPYING | 2 +- README.md | 10 +++++-- examples/example_01.ipynb | 38 ++++------------------- tests/test_asd.py | 12 ++------ topofileformats/__init__.py | 1 + topofileformats/asd.py | 60 +++++++++++++++++-------------------- topofileformats/io.py | 12 ++++---- 7 files changed, 52 insertions(+), 83 deletions(-) rename LICENSE.md => COPYING (99%) diff --git a/LICENSE.md b/COPYING similarity index 99% rename from LICENSE.md rename to COPYING index 5dc6b42..4d77317 100644 --- a/LICENSE.md +++ b/COPYING @@ -658,7 +658,7 @@ notice like this when it starts in an interactive mode: This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. -The hypothetical commands `show w' and `show c' should show the appropriate +The hypothetical commands `show w' and`show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". diff --git a/README.md b/README.md index 4747745..75c5521 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,18 @@ A library for loading various AFM file formats. File format support: `.asd` -## Usage: +## Usage ## .asd -You can open `.asd` files using the `load_asd` function. Just pass in the path to the file and the channel name that you want to use. (If in doubt use the `"TP"` topography channel). +You can open `.asd` files using the `load_asd` function. Just pass in the path to the file and the channel name that you +want to use. (If in doubt use the `"TP"` topography channel). + +Note: For `.asd` files, there seem to only ever be two channels in one file. `"TP"` (topography) is the main one you +will want to use unless you know you specifically want something else. -Note: For `.asd` files, there seem to only ever be two channels in one file. `"TP"` (topography) is the main one you will want to use unless you know you specifically want something else. Other channels: `"ER"` - Error, `"PH"` - Phase + ```python from topofileformats import load_asd diff --git a/examples/example_01.ipynb b/examples/example_01.ipynb index a7c7ca1..bd25239 100644 --- a/examples/example_01.ipynb +++ b/examples/example_01.ipynb @@ -2,7 +2,7 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -11,23 +11,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "file version: 0\n", - "{'channel1': 'TP', 'channel2': 'PH', 'header_length': 131, 'frame_header_length': 32, 'user_name_size': 14, 'comment_offset_size': 88, 'comment_size': 8, 'x_pixels': 256, 'y_pixels': 256, 'x_nm': 200, 'y_nm': 200, 'frame_time': 412.6285705566406, 'z_piezo_extension': 45.0, 'z_piezo_gain': 2.0, 'analogue_digital_range': '0x40000', 'analogue_digital_data_bits_size': 12, 'analogue_digital_resolution': 14, 'is_averaged': True, 'averaging_window': 1, 'year': 2022, 'month': 7, 'day': 15, 'hour': 16, 'minute': 44, 'second': 10, 'rounding_degree': 15, 'max_x_scan_range': 9900.0, 'max_y_scan_range': 4500.0, 'initial_frames': 142, 'num_frames': 142, 'afm_id': 0, 'file_id': 1110, 'user_name': 'biophys', 'scanner_sensitivity': 0.0, 'phase_sensitivity': 0.0, 'scan_direction': 10, 'comment_without_null': 'mica'}\n", - "Requested channel TP matches first channel in file: TP\n", - "Scaling factor: Type: TP -> TP | piezo extension 2.0 * piezo gain 45.0 = scaling factor 90.0\n", - "created voltage converter. ad_range: 0x40000 -> 262144, max voltage: 5.0, scaling factor: 90.0, resolution: 4096\n", - "Analogue to digital mapping | Range: 0x40000 -> (-5.0, 5.0)\n", - "Converter: \n" - ] - } - ], + "outputs": [], "source": [ "FILE = \"../tests/resources/sample_0.asd\"\n", "frames, pixel_to_nm_scaling, metadata = load_asd(file_path=FILE, channel=\"TP\")" @@ -35,20 +21,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAa4AAAGiCAYAAAC/NyLhAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAeoUlEQVR4nO3df2yV5f3/8VdL2yO/zulKaU+rgAWVH/JDBlgblbHR0AJjICwR7BwYApG1ZlBEVqMgblkdW7ZFhyNLFuoSQCURiWSS1WLLmKVKlSCgDSXMwugpCuk5UKS09Pr8sS/nu6MVKLQc3/T5SO6k576vc3rdV1qfnnPuU2Kcc04AABgRG+0JAADQEYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYErUwrVu3TrdfvvtuuWWW5SZman3338/WlMBABgSlXC99tprKiws1OrVq/Xhhx9qzJgxysnJ0cmTJ6MxHQCAITHR+CO7mZmZmjBhgv70pz9Jktra2jRgwAA98cQT+sUvfnGjpwMAMCTuRn/DCxcuqLq6WkVFReF9sbGxys7OVmVlZbv3aW5uVnNzc/h2W1ubTp8+rX79+ikmJqbL5wwA6FzOOZ05c0bp6emKje3Yi383PFxffPGFLl68qNTU1Ij9qamp+vTTT9u9T3FxsdasWXMjpgcAuIGOHTum2267rUP3ueHhuhZFRUUqLCwM3w4Ggxo4cKAe0DTFKT6KMwMAXItWtWi3/q6+fft2+L43PFzJycnq0aOHGhoaIvY3NDTI7/e3ex+PxyOPx/O1/XGKV1wM4QIAc/7f1RXX8nbPDb+qMCEhQePGjVNZWVl4X1tbm8rKypSVlXWjpwMAMCYqLxUWFhZq/vz5Gj9+vO6991798Y9/VFNTkx577LFoTAcAYEhUwvXwww/r888/16pVqxQIBHTPPfdox44dX7tgAwCAr4rK57iuVygUks/n0yTN5D0uADCo1bWoXNsUDAbl9Xo7dF/+ViEAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwJROD9dzzz2nmJiYiG3YsGHh4+fPn1d+fr769eunPn36aM6cOWpoaOjsaQAAblJd8ozr7rvvVn19fXjbvXt3+NiyZcv01ltvacuWLaqoqNCJEyc0e/bsrpgGAOAmFNclDxoXJ7/f/7X9wWBQf/3rX7Vp0yb94Ac/kCRt2LBBw4cP1549e3Tfffd1xXQAADeRLnnGdfjwYaWnp2vw4MHKy8tTXV2dJKm6ulotLS3Kzs4Ojx02bJgGDhyoysrKrpgKAOAm0+nPuDIzM1VSUqKhQ4eqvr5ea9as0YMPPqgDBw4oEAgoISFBiYmJEfdJTU1VIBD4xsdsbm5Wc3Nz+HYoFOrsaQMAjOj0cE2dOjX89ejRo5WZmalBgwbp9ddfV8+ePa/pMYuLi7VmzZrOmiIAwLAuvxw+MTFRd911l2pra+X3+3XhwgU1NjZGjGloaGj3PbFLioqKFAwGw9uxY8e6eNYAgG+rLg/X2bNndeTIEaWlpWncuHGKj49XWVlZ+HhNTY3q6uqUlZX1jY/h8Xjk9XojNgBA99TpLxU++eSTmjFjhgYNGqQTJ05o9erV6tGjh+bNmyefz6eFCxeqsLBQSUlJ8nq9euKJJ5SVlcUVhQCAq9Lp4Tp+/LjmzZunU6dOqX///nrggQe0Z88e9e/fX5L0hz/8QbGxsZozZ46am5uVk5Ojl19+ubOnAQC4ScU451y0J9FRoVBIPp9PkzRTcTHx0Z4OAKCDWl2LyrVNwWCww2//8LcKAQCmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmdDhcu3bt0owZM5Senq6YmBi9+eabEcedc1q1apXS0tLUs2dPZWdn6/DhwxFjTp8+rby8PHm9XiUmJmrhwoU6e/bsdZ0IAKB76HC4mpqaNGbMGK1bt67d42vXrtWLL76o9evXq6qqSr1791ZOTo7Onz8fHpOXl6eDBw+qtLRU27dv165du7R48eJrPwsAQLcR45xz13znmBht3bpVs2bNkvTfZ1vp6elavny5nnzySUlSMBhUamqqSkpKNHfuXH3yyScaMWKEPvjgA40fP16StGPHDk2bNk3Hjx9Xenr6Fb9vKBSSz+fTJM1UXEz8tU4fABAlra5F5dqmYDAor9fboft26ntcR48eVSAQUHZ2dnifz+dTZmamKisrJUmVlZVKTEwMR0uSsrOzFRsbq6qqqs6cDgDgJhTXmQ8WCAQkSampqRH7U1NTw8cCgYBSUlIiJxEXp6SkpPCYr2publZzc3P4digU6sxpAwAMMXFVYXFxsXw+X3gbMGBAtKcEAIiSTg2X3++XJDU0NETsb2hoCB/z+/06efJkxPHW1ladPn06POarioqKFAwGw9uxY8c6c9oAAEM6NVwZGRny+/0qKysL7wuFQqqqqlJWVpYkKSsrS42Njaqurg6P2blzp9ra2pSZmdnu43o8Hnm93ogNANA9dfg9rrNnz6q2tjZ8++jRo9q3b5+SkpI0cOBALV26VL/61a905513KiMjQ88++6zS09PDVx4OHz5cubm5WrRokdavX6+WlhYVFBRo7ty5V3VFIQCge+twuPbu3avvf//74duFhYWSpPnz56ukpERPPfWUmpqatHjxYjU2NuqBBx7Qjh07dMstt4Tvs3HjRhUUFGjy5MmKjY3VnDlz9OKLL3bC6QAAbnbX9TmuaOFzXABg27fmc1wAAHQ1wgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMKXD4dq1a5dmzJih9PR0xcTE6M0334w4vmDBAsXExERsubm5EWNOnz6tvLw8eb1eJSYmauHChTp79ux1nQgAoHvocLiampo0ZswYrVu37hvH5Obmqr6+Prxt3rw54nheXp4OHjyo0tJSbd++Xbt27dLixYs7PnsAQLcT19E7TJ06VVOnTr3sGI/HI7/f3+6xTz75RDt27NAHH3yg8ePHS5JeeuklTZs2Tb/73e+Unp7e0SkBALqRLnmPq7y8XCkpKRo6dKiWLFmiU6dOhY9VVlYqMTExHC1Jys7OVmxsrKqqqtp9vObmZoVCoYgNANA9dXq4cnNz9be//U1lZWX6zW9+o4qKCk2dOlUXL16UJAUCAaWkpETcJy4uTklJSQoEAu0+ZnFxsXw+X3gbMGBAZ08bAGBEh18qvJK5c+eGvx41apRGjx6tIUOGqLy8XJMnT76mxywqKlJhYWH4digUIl4A0E11+eXwgwcPVnJysmprayVJfr9fJ0+ejBjT2tqq06dPf+P7Yh6PR16vN2IDAHRPXR6u48eP69SpU0pLS5MkZWVlqbGxUdXV1eExO3fuVFtbmzIzM7t6OgAA4zr8UuHZs2fDz54k6ejRo9q3b5+SkpKUlJSkNWvWaM6cOfL7/Tpy5Iieeuop3XHHHcrJyZEkDR8+XLm5uVq0aJHWr1+vlpYWFRQUaO7cuVxRCAC4og4/49q7d6/Gjh2rsWPHSpIKCws1duxYrVq1Sj169ND+/fv1ox/9SHfddZcWLlyocePG6Z///Kc8Hk/4MTZu3Khhw4Zp8uTJmjZtmh544AH95S9/6byzAgDctGKccy7ak+ioUCgkn8+nSZqpuJj4aE8HANBBra5F5dqmYDDY4esW+FuFAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTCBcAwBTCBQAwhXABAEwhXAAAUwgXAMAUwgUAMIVwAQBMIVwAAFMIFwDAFMIFADCFcAEATCFcAABTOhSu4uJiTZgwQX379lVKSopmzZqlmpqaiDHnz59Xfn6++vXrpz59+mjOnDlqaGiIGFNXV6fp06erV69eSklJ0YoVK9Ta2nr9ZwMAuOl1KFwVFRXKz8/Xnj17VFpaqpaWFk2ZMkVNTU3hMcuWLdNbb72lLVu2qKKiQidOnNDs2bPDxy9evKjp06frwoULeu+99/TKK6+opKREq1at6ryzAgDctGKcc+5a7/z5558rJSVFFRUVmjhxooLBoPr3769Nmzbpxz/+sSTp008/1fDhw1VZWan77rtPb7/9tn74wx/qxIkTSk1NlSStX79eK1eu1Oeff66EhIQrft9QKCSfz6dJmqm4mPhrnT4AIEpaXYvKtU3BYFBer7dD972u97iCwaAkKSkpSZJUXV2tlpYWZWdnh8cMGzZMAwcOVGVlpSSpsrJSo0aNCkdLknJychQKhXTw4MF2v09zc7NCoVDEBgDonq45XG1tbVq6dKnuv/9+jRw5UpIUCASUkJCgxMTEiLGpqakKBALhMf8brUvHLx1rT3FxsXw+X3gbMGDAtU4bAGDcNYcrPz9fBw4c0KuvvtqZ82lXUVGRgsFgeDt27FiXf08AwLdT3LXcqaCgQNu3b9euXbt02223hff7/X5duHBBjY2NEc+6Ghoa5Pf7w2Pef//9iMe7dNXhpTFf5fF45PF4rmWqAICbTIeecTnnVFBQoK1bt2rnzp3KyMiIOD5u3DjFx8errKwsvK+mpkZ1dXXKysqSJGVlZenjjz/WyZMnw2NKS0vl9Xo1YsSI6zkXAEA30KFnXPn5+dq0aZO2bdumvn37ht+T8vl86tmzp3w+nxYuXKjCwkIlJSXJ6/XqiSeeUFZWlu677z5J0pQpUzRixAg9+uijWrt2rQKBgJ555hnl5+fzrAoAcEUduhw+Jiam3f0bNmzQggULJP33A8jLly/X5s2b1dzcrJycHL388ssRLwN+9tlnWrJkicrLy9W7d2/Nnz9fL7zwguLirq6jXA4PALZdz+Xw1/U5rmghXABgW9Q+xwUAwI1GuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJhCuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgCuECAJjSoXAVFxdrwoQJ6tu3r1JSUjRr1izV1NREjJk0aZJiYmIitscffzxiTF1dnaZPn65evXopJSVFK1asUGtr6/WfDQDgphfXkcEVFRXKz8/XhAkT1NraqqefflpTpkzRoUOH1Lt37/C4RYsW6fnnnw/f7tWrV/jrixcvavr06fL7/XrvvfdUX1+vn/70p4qPj9evf/3rTjglAMDNrEPh2rFjR8TtkpISpaSkqLq6WhMnTgzv79Wrl/x+f7uP8Y9//EOHDh3SO++8o9TUVN1zzz365S9/qZUrV+q5555TQkLCNZwGAKC7uK73uILBoCQpKSkpYv/GjRuVnJyskSNHqqioSOfOnQsfq6ys1KhRo5Samhrel5OTo1AopIMHD7b7fZqbmxUKhSI2AED31KFnXP+rra1NS5cu1f3336+RI0eG9z/yyCMaNGiQ0tPTtX//fq1cuVI1NTV64403JEmBQCAiWpLCtwOBQLvfq7i4WGvWrLnWqQIAbiLXHK78/HwdOHBAu3fvjti/ePHi8NejRo1SWlqaJk+erCNHjmjIkCHX9L2KiopUWFgYvh0KhTRgwIBrmzgAwLRreqmwoKBA27dv17vvvqvbbrvtsmMzMzMlSbW1tZIkv9+vhoaGiDGXbn/T+2Iej0derzdiAwB0Tx0Kl3NOBQUF2rp1q3bu3KmMjIwr3mffvn2SpLS0NElSVlaWPv74Y508eTI8prS0VF6vVyNGjOjIdAAA3VCHXirMz8/Xpk2btG3bNvXt2zf8npTP51PPnj115MgRbdq0SdOmTVO/fv20f/9+LVu2TBMnTtTo0aMlSVOmTNGIESP06KOPau3atQoEAnrmmWeUn58vj8fT+WcIALipxDjn3FUPjolpd/+GDRu0YMECHTt2TD/5yU904MABNTU1acCAAXrooYf0zDPPRLy899lnn2nJkiUqLy9X7969NX/+fL3wwguKi7u6joZCIfl8Pk3STMXFxF/t9AEA3xKtrkXl2qZgMNjht386FK5vC8IFALZdT7iu+arCaLrU2la1SOayCwBoVYuk///f844wGa4zZ85Iknbr71GeCQDgepw5c0Y+n69D9zH5UmFbW5tqamo0YsQIHTt2jMvj23Hps26sT/tYn8tjfa6MNbq8K62Pc05nzpxRenq6YmM79sksk8+4YmNjdeutt0oSn+u6Atbn8lify2N9row1urzLrU9Hn2ldwr/HBQAwhXABAEwxGy6Px6PVq1fzoeVvwPpcHutzeazPlbFGl9eV62Py4gwAQPdl9hkXAKB7IlwAAFMIFwDAFMIFADDFZLjWrVun22+/XbfccosyMzP1/vvvR3tKUfHcc88pJiYmYhs2bFj4+Pnz55Wfn69+/fqpT58+mjNnztf+Ec+bza5duzRjxgylp6crJiZGb775ZsRx55xWrVqltLQ09ezZU9nZ2Tp8+HDEmNOnTysvL09er1eJiYlauHChzp49ewPPoutcaX0WLFjwtZ+p3NzciDE36/oUFxdrwoQJ6tu3r1JSUjRr1izV1NREjLma36m6ujpNnz5dvXr1UkpKilasWKHW1tYbeSpd5mrWaNKkSV/7GXr88ccjxlzvGpkL12uvvabCwkKtXr1aH374ocaMGaOcnJyIf5iyO7n77rtVX18f3nbv3h0+tmzZMr311lvasmWLKioqdOLECc2ePTuKs+16TU1NGjNmjNatW9fu8bVr1+rFF1/U+vXrVVVVpd69eysnJ0fnz58Pj8nLy9PBgwdVWlqq7du3a9euXVq8ePGNOoUudaX1kaTc3NyIn6nNmzdHHL9Z16eiokL5+fnas2ePSktL1dLSoilTpqipqSk85kq/UxcvXtT06dN14cIFvffee3rllVdUUlKiVatWReOUOt3VrJEkLVq0KOJnaO3ateFjnbJGzph7773X5efnh29fvHjRpaenu+Li4ijOKjpWr17txowZ0+6xxsZGFx8f77Zs2RLe98knnzhJrrKy8gbNMLokua1bt4Zvt7W1Ob/f737729+G9zU2NjqPx+M2b97snHPu0KFDTpL74IMPwmPefvttFxMT4/7zn//csLnfCF9dH+ecmz9/vps5c+Y33qc7rc/JkyedJFdRUeGcu7rfqb///e8uNjbWBQKB8Jg///nPzuv1uubm5ht7AjfAV9fIOee+973vuZ///OffeJ/OWCNTz7guXLig6upqZWdnh/fFxsYqOztblZWVUZxZ9Bw+fFjp6ekaPHiw8vLyVFdXJ0mqrq5WS0tLxFoNGzZMAwcO7LZrdfToUQUCgYg18fl8yszMDK9JZWWlEhMTNX78+PCY7OxsxcbGqqqq6obPORrKy8uVkpKioUOHasmSJTp16lT4WHdan2AwKElKSkqSdHW/U5WVlRo1apRSU1PDY3JychQKhXTw4MEbOPsb46trdMnGjRuVnJyskSNHqqioSOfOnQsf64w1MvVHdr/44gtdvHgx4oQlKTU1VZ9++mmUZhU9mZmZKikp0dChQ1VfX681a9bowQcf1IEDBxQIBJSQkKDExMSI+6SmpioQCERnwlF26bzb+/m5dCwQCCglJSXieFxcnJKSkrrFuuXm5mr27NnKyMjQkSNH9PTTT2vq1KmqrKxUjx49us36tLW1aenSpbr//vs1cuRISbqq36lAINDuz9elYzeT9tZIkh555BENGjRI6enp2r9/v1auXKmamhq98cYbkjpnjUyFC5GmTp0a/nr06NHKzMzUoEGD9Prrr6tnz55RnBmsmjt3bvjrUaNGafTo0RoyZIjKy8s1efLkKM7sxsrPz9eBAwci3jNGpG9ao/99v3PUqFFKS0vT5MmTdeTIEQ0ZMqRTvreplwqTk5PVo0ePr13F09DQIL/fH6VZfXskJibqrrvuUm1trfx+vy5cuKDGxsaIMd15rS6d9+V+fvx+/9cu9GltbdXp06e75boNHjxYycnJqq2tldQ91qegoEDbt2/Xu+++q9tuuy28/2p+p/x+f7s/X5eO3Sy+aY3ak5mZKUkRP0PXu0amwpWQkKBx48aprKwsvK+trU1lZWXKysqK4sy+Hc6ePasjR44oLS1N48aNU3x8fMRa1dTUqK6urtuuVUZGhvx+f8SahEIhVVVVhdckKytLjY2Nqq6uDo/ZuXOn2trawr+A3cnx48d16tQppaWlSbq518c5p4KCAm3dulU7d+5URkZGxPGr+Z3KysrSxx9/HBH30tJSeb1ejRgx4sacSBe60hq1Z9++fZIU8TN03Wt0jReTRM2rr77qPB6PKykpcYcOHXKLFy92iYmJEVeodBfLly935eXl7ujRo+5f//qXy87OdsnJye7kyZPOOecef/xxN3DgQLdz5063d+9el5WV5bKysqI866515swZ99FHH7mPPvrISXK///3v3UcffeQ+++wz55xzL7zwgktMTHTbtm1z+/fvdzNnznQZGRnuyy+/DD9Gbm6uGzt2rKuqqnK7d+92d955p5s3b160TqlTXW59zpw545588klXWVnpjh496t555x333e9+1915553u/Pnz4ce4WddnyZIlzufzufLycldfXx/ezp07Fx5zpd+p1tZWN3LkSDdlyhS3b98+t2PHDte/f39XVFQUjVPqdFdao9raWvf888+7vXv3uqNHj7pt27a5wYMHu4kTJ4YfozPWyFy4nHPupZdecgMHDnQJCQnu3nvvdXv27In2lKLi4YcfdmlpaS4hIcHdeuut7uGHH3a1tbXh419++aX72c9+5r7zne+4Xr16uYceesjV19dHccZd791333WSvrbNnz/fOfffS+KfffZZl5qa6jwej5s8ebKrqamJeIxTp065efPmuT59+jiv1+see+wxd+bMmSicTee73PqcO3fOTZkyxfXv39/Fx8e7QYMGuUWLFn3tfwpv1vVpb10kuQ0bNoTHXM3v1L///W83depU17NnT5ecnOyWL1/uWlpabvDZdI0rrVFdXZ2bOHGiS0pKch6Px91xxx1uxYoVLhgMRjzO9a4R/6wJAMAUU+9xAQBAuAAAphAuAIAphAsAYArhAgCYQrgAAKYQLgCAKYQLAGAK4QIAmEK4AACmEC4AgCmECwBgyv8BeuOo1mVX2gkAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "create_animation(file_name=\"sample_0\", frames=frames)" ] @@ -71,8 +46,7 @@ "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.9" - }, - "orig_nbformat": 4 + } }, "nbformat": 4, "nbformat_minor": 2 diff --git a/tests/test_asd.py b/tests/test_asd.py index d8ac54d..8140cf4 100644 --- a/tests/test_asd.py +++ b/tests/test_asd.py @@ -1,18 +1,15 @@ """Test the functioning of loading .asd files.""" - -from topofileformats.asd import load_asd - from pathlib import Path import pytest -import numpy as np +from topofileformats.asd import load_asd BASE_DIR = Path.cwd() RESOURCES = BASE_DIR / "tests" / "resources" @pytest.mark.parametrize( - "file_name, channel, number_of_frames, pixel_to_nm_scaling", + ("file_name", "channel", "number_of_frames", "pixel_to_nm_scaling"), [ # File type 0 ( @@ -30,11 +27,8 @@ ), ], ) -def test_load_asd( - file_name: str, channel: str, number_of_frames: int, pixel_to_nm_scaling: float -) -> None: +def test_load_asd(file_name: str, channel: str, number_of_frames: int, pixel_to_nm_scaling: float) -> None: """Test the normal operation of loading a .asd file.""" - result_frames = list result_pixel_to_nm_scaling = float result_metadata = dict diff --git a/topofileformats/__init__.py b/topofileformats/__init__.py index e69de29..eedcb4f 100644 --- a/topofileformats/__init__.py +++ b/topofileformats/__init__.py @@ -0,0 +1 @@ +"""topofileformats.""" diff --git a/topofileformats/asd.py b/topofileformats/asd.py index 069a25a..61c1dd6 100644 --- a/topofileformats/asd.py +++ b/topofileformats/asd.py @@ -1,7 +1,7 @@ -"""For decoding and loading .asd AFM file format into Python Numpy arrays""" +"""For decoding and loading .asd AFM file format into Python Numpy arrays.""" from pathlib import Path -from typing import BinaryIO, Union +from typing import BinaryIO import numpy as np import matplotlib.pyplot as plt @@ -24,11 +24,12 @@ # pylint: disable=too-few-public-methods class VoltageLevelConverter: - """A class for converting arbitrary height levels from the AFM into real world - nanometre heights. + """A class for converting arbitrary height levels from the AFM into real world nanometre heights. + Different .asd files require different functions to perform this calculation based on many factors, hence why we need to define the correct function in - each case.""" + each case. + """ def __init__(self, analogue_digital_range, max_voltage, scaling_factor, resolution): self.ad_range = int(analogue_digital_range, 16) @@ -43,7 +44,7 @@ def __init__(self, analogue_digital_range, max_voltage, scaling_factor, resoluti # pylint: disable=too-few-public-methods class UnipolarConverter(VoltageLevelConverter): - """A VoltageLevelConverter for unipolar encodings. (0 to +X Volts)""" + """A VoltageLevelConverter for unipolar encodings. (0 to +X Volts).""" def level_to_voltage(self, level): """Calculate the real world height scale in nanometres for an arbitrary level value. @@ -64,7 +65,7 @@ def level_to_voltage(self, level): # pylint: disable=too-few-public-methods class BipolarConverter(VoltageLevelConverter): - """A VoltageLevelConverter for bipolar encodings. (-X to +X Volts)""" + """A VoltageLevelConverter for bipolar encodings. (-X to +X Volts).""" def level_to_voltage(self, level): """Calculate the real world height scale in nanometres for an arbitrary level value. @@ -90,9 +91,10 @@ def calculate_scaling_factor( scanner_sensitivity: float, phase_sensitivity: float, ) -> float: - """Calculate the correct scaling factor to enable conversion between arbitrary level values from - the AFM into real world nanometre height values. To be used in conjunction with the - VoltageLevelConverter class to define the correct function to perform this operation. + """Calculate the correct scaling factor. + + This function should be used in conjunction with the VoltageLevelConverter class to define the correct function and + enables conversion between arbitrary level values from the AFM into real world nanometre height values. Parameters ---------- @@ -136,7 +138,7 @@ def calculate_scaling_factor( raise ValueError(f"channel {channel} not known for .asd file type.") -def load_asd(file_path: Union[Path, str], channel: str): +def load_asd(file_path: Path | str, channel: str): """Load a .asd file. Parameters @@ -144,8 +146,8 @@ def load_asd(file_path: Union[Path, str], channel: str): file_path: Union[Path, str] Path to the .asd file. channel: str - Channel to load. Note that only two channels seem to be - present in a single .asd file. Options: TP, ER, PH + Channel to load. Note that only three channels seem to be present in a single .asd file. Options: TP + (Topograph), ER (Error) and PH (Phase). Returns ------- @@ -154,16 +156,14 @@ def load_asd(file_path: Union[Path, str], channel: str): (Number of frames x Width of each frame x height of each frame). pixel_to_nanometre_scaling_factor: float The number of nanometres per pixel for the .asd file. (AKA the resolution). - Enables converting between pixels and nanometres - when working with the data, in order to use real-world length scales. + Enables converting between pixels and nanometres when working with the data, in order to use real-world length + scales. metadata: dict - Dictionary of metadata for the .asd file. The number of entries is too long to list here, - and changes based on the file version please either look into the - `read_header_file_version_x` functions or print the keys too see what metadata is - available. + Metadata for the .asd file. The number of entries is too long to list here, and changes based on the file + version please either look into the `read_header_file_version_x` functions or print the keys too see what metadata + is available. """ - - with open(file_path, "rb") as open_file: + with Path.open(file_path, "rb", encoding="UTF-8") as open_file: file_version = read_file_version(open_file) if file_version == 0: @@ -206,12 +206,9 @@ def load_asd(file_path: Union[Path, str], channel: str): _size_of_frame_header = header_dict["frame_header_length"] # Remember that each value is two bytes (since signed int16) size_of_single_frame_plus_header = ( - header_dict["frame_header_length"] - + header_dict["x_pixels"] * header_dict["y_pixels"] * 2 - ) - length_of_all_first_channel_frames = ( - header_dict["num_frames"] * size_of_single_frame_plus_header + header_dict["frame_header_length"] + header_dict["x_pixels"] * header_dict["y_pixels"] * 2 ) + length_of_all_first_channel_frames = header_dict["num_frames"] * size_of_single_frame_plus_header _ = open_file.read(length_of_all_first_channel_frames) else: raise ValueError( @@ -245,6 +242,7 @@ def load_asd(file_path: Union[Path, str], channel: str): def read_file_version(open_file): """Read the file version from an open asd file. File versions are 0, 1 and 2. + Different file versions require different functions to read the headers as the formatting changes between them. @@ -345,9 +343,7 @@ def read_header_file_version_0(open_file: BinaryIO): # ID of the file header_dict["file_id"] = read_int16(open_file) # Name of the user - header_dict["user_name"] = read_null_separated_utf8( - open_file, length_bytes=header_dict["user_name_size"] - ) + header_dict["user_name"] = read_null_separated_utf8(open_file, length_bytes=header_dict["user_name_size"]) # Sensitivity of the scanner in nm / V header_dict["scanner_sensitivity"] = read_float(open_file) # Phase sensitivity @@ -379,7 +375,6 @@ def read_header_file_version_1(open_file: BinaryIO): header_dict: dict Dictionary of metadata decoded from the file header. """ - header_dict = {} # length of file metadata header in bytes - so we can skip it to get to the data @@ -485,7 +480,6 @@ def read_header_file_version_2(open_file): header_dict: dict Dictionary of metadata decoded from the file header. """ - header_dict = {} # length of file metadata header in bytes - so we can skip it to get to the data @@ -632,7 +626,6 @@ def read_channel_data(open_file, num_frames, x_pixels, y_pixels, analogue_digita The extracted frame heightmap data as a N x W x H 3D numpy array (number of frames x width of each frame x height of each frame). Units are nanometres. """ - # List to store the frames as numpy arrays frames = [] # Dictionary to store all the variables together in case we want to return them. @@ -671,6 +664,7 @@ def read_channel_data(open_file, num_frames, x_pixels, y_pixels, analogue_digita def create_analogue_digital_converter(analogue_digital_range, scaling_factor, resolution=4096): """Create an analogue to digital converter for a given range, scaling factor and resolution. + Used for converting raw level values into real world height scales in nanometres. Parameters @@ -691,7 +685,6 @@ def create_analogue_digital_converter(analogue_digital_range, scaling_factor, re which converts arbitrary level values into real world nanometre heights for the given .asd file. Note that this is file specific since the parameters will change between files. """ - # Analogue to digital hex conversion range encoding: # unipolar_1_0V : 0x00000001 +0.0 to +1.0 V # unipolar_2_5V : 0x00000002 +0.0 to +2.5 V @@ -766,6 +759,7 @@ def create_analogue_digital_converter(analogue_digital_range, scaling_factor, re def create_animation(file_name: str, frames: np.ndarray, file_format: str = ".gif") -> None: """Create animation from a numpy array of frames (2d numpy arrays). + File format can be specified, defaults to .gif. Parameters diff --git a/topofileformats/io.py b/topofileformats/io.py index c7e70fc..1dd5e02 100644 --- a/topofileformats/io.py +++ b/topofileformats/io.py @@ -111,12 +111,13 @@ def read_float(open_file: BinaryIO) -> float: Returns ------- float - Float decoded value.""" + Float decoded value. + """ return struct.unpack("f", open_file.read(4))[0] def read_bool(open_file: BinaryIO) -> bool: - """Read a boolean from an open binary file + """Read a boolean from an open binary file. Parameters ---------- @@ -132,7 +133,7 @@ def read_bool(open_file: BinaryIO) -> bool: def read_double(open_file: BinaryIO) -> float: - """Read an 8 byte double from an open binary file + """Read an 8 byte double from an open binary file. Parameters ---------- @@ -166,8 +167,9 @@ def read_ascii(open_file: BinaryIO, length_bytes: int = 1) -> str: def read_null_separated_utf8(open_file: BinaryIO, length_bytes: int = 2) -> str: - """Read an ascii string of defined length from an open binary file where each - character is separated by a null byte. This encodingis known as UTF-16LE (Little Endian). + r"""Read an ASCII string of defined length from an open binary file. + + Each character is separated by a null byte. This encoding is known as UTF-16LE (Little Endian). Eg: b'\x74\x00\x6f\x00\x70\x00\x6f' would decode to 'topo' in this format. Parameters