Skip to content

Instantly share code, notes, and snippets.

@alexlib
Last active November 28, 2022 09:32
Show Gist options
  • Save alexlib/b9f7833694021aafc35126a1cb1fe884 to your computer and use it in GitHub Desktop.
Save alexlib/b9f7833694021aafc35126a1cb1fe884 to your computer and use it in GitHub Desktop.
Create colored vector field on image background using napari, based on https://napari.org/stable/gallery/add_vectors_color_by_angle.html
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"id": "b455d2a7",
"metadata": {},
"outputs": [],
"source": [
"# napari attempt"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d18965e5",
"metadata": {},
"outputs": [],
"source": [
"import napari\n",
"import numpy as np\n",
"from skimage import data\n",
"\n",
"# create vector data\n",
"n = 250\n",
"vectors = np.zeros((n, 2, 2), dtype=np.float32)\n",
"phi_space = np.linspace(0, 4 * np.pi, n)\n",
"radius_space = np.linspace(0, 100, n)\n",
"# assign x-y projection\n",
"vectors[:, 1, 0] = radius_space * np.cos(phi_space)\n",
"vectors[:, 1, 1] = radius_space * np.sin(phi_space)\n",
"# assign x-y position\n",
"vectors[:, 0] = vectors[:, 1] + 256\n",
"\n",
"# add the image\n",
"viewer = napari.view_image(data.camera(), name='photographer')\n",
"# add the vectors\n",
"vectors_layer = viewer.add_vectors(vectors, edge_width=3, edge_colormap = 'RdBu')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6c2b618d",
"metadata": {},
"outputs": [],
"source": [
"import napari\n",
"from skimage import data\n",
"import numpy as np\n",
"\n",
"\n",
"# create the viewer and window\n",
"viewer = napari.Viewer()\n",
"\n",
"layer = viewer.add_image(data.camera(), name='photographer')\n",
"\n",
"# sample vector coord-like data\n",
"n = 300\n",
"pos = np.zeros((n, 2, 2), dtype=np.float32)\n",
"phi_space = np.linspace(0, 4 * np.pi, n)\n",
"radius_space = np.linspace(0, 100, n)\n",
"\n",
"# assign x-y position\n",
"pos[:, 0, 0] = radius_space * np.cos(phi_space) + 300\n",
"pos[:, 0, 1] = radius_space * np.sin(phi_space) + 256\n",
"\n",
"# assign x-y projection\n",
"pos[:, 1, 0] = 2 * radius_space * np.cos(phi_space)\n",
"pos[:, 1, 1] = 2 * radius_space * np.sin(phi_space)\n",
"\n",
"# make the angle feature, range 0-2pi\n",
"angle = np.mod(phi_space, 2 * np.pi)\n",
"\n",
"# create a feature that is true for all angles > pi\n",
"pos_angle = angle > np.pi\n",
"\n",
"\n",
"\n",
"# create the features dictionary.\n",
"features = {\n",
" 'angle': angle,\n",
" 'pos_angle': pos_angle,\n",
" 'magnitude': radius_space,\n",
"}\n",
"\n",
"# add the vectors\n",
"layer = viewer.add_vectors(\n",
" pos,\n",
" edge_width=3,\n",
" features=features,\n",
" edge_color='magnitude',\n",
" edge_colormap='husl',\n",
" name='vectors'\n",
")\n",
"\n",
"# set the edge color mode to colormap\n",
"layer.edge_color_mode = 'colormap'"
]
},
{
"cell_type": "code",
"execution_count": 45,
"id": "cd0a0c98",
"metadata": {},
"outputs": [],
"source": [
"viewer = napari.Viewer()\n",
"layer = viewer.add_image(a, name='a')\n",
"\n",
"# viewer.add_image(b, name ='b')\n",
"\n",
"s = 10\n",
"\n",
"vectors = np.zeros((len(u.flatten()), 2, 2), dtype=np.float32)\n",
"vectors[:,0,1] = x.flatten()\n",
"vectors[:,0,0] = y.flatten()\n",
"\n",
"\n",
"u[np.isnan(u)] = 0\n",
"v[np.isnan(v)] = 0\n",
"\n",
"vectors[:,1,1] = s*u.flatten()\n",
"vectors[:,1,0] = s*v.flatten()\n",
"\n",
"magnitude = np.sqrt(u.flatten()**2 + v.flatten()**2)\n",
"angle = np.arctan2(u.flatten(),v.flatten())\n",
"\n",
"# create the features dictionary.\n",
"features = {\n",
" 'angle': angle,\n",
" # 'pos_angle': pos_angle,\n",
" 'magnitude': magnitude,\n",
"}\n",
"\n",
"\n",
"# add the vectors\n",
"layer = viewer.add_vectors(\n",
" vectors,\n",
" edge_width=3,\n",
" features=features,\n",
" edge_color='magnitude',\n",
" edge_colormap='husl',\n",
" name='vectors'\n",
")\n",
"\n",
"# set the edge color mode to colormap\n",
"layer.edge_color_mode = 'colormap'\n"
]
},
{
"cell_type": "code",
"execution_count": 53,
"id": "16d3ba68",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/home/user/.edm/envs/napari/lib/python3.8/site-packages/ipykernel/eventloops.py:107: UserWarning: constrained_layout not applied because axes sizes collapsed to zero. Try making figure larger or axes decorations smaller.\n",
" app.exec_()\n"
]
}
],
"source": [
"\"\"\"\n",
"Viewing mass spec imaging data in napari.\n",
"\"\"\"\n",
"\n",
"import numpy as np\n",
"import napari\n",
"import matplotlib.pyplot as plt\n",
"from matplotlib.backends.backend_qt5agg import FigureCanvas\n",
"from matplotlib.figure import Figure\n",
"\n",
"\n",
"# # load the data\n",
"# cube = np.load('datacube.npy')\n",
"# peaks = np.load('peaklist.npy')\n",
"# mz = peaks[0]\n",
"# thresh = np.load('hsr_thresholds.npy')\n",
"# cubet = np.transpose(cube, (2, 0, 1))\n",
"# cubet_norm = cubet / thresh[:, np.newaxis, np.newaxis]\n",
"\n",
"\n",
"# # create the viewer\n",
"# viewer = napari.view_image(cubet_norm)\n",
"\n",
"\n",
"\n",
"\n",
"viewer = napari.Viewer()\n",
"layer = viewer.add_image(a, name='a')\n",
"\n",
"# viewer.add_image(b, name ='b')\n",
"\n",
"s = 10\n",
"\n",
"vectors = np.zeros((len(u.flatten()), 2, 2), dtype=np.float32)\n",
"vectors[:,0,1] = x.flatten()\n",
"vectors[:,0,0] = y.flatten()\n",
"\n",
"\n",
"u[np.isnan(u)] = 0\n",
"v[np.isnan(v)] = 0\n",
"\n",
"vectors[:,1,1] = s*u.flatten()\n",
"vectors[:,1,0] = s*v.flatten()\n",
"\n",
"magnitude = np.sqrt(u.flatten()**2 + v.flatten()**2)\n",
"angle = np.arctan2(u.flatten(),v.flatten())\n",
"\n",
"# create the features dictionary.\n",
"features = {\n",
" 'angle': angle,\n",
" # 'pos_angle': pos_angle,\n",
" 'magnitude': magnitude,\n",
"}\n",
"\n",
"\n",
"# add the vectors\n",
"layer = viewer.add_vectors(\n",
" vectors,\n",
" edge_width=3,\n",
" features=features,\n",
" edge_color='magnitude',\n",
" edge_colormap='bwr',\n",
" name='vectors'\n",
")\n",
"\n",
"# set the edge color mode to colormap\n",
"layer.edge_color_mode = 'colormap'\n",
"\n",
"with plt.style.context('dark_background'):\n",
"\n",
" colorbars_widget = FigureCanvas(Figure(constrained_layout=True))\n",
" fig = colorbars_widget.figure\n",
"\n",
" gs = fig.add_gridspec(1, 1)\n",
" ax1 = fig.add_subplot(gs[0, 0])\n",
" # ax2 = fig.add_subplot(gs[1, 0])\n",
" # ax3 = fig.add_subplot(gs[2, 0])\n",
"\n",
" cmap1 = mpl.cm.bwr\n",
" mappable1 = mpl.cm.ScalarMappable(cmap=cmap1)\n",
" colorbar1 = fig.colorbar(mappable1, cax=ax1, orientation='vertical')\n",
" colorbar1.set_label('husl')\n",
"\n",
"# cmap2 = mpl.cm.gist_rainbow\n",
"# mappable2 = mpl.cm.ScalarMappable(cmap=cmap2)\n",
"# colorbar2 = fig.colorbar(mappable2, cax=ax2, orientation='horizontal')\n",
"# colorbar2.set_label('gist_rainbow')\n",
"\n",
"# cmap3 = mpl.cm.viridis\n",
"# mappable3 = mpl.cm.ScalarMappable(cmap=cmap3)\n",
"# colorbar3 = fig.colorbar(mappable3, cax=ax3, orientation='horizontal')\n",
"# colorbar3.set_label('viridis')\n",
"\n",
"\n",
"# layer = viewer.add_surface((brain_vertices, brain_faces, timeseries))\n",
"# layer.colormap = cmap1.name\n",
"\n",
"viewer.dims.events.connect(axis_changed)\n",
"\n",
"colorbars_widget.setFixedWidth(30)\n",
"# colorbars_widget.setFixedHeight(200)\n",
"\n",
"colorbars_dock = viewer.window.add_dock_widget(colorbars_widget, name='Colorbars', area = 'right')\n",
"\n",
"# # create a function to update the plot\n",
"# def update_plot(step_event):\n",
"# steps = step_event.value\n",
"# slice_num = steps[0]\n",
"# x = mz[slice_num]\n",
"# current_pos = position_line.get_data()[0][0]\n",
"# if x == current_pos:\n",
"# return\n",
"# position_line.set_data([x, x], [0, 1])\n",
"# coord_str, mz_str = title.get_text().split(';')\n",
"# title.set_text(coord_str + '; ' + f'm/z={x:.3f}')\n",
"# mz_canvas.draw_idle()\n",
"\n",
"\n",
"# # connect the function to the dims axis\n",
"# viewer.dims.events.current_step.connect(update_plot)\n",
"\n",
"# # grab the image layer\n",
"# layer = viewer.layers[0]\n",
"\n",
"\n",
"# # add a click callback to the layer to update the spectrum being viewed\n",
"# @layer.mouse_drag_callbacks.append\n",
"# def update_intensity(layer, event):\n",
"# xs, ys = intensity_line.get_data()\n",
"# coords_full = tuple(np.round(layer.coordinates).astype(int))\n",
"# if all(coords_full[i] in range(cubet.shape[i])\n",
"# for i in range(cubet.ndim)):\n",
"# coords = coords_full[1:] # rows, columns\n",
"# new_ys = cube[coords]\n",
"# intensity_line.set_data(xs, new_ys)\n",
"# coord_str, mz_str = title.get_text().split(';')\n",
"# title.set_text(str(coords) + '; ' + mz_str)\n",
"# mz_canvas.draw_idle()\n",
"\n",
"# napari.run()"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f70580c9",
"metadata": {},
"outputs": [],
"source": [
"# from matplotlib.backends.backend_qt5agg import FigureCanvas\n",
"# from matplotlib.colors import ListedColormap, LinearSegmentedColormap\n",
"# from matplotlib.figure import Figure\n",
"# import matplotlib.pyplot as plt\n",
"# import napari\n",
"\n",
"# %gui qt\n",
"\n",
"# def get_colour(layer,track_IDs):\n",
" \n",
"# colors = np.ones((max(track_IDs)+1,4))\n",
" \n",
"# for cell in track_IDs:\n",
"# colors[cell] = layer.get_color(cell)\n",
"# colors[0] = [0,0,0,1]\n",
"# newcmp = ListedColormap(colors)\n",
" \n",
"# return newcmp\n",
"\n",
"# def update_time(event):\n",
"# static_ax.ti_vline.set_xdata([event.value,event.value])\n",
"# static_ax.figure.canvas.draw()\n",
"\n",
"# # data variables\n",
"# # tracks_img = fov.tracks_curated.mod\n",
"# # tracks_length = fov.tracks_curated.tracks_length\n",
"# # cellIDs = fov.tracks_curated.cellIDs\n",
"\n",
"# viewer = napari.view_labels(tracks_img,name='Curation',opacity=1)\n",
"\n",
"# #generate colourmap\n",
"# newcmp = get_colour(viewer.layers['Curation'],cellIDs)\n",
"\n",
"# cellIDs_text = [str(int(integer)) for integer in cellIDs]\n",
"\n",
"# with plt.style.context('dark_background'):\n",
"# plt.rcParams['figure.dpi'] = 110\n",
"# mpl_widget = FigureCanvas(Figure(figsize=(8.5, 13)))\n",
"# static_ax = mpl_widget.figure.subplots()\n",
"# static_ax.imshow(tracks_length,cmap=newcmp,aspect='auto')\n",
"# static_ax.set(xlim=(0, 120), ylim=len(cellIDs))\n",
"# static_ax.ti_vline = static_ax.axvline(0,0,len(cellIDs)+0.5,color='yellow',linewidth=4)\n",
"# static_ax.set_xticks(np.arange(0, 121, 6))\n",
"# static_ax.set_yticks(np.arange(0, len(cellIDs)+1, 1))\n",
"# static_ax.set_yticklabels(cellIDs_text)\n",
"# static_ax.tick_params(labelright=True, right=True,labeltop=True,top=True,colors='white')\n",
"# mpl_widget.figure.tight_layout()\n",
" \n",
"# mywidget = viewer.window.add_dock_widget(mpl_widget,name='tracks_length',area='right',shortcut='t')\n",
"\n",
"# viewer.dims.events.axis.connect(update_time)"
]
},
{
"cell_type": "code",
"execution_count": 59,
"id": "c0d03b01",
"metadata": {},
"outputs": [
{
"ename": "NameError",
"evalue": "name 'flux_from_day' is not defined",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)",
"Input \u001b[0;32mIn [59]\u001b[0m, in \u001b[0;36m<cell line: 58>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 54\u001b[0m update \u001b[38;5;241m=\u001b[39m partial(update_artists, artists\u001b[38;5;241m=\u001b[39martists,\n\u001b[1;32m 55\u001b[0m lambdas\u001b[38;5;241m=\u001b[39mnp\u001b[38;5;241m.\u001b[39marange(\u001b[38;5;241m3298\u001b[39m, \u001b[38;5;241m9700\u001b[39m, \u001b[38;5;241m2.5\u001b[39m))\n\u001b[1;32m 57\u001b[0m \u001b[38;5;66;03m# 4. Generate the animation\u001b[39;00m\n\u001b[1;32m 58\u001b[0m anim \u001b[38;5;241m=\u001b[39m animation\u001b[38;5;241m.\u001b[39mFuncAnimation(\n\u001b[1;32m 59\u001b[0m fig\u001b[38;5;241m=\u001b[39mfig,\n\u001b[1;32m 60\u001b[0m func\u001b[38;5;241m=\u001b[39mupdate,\n\u001b[1;32m 61\u001b[0m frames\u001b[38;5;241m=\u001b[39mstep,\n\u001b[1;32m 62\u001b[0m init_func\u001b[38;5;241m=\u001b[39minit,\n\u001b[0;32m---> 63\u001b[0m save_count\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mlen\u001b[39m(\u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[43mstep\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m),\n\u001b[1;32m 64\u001b[0m repeat_delay\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m5000\u001b[39m,\n\u001b[1;32m 65\u001b[0m )\n\u001b[1;32m 67\u001b[0m \u001b[38;5;66;03m# 5. Save the animation\u001b[39;00m\n\u001b[1;32m 68\u001b[0m anim\u001b[38;5;241m.\u001b[39msave(\n\u001b[1;32m 69\u001b[0m filename\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m/tmp/sn2011fe_spectral_time_series.mp4\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m 70\u001b[0m fps\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m24\u001b[39m,\n\u001b[1;32m 71\u001b[0m extra_args\u001b[38;5;241m=\u001b[39m[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124m-vcodec\u001b[39m\u001b[38;5;124m'\u001b[39m, \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mlibx264\u001b[39m\u001b[38;5;124m'\u001b[39m],\n\u001b[1;32m 72\u001b[0m dpi\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m300\u001b[39m,\n\u001b[1;32m 73\u001b[0m )\n",
"Input \u001b[0;32mIn [59]\u001b[0m, in \u001b[0;36mframe_iter\u001b[0;34m(from_day, until_day)\u001b[0m\n\u001b[1;32m 24\u001b[0m \u001b[38;5;124;03m\"\"\"Iterate through the days of the spectra and return\u001b[39;00m\n\u001b[1;32m 25\u001b[0m \u001b[38;5;124;03mflux and day number.\u001b[39;00m\n\u001b[1;32m 26\u001b[0m \u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[1;32m 27\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m day \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mrange\u001b[39m(from_day, until_day):\n\u001b[0;32m---> 28\u001b[0m flux \u001b[38;5;241m=\u001b[39m \u001b[43mflux_from_day\u001b[49m(day)\n\u001b[1;32m 29\u001b[0m \u001b[38;5;66;03m# Yield events so the function can be looped over\u001b[39;00m\n\u001b[1;32m 30\u001b[0m \u001b[38;5;28;01myield\u001b[39;00m (flux, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDay: \u001b[39m\u001b[38;5;132;01m{day}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(day))\n",
"\u001b[0;31mNameError\u001b[0m: name 'flux_from_day' is not defined"
]
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 864x504 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"from collections import namedtuple\n",
"from functools import partial\n",
"from matplotlib import animation\n",
"\n",
"def init_fig(fig, ax, artists):\n",
" \"\"\"Initialize the figure, used to draw the first\n",
" frame for the animation.\n",
" \"\"\"\n",
" # Set the axis and plot titles\n",
" ax.set_title(\"Supernova 2011fe Spectrum\", fontsize=22)\n",
" ax.set_xlabel(\"Wavelength [Å]\", fontsize=20)\n",
" FLUX_LABEL = \"Flux [erg s$^{-1}$ cm$^{-2}$ Å$^{-1}$]\"\n",
" ax.set_ylabel(FLUX_LABEL, fontsize=20)\n",
"\n",
" # Set the axis range\n",
" plt.xlim(3000, 10000)\n",
" plt.ylim(0, 1.25e-12)\n",
"\n",
" # Must return the list of artists, but we use a pass\n",
" # through so that they aren't created multiple times\n",
" return artists\n",
"\n",
"def frame_iter(from_day, until_day):\n",
" \"\"\"Iterate through the days of the spectra and return\n",
" flux and day number.\n",
" \"\"\"\n",
" for day in range(from_day, until_day):\n",
" flux = flux_from_day(day)\n",
" # Yield events so the function can be looped over\n",
" yield (flux, \"Day: {day}\".format(day))\n",
"\n",
"def update_artists(frames, artists, lambdas):\n",
" \"\"\"Update artists with data from each frame.\"\"\"\n",
" flux, day = frames\n",
"\n",
" artists.flux_line.set_data(lambdas, flux)\n",
" artists.day.set_text(day)\n",
"\n",
" \n",
"\n",
"# 1. Create the plot\n",
"fig, ax = plt.subplots(figsize=(12, 7))\n",
"\n",
"# 2. Initialize the artists with empty data\n",
"Artists = namedtuple(\"Artists\", (\"flux_line\", \"day\"))\n",
"artists = Artists(\n",
" plt.plot([], [], animated=True)[0],\n",
" ax.text(x=0.987, y=0.955, s=\"\"),\n",
")\n",
"\n",
"# 3. Apply the three plotting functions written above\n",
"init = partial(init_fig, fig=fig, ax=ax, artists=artists)\n",
"step = partial(frame_iter, from_day=-15, until_day=25)\n",
"update = partial(update_artists, artists=artists,\n",
" lambdas=np.arange(3298, 9700, 2.5))\n",
"\n",
"# 4. Generate the animation\n",
"anim = animation.FuncAnimation(\n",
" fig=fig,\n",
" func=update,\n",
" frames=step,\n",
" init_func=init,\n",
" save_count=len(list(step())),\n",
" repeat_delay=5000,\n",
")\n",
"\n",
"# 5. Save the animation\n",
"anim.save(\n",
" filename='/tmp/sn2011fe_spectral_time_series.mp4',\n",
" fps=24,\n",
" extra_args=['-vcodec', 'libx264'],\n",
" dpi=300,\n",
")\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "9b316278",
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"id": "68b650a5",
"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.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment