diff --git a/notebooks/optical.ipynb b/notebooks/optical.ipynb index 8103f04..c52aadd 100644 --- a/notebooks/optical.ipynb +++ b/notebooks/optical.ipynb @@ -1,46 +1,88 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "57b4960f-e126-4439-a53c-a58f1bfdcdfd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "# Optical Example notebook\n", + "\n", + "This notebook will outline basic usage of DefDAP, including loading an image and EBSD map, linking them with homologous points and producing maps" + ] + }, + { + "cell_type": "markdown", + "id": "28930750-ec9b-4f73-876c-639afe7531cd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Load in packages" + ] + }, + { + "cell_type": "markdown", + "id": "e518d33b-73cc-4208-a1ee-354943464a3c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "DefDAP is split into modules for processing EBSD (`defdap.ebsd`) and image (`defdap.optical`) data. There are also modules for manpulating orientations (`defdap.quat`) and creating custom figures (`defdap.plotting`) which is introduced later. We also import some of the usual suspects of the python scientific stack: `numpy` and `matplotlib`." + ] + }, { "cell_type": "code", "execution_count": 1, - "id": "a167425e-fc5d-4f0d-ad30-96ab225104a9", - "metadata": {}, + "id": "fcd0edc9-7d79-412b-84b7-1f3091cb090c", + "metadata": { + "pycharm": { + "name": "#%%\n" + }, + "tags": [] + }, "outputs": [], "source": [ - "from defdap import ebsd, optical\n", - "import matplotlib.pyplot as plt\n", - "from defdap import plotting\n", "import numpy as np\n", - "import defdap\n", + "import matplotlib.pyplot as plt\n", + "\n", + "import defdap.optical as optical\n", + "import defdap.ebsd as ebsd\n", + "import defdap.plotting as plotting\n", + "from defdap.quat import Quat\n", + "\n", + "# try tk, qt, osx (if using mac) or notebook for interactive plots. If none work, use inline\n", "%matplotlib tk" ] }, { - "cell_type": "code", - "execution_count": 2, - "id": "a9b4bfb9", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'C:\\\\Users\\\\mbgm5pc3\\\\DF_analysis\\\\DefDAP\\\\notebooks'" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "id": "93366c53-2e3e-454d-b3a6-6eea264b4efd", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "pwd" + "## Load in a optical/SEM image" ] }, { "cell_type": "code", - "execution_count": 3, - "id": "6ae24a9b-6842-4540-b36b-3795c1d85f05", - "metadata": {}, + "execution_count": 2, + "id": "1ea4e773-0af0-4748-b0e9-f2b2daca0745", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", @@ -51,47 +93,112 @@ } ], "source": [ - "path = \"../tests/data/\"\n", - "fname = \"F5-pol-Cy50.png\"\n", - "# metadata = \"test-meta-data.xlsx\"\n", - "optical_map = optical.Map(file_name = path + fname)" + "optical_filepath = \"../tests/data/testOptical.png\"\n", + "optical_map = optical.Map(file_name = optical_filepath)" + ] + }, + { + "cell_type": "markdown", + "id": "fa1ca733-53ad-499b-af61-1eeb1e047217", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Set the scale of the map\n", + "This is defined as the pixel size in the images, measured in microns per pixel." ] }, { "cell_type": "code", - "execution_count": 4, - "id": "8bcb125c-55be-4745-a22c-3578cef3f7ee", - "metadata": {}, + "execution_count": 3, + "id": "6e1489dc-78e1-4d00-98d1-243546fa3308", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "optical_map.set_scale(2.105) #um/pixel" + "optical_map.set_scale(2.105) # um/pixel" + ] + }, + { + "cell_type": "markdown", + "id": "29d890a1-71a6-4f9d-855f-e891e8ac0d76", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Plot the map with a scale bar" ] }, { "cell_type": "code", - "execution_count": 5, - "id": "4387f479-785f-4639-b778-b60148f849cb", - "metadata": {}, + "execution_count": null, + "id": "bb82e614-bb95-4e40-9309-e7bfc5df2e0c", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "#Opt.set_crop (left = 10, right = 10, top = 10, bottom = 10)" + "optical_map.plot_map('image', vmin=0, vmax=1, plot_scale_bar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "2331ad9a-35e4-4ee3-ae61-f3c532dcd52d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Crop the map\n", + "Optical maps can contain spurious data at the edges which should be removed before performing any analysis. The crop is defined by the number of points to remove from each edge of the map, where `xMin`, `xMax`, `yMin` and `yMax` are the left, right, top and bottom edges respectively. Note that the test data doesn not require cropping as it is a subset of a larger dataset." ] }, { "cell_type": "code", - "execution_count": 6, - "id": "de922a4a-44ff-45a9-8f1d-2fb99297b698", - "metadata": {}, + "execution_count": 4, + "id": "546c6f28-3982-4401-8ce1-81176f144181", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "#optical_map.plot_map('image', plot_scale_bar=True)" + "optical_map.set_crop(left=10, right=10, top=10, bottom=10)" + ] + }, + { + "cell_type": "markdown", + "id": "d27e69a0-4f2d-4a22-a78c-056d10092627", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Load in an EBSD map\n", + "Currently, OxfordBinary (a .crc and .cpr file pair), OxfordText (.ctf file), EdaxAng (.ang file) or PythonDict (Python dictionary) filetypes are supported. The crystal structure and slip systems are automatically loaded for each phase in the map. The orientation in the EBSD are converted to a quaternion representation so calculations can be applied later." ] }, { "cell_type": "code", - "execution_count": 7, - "id": "a0eaeccb-5e58-428e-b448-903ed9bb1942", - "metadata": {}, + "execution_count": 5, + "id": "8da89bf7-685b-4bda-97ac-84def01b93c2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", @@ -102,781 +209,750 @@ } ], "source": [ - "ebsd_map = ebsd.Map(path + \"f-5-test-region\")" + "ebsd_map = ebsd.Map(\"../tests/data/f-5-test-region\")" ] }, { - "cell_type": "code", - "execution_count": 8, - "id": "2a53dd86", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Finished building quaternion array (0:00:06) \n", - "Finished finding grain boundaries (0:00:15) \n", - "Finished finding grains (0:00:06) \n" - ] + "cell_type": "markdown", + "id": "5c7c1683-a93e-4a92-ae15-939e8837b758", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "ebsd_map.data.generate('grain_boundaries', misori_tol=10)\n", - "ebsd_map.data.generate('grains', min_grain_size=200)" + "A list of detected phases and crystal structures can be printed" ] }, { "cell_type": "code", - "execution_count": 9, - "id": "df57b528", - "metadata": {}, + "execution_count": null, + "id": "40afadd4-0f21-46d9-976e-c0efe52d0f34", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "#ebsd_map.plot_map('orientation', 'IPF_x', plot_scale_bar=True)" + "for i, phase in enumerate(ebsd_map.phases):\n", + " print(i+1)\n", + " print(phase)" + ] + }, + { + "cell_type": "markdown", + "id": "f813cee6-fcba-4916-9bff-85fb8f08219a", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A list of the slip planes, colours and slip directions can be printed" ] }, { "cell_type": "code", - "execution_count": 10, - "id": "bb9b6f7c-a22a-4ca5-83be-604b40ae67f8", - "metadata": {}, + "execution_count": null, + "id": "f4698cd1-3211-4c58-a197-0ac17103f1db", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "#ebsd_map.set_homog_point(map_name=\"orientation\", component='IPF_z')\n", - "#optical_map.set_homog_point()" + "ebsd_map.phases[0].print_slip_systems()" + ] + }, + { + "cell_type": "markdown", + "id": "7ed8a89a-e756-443e-b20d-7b629aa56ef7", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Plot the EBSD map\n", + "Using an Euler colour mapping or inverse pole figure colouring with the sample reference direction passed as a vector." ] }, { "cell_type": "code", - "execution_count": 11, - "id": "e8032bfb-1f04-4ffc-9ad4-20a47b3bb9e9", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[]\n", - "[]\n" - ] + "execution_count": null, + "id": "321c2a28-5c5c-4ab4-a63a-de8f60693a42", + "metadata": { + "pycharm": { + "name": "#%%\n" } - ], + }, + "outputs": [], "source": [ - "print(ebsd_map.frame.homog_points)\n", - "print(optical_map.frame.homog_points)" + "ebsd_map.plot_map('euler_angle', 'all_euler', plot_scale_bar=True)" ] }, { "cell_type": "code", - "execution_count": 12, - "id": "4083f81f", - "metadata": {}, + "execution_count": null, + "id": "2d996f21-6d1d-4e59-b187-e9a38e0e1b36", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "ebsd_map.frame.homog_points = [\n", - " (314, 533), \n", - " (543, 242), \n", - " (97, 143)\n", - "]\n", - "optical_map.frame.homog_points = [\n", - " (467, 653), \n", - " (806, 239), \n", - " (180, 94)\n", - "]" + "ebsd_map.plot_map('orientation', 'IPF_x', plot_scale_bar=True)" + ] + }, + { + "cell_type": "markdown", + "id": "3f7a242d-41b2-4c2c-83f2-db8c65036b3c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A KAM map can also be plotted as follows" ] }, { "cell_type": "code", - "execution_count": 13, - "id": "df2355a3", - "metadata": {}, + "execution_count": null, + "id": "af64b232-f523-4cc2-9692-6e680b69881a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "optical_map.link_ebsd_map(ebsd_map, transform_type=\"affine\")" + "ebsd_map.plot_map('KAM', vmin=0, vmax=2*np.pi/180)" + ] + }, + { + "cell_type": "markdown", + "id": "7dd951a3-3c33-4d0d-acb9-7bb6cb44518d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Detect grains in the EBSD\n", + "This is done in two stages: first bounaries are detected in the map as any point with a misorientation to a neighbouring point greater than a critical value (`boundDef` in degrees). A flood fill type algorithm is then applied to segment the map into grains, with any grains containining fewer than a critical number of pixels removed (`minGrainSize` in pixels). The data e.g. orientations associated with each grain are then stored (referenced strictly, the data isn't stored twice) in a grain object and a list of the grains is stored in the EBSD map (named `grainList`). This allows analysis routines to be applied to each grain in a map in turn." ] }, { "cell_type": "code", - "execution_count": 14, - "id": "f3868080", - "metadata": {}, + "execution_count": 6, + "id": "88510a8e-a612-4705-bd9e-86b992ced80f", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ + "Finished building quaternion array (0:00:00) \n", + "Finished finding grain boundaries (0:00:01) \n", "Finished finding grains (0:00:00) \n" ] } ], "source": [ - "optical_map.data.generate('grains', min_grain_size=10, algorithm='warp')" + "ebsd_map.data.generate('grain_boundaries', misori_tol=8)\n", + "ebsd_map.data.generate('grains', min_grain_size=200)" ] }, { - "cell_type": "code", - "execution_count": 15, - "id": "95a897d4", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "3630d208-2904-42ac-be21-a4dae5b9491d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "#optical_map.plot_map('image', plot_scale_bar=True, plot_gbs='pixel')" + "The Schmid factors for each grain can be calculated and plotted. The `slipSystems` argument can be specified, to only calculate the Schmid factor for certain planes, otherwise the maximum for all slip systems is calculated." ] }, { "cell_type": "code", - "execution_count": 16, - "id": "45efae0c", - "metadata": {}, + "execution_count": 7, + "id": "5cd4c838-c45f-443f-ba99-85903b63d6ec", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Datastore\n", - " image\n", - " proxigram\n", - " grains\n", - " Derived data:\n", - " phase_boundaries\n", - " grain_boundaries\n", - " point\n", - "Datastore\n", - " point\n", - " Derived data:\n", - " image\n", - " proxigram\n", - " grains\n" + "Finished calculating grain average Schmid factors (0:00:01) \n" ] } ], "source": [ - "# data available for map\n", - "print(optical_map.data)\n", - "# data available for grain\n", - "print(optical_map[20].data)" + "ebsd_map.calc_average_grain_schmid_factors(load_vector=np.array([1,0,0]), slip_systems=None)" ] }, { "cell_type": "code", - "execution_count": 17, - "id": "a9a65d90", - "metadata": {}, + "execution_count": null, + "id": "14e99911-5664-4ca9-b652-77510576a929", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "#optical_map.locate_grain()" + "ebsd_map.plot_average_grain_schmid_factors_map()" + ] + }, + { + "cell_type": "markdown", + "id": "cb38b166-bcc1-42d2-95cf-80725bdb9843", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Single grain analysis\n", + "The `locate_grain` method allows interactive selection of a grain of intereset to apply any analysis to. Clicking on grains in the map will highlight the grain and print out the grain ID (position in the grain list) of the grain." ] }, { "cell_type": "code", - "execution_count": 18, - "id": "b955afea", + "execution_count": null, + "id": "1815f9c2-4271-4c42-ae8c-78faab5506b2", "metadata": {}, "outputs": [], "source": [ - "grain = optical_map[0]\n", - "#grain.plot_grain_data(grain_data=grain.data.image)" + "ebsd_map.locate_grain()" ] }, { - "cell_type": "code", - "execution_count": 19, - "id": "4a647a29", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[np.float64(2.999151474212655),\n", - " np.float64(1.0753148211635188),\n", - " np.float64(3.0851021670346883),\n", - " np.float64(1.8888338214513343),\n", - " np.float64(1.4904308647148845),\n", - " np.float64(2.1774646990300246),\n", - " np.float64(0.7713158756193379),\n", - " np.float64(1.4627577132738598),\n", - " np.float64(0.023630610288391658),\n", - " np.float64(3.0570717723901626)]" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" + "cell_type": "markdown", + "id": "dcf101f3-41fb-4282-b3d9-d503e5215d77", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "grain.slip_traces" + "A built-in example is to calculate the average orientation of the grain and plot this orientation in a IPF" ] }, { "cell_type": "code", - "execution_count": 20, - "id": "62d67bd5-a5bd-4a7e-8948-b405ca58f6d7", - "metadata": {}, + "execution_count": null, + "id": "f38acf82-dc55-4ca5-86a1-5eae2b1d73da", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "from defdap.plotting import Plot, GrainPlot, MapPlot\n", - "from matplotlib import gridspec" + "grain_id = 48\n", + "grain = ebsd_map[grain_id]\n", + "grain.calc_average_ori() # stored as a quaternion named grain.refOri\n", + "print(grain.ref_ori)\n", + "grain.plot_ref_ori(direction=[0, 0, 1])" ] }, { - "cell_type": "code", - "execution_count": 24, - "id": "0ad2c033-9c5d-4f77-b870-dec10b645e10", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "b59d8a8d-0da3-4252-a1e9-8fe8948ff33d", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "optical_map.grain_inspector()" + "The spread of orientations in a given grain can also be plotted on an IPF" ] }, { "cell_type": "code", - "execution_count": 22, - "id": "c7ae2f85-50c2-4072-a9cd-37723f18cc24", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "defdap.plotting.GrainPlot" - ] - }, - "execution_count": 22, - "metadata": {}, - "output_type": "execute_result" + "execution_count": null, + "id": "ecf0d23e-1566-4cdd-a37e-82587d1f3207", + "metadata": { + "pycharm": { + "name": "#%%\n" } - ], + }, + "outputs": [], "source": [ - "GrainPlot" + "plot = grain.plot_ori_spread(direction=np.array([0, 0, 1]), c='b', s=1, alpha=0.2)\n", + "grain.plot_ref_ori(direction=[0, 0, 1], c='k', plot=plot)" ] }, { - "cell_type": "code", - "execution_count": 23, - "id": "e5844b01-86c3-4830-a078-2976dfaeeaaf", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n", - "Traceback (most recent call last):\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\cbook.py\", line 298, in process\n", - " func(*args, **kwargs)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\Lib\\site-packages\\matplotlib\\widgets.py\", line 244, in \n", - " return self._observers.connect('clicked', lambda event: func(event))\n", - " ^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\plotting.py\", line 126, in \n", - " btn.on_clicked(lambda e: click_handler(e, self))\n", - " ^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 64, in \n", - " 'Next\\nGrain', lambda e, p: self.goto_grain(self.grain_id + 1, p), (div_frac + 0.06, 0.94, 0.05, 0.04))\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 110, in goto_grain\n", - " self.redraw()\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\inspector_optical.py\", line 237, in redraw\n", - " self.selected_ebsd_grain.plot_unit_cell(fig=self.plot.fig, ax=self.unit_cell_axis)\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\ebsd.py\", line 1365, in plot_unit_cell\n", - " plot = Quat.plot_unit_cell(self.ref_ori, fig=fig, ax=ax, plot=plot,\n", - " ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n", - " File \"C:\\Users\\mbgm5pc3\\DF_analysis\\DefDAP\\defdap\\quat.py\", line 557, in plot_unit_cell\n", - " eulerAngles = self.euler_angles()\n", - " ^^^^^^^^^^^^^^^^^\n", - "AttributeError: 'NoneType' object has no attribute 'euler_angles'\n" - ] + "cell_type": "markdown", + "id": "74f31034-9034-488d-9c63-dd20f7242a97", + "metadata": { + "pycharm": { + "name": "#%% md\n" } - ], + }, "source": [ - "grain_0 = optical_map[0].ebsd_grain" + "The unit cell for the average grain orientation can also be ploted" ] }, { "cell_type": "code", "execution_count": null, - "id": "f24b563b-2936-401b-8d59-b5378cf1f466", - "metadata": {}, + "id": "c8abdc41-199d-4a83-8896-c174916b5796", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "print(grain_0)" + "grain.plot_unit_cell()" + ] + }, + { + "cell_type": "markdown", + "id": "883f6a7c-c7b1-4489-8b5f-9d156cafc374", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Printing a list of the slip plane indices, angle of slip plane intersection with the screen (defined as counter-clockwise from upwards), colour defined for the slip plane and also the slip directions and corresponding Schmid factors, is also built in" ] }, { "cell_type": "code", "execution_count": null, - "id": "17cd1902-bde4-4728-a6ad-5c72f167dc79", - "metadata": {}, + "id": "a7e9ef68-e2f4-493e-b331-4c85176e5af6", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "fig = plt.figure(figsize=(9, 4))\n", - "\n", - "gs = gridspec.GridSpec(1, 2)\n", - "ax0 = plt.subplot(gs[0])\n", - "ax1 = plt.subplot(gs[1])\n", - "slipPlot = GrainPlot(fig=fig, calling_grain=ebsd_map[3], ax=ax0)\n", - "slipPlot.add_slip_traces()\n", - "\n", - "grain = optical_map[0]\n", - "ax0.axis('off')\n", - "grain.plot_grain_data(grain_data=grain.data.image, fig=fig, ax=ax1)" + "grain.print_slip_traces()" + ] + }, + { + "cell_type": "markdown", + "id": "3fb6ca64-3e97-4dd3-90b4-9393e89e0746", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "A second built-in example is to calcuate the grain misorientation, specifically the grain reference orientation deviation (GROD). This shows another feature of the `locate_grain` method, which stores the last selected grain in a variable called `sel_grain` in the EBSD map." ] }, { "cell_type": "code", "execution_count": null, - "id": "3c1a461c-c4ef-4c23-ab1e-07692d11b4f1", - "metadata": {}, + "id": "0c28f0b3-0b94-4fbe-b3ba-c3333dc20e2d", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "# List slip angles for all the planes, draw a line and get its angle (need to be done within a interaction window), find the best match between \n", - "# the angles of slip planes and the line we draw\n", - "def calc_angle_drawn():\n", + "if ebsd_map.sel_grain == None: \n", + " ebsd_map.sel_grain = ebsd_map[57]\n", " \n", - "lineAngle = 90-np.rad2deg(np.arctan2(self.grainPlot.p2[1]-self.grainPlot.p1[1],\n", - " self.grainPlot.p2[0]-self.grainPlot.p1[0]))" + "ebsd_map.sel_grain.build_mis_ori_list()\n", + "ebsd_map.sel_grain.plot_mis_ori(plot_scale_bar=True, vmin=0, vmax=5)" + ] + }, + { + "cell_type": "markdown", + "id": "f9b73c12-60f2-4f47-af7e-ebdbe07b5979", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Multi grain analysis\n", + "Once an analysis routine has been prototyped for a single grain it can be applied to all the grains in a map using a loop over the grains and any results added to a list for use later. Of couse you could also apply to a smaller subset of grains as well." ] }, { "cell_type": "code", "execution_count": null, - "id": "2f10bf5c-c696-4295-9fb2-bf520cda68c3", - "metadata": {}, + "id": "0e9ce3da-a3bb-4e09-9b89-fe475b292f70", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "fig = plt.figure(figsize=(13, 4))\n", + "grain_av_oris = []\n", + "for grain in ebsd_map:\n", + " grain.calc_average_ori()\n", + " grain_av_oris.append(grain.ref_ori)\n", "\n", - "gs = gridspec.GridSpec(1, 3)\n", - "ax0 = plt.subplot(gs[0])\n", - "ax1 = plt.subplot(gs[1])\n", - "ax2 = plt.subplot(gs[2])\n", - "\n", - "grain_information = grain.slip_traces\n", - "\n", - "for i,angle in enumerate(grain_information):\n", - " if i == 0:\n", - " Color = 'red'\n", - " slip_plane = 'Basal'\n", - " elif i in [1,2,3]:\n", - " Color = 'blue'\n", - " slip_plane = 'Primastic'\n", - " elif i >3:\n", - " Color = 'green'\n", - " slip_plane = 'Pyramidal'\n", - " ax0.text(0, 1 - 0.1 * i, '{0} | Angle: {1}'.format(slip_plane,np.round(angle*180/np.pi,1)), color=Color)\n", - "\n", - "ax1.imshow(grain.data.image)\n", - "\n", - "\n", - "ax0.axis('off')\n", - "ax1.axis('off')\n", - "ax2.axis('off')" + "# Plot all the grain orientations in the map\n", + "Quat.plot_ipf(grain_av_oris, [0, 0, 1], ebsd_map.crystal_sym, marker='o', s=10)\n", + "plt.tight_layout()" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "2b73c99d-973a-40bc-a76c-6d3b6aef2795", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "3ff0c852-be44-4088-a5de-669b0fa229fd", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "#grain.plot_grain_data(grain_data=grain.data.image,ax=ax1)\n", - "np.shape(grain.data.image)" + "Some common grain analysis routines are built into the EBSD map object, including:" ] }, { "cell_type": "code", "execution_count": null, - "id": "0ce037c8-075c-47b2-8ac6-e1b33009459f", - "metadata": {}, + "id": "66aa6bd5-1f88-4a4f-8294-d88ff61c659d", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "type(optical_map[0].extreme_coords)" + "ebsd_map.calc_grain_av_oris()" ] }, { "cell_type": "code", "execution_count": null, - "id": "983fd2f2-852f-4b5f-8111-dbde514fecfc", - "metadata": {}, + "id": "5be22991-2cc8-4e7d-9b45-ab2ca1378632", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "optical_map[0].grain_map_data()" + "ebsd_map.calc_grain_mis_ori()\n", + "ebsd_map.plot_mis_ori_map(vmin=0, vmax=5, plot_gbs=True, plot_scale_bar=True)" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "35c6a930-016e-4f67-a42c-930871bf589e", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "a4a94c7e-03c6-40c3-b17e-cac3c282d636", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "outline = optical_map[0].grain_outline(bg=0, fg=1)" + "There are also methods for plotting GND density, phases and boundaries. All of the plotting functions in DefDAP use the same parameters to modify the plot, examples seen so far are `plot_gbs`, `plotScaleBar`, `vmin`, `vmax`." ] }, { - "cell_type": "code", - "execution_count": null, - "id": "02299089-56f8-4f27-bfeb-8779e74a89d0", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "713e6f8b-a1d4-491d-96d5-9cf12a2956f0", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "plt.figure()\n", - "plt.imshow(outline)" + "## Linking the optical and EBSD maps\n", + "### Define homologous points\n", + "To register the two datasets, homologous points (points at the same material location) within each map are used to estimate a transformation between the two frames the data are defined in. The homologous points are selected manually using an interactive tool within DefDAP. To select homologous call the method `setHomogPoint` on each of the data maps, which will open a plot window with a button labelled 'save point' in the bottom right. You select a point by right clicking on the map, adjust the position with the arrow and accept the point by with the save point button. Then select the same location in the other map." ] }, { "cell_type": "code", "execution_count": null, - "id": "31c25023-146a-4989-a605-4d199a201ac4", - "metadata": {}, + "id": "c6fcdb04-369b-4101-9478-9f3c765fc7ad", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "outline" + "optical_map.set_homog_point()" ] }, { "cell_type": "code", "execution_count": null, - "id": "d7cc4b5d-4f98-4d91-a081-536fb3d01ac9", - "metadata": {}, + "id": "ecefe035-a5c9-40e9-bf0b-a46319df3fd9", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "grain_data = optical_map[0].grain_data" + "ebsd_map.set_homog_point()" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "ca7272ff-6d67-476f-8d17-a479fc6bd929", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "98e0aae0-1526-43e1-b6f9-c87eb2a5054e", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "print(grain_data)" + "The points are stored as a list of tuples `(x, y)` in each of the maps. This means the points can be set from previous values." ] }, { "cell_type": "code", "execution_count": null, - "id": "68bfb305-51d4-4787-809a-82f8237969a9", - "metadata": {}, + "id": "f86b6dee-453a-4545-b752-57dabd7c16e9", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "optical_map[0].centre_coords()" + "optical_map.frame.homog_points" ] }, { "cell_type": "code", "execution_count": null, - "id": "4c538534-ddca-4634-8b16-335dbadc7bb1", - "metadata": {}, + "id": "b73e8887-aa39-4759-8fee-984c0e2b3786", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "np.shape(grain_data)" + "ebsd_map.frame.homog_points" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "c61fde56-5d78-4153-9a17-038d0a91e217", - "metadata": {}, - "outputs": [], + "cell_type": "markdown", + "id": "7e06cda2-1ccb-4b38-9c60-534ab8254deb", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, "source": [ - "plt.imshow(grain_data)" + "Here are some example homologous points for this data, after setting these by running the cells below you can view the locations in the maps by running the `setHomogPoint` methods (above) again" ] }, { "cell_type": "code", - "execution_count": null, - "id": "c00c2c00-c5c5-4306-9e2d-d2cdb9ab832f", - "metadata": {}, + "execution_count": 8, + "id": "5db8cb21-0612-4900-9af5-7c69e059c73a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "ebsd_map[0].slip_traces" + "optical_map.frame.homog_points = [\n", + " (467, 653), \n", + " (806, 239), \n", + " (180, 94)\n", + "]" ] }, { "cell_type": "code", - "execution_count": null, - "id": "05bce901-c239-4aac-a4b9-60b70d6414e9", - "metadata": {}, + "execution_count": 9, + "id": "e9c2b077-67b3-4eea-865f-39aacba48246", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "Plot.add_grain_numbers(ebsd_map)" + "ebsd_map.frame.homog_points = [\n", + " (314, 533), \n", + " (543, 242), \n", + " (97, 143)\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "aca05b18-d4d0-4015-ac3e-dc28ebc6065f", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Link the maps\n", + "Finally the two data maps are linked. The type of transform between the two frames can be affine, projective, polynomial." ] }, { "cell_type": "code", - "execution_count": null, - "id": "1a3dda64-4162-4cb5-9a44-8cd657830b88", - "metadata": {}, + "execution_count": 10, + "id": "223a0c85-4204-4803-984b-b026252b2152", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "ebsd_map.add_grain_numbers()" + "optical_map.link_ebsd_map(ebsd_map, transform_type=\"affine\")\n", + "# optical_map.link_ebsd_map(ebsd_map, transform_type=\"projective\")\n", + "# optical_map.link_ebsd_map(ebsd_map, transform_type=\"polynomial\", order=2)" + ] + }, + { + "cell_type": "markdown", + "id": "e6784cf6-8dcd-4134-990d-b6dba399243b", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Show the transformation" ] }, { "cell_type": "code", "execution_count": null, - "id": "68bcc855-9aa3-4887-ab1a-94c773a54504", - "metadata": {}, + "id": "5aa0d397-4c57-42c0-b9cf-b571ea0c979b", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "np.shape(grain)" + "from skimage import transform as tf\n", + "\n", + "data = np.zeros((2000, 2000), dtype=float)\n", + "data[500:1200, 500:1200] = 1.\n", + "transform = optical_map.experiment.get_frame_transform(optical_map.frame, ebsd_map.frame)\n", + "dataWarped = tf.warp(data, transform)\n", + "\n", + "fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(8,4))\n", + "ax1.set_title('Reference')\n", + "ax1.imshow(data)\n", + "ax2.set_title('Transformed')\n", + "ax2.imshow(dataWarped)" + ] + }, + { + "cell_type": "markdown", + "id": "36579474-98fd-46bc-bba1-1cd59ecc482c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "### Segment into grains\n", + "The optical map can now be segmented into grains using the grain boundaries detected in the EBSD map. Analysis rountines can then be applied to individual grain, as with the EBSD grains. The grain finding process will also attempt to link the grains between the EBSD and optical maps and each grain in the optical image has a reference (`ebsdGrain`) to the corrosponding grain in the EBSD map." ] }, { "cell_type": "code", - "execution_count": null, - "id": "71b8f64c-85cf-46b8-bb3f-244fc53133bb", - "metadata": {}, - "outputs": [], + "execution_count": 11, + "id": "bb95be4e-5bca-43ec-a9c6-09243c000d8a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Finished finding grains (0:00:00) \n" + ] + } + ], "source": [ - "grain" + "optical_map.data.generate('grains', algorithm='warp', min_grain_size=10)" ] }, { "cell_type": "code", "execution_count": null, - "id": "72a9a7c9-b8dd-4556-b24d-14269f524df5", + "id": "2ef9e5ee-3ada-4bc6-ac23-8ea1ce4e0f5d", "metadata": {}, "outputs": [], "source": [ - "\n", - "\n" + "optical_map.plot_map('image', vmin=0, vmax=1, plot_scale_bar=True, plot_gbs='line')" + ] + }, + { + "cell_type": "markdown", + "id": "ac310178-33b2-46a2-9f5a-7a94878cade6", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "Now, a grain can also be selected interactively in the optical map, in the same way a grain can be selected from an EBSD map. If `displaySelected` is set to true, then a pop-out window shows the map segmented for the grain" ] }, { "cell_type": "code", "execution_count": null, - "id": "8cdd7a0e-8a1b-468f-a03e-a895bc1ba990", - "metadata": {}, + "id": "fa2a0497-3fd7-4dff-bf71-797b601c75f8", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, "outputs": [], "source": [ - "optical_map.grain_inspector()" + "optical_map.locate_grain(display_grain=True)" ] }, { - "cell_type": "code", - "execution_count": null, - "id": "8965788e-e950-4db6-a0fb-e29b4c4583e5", + "cell_type": "markdown", + "id": "908017fb-24e1-4963-aa09-03c52567dcc8", "metadata": {}, - "outputs": [], - "source": [] + "source": [ + "### Grain inspector\n", + "This is an interactive tool used to perform slip trace analysis" + ] }, { "cell_type": "code", - "execution_count": null, - "id": "608d59f3-b6fa-48d8-84e8-c3446694c1f2", + "execution_count": 12, + "id": "b6d7a470-7bcf-4b7f-8902-de3d53c0febc", "metadata": {}, "outputs": [], - "source": [] + "source": [ + "optical_map.grain_inspector()" + ] } ], "metadata": { @@ -895,7 +971,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.6" + "version": "3.12.2" } }, "nbformat": 4, diff --git a/tests/data/F5-pol-Cy50.png b/tests/data/testOptical.png similarity index 100% rename from tests/data/F5-pol-Cy50.png rename to tests/data/testOptical.png diff --git a/tests/data/f-5-test-region.cpr b/tests/data/testOpticalEBSD.cpr similarity index 100% rename from tests/data/f-5-test-region.cpr rename to tests/data/testOpticalEBSD.cpr diff --git a/tests/data/f-5-test-region.crc b/tests/data/testOpticalEBSD.crc similarity index 100% rename from tests/data/f-5-test-region.crc rename to tests/data/testOpticalEBSD.crc