{ "cells": [ { "cell_type": "markdown", "id": "24a96c62", "metadata": {}, "source": [ "# Plotting spherical polar mapping data\n", "\n", "The below code creates and interactive plot, with the mapped data for a set radius on the left, and a plot of all selected vectors on the right. To select a vector simply click anywhere on the left hand 2d plot and the selected point will have its associated vector plotted on the right-hand side 3d axis, along with a star marker on the left-hand side plot. \n", "To clear all selected vectors from the right-hand side plot and star markers from the left-hand plot click the 'clear vectors' button displayed as a widget in the cell output. " ] }, { "cell_type": "code", "execution_count": 1, "id": "859c22ab-cf25-4090-8065-b450e7090dd0", "metadata": {}, "outputs": [], "source": [ "#import the required modules\n", "#----------------------------\n", "import h5py\n", "import ipywidgets as wg\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", "from mpl_toolkits.mplot3d import Axes3D\n", "\n", "from matplotlib.collections import PathCollection\n", "from scipy.spatial.transform import Rotation as R\n", "import transformations as tf" ] }, { "cell_type": "code", "execution_count": 2, "id": "97afb7ba-11d0-4416-a7a3-12c57dba46ab", "metadata": {}, "outputs": [], "source": [ "\n", "#define functions needed for plotting\n", "#--------------------------------------\n", "markers=[]\n", "def drawarrow(vec1,vec2,axs,col,style='-',alp=1):\n", " axs.quiver(vec1[0],vec1[1],vec1[2],vec2[0],vec2[1],vec2[2],color = col,arrow_length_ratio=0.1,ls=style,alpha=alp)\n", "\n", "def point2vec(axes,counts,r_int,th_int,phi_int,zoom,click=False):\n", " global updating\n", " if updating:\n", " return\n", " #ax2.cla()\n", " \n", "\n", " markernew=ax1.scatter(phi_int,th_int,marker='*',s=50,c='aqua',ec='black')\n", " markers.append(markernew)\n", " vector0=[0,0,0]\n", " rstart,rstop,rstep=axes[0][1:4]\n", " thstart,thstop,thstep=axes[1][1:4]\n", " phistart,phistop,phistep=axes[2][1:4]\n", " \n", " thetarad=thstart+(th_int*thstep)\n", " phirad=phistart+(phi_int*phistep)\n", " radius=rstart+(r_int*rstep)\n", " if click==False:\n", " \n", " title = ax1.get_title().split('=')[0]\n", " ax1.cla()\n", " ax1.set_title(title+f\"={radius}\")\n", " ax1.imshow(counts[r_int,:,:],norm='log',cmap='jet')\n", " theta=np.degrees(thetarad)\n", " phi=np.degrees(phirad)\n", " \n", " vector1=[0,0,radius]\n", " rotyzmat=R.from_euler('x', theta, degrees=True)\n", " rotxymat=R.from_euler('z',phi,degrees=True)\n", " totalrot=rotxymat*rotyzmat\n", " plotexitvec=totalrot.apply(vector1)\n", " ax1.set_ylabel('theta: angle from +z axis')\n", " ax1.set_xlabel('phi: angle from +x axis')\n", " drawarrow(vector0,plotexitvec,ax2,'orange')\n", " ax2.set_xlim(-zoom,zoom)\n", " ax2.set_xlabel('x')\n", " ax2.set_ylim(-zoom,zoom)\n", " ax2.set_ylabel('y')\n", " ax2.set_zlim(-zoom,zoom)\n", " ax2.set_zlabel('z')" ] }, { "cell_type": "code", "execution_count": 34, "id": "f7bfb475-9248-45dd-b465-ace02529b54e", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1ba7edd04ec54921a4338aed08b04436", "version_major": 2, "version_minor": 0 }, "text/plain": [ "Button(description='clear vectors', style=ButtonStyle())" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "2df0cd8141f64e4fa1186a4abd7c00b0", "version_major": 2, "version_minor": 0 }, "text/plain": [ "interactive(children=(IntSlider(value=1, description='select radius', layout=Layout(width='350px'), max=193, s…" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#setup the active figure\n", "#------------------------- \n", "%matplotlib qt \n", "#other options are available for interactive plotting e.g %matplotlib widget\n", "fig = plt.figure(figsize=(20, 10))\n", "\n", "fig.canvas.manager.set_window_title(\"Spherical polar plot and vector selection\")\n", "ax1 = fig.add_subplot(121)\n", "ax2= fig.add_subplot(122, projection='3d')\n", "\n", "#import data from hdf5 file\n", "#--------------------\n", "filename='/dls/science/users/rpy65944/output/mapped_scan_519528_1.hdf5'\n", "datah5=h5py.File(filename)\n", "ax1.set_title(filename+'\\n radius=1')\n", "#'/dls/science/users/rpy65944/output/mapped_scan_519445_1.hdf5')\n", "counts=datah5['binoculars/counts']\n", "\n", "#grab axis details from file\n", "axinfo=datah5['binoculars/axes']\n", "r_ax=np.array(axinfo['h'])\n", "th_ax=np.array(axinfo['k'])\n", "phi_ax=np.array(axinfo['l'])\n", "\n", "axes=[r_ax,th_ax,phi_ax]\n", "\n", "#setup widgets and start the interactive sliders, button and plot \n", "slider_r = wg.IntSlider(value=1, min=0, max=np.shape(counts)[0]-1, step=1,description='select radius',description_width ='300px',layout=wg.Layout(width='350px'))\n", "slider_r.style.description_width='150px'\n", "slider_th = wg.IntSlider(value=1, min=0, max=np.shape(counts)[1]-1, step=1,description='select theta value',description_width ='300px',layout=wg.Layout(width='350px'))\n", "slider_th.style.description_width='150px'\n", "slider_phi = wg.IntSlider(value=1, min=0, max=np.shape(counts)[2]-1, step=1,description='select phi value',description_width ='300px',layout=wg.Layout(width='350px'))\n", "slider_phi.style.description_width='150px'\n", "slider_zoom=wg.FloatSlider(value=1, min=0, max=5.00, step=0.1,description='select zoom value',description_width ='300px',layout=wg.Layout(width='350px'))\n", "slider_zoom.style.description_width='150px'\n", "clear_button=wg.Button(description=\"clear vectors\")\n", "click_sliders=[slider_th,slider_phi]\n", "updating=False\n", "\n", "def onclick(event):\n", " global updating,axes,counts,click_sliders\n", " if event.inaxes == ax1:\n", " updating=True\n", " #ax2.cla()\n", " newth=int(event.ydata)\n", " newphi=int(event.xdata)\n", " click_sliders=[slider_th,slider_phi]\n", " newslidevals=[newth,newphi]\n", " for i,slider in enumerate(click_sliders):\n", " slider.value=newslidevals[i]\n", " updating=False\n", " point2vec(axes,counts,r_int=slider_r.value,th_int=slider_th.value,phi_int=slider_phi.value,zoom=slider_zoom.value,click=True)\n", " fig.canvas.draw_idle() \n", "\n", "def clearaxmarkers():\n", " scatter_markers = [artist for artist in ax1.collections if isinstance(artist, PathCollection)]\n", " for marker in scatter_markers:\n", " marker.remove()\n", " ax2.cla()\n", "clear_button.on_click(lambda b: clearaxmarkers())\n", "display(clear_button)\n", " \n", "fig.canvas.mpl_connect('button_press_event', onclick)\n", "\n", "\n", "wg.interact(point2vec,axes=wg.fixed(axes),counts=wg.fixed(counts),r_int=slider_r,th_int=slider_th,phi_int=slider_phi,zoom=slider_zoom)" ] }, { "cell_type": "code", "execution_count": 10, "id": "349176aa-18c9-4cef-ae50-91adf061df46", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "Text(0.5, 1.0, '/dls/science/users/rpy65944/output/mapped_scan_519528_19.hdf5')" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ax1.set_title(filename)\n" ] }, { "cell_type": "code", "execution_count": 24, "id": "3c30966d-082c-4fdf-99c3-23689091f55e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": 37, "id": "79ef30f2-6cde-4ec8-afda-ec705da9a2ac", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "910cec0b-87c3-442c-acef-59fdc5689225", "metadata": {}, "outputs": [], "source": [] } ], "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.16" } }, "nbformat": 4, "nbformat_minor": 5 }