{ "cells": [ { "cell_type": "markdown", "id": "5db3db46-6e5d-4ba8-b4a4-056e2b2a5bdf", "metadata": { "nbsphinx": "hidden", "tags": [] }, "source": [ "This notebook is part of the `kikuchipy` documentation https://kikuchipy.org.\n", "Links to the documentation won't work from the notebook." ] }, { "cell_type": "markdown", "id": "c29c9122-a8f7-46cf-85cb-a4eccb4327fd", "metadata": {}, "source": [ "# Kinematical EBSD simulations\n", "\n", "In this tutorial, we will perform kinematical Kikuchi pattern simulations of nickel, a variant of the $\\sigma$-phase (Fe, Cr) in steels, and silicon carbide 6H.\n", "\n", "We can obtain kinematical master patterns using [KikuchiPatternSimulator.calculate_master_pattern()](../reference/generated/kikuchipy.simulations.KikuchiPatternSimulator.calculate_master_pattern.rst), provided that the simulator is created from a [ReciprocalLatticeVector](https://diffsims.readthedocs.io/en/stable/reference.html#diffsims.crystallography.ReciprocalLatticeVector) instance that satisfy these conditions:\n", "\n", "1. The unit cell, i.e. the `structure` used to create the `phase` used in `ReciprocalLatticeVector`, must have all asymmetric atom positions filled, which can either be done by creating a `Phase` instance from a valid CIF file with [Phase.from_cif()](https://orix.readthedocs.io/en/stable/reference/generated/orix.crystal_map.Phase.from_cif.html) or calling [ReciprocalLatticeVector.sanitise_phase()](https://diffsims.readthedocs.io/en/stable/reference.html#diffsims.crystallography.ReciprocalLatticeVector.sanitise_phase)\n", "2. The atoms in the `structure` have their elements described by the symbol (Ni), not by the atomic number (28)\n", "3. The lattice parameters are in given in Ångström.\n", "4. Kinematical structure factors $F_{hkl}$ have been calculated with [ReciprocalLatticeVector.calculate_structure_factor()](https://diffsims.readthedocs.io/en/stable/reference.html#diffsims.crystallography.ReciprocalLatticeVector.calculate_structure_factor)\n", "5. Bragg angles $\\theta_B$ have been calculated with [ReciprocalLatticeVector.calculate_theta()](https://diffsims.readthedocs.io/en/stable/reference.html#diffsims.crystallography.ReciprocalLatticeVector.calculate_theta)\n", "\n", "Let's import the necessary libraries" ] }, { "cell_type": "code", "execution_count": null, "id": "6a2ce51b-ca2f-4ebb-98fd-113337505ca1", "metadata": {}, "outputs": [], "source": [ "# Exchange inline for notebook or qt5 (from pyqt) for interactive plotting\n", "%matplotlib inline\n", "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pyvista\n", "\n", "from diffpy.structure import Atom, Lattice, Structure\n", "from diffsims.crystallography import ReciprocalLatticeVector\n", "import hyperspy.api as hs\n", "import kikuchipy as kp\n", "from orix.crystal_map import Phase\n", "\n", "\n", "# Plotting parameters\n", "plt.rcParams.update(\n", " {\"figure.figsize\": (10, 10), \"font.size\": 20, \"lines.markersize\": 10}\n", ")\n", "# See https://docs.pyvista.org/user-guide/jupyter/index.html\n", "pyvista.set_jupyter_backend(\"panel\")" ] }, { "cell_type": "markdown", "id": "12889e10-9cef-4fe9-a8c3-ee15cdb8eaba", "metadata": {}, "source": [ "## Nickel\n", "\n", "We'll compare our kinematical simulations to dynamical simulations performed with EMsoft (see Callahan and De Graef (2013)), since we have a Ni master pattern available in the [kikuchipy.data](../reference/generated/kikuchipy.data.rst) module" ] }, { "cell_type": "code", "execution_count": null, "id": "68eeb086-af25-4050-88f8-4b8004d4005f", "metadata": {}, "outputs": [], "source": [ "mp_ni_dyn = kp.data.nickel_ebsd_master_pattern_small(\n", " projection=\"stereographic\"\n", ")" ] }, { "cell_type": "markdown", "id": "ca4b1454-f303-4992-9be9-4c29c944eea3", "metadata": {}, "source": [ "Inspect phase" ] }, { "cell_type": "code", "execution_count": null, "id": "406f1bd3-d11f-4d8f-82ac-702aeac5a4f4", "metadata": {}, "outputs": [], "source": [ "phase_ni = mp_ni_dyn.phase.deepcopy()\n", "\n", "print(phase_ni)\n", "print(phase_ni.structure.lattice)" ] }, { "cell_type": "markdown", "id": "b52380ec-25c8-4144-a7cc-19d6c1491fee", "metadata": {}, "source": [ "Change lattice parameters from nm to Ångström" ] }, { "cell_type": "code", "execution_count": null, "id": "c4393223-4b49-442e-8a8b-2d7ab6fa6bd0", "metadata": {}, "outputs": [], "source": [ "lat_ni = phase_ni.structure.lattice # Shallow copy\n", "lat_ni.setLatPar(lat_ni.a * 10, lat_ni.b * 10, lat_ni.c * 10)\n", "\n", "print(phase_ni.structure.lattice)" ] }, { "cell_type": "markdown", "id": "cdff1303-5341-4557-b024-967ee298be7b", "metadata": {}, "source": [ "We'll build up the reflector list by:\n", "\n", "1. Finding all reflectors with a minimal interplanar spacing $d$\n", "2. Keeping those that have a structure factor above 0.5% of the reflector with the highest structure factor" ] }, { "cell_type": "code", "execution_count": null, "id": "fc6eccb3-848d-4d5a-8617-58a8695581a3", "metadata": {}, "outputs": [], "source": [ "rlv_ni = ReciprocalLatticeVector.from_min_dspacing(phase_ni, 0.5)\n", "\n", "# Exclude non-allowed reflectors (not available for hexagonal or trigonal\n", "# phases!)\n", "rlv_ni = rlv_ni[rlv_ni.allowed]\n", "rlv_ni = rlv_ni.unique(use_symmetry=True).symmetrise()" ] }, { "cell_type": "markdown", "id": "1f747220-22bf-42d4-8af6-088684e3869b", "metadata": {}, "source": [ "Sanitise `phase` by completing the unit cell" ] }, { "cell_type": "code", "execution_count": null, "id": "a164d547-09c2-4b67-ada1-fb16c59afd2f", "metadata": {}, "outputs": [], "source": [ "rlv_ni.phase.structure" ] }, { "cell_type": "code", "execution_count": null, "id": "9fa50624-6b84-473c-9546-fd485ea9e2d4", "metadata": {}, "outputs": [], "source": [ "rlv_ni.sanitise_phase()\n", "rlv_ni.phase.structure" ] }, { "cell_type": "markdown", "id": "af32ad92-25fb-4a2e-a21b-6bf8da96fa58", "metadata": {}, "source": [ "We can now calculate the structure factors.\n", "Two parametrizations are available, from Kirkland (1998) (`\"xtables\"`, the default) or Lobato and Van Dyck (2014) (`\"lobato\"`)" ] }, { "cell_type": "code", "execution_count": null, "id": "3c72f1d8-17fc-45dd-a960-a6be7f3ff4c3", "metadata": {}, "outputs": [], "source": [ "rlv_ni.calculate_structure_factor()" ] }, { "cell_type": "code", "execution_count": null, "id": "beaf0bef-a767-4d4f-a78b-4e14b7e824bd", "metadata": {}, "outputs": [], "source": [ "structure_factor_ni = abs(rlv_ni.structure_factor)\n", "rlv_ni = rlv_ni[structure_factor_ni > 0.05 * structure_factor_ni.max()]\n", "\n", "rlv_ni.print_table()" ] }, { "cell_type": "code", "execution_count": null, "id": "487a6704-323f-4a44-9df5-c30ee18ad4cc", "metadata": {}, "outputs": [], "source": [ "rlv_ni.calculate_theta(20e3)" ] }, { "cell_type": "markdown", "id": "eacde2eb-beed-40ae-a980-4ab698ee0151", "metadata": {}, "source": [ "We can now create our simulator and plot the simulation" ] }, { "cell_type": "code", "execution_count": null, "id": "dfe1fdd7-f622-4f78-a81b-ab868cdac16b", "metadata": {}, "outputs": [], "source": [ "simulator_ni = kp.simulations.KikuchiPatternSimulator(rlv_ni)\n", "simulator_ni.reflectors.size" ] }, { "cell_type": "markdown", "id": "f9124e84-b03c-4ad3-803a-5fa866529037", "metadata": {}, "source": [ "Plotting the band centers with intensities scaled by the structure factor" ] }, { "cell_type": "code", "execution_count": null, "id": "f0741f7a-5c63-4424-98dc-4f5a17abacdf", "metadata": {}, "outputs": [], "source": [ "simulator_ni.plot()" ] }, { "cell_type": "markdown", "id": "6e2b9b35-ab20-435d-b892-b4d3558cb12a", "metadata": {}, "source": [ "Or no scaling (`scaling=\"square\"` for the structure factor squared)" ] }, { "cell_type": "code", "execution_count": null, "id": "c7b7b0a5-c80a-4278-9326-d89928f38616", "metadata": {}, "outputs": [], "source": [ "simulator_ni.plot(scaling=None)" ] }, { "cell_type": "markdown", "id": "3eefc01e-0ad1-477b-abd7-791dc6e66cfe", "metadata": {}, "source": [ "We can also plot the Kikuchi bands, showing both hemispheres, also adding the crystal axes alignment" ] }, { "cell_type": "code", "execution_count": null, "id": "22bc9bb4-e274-4b33-aa62-577037c9a954", "metadata": { "tags": [] }, "outputs": [], "source": [ "fig = simulator_ni.plot(hemisphere=\"both\", mode=\"bands\", return_figure=True)\n", "\n", "ax = fig.axes[0]\n", "ax.scatter(simulator_ni.phase.a_axis, c=\"r\")\n", "ax.scatter(simulator_ni.phase.b_axis, c=\"g\")\n", "ax.scatter(simulator_ni.phase.c_axis, c=\"b\")" ] }, { "cell_type": "markdown", "id": "2045c5c2-6c91-441d-b60b-e46fbf40e2d3", "metadata": {}, "source": [ "The simulation can be plotted in spherical projection as well using *Matplotlib*, or *PyVista* provided that it is [installed](../user/installation.rst#with-pip)" ] }, { "cell_type": "code", "execution_count": null, "id": "2c348b27-306b-47aa-b8c7-c59c06570361", "metadata": {}, "outputs": [], "source": [ "simulator_ni.plot(\"spherical\", mode=\"bands\")" ] }, { "cell_type": "code", "execution_count": null, "id": "6cb3cd28-3202-4bb2-9de4-b3b8f7238aa3", "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "# Interactive!\n", "simulator_ni.plot(\"spherical\", mode=\"bands\", backend=\"pyvista\")" ] }, { "cell_type": "markdown", "id": "37392f41-bb47-4eae-8e5a-68e5b802fbe8", "metadata": {}, "source": [ "When we're happy with the reflector list in the simulator, we can generate our kinematical master pattern" ] }, { "cell_type": "code", "execution_count": null, "id": "00a59a81-13b3-4fb5-937f-08e8ed9bde65", "metadata": {}, "outputs": [], "source": [ "mp_ni_kin = simulator_ni.calculate_master_pattern(half_size=200)" ] }, { "cell_type": "markdown", "id": "8f82dc33-8268-47d1-8f07-ee9444f2f833", "metadata": {}, "source": [ "The returned master pattern is an instance of [EBSDMasterPattern](../reference/generated/kikuchipy.signals.EBSDMasterPattern.rst) in the stereographic projection." ] }, { "cell_type": "code", "execution_count": null, "id": "d512875a-d1cc-46d8-91a0-871d47a54fc2", "metadata": {}, "outputs": [], "source": [ "mp_ni_kin" ] }, { "cell_type": "markdown", "id": "2e1e8ecf-1539-4e6b-845b-4d68b1fa384c", "metadata": {}, "source": [ "A spherical plot (requires that *PyVista* is installed)" ] }, { "cell_type": "code", "execution_count": null, "id": "60c19c07-6e59-43c3-bac3-de707af61d04", "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "# Interactive!\n", "mp_ni_kin.plot_spherical(style=\"points\")" ] }, { "cell_type": "markdown", "id": "c10cde45-a367-4f09-8045-2712266b5523", "metadata": {}, "source": [ "Comparing kinematical and dynamical simulations" ] }, { "cell_type": "code", "execution_count": null, "id": "7ea20aaf-04de-4d55-86dd-e9ca42db696c", "metadata": {}, "outputs": [], "source": [ "# Exclude outside equator\n", "ni_dyn_data = mp_ni_dyn.data.astype(\"float32\")\n", "ni_kin_data = mp_ni_kin.data.astype(\"float32\")\n", "mask = ni_dyn_data == 0\n", "ni_dyn_data[mask] = np.nan\n", "ni_kin_data[mask] = np.nan\n", "\n", "fig, ax = plt.subplots(ncols=2)\n", "ax[0].imshow(ni_kin_data, cmap=\"gray\")\n", "ax[1].imshow(ni_dyn_data, cmap=\"gray\")\n", "ax[0].axis(\"off\")\n", "ax[1].axis(\"off\")\n", "ax[0].set_title(\"Ni kinematical 20 kV\")\n", "ax[1].set_title(\"Ni dynamical 20 kV\")\n", "fig.tight_layout()" ] }, { "cell_type": "markdown", "id": "08d19808-76f3-4666-a7bb-0ccf04af0fa8", "metadata": {}, "source": [ "
\n", "\n", "Warning\n", " \n", "Use dynamical simulations when performing pattern matching, not kinematical simulations.\n", "The latter intensities are not realistic, as demonstrated in the above comparison.\n", "\n", "
\n", "\n", "Finally, we can transform the master pattern in the stereographic projection to one in the Lambert projection" ] }, { "cell_type": "code", "execution_count": null, "id": "5f44e712-031c-4556-a2a2-dd7b91e9ca5e", "metadata": {}, "outputs": [], "source": [ "mp_ni_kin_lp = mp_ni_kin.as_lambert()" ] }, { "cell_type": "code", "execution_count": null, "id": "76610f0f-ac3a-4fd0-8a42-ec87adcab33b", "metadata": {}, "outputs": [], "source": [ "mp_ni_kin_lp.plot()" ] }, { "cell_type": "markdown", "id": "fd6f87ee-fc40-4166-978f-8ac071211e51", "metadata": {}, "source": [ "We can then project parts of this pattern onto our EBSD detector using [get_patterns()](../reference/generated/kikuchipy.signals.EBSDMasterPattern.get_patterns.rst).\n", "Let's do this for the (3, 3) patterns used to demonstrate geometrical simulations in the [geometrical EBSD simulations tutorial](geometrical_ebsd_simulations.ipynb): the patterns are stored with the indexed solutions and an optimized detector-sample geometry (both found using *PyEBSDIndex*, see the [Hough indexing](hough_indexing.ipynb) for details)" ] }, { "cell_type": "code", "execution_count": null, "id": "255d539e-7fa6-4706-b5f0-9a75f0f966ca", "metadata": {}, "outputs": [], "source": [ "s = kp.data.nickel_ebsd_small(lazy=True) # Don't load the patterns\n", "\n", "rot = s.xmap.rotations\n", "rot = rot.reshape(*s.xmap.shape)\n", "print(rot)\n", "\n", "print(s.detector)" ] }, { "cell_type": "code", "execution_count": null, "id": "fcbd1b95-b1cd-4a37-a9d6-e12b28993e3f", "metadata": {}, "outputs": [], "source": [ "s_kin = mp_ni_kin_lp.get_patterns(rot, s.detector, energy=20, compute=True)" ] }, { "cell_type": "code", "execution_count": null, "id": "2893b4be-5041-42d0-9825-a2cb49707a71", "metadata": {}, "outputs": [], "source": [ "_ = hs.plot.plot_images(\n", " s_kin, axes_decor=None, label=None, colorbar=False, tight_layout=True\n", ")" ] }, { "cell_type": "markdown", "id": "d4376034-61c3-42f2-bca8-578ab8c8fd8c", "metadata": {}, "source": [ "Compare these to the ones in the\n", "[geometrical EBSD simulations tutorial](geometrical_ebsd_simulations.ipynb)!" ] }, { "cell_type": "markdown", "id": "f3077007-a0cb-4429-a87f-70478173fab4", "metadata": {}, "source": [ "## Sigma phase" ] }, { "cell_type": "code", "execution_count": null, "id": "c8532730-d0fc-4b66-b577-c52f5724e1e9", "metadata": {}, "outputs": [], "source": [ "phase_sigma = Phase(\n", " name=\"sigma\",\n", " space_group=136,\n", " structure=Structure(\n", " atoms=[\n", " Atom(\"Cr\", [0, 0, 0], 0.5),\n", " Atom(\"Fe\", [0, 0, 0], 0.5),\n", " Atom(\"Cr\", [0.31773, 0.31773, 0], 0.5),\n", " Atom(\"Fe\", [0.31773, 0.31773, 0], 0.5),\n", " Atom(\"Cr\", [0.06609, 0.26067, 0], 0.5),\n", " Atom(\"Fe\", [0.06609, 0.26067, 0], 0.5),\n", " Atom(\"Cr\", [0.13122, 0.53651, 0], 0.5),\n", " Atom(\"Fe\", [0.13122, 0.53651, 0], 0.5),\n", " ],\n", " lattice=Lattice(8.802, 8.802, 4.548, 90, 90, 90),\n", " ),\n", ")\n", "phase_sigma" ] }, { "cell_type": "code", "execution_count": null, "id": "3b485cef-8a71-427b-8787-d519dd4d758d", "metadata": {}, "outputs": [], "source": [ "rlv_sigma = ReciprocalLatticeVector.from_min_dspacing(phase_sigma, 1)\n", "\n", "rlv_sigma.sanitise_phase()\n", "\n", "rlv_sigma.calculate_structure_factor(\"lobato\")\n", "\n", "structure_factor = abs(rlv_sigma.structure_factor)\n", "rlv_sigma = rlv_sigma[structure_factor > 0.05 * structure_factor.max()]\n", "\n", "rlv_sigma.calculate_theta(20e3)\n", "\n", "rlv_sigma.print_table()" ] }, { "cell_type": "code", "execution_count": null, "id": "e3c82201-762f-4bff-b994-b697264be68c", "metadata": {}, "outputs": [], "source": [ "simulator_sigma = kp.simulations.KikuchiPatternSimulator(rlv_sigma)\n", "simulator_sigma" ] }, { "cell_type": "code", "execution_count": null, "id": "a358a264-77b5-4f51-9fbb-f06330be9b25", "metadata": {}, "outputs": [], "source": [ "fig = simulator_sigma.plot(\n", " hemisphere=\"both\", mode=\"bands\", return_figure=True\n", ")\n", "\n", "ax = fig.axes[0]\n", "ax.scatter(simulator_sigma.phase.a_axis, c=\"r\")\n", "ax.scatter(simulator_sigma.phase.b_axis, c=\"g\")\n", "ax.scatter(simulator_sigma.phase.c_axis, c=\"b\")\n", "fig.tight_layout()" ] }, { "cell_type": "code", "execution_count": null, "id": "7e2b3bbf-03af-4ef0-87c1-3c27b4a71e0f", "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "# Interactive!\n", "simulator_sigma.plot(\"spherical\", mode=\"bands\", backend=\"pyvista\")" ] }, { "cell_type": "code", "execution_count": null, "id": "c22e5695-17e3-497d-8853-e7401bb5c9b4", "metadata": {}, "outputs": [], "source": [ "mp_sigma = simulator_sigma.calculate_master_pattern()" ] }, { "cell_type": "code", "execution_count": null, "id": "22d8bf0e-6877-4213-8918-74e7180e1947", "metadata": { "nbsphinx-thumbnail": { "tooltip": "Kinematical simulations of master patterns and on the detector" }, "tags": [ "nbsphinx-thumbnail" ] }, "outputs": [], "source": [ "mp_sigma.plot()" ] }, { "cell_type": "code", "execution_count": null, "id": "b44b00f6-cb8d-4183-8a18-4c856fdf267b", "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "# Interactive!\n", "mp_sigma.plot_spherical(style=\"points\")" ] }, { "cell_type": "markdown", "id": "80e5bb4f-e1d9-4916-92f7-6d7ebd492c2e", "metadata": {}, "source": [ "## Silicon carbide 6H" ] }, { "cell_type": "code", "execution_count": null, "id": "b2620d7b-227a-4b9f-946e-25e853385c6f", "metadata": {}, "outputs": [], "source": [ "phase_sic = Phase(\n", " name=\"sic_6h\",\n", " space_group=186,\n", " structure=Structure(\n", " atoms=[\n", " Atom(\"Si\", [1 / 3, 2 / 3, 0.20778]),\n", " Atom(\"C\", [1 / 3, 2 / 3, 0.33298]),\n", " Atom(\"Si\", [1 / 3, 2 / 3, 0.54134]),\n", " Atom(\"C\", [1 / 3, 2 / 3, 0.66647]),\n", " Atom(\"C\", [0, 0, 0]),\n", " Atom(\"Si\", [0, 0, 0.37461]),\n", " ],\n", " lattice=Lattice(3.081, 3.081, 15.2101, 90, 90, 120),\n", " ),\n", ")\n", "phase_sic" ] }, { "cell_type": "code", "execution_count": null, "id": "cd80c552-da89-4260-81d9-aa24a622a6af", "metadata": {}, "outputs": [], "source": [ "rlv_sic = ReciprocalLatticeVector.from_min_dspacing(phase_sic)\n", "rlv_sic.sanitise_phase()\n", "\n", "rlv_sic.calculate_structure_factor()\n", "\n", "structure_factor = abs(rlv_sic.structure_factor)\n", "rlv_sic = rlv_sic[structure_factor > 0.05 * structure_factor.max()]\n", "\n", "rlv_sic.calculate_theta(20e3)\n", "\n", "rlv_sic.print_table()" ] }, { "cell_type": "code", "execution_count": null, "id": "d9516381-6bd7-4f52-9482-ffbef9cc3bd0", "metadata": {}, "outputs": [], "source": [ "simulator_sic = kp.simulations.KikuchiPatternSimulator(rlv_sic)\n", "simulator_sic" ] }, { "cell_type": "code", "execution_count": null, "id": "89b7403d-9928-42af-820b-d6ea3c56a3a9", "metadata": {}, "outputs": [], "source": [ "fig = simulator_sic.plot(hemisphere=\"both\", mode=\"bands\", return_figure=True)\n", "\n", "ax = fig.axes[0]\n", "ax.scatter(simulator_sic.phase.a_axis, c=\"r\")\n", "ax.scatter(simulator_sic.phase.b_axis, c=\"g\")\n", "ax.scatter(simulator_sic.phase.c_axis, c=\"b\")" ] }, { "cell_type": "code", "execution_count": null, "id": "4ac896e9-ee68-415d-8ea8-81feb511bab5", "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "# Interactive!\n", "simulator_sic.plot(\"spherical\", mode=\"bands\", backend=\"pyvista\")" ] }, { "cell_type": "code", "execution_count": null, "id": "59c3aa20-308f-4f39-b328-960d21433090", "metadata": {}, "outputs": [], "source": [ "mp_sic = simulator_sic.calculate_master_pattern(\n", " hemisphere=\"both\", half_size=200\n", ")" ] }, { "cell_type": "code", "execution_count": null, "id": "e2d2bf84-9aa9-406d-bec8-82850ce675cc", "metadata": {}, "outputs": [], "source": [ "mp_sic" ] }, { "cell_type": "code", "execution_count": null, "id": "421f8770-4c6b-4340-8330-7494e961e96c", "metadata": {}, "outputs": [], "source": [ "mp_sic.plot(navigator=None)" ] }, { "cell_type": "code", "execution_count": null, "id": "0e56039d-803a-429b-89b1-5728cd90b745", "metadata": { "tags": [ "nbval-skip" ] }, "outputs": [], "source": [ "# Interactive!\n", "mp_sic.plot_spherical(style=\"points\")" ] } ], "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.9" }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 5 }