{ "cells": [ { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "\"\"\"\n", "Created on Mon Sep 16 09:47:15 2019\n", "@author: daniel\n", "\"\"\"\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", "\n", "def fractal_dimension(array, max_box_size=None, min_box_size=1, n_samples=20, n_offsets=0, plot=False):\n", " \"\"\"Calculates the fractal dimension of a 3D numpy array.\n", "\n", " Args:\n", " array (np.ndarray): The array to calculate the fractal dimension of.\n", " max_box_size (int): The largest box size, given as the power of 2 so that\n", " 2**max_box_size gives the sidelength of the largest box.\n", " min_box_size (int): The smallest box size, given as the power of 2 so that\n", " 2**min_box_size gives the sidelength of the smallest box.\n", " Default value 1.\n", " n_samples (int): number of scales to measure over.\n", " n_offsets (int): number of offsets to search over to find the smallest set N(s) to\n", " cover all voxels>0.\n", " plot (bool): set to true to see the analytical plot of a calculation.\n", "\n", "\n", " \"\"\"\n", " # determine the scales to measure on\n", " if max_box_size == None:\n", " # default max size is the largest power of 2 that fits in the smallest dimension of the array:\n", " max_box_size = int(np.floor(np.log2(np.min(array.shape))))\n", " scales = np.floor(np.logspace(max_box_size, min_box_size, num=n_samples, base=2))\n", " scales = np.unique(scales) # remove duplicates that could occur as a result of the floor\n", "\n", " # get the locations of all non-zero pixels\n", " locs = np.where(array > 0)\n", " voxels = np.array([(x, y, z) for x, y, z in zip(*locs)])\n", "\n", " # count the minimum amount of boxes touched\n", " Ns = []\n", " # loop over all scales\n", " for scale in scales:\n", " touched = []\n", " if n_offsets == 0:\n", " offsets = [0]\n", " else:\n", " offsets = np.linspace(0, scale, n_offsets)\n", " # search over all offsets\n", " for offset in offsets:\n", " bin_edges = [np.arange(0, i, scale) for i in array.shape]\n", " bin_edges = [np.hstack([0 - offset, x + offset]) for x in bin_edges]\n", " H1, e = np.histogramdd(voxels, bins=bin_edges)\n", " touched.append(np.sum(H1 > 0))\n", " Ns.append(touched)\n", " Ns = np.array(Ns)\n", "\n", " # From all sets N found, keep the smallest one at each scale\n", " Ns = Ns.min(axis=1)\n", "\n", " # Only keep scales at which Ns changed\n", " scales = np.array([np.min(scales[Ns == x]) for x in np.unique(Ns)])\n", "\n", " Ns = np.unique(Ns)\n", " Ns = Ns[Ns > 0]\n", " scales = scales[:len(Ns)]\n", " # perform fit\n", " coeffs = np.polyfit(np.log(1 / scales), np.log(Ns), 1)\n", "\n", " # make plot\n", " if plot:\n", " fig, ax = plt.subplots(figsize=(8, 6))\n", " ax.scatter(np.log(1 / scales), np.log(np.unique(Ns)), c=\"teal\", label=\"Measured ratios\")\n", " ax.set_ylabel(\"$\\log N(\\epsilon)$\")\n", " ax.set_xlabel(\"$\\log 1/ \\epsilon$\")\n", " fitted_y_vals = np.polyval(coeffs, np.log(1 / scales))\n", " ax.plot(np.log(1 / scales), fitted_y_vals, \"k--\", label=f\"Fit: {np.round(coeffs[0], 3)}X+{coeffs[1]}\")\n", " ax.legend();\n", " return (coeffs[0])\n" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "from lib.lib import read_xy_alt, read_load\n", "\n", "full_data = read_load(\"/Users/joshuacoles/Developer/checkouts/jc3091/CompB DLA/data-analysis/data/rust-3d\", read_xy_alt)\n", "df = full_data[full_data.run == '1']" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "max_actual_radius = max(df.x.abs().max(), df.y.abs().max(), df.z.abs().max())\n", "max_radius = int(np.exp2(np.floor(np.log2(max_actual_radius)) + 1))\n", "data = np.zeros((max_radius * 2, max_radius * 2, max_radius * 2))\n", "data[df.x + max_radius, df.y + max_radius, df.z + max_radius] = 1" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/plain": "(128, 128, 128)" }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data.shape" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/plain": "5000.0" }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data.sum()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": "(5000, 8)" }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.shape" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [], "source": [ "dfs = []\n", "for _, df in full_data.groupby('run'):\n", " max_actual_radius = max(df.x.abs().max(), df.y.abs().max(), df.z.abs().max())\n", " max_radius = int(np.exp2(np.floor(np.log2(max_actual_radius)) + 1))\n", " data = np.zeros((max_radius * 2, max_radius * 2, max_radius * 2))\n", " data[df.x + max_radius, df.y + max_radius, df.z + max_radius] = 1\n", " dfs.append(fractal_dimension(data))" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": "0.1543448984741014" }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.mean(np.array(dfs))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "plt.scatter(run1.x, run1.y, run1.z)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from mpl_toolkits.mplot3d import Axes3D\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import matplotlib as mpl\n", "from mpl_toolkits.mplot3d import Axes3D\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fig = plt.figure(figsize=(10, 10))\n", "ax = fig.add_subplot(projection='3d')\n", "ax.scatter(run1.x, run1.y,run1.z, c=run1.N)\n", "fig" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "run1" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "ename": "ModuleNotFoundError", "evalue": "No module named 'mpld3'", "output_type": "error", "traceback": [ "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", "\u001B[0;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", "Cell \u001B[0;32mIn[24], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mmatplotlib\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mpyplot\u001B[39;00m \u001B[38;5;28;01mas\u001B[39;00m \u001B[38;5;21;01mplt\u001B[39;00m\u001B[38;5;241m,\u001B[39m \u001B[38;5;21;01mmpld3\u001B[39;00m\n", "\u001B[0;31mModuleNotFoundError\u001B[0m: No module named 'mpld3'" ] } ], "source": [ "import matplotlib.pyplot as plt, mpld3" ] }, { "cell_type": "code", "execution_count": null, "outputs": [], "source": [], "metadata": { "collapsed": false } } ], "metadata": { "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.6" } }, "nbformat": 4, "nbformat_minor": 1 }