00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "py_commands.h"
00022 #include "VMDApp.h"
00023
00024 static const char categories_doc[] =
00025 "Get available color categories\n\n"
00026 "Returns:\n"
00027 " (list of str): Available color categories";
00028 static PyObject* py_categories(PyObject *self, PyObject *args) {
00029 PyObject *newlist = NULL;
00030 int i;
00031
00032 VMDApp *app;
00033 if (!(app = get_vmdapp()))
00034 return NULL;
00035
00036 int num = app->num_color_categories();
00037
00038 if (!(newlist = PyList_New(num)))
00039 goto failure;
00040
00041 for (i = 0; i < num; i++) {
00042 PyList_SET_ITEM(newlist, i, as_pystring(app->color_category(i)));
00043 if (PyErr_Occurred())
00044 goto failure;
00045 }
00046 return newlist;
00047
00048 failure:
00049 PyErr_SetString(PyExc_RuntimeError, "Problem listing color categories");
00050 Py_XDECREF(newlist);
00051 return NULL;
00052 }
00053
00054
00055 static const char get_colormap_doc[] =
00056 "Get name/color pairs in a given colormap category\n\n"
00057 "Args:\n"
00058 " name (str): Colormap to query\n\n"
00059 "Returns:\n"
00060 " (dict str->str): Name/color pairs in colormap";
00061 static PyObject* py_get_colormap(PyObject *self, PyObject *args,
00062 PyObject *kwargs) {
00063 const char *kwnames[] = {"name", NULL};
00064 PyObject *newdict = NULL;
00065 char *name;
00066 int i;
00067
00068 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:color.get_colormap",
00069 (char**) kwnames, &name))
00070 return NULL;
00071
00072 VMDApp *app;
00073 if (!(app = get_vmdapp()))
00074 return NULL;
00075
00076 int num_names = app->num_color_category_items(name);
00077 if (!num_names) {
00078 PyErr_Format(PyExc_ValueError, "Colormap '%s' does not exist", name);
00079 return NULL;
00080 }
00081
00082 if (!(newdict = PyDict_New()))
00083 goto failure;
00084
00085
00086 for (i = 0; i < num_names; i++) {
00087 const char *key = app->color_category_item(name, i);
00088 const char *value = app->color_mapping(name, key);
00089
00090
00091 if (PyDict_SetItemString(newdict, key, as_pystring(value)))
00092 goto failure;
00093 }
00094 return newdict;
00095
00096 failure:
00097 PyErr_Format(PyExc_RuntimeError, "Problem getting colormap '%s'", name);
00098 Py_XDECREF(newdict);
00099 return NULL;
00100 }
00101
00102
00103 static const char set_colormap_doc[] =
00104 "Update name/color pairs in given color category\n\n"
00105 "Args:\n"
00106 " name (str): Name of colormap to update\n"
00107 " pairs (dict str->str): Colors to update and new values. Keys must come\n"
00108 " from the keys listed by `get_colormap` for that color category. Not\n"
00109 " all keys need to be listed. Values must be legal color names";
00110 static PyObject* py_set_colormap(PyObject *self, PyObject *args,
00111 PyObject *kwargs) {
00112 const char *kwnames[] = {"name", "pairs", NULL};
00113 PyObject *newdict, *keys, *vals;
00114 PyObject *result = NULL;
00115 char *name;
00116
00117 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO!:color.set_colormap",
00118 (char**) kwnames, &name, &PyDict_Type,
00119 &newdict))
00120 return NULL;
00121
00122 VMDApp *app;
00123 if (!(app = get_vmdapp()))
00124 return NULL;
00125
00126 keys = PyDict_Keys(newdict);
00127 vals = PyDict_Values(newdict);
00128
00129 for (int i=0; i<PyList_Size(keys); i++) {
00130 const char *keyname = as_constcharptr(PyList_GetItem(keys, i));
00131 const char *valname = as_constcharptr(PyList_GetItem(vals, i));
00132
00133 if (!keyname || !valname || PyErr_Occurred()) {
00134 PyErr_SetString(PyExc_ValueError, "set_colormap dictionary invalid");
00135 goto cleanup;
00136 }
00137
00138 if (!app->color_change_name(name, keyname, valname)) {
00139 PyErr_SetString(PyExc_ValueError,
00140 "Invalid color category or item specified");
00141 goto cleanup;
00142 }
00143 }
00144 result = Py_None;
00145
00146
00147
00148
00149
00150 cleanup:
00151 Py_DECREF(keys);
00152 Py_DECREF(vals);
00153
00154 Py_XINCREF(result);
00155 return result;
00156 }
00157
00158
00159 static const char get_colors_doc[] =
00160 "Get all legal color names and corresponding RGB values.\n\n"
00161 "Returns:\n"
00162 " (dict str->3 tuple of float): Color name and RGB value. RGB values\n"
00163 " should be in the range 0 to 1.";
00164 static PyObject* py_get_colors(PyObject *self, PyObject *args) {
00165 PyObject *newdict = NULL, *newtuple = NULL;
00166 const char *name;
00167 float col[3];
00168 int i, j;
00169
00170 VMDApp *app;
00171 if (!(app = get_vmdapp()))
00172 return NULL;
00173
00174 if (!(newdict = PyDict_New()))
00175 goto failure;
00176
00177 for (i = 0; i < app->num_regular_colors(); i++) {
00178 name = app->color_name(i);
00179 if (!app->color_value(name, col, col+1, col+2))
00180 goto failure;
00181
00182 if (!(newtuple = PyTuple_New(3)))
00183 goto failure;
00184
00185 for (j = 0; j < 3; j++) {
00186 PyTuple_SET_ITEM(newtuple, j, PyFloat_FromDouble(col[j]));
00187 if (PyErr_Occurred())
00188 goto failure;
00189 }
00190
00191 PyDict_SetItemString(newdict, name, newtuple);
00192
00193 if (PyErr_Occurred())
00194 goto failure;
00195 }
00196 return newdict;
00197
00198 failure:
00199 PyErr_SetString(PyExc_RuntimeError, "Problem getting color names");
00200 Py_XDECREF(newdict);
00201 Py_XDECREF(newtuple);
00202 return NULL;
00203 }
00204
00205
00206 static const char get_colorlist_doc[] =
00207 "Get list of all defined colors by RGB value\n\n"
00208 "Returns:\n"
00209 " (list of 3-tuple): Currently defined RGB values";
00210 static PyObject* py_get_colorlist(PyObject *self, PyObject *args) {
00211 PyObject *newlist = NULL, *newtuple = NULL;
00212 int i, j, listlen;
00213 const char *name;
00214 float col[3];
00215
00216 VMDApp *app;
00217 if (!(app = get_vmdapp()))
00218 return NULL;
00219
00220 listlen = app->num_regular_colors();
00221 if (!(newlist = PyList_New(listlen)))
00222 goto failure;
00223
00224 for (i = 0; i < listlen; i++) {
00225 name = app->color_name(i);
00226 if (!app->color_value(name, col, col+1, col+2))
00227 goto failure;
00228
00229 if (!(newtuple = PyTuple_New(3)))
00230 goto failure;
00231
00232 for (j = 0; j < 3; j++) {
00233 PyTuple_SET_ITEM(newtuple, j, PyFloat_FromDouble(col[j]));
00234 if (PyErr_Occurred())
00235 goto failure;
00236 }
00237
00238 PyList_SET_ITEM(newlist, i, newtuple);
00239 if (PyErr_Occurred())
00240 goto failure;
00241 }
00242 return newlist;
00243
00244 failure:
00245 PyErr_SetString(PyExc_RuntimeError, "Problem getting color list");
00246 Py_XDECREF(newlist);
00247 Py_XDECREF(newtuple);
00248 return NULL;
00249 }
00250
00251
00252 static const char set_colors_doc[] =
00253 "Change the RGB values for named colors.\n\n"
00254 "Args:\n"
00255 " colors (dict str->3-tuple of floats): Name and RGB values for colors \n"
00256 " to update. RGB values should be in the range 0 to 1.";
00257 static PyObject* py_set_colors(PyObject *self, PyObject *args, PyObject *kwargs) {
00258 PyObject *newdict, *newtuple, *keys, *vals;
00259 const char *kwnames[] = {"colors", NULL};
00260 PyObject *retval = NULL;
00261 const char *keyname;
00262 float rgb[3];
00263
00264 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:color.set_colors",
00265 (char**) kwnames, &PyDict_Type, &newdict))
00266 return NULL;
00267
00268 VMDApp *app;
00269 if (!(app = get_vmdapp()))
00270 return NULL;
00271
00272 keys = PyDict_Keys(newdict);
00273 vals = PyDict_Values(newdict);
00274
00275 for (int i=0; i<PyList_Size(keys); i++) {
00276
00277 keyname = as_constcharptr(PyList_GetItem(keys, i));
00278 if (PyErr_Occurred())
00279 goto cleanup;
00280
00281
00282 if (app->color_index(keyname) < 0) {
00283 PyErr_Format(PyExc_ValueError, "Unknown color '%s'", keyname);
00284 goto cleanup;
00285 }
00286
00287
00288 newtuple = PyList_GetItem(vals, i);
00289 if (!PyTuple_Check(newtuple) || PyTuple_Size(newtuple) != 3) {
00290 PyErr_SetString(PyExc_ValueError,
00291 "color definition must be 3-tuple of floats");
00292 goto cleanup;
00293 }
00294
00295 for (int j=0; j<3; j++) {
00296 rgb[j] = (float)PyFloat_AsDouble(PyTuple_GET_ITEM(newtuple, j));
00297
00298 if (PyErr_Occurred()) {
00299 PyErr_SetString(PyExc_ValueError, "color definition must be floats");
00300 goto cleanup;
00301 }
00302 }
00303
00304
00305 app->color_change_rgb(keyname, rgb[0], rgb[1], rgb[2]);
00306 }
00307 retval = Py_None;
00308
00309
00310
00311
00312
00313 cleanup:
00314 Py_DECREF(keys);
00315 Py_DECREF(vals);
00316
00317 Py_XINCREF(retval);
00318 return retval;
00319 }
00320
00321
00322 static const char set_colorid_doc[] =
00323 "Set RGB value of a color at a given index\n\n"
00324 "Args:\n"
00325 " id (int): Color ID to change\n"
00326 " rgb (3-tuple of floats): New RGB value for color. Values should be in\n"
00327 " the range 0 to 1.";
00328 static PyObject* py_set_colorid(PyObject *self, PyObject *args,
00329 PyObject *kwargs) {
00330 const char *kwnames[] = {"id", "rgb", NULL};
00331 float rgb[3];
00332 int colorid;
00333
00334 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i(fff):color.set_colorid",
00335 (char**) kwnames, &colorid, &rgb[0], &rgb[1],
00336 &rgb[2]))
00337 return NULL;
00338
00339 VMDApp *app;
00340 if (!(app = get_vmdapp()))
00341 return NULL;
00342
00343 if (colorid >= app->num_regular_colors() || colorid < 0) {
00344 PyErr_Format(PyExc_ValueError, "color index '%d' out of range", colorid);
00345 return NULL;
00346 }
00347
00348 app->color_change_rgb(app->color_name(colorid), rgb[0], rgb[1], rgb[2]);
00349
00350 Py_INCREF(Py_None);
00351 return Py_None;
00352 }
00353
00354
00355 static const char scale_method_doc[] =
00356 "Get the current colorscale method\n\n"
00357 "Returns:\n"
00358 " (str) Current method name";
00359 static PyObject* py_scale_method(PyObject *self, PyObject *args) {
00360 const char *method;
00361
00362 VMDApp *app;
00363 if (!(app = get_vmdapp()))
00364 return NULL;
00365
00366 method = app->colorscale_method_name(app->colorscale_method_current());
00367
00368 return as_pystring(method);
00369 }
00370
00371
00372 static const char scale_methods_doc[] =
00373 "Get list of available colorscale methods\n\n"
00374 "Returns:\n"
00375 " (list of str) Available colorscale methods";
00376 static PyObject* py_scale_methods(PyObject *self, PyObject *args) {
00377 PyObject *newlist = NULL;
00378 int i;
00379
00380 VMDApp *app;
00381 if (!(app = get_vmdapp()))
00382 return NULL;
00383
00384 int num = app->num_colorscale_methods();
00385 if (!(newlist = PyList_New(num)))
00386 goto failure;
00387
00388 for (i = 0; i < num; i++) {
00389 PyList_SET_ITEM(newlist, i, as_pystring(app->colorscale_method_name(i)));
00390 if (PyErr_Occurred())
00391 goto failure;
00392 }
00393
00394 return newlist;
00395
00396 failure:
00397 PyErr_SetString(PyExc_RuntimeError, "Problem listing colorscales");
00398 Py_XDECREF(newlist);
00399 return NULL;
00400 }
00401
00402
00403 static const char scale_midpoint_doc[] =
00404 "Get current colorscale midpoint value\n\n"
00405 "Returns:\n"
00406 " (float) Current midpoint";
00407 static PyObject* py_scale_midpoint(PyObject *self, PyObject *args) {
00408 float mid, min, max;
00409 int rev, posterize;
00410
00411 VMDApp *app;
00412 if (!(app = get_vmdapp()))
00413 return NULL;
00414
00415
00416 app->colorscale_params(&mid, &min, &max, &rev, &posterize);
00417 return PyFloat_FromDouble(mid);
00418 }
00419
00420
00421 static const char scale_min_doc[] =
00422 "Get current colorscale minimum value\n\n"
00423 "Returns:\n"
00424 " (float): Current minimum";
00425 static PyObject* py_scale_min(PyObject *self, PyObject *args) {
00426 float mid, min, max;
00427 int rev, posterize;
00428
00429 VMDApp *app;
00430 if (!(app = get_vmdapp()))
00431 return NULL;
00432
00433
00434 app->colorscale_params(&mid, &min, &max, &rev, &posterize);
00435 return PyFloat_FromDouble(min);
00436 }
00437
00438
00439 static const char scale_max_doc[] =
00440 "Get current colorscale max.\n\n"
00441 "Returns:\n"
00442 " (float) Current maximum value";
00443 static PyObject* py_scale_max(PyObject *self, PyObject *args) {
00444 float mid, min, max;
00445 int rev, posterize;
00446
00447 VMDApp *app;
00448 if (!(app = get_vmdapp()))
00449 return NULL;
00450
00451
00452 app->colorscale_params(&mid, &min, &max, &rev, &posterize);
00453 return PyFloat_FromDouble(max);
00454 }
00455
00456
00457 static const char scale_reverse_doc[] =
00458 "Get current colorscale reversal flag.\n\n"
00459 "Returns:\n"
00460 " (int) Reversed color scale flag";
00461 static PyObject* py_scale_reverse(PyObject *self, PyObject *args) {
00462 float mid, min, max;
00463 int rev, posterize;
00464
00465 VMDApp *app;
00466 if (!(app = get_vmdapp()))
00467 return NULL;
00468
00469
00470 app->colorscale_params(&mid, &min, &max, &rev, &posterize);
00471 return as_pyint(rev);
00472 }
00473
00474
00475 static const char scale_posterize_doc[] =
00476 "Get current colorscale posterization count.\n\n"
00477 "Returns:\n"
00478 " (int) Color scale posterization count";
00479 static PyObject* py_scale_posterize(PyObject *self, PyObject *args) {
00480 float mid, min, max;
00481 int rev, posterize;
00482
00483 VMDApp *app;
00484 if (!(app = get_vmdapp()))
00485 return NULL;
00486
00487
00488 app->colorscale_params(&mid, &min, &max, &rev, &posterize);
00489 return as_pyint(posterize);
00490 }
00491
00492
00493 static const char set_scale_doc[] =
00494 "Set colorscale parameters. One or more parameters may be set with each "
00495 "function invocation.\n\n"
00496 "Args:\n"
00497 " method (str): Coloring method. Valid values are in scale_methods()\n"
00498 " midpoint (float): Midpoint of color scale\n"
00499 " min (float): Minimum value of color scale\n"
00500 " max (float): Maximum value of color scale\n"
00501 " reverse (int): Reverse color scale order\n";
00502 static PyObject* py_set_scale(PyObject *self, PyObject *args, PyObject *kwargs) {
00503 const char *kwnames[] = {"method", "midpoint", "min", "max", "reverse", "posterize", NULL};
00504 float midpoint = -1, min = -1, max = -1;
00505 int reverse = 0, posterize = 0;
00506 char *method = NULL;
00507
00508 VMDApp *app;
00509 if (!(app = get_vmdapp()))
00510 return NULL;
00511
00512 app->colorscale_params(&midpoint, &min, &max, &reverse, &posterize);
00513
00514 if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|zfffii:color.set_scale",
00515 (char**) kwnames, &method, &midpoint, &min,
00516 &max, &reverse, &posterize))
00517 return NULL;
00518
00519 if (method) {
00520 int ind = app->colorscale_method_index(method);
00521 if (ind < 0) {
00522 PyErr_SetString(PyExc_ValueError, "Invalid color scale method");
00523 return NULL;
00524 }
00525 app->colorscale_setmethod(ind);
00526 }
00527 app->colorscale_setparams(midpoint, min, max, reverse, posterize);
00528
00529 Py_INCREF(Py_None);
00530 return Py_None;
00531 }
00532
00533
00534 static PyMethodDef ColorMethods[] = {
00535 {"categories", (PyCFunction)py_categories, METH_NOARGS, categories_doc},
00536 {"get_colormap", (PyCFunction)py_get_colormap, METH_VARARGS | METH_KEYWORDS, get_colormap_doc},
00537 {"set_colormap", (PyCFunction)py_set_colormap, METH_VARARGS | METH_KEYWORDS, set_colormap_doc},
00538 {"get_colors", (PyCFunction)py_get_colors, METH_NOARGS, get_colors_doc},
00539 {"get_colorlist", (PyCFunction)py_get_colorlist, METH_NOARGS, get_colorlist_doc},
00540 {"set_colors", (PyCFunction)py_set_colors, METH_VARARGS | METH_KEYWORDS, set_colors_doc},
00541 {"set_colorid", (PyCFunction)py_set_colorid, METH_VARARGS | METH_KEYWORDS, set_colorid_doc},
00542 {"scale_method", (PyCFunction)py_scale_method, METH_NOARGS, scale_method_doc},
00543 {"scale_methods", (PyCFunction)py_scale_methods, METH_NOARGS, scale_methods_doc},
00544 {"scale_midpoint", (PyCFunction)py_scale_midpoint, METH_NOARGS, scale_midpoint_doc},
00545 {"scale_min", (PyCFunction)py_scale_min, METH_NOARGS, scale_min_doc},
00546 {"scale_max", (PyCFunction)py_scale_max, METH_NOARGS, scale_max_doc},
00547 {"scale_reverse", (PyCFunction)py_scale_reverse, METH_NOARGS, scale_reverse_doc},
00548 {"scale_posterize", (PyCFunction)py_scale_posterize, METH_NOARGS, scale_posterize_doc},
00549 {"set_scale", (PyCFunction)py_set_scale, METH_VARARGS | METH_KEYWORDS, set_scale_doc},
00550 {NULL, NULL}
00551 };
00552
00553
00554 static const char color_moddoc[] =
00555 "Contains methods for working with colors, including changing color "
00556 "definitions, color maps, or edit the color scale. All RGB and color scale "
00557 "values should be in the range 0 to 1";
00558
00559
00560 #if PY_MAJOR_VERSION >= 3
00561 struct PyModuleDef colordef = {
00562 PyModuleDef_HEAD_INIT,
00563 "color",
00564 color_moddoc,
00565 -1,
00566 ColorMethods,
00567 };
00568 #endif
00569
00570
00571 PyObject* initcolor() {
00572 #if PY_MAJOR_VERSION >= 3
00573 PyObject *m = PyModule_Create(&colordef);
00574 #else
00575 PyObject *m = Py_InitModule3("color", ColorMethods, color_moddoc);
00576 #endif
00577
00578 return m;
00579 }
00580
00581