{ "cells": [ { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "Pushing data to the server\n", "**************************\n", "``pymaid`` does not only let you fetch data *from* a CATMAID server but you can also push data back to the server. Most things you can do with your browers (like placing nodes or adding annotations), you can als do programmatically with ``pymaid``.\n", "\n", "Notably you can:\n", "\n", "- add/remove (meta-)annotations\n", "- add/remove node tags\n", "- rename/reroot/delete existing neurons \n", "- upload new skeletons\n", "- upload/delete volumes \n", "- transfer neurons between CATMAID servers\n", "\n", "\n", "Another quick primer\n", "====================\n", "**First and foremost: be very, very carefull when pushing data to the CATMAID server!**\n", "\n", "When using ``pymaid`` to manipulate data on the server, the same retrictions (e.g. permission to edit somebody's nodes, annotations, etc.) apply as when you are using a web browser. However, making changes programmatically has the potential to accidentally mess things up at a much larger scale: consider, for example, accidentally renaming 100 neurons instead of 1 because you used the wrong annotation. \n", "\n", "Should something like this happen and you can't fix it yourself, the last resort is to ask a server admin to revert the accidental transactions. \n", "\n", "Second: pushing data programmatically requires you to have \"API write access\". If you get a permission error using below functions, you need to ask an admin to give you the required permissions.\n", "\n", "\n", "Annotations\n", "===========\n", "As with the tutorial on fetching data, we won't be able to cover all functions but rather give you a flavour of what's available. If you know what you want to do, head over to the :ref:`API reference ` and search for keywords to find the respective function - they almost always contain examples of how to use them!\n", "\n", "First, we need to set up the connection to the CATMAID server. This should already look familiar - if not check out the `quickstart tutorial ` first:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ " \n", " " ] }, "metadata": {}, "output_type": "display_data" }, { "name": "stderr", "output_type": "stream", "text": [ "INFO : Global CATMAID instance set. Caching is OFF. (pymaid)\n" ] } ], "source": [ "import pymaid\n", "\n", "# We will deactivate caching so that we always have the live data\n", "rm = pymaid.connect_catmaid(caching=False)" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "Let's start by adding an annotation to my favourite neuron (skeleton ID 16) using :func:`pymaid.add_annotations`:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "resp = pymaid.add_annotations(16, \"favourite neuron of Philipp\")" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "``resp`` is just the server's response which is usually just a confirmation that things have worked:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'message': 'success',\n", " 'annotations': [{'name': 'favourite neuron of Philipp',\n", " 'id': 16954141,\n", " 'entities': [17]}],\n", " 'new_annotations': [16954141],\n", " 'existing_annotations': []}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "resp" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "Looks like it worked - let's check by querying by annotation using :func:`pymaid.get_skids_by_annotation`" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[16]" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pymaid.get_skids_by_annotation('favourite neuron of Philipp')" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "It did! But now we want to get rid of it again using :func:`pymaid.remove_annotations`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO : Removed \"favourite neuron of Philipp\" from 1 entities (0 uses left) (pymaid)\n" ] }, { "data": { "text/plain": [ "{'deleted_annotations': {'16954141': {'targetIds': [17]}},\n", " 'deleted_links': [16954142],\n", " 'left_uses': {'16954141': 0}}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "resp = pymaid.remove_annotations(16, 'favourite neuron of Philipp')\n", "resp" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "That worked too!\n", "\n", "Importing neurons\n", "=================\n", "How about importing neurons? Nothing easier than that! First, you need to load your neuron via ``pymaid`` (e.g. from another CATMAID server) or ``navis`` (e.g. from an SWC file).\n", "\n", "Let's create a mock neuron consisting of only two nodes:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
typenavis.TreeNeuron
nameNone
n_nodes2
n_connectorsNone
n_branches0
n_leafsNone
cable_length17.3205
somaNone
units1 dimensionless
\n", "
" ], "text/plain": [ "type navis.TreeNeuron\n", "name None\n", "n_nodes 2\n", "n_connectors None\n", "n_branches 0\n", "n_leafs None\n", "cable_length 17.3205\n", "soma None\n", "units 1 dimensionless\n", "dtype: object" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import navis\n", "import pandas as pd\n", "\n", "# Create node table\n", "node_table = pd.DataFrame([[0, -1, 0, 0, 0, -1],\n", " [1, 0, 10, 10, 10, -1]],\n", " columns=['node_id', 'parent_id', 'x', 'y', 'z', 'radius'])\n", "# Turn node table into navis neuron\n", "n = navis.TreeNeuron(node_table)\n", "n" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "Upload the mock neuron via :func:`pymaid.upload_neuron`:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'neuron_id': 16954144,\n", " 'skeleton_id': 16954143,\n", " 'node_id_map': {0: 66611224, 1: 66611225}}" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Upload neuron to our CATMAID server\n", "resp = pymaid.upload_neuron(n)\n", "resp" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "As you can see from the response, our mock neuron was successfully uploaded and now has the skeleton ID ``16954143``." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "", "version_major": 2, "version_minor": 0 }, "text/plain": [ "HBox(children=(HTML(value='Make nrn'), FloatProgress(value=0.0, max=1.0), HTML(value='')))" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
typeCatmaidNeuron
nameneuron 16954144
id16954143
n_nodes2
n_connectors0
n_branches0
n_leafsNone
cable_length17.3205
somaNone
units1 nanometer
\n", "
" ], "text/plain": [ "type CatmaidNeuron\n", "name neuron 16954144\n", "id 16954143\n", "n_nodes 2\n", "n_connectors 0\n", "n_branches 0\n", "n_leafs None\n", "cable_length 17.3205\n", "soma None\n", "units 1 nanometer\n", "dtype: object" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pymaid.get_neuron(resp['skeleton_id'])" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "How about giving it a better name using :func:`pymaid.rename_neurons`? " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " Current name New name Skeleton ID\n", "0 neuron 16954144 Philipps mock neuron 16954143\n", "Please confirm above renaming [Y/N] y\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "INFO : All neurons successfully renamed. (pymaid)\n" ] }, { "data": { "text/plain": [ "{'16954143': 'Philipps mock neuron'}" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "_ = pymaid.rename_neurons(resp['skeleton_id'], 'Philipps mock neuron')\n", "pymaid.get_names(resp['skeleton_id'])" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "OK that also worked! Let's put that neuron out of its misery and delete it via :func:`pymaid.delete_neuron`:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ " \r" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Neuron \"Philipps mock neuron\" (#16954143) has 2 nodes (0 reviewed) and 1 annotation(s)\n", "Please confirm deletion [Y/N] y\n" ] }, { "data": { "text/plain": [ "{'skeleton_ids': [16954143],\n", " 'success': 'Deleted neuron #16954144 as well as its skeletons and annotations.'}" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pymaid.delete_neuron(resp['skeleton_id'])" ] }, { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ "Again, I cannot stress enough that you have to be careful using these functions! In particular if you have broad permissions to edit other people's tracings. If I had accidentally used the wrong skeleton ID here, I could have deleted a neuron somebody else spent days constructing." ] } ], "metadata": { "celltoolbar": "Raw Cell Format", "kernelspec": { "display_name": "Python 3", "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.7.5" } }, "nbformat": 4, "nbformat_minor": 2 }