Skip to content

Instantly share code, notes, and snippets.

@krassowski
Created July 23, 2022 22:10
Show Gist options
  • Save krassowski/5b370eeb626ae9bc84b38ca248b8066e to your computer and use it in GitHub Desktop.
Save krassowski/5b370eeb626ae9bc84b38ca248b8066e to your computer and use it in GitHub Desktop.
rpy2-complex-heatmap-repro
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"id": "2e5fc3f2-08fc-4ba4-b83e-7aae97c7c682",
"metadata": {},
"source": [
"# Demonstration"
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "df31a3e9-8817-49cd-87d6-ba05286b6720",
"metadata": {},
"outputs": [],
"source": [
"from heatmap_grammar.rpy2_helpers import rternalize_with_signature\n",
"from rpy2.rinterface import rternalize\n",
"from rpy2.robjects.packages import importr\n",
"\n",
"\n",
"base = importr('base')\n",
"complex_heatmap = importr('ComplexHeatmap')\n",
"\n",
"m = base.rbind(base.c(*range(10)), base.c(*range(10, 20)))"
]
},
{
"cell_type": "markdown",
"id": "e6a9f608-26f1-4367-8541-1522cc3ecca3",
"metadata": {},
"source": [
"## Works"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "6f2db710-f472-40da-aa43-0e4cf864bcd6",
"metadata": {},
"outputs": [],
"source": [
"@rternalize_with_signature\n",
"def draw_1(index, k, n):\n",
" print('success 1')\n",
" return 1"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "153eceee-04fe-4da6-938f-d8a58ee87800",
"metadata": {},
"outputs": [],
"source": [
"anno1 = complex_heatmap.AnnotationFunction(fun=draw_1)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "dc3d6512-ad8b-49dd-894a-f95fa11cd37a",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"success 1\n"
]
}
],
"source": [
"complex_heatmap.draw(\n",
" complex_heatmap.HeatmapAnnotation(df=m, foo=anno1)\n",
");"
]
},
{
"cell_type": "markdown",
"id": "636885c4-2a94-4110-a16d-d9809aa33a81",
"metadata": {},
"source": [
"## Doesn't work"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "e8321c10-b7c5-43c5-b65d-189ba3a1e165",
"metadata": {},
"outputs": [],
"source": [
"@rternalize\n",
"def draw_2(index, k, n):\n",
" print('success 2')\n",
" return 2"
]
},
{
"cell_type": "code",
"execution_count": 6,
"id": "ce72d657-64ef-4d40-8b2b-88308e1a2c24",
"metadata": {},
"outputs": [],
"source": [
"anno2 = complex_heatmap.AnnotationFunction(fun=draw_2)"
]
},
{
"cell_type": "code",
"execution_count": 7,
"id": "4bec535a-b597-4f88-94f1-9ed9f042f256",
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"R[write to console]: Error in object@fun(index, k, n) : '...' used in an incorrect context\n",
"\n",
"R[write to console]: In addition: \n",
"R[write to console]: Warning messages:\n",
"\n",
"R[write to console]: 1: `df` should be a data frame while not a matrix. Convert it to data\n",
"frame. \n",
"\n",
"R[write to console]: 2: `df` should be a data frame while not a matrix. Convert it to data\n",
"frame. \n",
"\n"
]
},
{
"ename": "RRuntimeError",
"evalue": "Error in object@fun(index, k, n) : '...' used in an incorrect context\n",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mRRuntimeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m/tmp/ipykernel_526955/293212760.py\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m complex_heatmap.draw(\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mcomplex_heatmap\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mHeatmapAnnotation\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mdf\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mm\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mfoo\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0manno2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m );\n",
"\u001b[0;32m~site-packages/rpy2/robjects/functions.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 200\u001b[0m \u001b[0mv\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mk\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 201\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mr_k\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 202\u001b[0;31m return (super(SignatureTranslatedFunction, self)\n\u001b[0m\u001b[1;32m 203\u001b[0m .__call__(*args, **kwargs))\n\u001b[1;32m 204\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~site-packages/rpy2/robjects/functions.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 123\u001b[0m \u001b[0;32melse\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 124\u001b[0m \u001b[0mnew_kwargs\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mk\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mpy2rpy\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mv\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 125\u001b[0;31m \u001b[0mres\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0msuper\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mFunction\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__call__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0mnew_args\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mnew_kwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 126\u001b[0m \u001b[0mres\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcv\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mrpy2py\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mres\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 127\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mres\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~site-packages/rpy2/rinterface_lib/conversion.py\u001b[0m in \u001b[0;36m_\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 43\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_cdata_res_to_rinterface\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mfunction\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 44\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m_\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 45\u001b[0;31m \u001b[0mcdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfunction\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0margs\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 46\u001b[0m \u001b[0;31m# TODO: test cdata is of the expected CType\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 47\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0m_cdata_to_rinterface\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m~site-packages/rpy2/rinterface.py\u001b[0m in \u001b[0;36m__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 811\u001b[0m )\n\u001b[1;32m 812\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0merror_occured\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m--> 813\u001b[0;31m \u001b[0;32mraise\u001b[0m \u001b[0membedded\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mRRuntimeError\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0m_rinterface\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m_geterrmessage\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 814\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0mres\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 815\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mRRuntimeError\u001b[0m: Error in object@fun(index, k, n) : '...' used in an incorrect context\n"
]
}
],
"source": [
"complex_heatmap.draw(\n",
" complex_heatmap.HeatmapAnnotation(df=m, foo=anno2)\n",
");"
]
},
{
"cell_type": "markdown",
"id": "41e151c5-ff02-48a2-a941-9fbc0a0ceb35",
"metadata": {},
"source": [
"# Attempts at narrowing it down"
]
},
{
"cell_type": "markdown",
"id": "7e2d4618-0794-4644-9cec-fcf0ab8646e3",
"metadata": {},
"source": [
"## 1. Calling from Python works"
]
},
{
"cell_type": "code",
"execution_count": 8,
"id": "297bce7c-71fa-4118-81b7-8433784c311b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"success 1\n"
]
},
{
"data": {
"text/plain": [
"<rpy2.rinterface.IntSexpVector object at 0x7f9ba88fd840> [RTYPES.INTSXP]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"draw_1(1, 1, 1)"
]
},
{
"cell_type": "code",
"execution_count": 9,
"id": "3b5e5e2b-f275-4b29-861a-7f751a483a9d",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"success 2\n"
]
},
{
"data": {
"text/plain": [
"<rpy2.rinterface.IntSexpVector object at 0x7f9bb47d0940> [RTYPES.INTSXP]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"draw_2(1, 1, 1)"
]
},
{
"cell_type": "markdown",
"id": "246490ec-060f-4dfe-89ea-caec29faaaf6",
"metadata": {},
"source": [
"## 2. Wrapping in env works"
]
},
{
"cell_type": "markdown",
"id": "184748de-917d-4f74-a417-41fad02bff75",
"metadata": {},
"source": [
"The call in [`object@fun(index, k, n)`](https://github.com/jokergoo/ComplexHeatmap/blob/31cf7167ddc6fc0ff27fd14067d65871254e8866/R/AnnotationFunction-class.R#L355) is accutally occuring on an environment-wrapped fun, see [this](https://github.com/jokergoo/ComplexHeatmap/blob/31cf7167ddc6fc0ff27fd14067d65871254e8866/R/AnnotationFunction-class.R#L405-L409):\n",
"\n",
"```R\n",
"\t\tobject2@var_env = new.env()\n",
"\t\tfor(var in names(object@var_env)) {\n",
"\t\t\tobject2@var_env[[var]] = object@var_env[[var]]\n",
"\t\t}\n",
"\t\tenvironment(object2@fun) = object2@var_env\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": 10,
"id": "ff43385c-4f1c-40cc-9b32-a0ab6e98f433",
"metadata": {},
"outputs": [],
"source": [
"env = base.new_env()\n",
"assign_environment = base._env['environment<-']\n",
"wrapped_draw_1 = assign_environment(draw_1, env)\n",
"wrapped_draw_2 = assign_environment(draw_2, env)"
]
},
{
"cell_type": "code",
"execution_count": 11,
"id": "d1b49903-f1ba-46ac-985d-a636a5376e87",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"success 1\n"
]
},
{
"data": {
"text/plain": [
"<rpy2.rinterface.IntSexpVector object at 0x7f9b9ef3cf40> [RTYPES.INTSXP]"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wrapped_draw_1(1, 1, 1)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"id": "bc42e017-22ea-4bf8-9621-4d3917022e23",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"success 2\n"
]
},
{
"data": {
"text/plain": [
"<rpy2.rinterface.IntSexpVector object at 0x7f9b9ef3d940> [RTYPES.INTSXP]"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"wrapped_draw_2(1, 1, 1)"
]
},
{
"cell_type": "markdown",
"id": "eaacd711-f499-4db4-a53f-e4fc88928fd7",
"metadata": {},
"source": [
"## 3. From R"
]
},
{
"cell_type": "code",
"execution_count": 13,
"id": "3aafd6cf-8f69-4ee8-9357-f8fed8edb0a9",
"metadata": {},
"outputs": [],
"source": [
"%load_ext rpy2.ipython"
]
},
{
"cell_type": "code",
"execution_count": 14,
"id": "e28fb917-37a4-4772-b286-8b39563ea08b",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"success 1\n",
"success 2\n",
"[1] 2\n"
]
}
],
"source": [
"%%R -i draw_1 -i draw_2\n",
"draw_1(1, 1, 1)\n",
"draw_2(1, 1, 1)"
]
},
{
"cell_type": "code",
"execution_count": 15,
"id": "b6ca8b80-d8ed-4670-8464-534ad5e0b186",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"function (index, k, n) \n",
"{\n",
" RPY2_ARGUMENTS <- base::list(\".Python\", <pointer: 0x7f9bdc717880>)\n",
" if (!base::missing(index)) {\n",
" RPY2_ARGUMENTS[[\"index\"]] <- index\n",
" }\n",
" if (!base::missing(k)) {\n",
" RPY2_ARGUMENTS[[\"k\"]] <- k\n",
" }\n",
" if (!base::missing(n)) {\n",
" RPY2_ARGUMENTS[[\"n\"]] <- n\n",
" }\n",
" do.call(.External, RPY2_ARGUMENTS)\n",
"}\n",
"<bytecode: 0x564831632d58>\n"
]
}
],
"source": [
"%%R\n",
"draw_1"
]
},
{
"cell_type": "code",
"execution_count": 16,
"id": "1da26543-80ed-4ba3-9580-66b52a5a43f6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"function (...) \n",
"{\n",
" .External(\".Python\", <pointer: 0x7f9ba8905a80>, ...)\n",
"}\n",
"<bytecode: 0x5648316c46b0>\n"
]
}
],
"source": [
"%%R\n",
"draw_2"
]
},
{
"cell_type": "markdown",
"id": "1155d3e0-2dff-425a-bc89-f2b0e59a74eb",
"metadata": {},
"source": [
"## 4. But the actual functions are different!"
]
},
{
"cell_type": "code",
"execution_count": 17,
"id": "0e4233fe-0da5-41ff-9a84-ac017f2cc565",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"function (index, k, n) \n",
"{\n",
" RPY2_ARGUMENTS <- base::list(\".Python\", <pointer: 0x7f9bdc717880>)\n",
" if (!base::missing(index)) {\n",
" RPY2_ARGUMENTS[[\"index\"]] <- index\n",
" }\n",
" if (!base::missing(k)) {\n",
" RPY2_ARGUMENTS[[\"k\"]] <- k\n",
" }\n",
" if (!base::missing(n)) {\n",
" RPY2_ARGUMENTS[[\"n\"]] <- n\n",
" }\n",
" do.call(.External, RPY2_ARGUMENTS)\n",
"}\n",
"<bytecode: 0x564831632d58>\n"
]
}
],
"source": [
"%%R -i anno1\n",
"anno1@fun"
]
},
{
"cell_type": "code",
"execution_count": 18,
"id": "bc476ff3-cd4f-4a34-a555-55e85e40f2da",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"function (index, k = 1, n = 1) \n",
"{\n",
" .External(\".Python\", <pointer: 0x7f9ba8905a80>, ...)\n",
"}\n"
]
}
],
"source": [
"%%R -i anno2\n",
"anno2@fun"
]
},
{
"cell_type": "markdown",
"id": "36079622-99f7-4e7d-bb06-bce5b0c54325",
"metadata": {},
"source": [
"Found it: https://github.com/jokergoo/ComplexHeatmap/blob/31cf7167ddc6fc0ff27fd14067d65871254e8866/R/AnnotationFunction-class.R#L220-L222:\n",
"\n",
"```R\n",
"if(length(as.list(formals(fun))) == 1) {\n",
"\tformals(fun) = alist(index = , k = 1, n = 1)\n",
"}\n",
"anno@fun = fun\n",
"```"
]
}
],
"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.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment