├── .gitignore ├── PyXspec-TheExtendedTutorial.ipynb ├── PyXspecUserGuide-QuickTutorial.ipynb ├── README.md └── data ├── spec.pha ├── spec.rmf ├── spec2.pha ├── spec2_bkg.pha ├── spec3.pha ├── spec3.rmf ├── spec3_bkg.pha ├── spec_bkg.pha ├── spec_sim.pha └── spec_sim_bkg.pha /.gitignore: -------------------------------------------------------------------------------- 1 | # MFC stuff 2 | *.orig 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | 56 | # Sphinx documentation 57 | docs/_build/ 58 | 59 | # PyBuilder 60 | target/ 61 | 62 | *.xml 63 | 64 | *.xml 65 | 66 | *.ipynb 67 | 68 | deprecated/cif_summary.py 69 | 70 | deprecated/cif2html.py 71 | 72 | deprecated/tmp/caldb.indx20160609 73 | 74 | doc/_build/.buildinfo 75 | 76 | *.doctree 77 | 78 | *.doctree 79 | -------------------------------------------------------------------------------- /PyXspec-TheExtendedTutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 142, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "#\n", 12 | "# some standard python imports\n", 13 | "#\n", 14 | "\n", 15 | "%matplotlib inline\n", 16 | "\n", 17 | "import matplotlib\n", 18 | "import numpy as np\n", 19 | "import matplotlib.pyplot as plt\n", 20 | "\n", 21 | "import xspec # this imports the xspec package \n", 22 | "\n", 23 | "xspec.Xset.allowPrompting = False # keeps pyxspec from hanging, waiting for a response to a prompt\n" 24 | ] 25 | }, 26 | { 27 | "cell_type": "markdown", 28 | "metadata": {}, 29 | "source": [ 30 | "----\n", 31 | "\n", 32 | "## Data\n", 33 | "\n", 34 | "### Background, Response, and Arf\n", 35 | "\n", 36 | "When a Spectrum object is created from a spectral data file, PyXspec also reads the file's BACKFILE, RESPFILE, and ANCRFILE keywords and will load the corresponding background, response, and arf files. The spectrum's Background and Response objects are then available as attributes of the Spectrum class, while the arf file name becomes an attribute of the Response class. Note that you never create Background and Response objects directly. They are accessible only through the Spectrum class attributes.\n", 37 | "\n" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 143, 43 | "metadata": {}, 44 | "outputs": [], 45 | "source": [ 46 | "s1 = xspec.Spectrum(\"data/spec\")\n", 47 | "try:\n", 48 | " b1 = s1.background\n", 49 | "except Exception:\n", 50 | " b1 = ''\n", 51 | "b1='' # spectrum has no background\n", 52 | "try: \n", 53 | " r1 = s1.response\n", 54 | "except Exception:\n", 55 | " r1='' # no response defined\n", 56 | "try:\n", 57 | " arfFileName = r1.arf\n", 58 | "except Exception:\n", 59 | " arfFileName = '' # no arf defined either" 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "Use these attributes if you need to add or change a response, arf or background file, for example:" 67 | ] 68 | }, 69 | { 70 | "cell_type": "code", 71 | "execution_count": 144, 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "name": "stdout", 76 | "output_type": "stream", 77 | "text": [ 78 | "New background = data/spec_bkg.pha\n", 79 | "New Response = data/spec.rmf\n" 80 | ] 81 | } 82 | ], 83 | "source": [ 84 | "# Add a background files:\n", 85 | "\n", 86 | "if not b1:\n", 87 | " s1.background = \"data/spec_bkg.pha\"\n", 88 | " print \"New background = {0}\".format(s1.background.fileName)\n", 89 | "\n", 90 | "# Add a response\n", 91 | "if not r1:\n", 92 | " s1.response = \"data/spec.rmf\"\n", 93 | " print \"New Response = {0}\".format(s1.response.rmf)\n", 94 | "\n" 95 | ] 96 | }, 97 | { 98 | "cell_type": "code", 99 | "execution_count": 19, 100 | "metadata": {}, 101 | "outputs": [ 102 | { 103 | "data": { 104 | "text/plain": [ 105 | "'data/spec.rmf'" 106 | ] 107 | }, 108 | "execution_count": 19, 109 | "metadata": {}, 110 | "output_type": "execute_result" 111 | } 112 | ], 113 | "source": [ 114 | "s1.response.rmf" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "#### To add an ARF:\n", 122 | "\n", 123 | "`s1.response.arf = \"newArf.pha\"`\n", 124 | "\n", 125 | "#### To remove backgrounds, etc:\n", 126 | "\n", 127 | "```\n", 128 | "s1.response = None\n", 129 | "s1.background = \"\"\n", 130 | "```\n", 131 | "\n", 132 | "Background and Spectrum files store their original file names in their `fileName` attribute. This means that while you SET the Spectrum.background object by assigning it a file name (as shown above), to GET the file name you must access its fileName attribute, as shown above.\n", 133 | "\n", 134 | "Response stores its RMF and optional ARF file names in its `rmf` and `arf` attributes respectively.\n", 135 | "\n", 136 | "```\n", 137 | "rmfFileName = r1.rmf\n", 138 | "arfFileName = r1.arf\n", 139 | "```\n", 140 | "\n", 141 | "Background objects have some of the same attributes as Spectrum objects, such as areaScale, exposure, energies, and values. The Spectrum object's values array (actually a tuple) does NOT include contributions from the background. Those are stored separately in the associated Background object. *Please see the Classes reference guide or call the Python help function for the full class descriptions.*\n", 142 | "\n", 143 | "The Spectrum class also provides a multiresponse array attribute for assigning multiple detectors (or sources) to a spectrum. The standard 0-based Python array indices corresponding to the 1-based XSPEC source numbers:\n", 144 | "\n", 145 | "```\n", 146 | "# Set a response for source 2\n", 147 | "s1.multiresponse[1] = \"resp2.rsp\"\n", 148 | "# Get the response object for source 2\n", 149 | "r2 = s1.multiresponse[1]\n", 150 | "# Remove the response from source 2\n", 151 | "s1.multiresponse[1] = None\n", 152 | "# This is the same as doing s1.response = \"resp1.rsp\"\n", 153 | "s1.multiresponse[0] = \"resp1.rsp\"\n", 154 | "\n", 155 | "```\n", 156 | "\n", 157 | "The rule is: when doing single-source analysis (typical of most XSPEC sessions) use the response attribute, otherwise use the multiresponse array.\n", 158 | "\n", 159 | "----\n", 160 | "### Ignore/Notice\n", 161 | "\n", 162 | "To ignore channels for a SINGLE spectrum, call the Spectrum object's ignore method passing a string following the same syntax as for Standard XSPEC's ignore command:\n", 163 | "\n", 164 | "\n" 165 | ] 166 | }, 167 | { 168 | "cell_type": "code", 169 | "execution_count": 43, 170 | "metadata": {}, 171 | "outputs": [ 172 | { 173 | "name": "stdout", 174 | "output_type": "stream", 175 | "text": [ 176 | "Noticed Channels:\n", 177 | "6 7 8 9 10 11 12 13 14 15 16 17 18 19 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49\n" 178 | ] 179 | } 180 | ], 181 | "source": [ 182 | "s1.ignore(\"20-30\") # ignore channels 20 to 30 and all channels above 50 keV\n", 183 | "s1.ignore(\"**-5\")\n", 184 | "print \"Noticed Channels:\"\n", 185 | "for no in s1.noticed:\n", 186 | " print no,\n" 187 | ] 188 | }, 189 | { 190 | "cell_type": "markdown", 191 | "metadata": {}, 192 | "source": [ 193 | "Similarly, to notice channels in a single spectrum:" 194 | ] 195 | }, 196 | { 197 | "cell_type": "code", 198 | "execution_count": 44, 199 | "metadata": {}, 200 | "outputs": [ 201 | { 202 | "name": "stdout", 203 | "output_type": "stream", 204 | "text": [ 205 | "Noticed Channels:\n", 206 | "6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49\n" 207 | ] 208 | } 209 | ], 210 | "source": [ 211 | "s1.notice(\"20-25\")\n", 212 | "# s1.notice(\"all\")\n", 213 | "print \"Noticed Channels:\"\n", 214 | "for no in s1.noticed:\n", 215 | " print no,\n" 216 | ] 217 | }, 218 | { 219 | "cell_type": "markdown", 220 | "metadata": {}, 221 | "source": [ 222 | "As with Standard XSPEC, if the x-axis plot units are set to energies or wavelengths, ignore and notice will accept floating-point input assumed to be in those same units:\n", 223 | "\n", 224 | "```\n", 225 | "# Ignore channel bins corresponding to 15.0 to 20.0 nm wavelengths:\n", 226 | "Plot.xAxis = \"nm\"\n", 227 | "s1.ignore(\"15.-20.\")\n", 228 | "```\n", 229 | "\n", 230 | "The currently noticed channel ranges are displayed for each spectrum in the AllData.show() output. You can also get a list of the individual noticed channel numbers from Spectrum's noticed attribute, as shown above.\n", 231 | "\n", 232 | "\n", 233 | "To apply ignore and notice commands to ALL loaded spectra, call the methods from the global AllData object. To apply to a subset of loaded spectra, add a range specifier to the left of the colon:\n", 234 | "\n", 235 | "```\n", 236 | "# These apply to all loaded spectra\n", 237 | "AllData.ignore(\"100-120, 150-200\")\n", 238 | "AllData.notice(\"all\")\n", 239 | "AllData.ignore(\"bad\")\n", 240 | "# These apply to a subset of loaded spectra\n", 241 | "AllData.ignore(\"1-3: 60-65\")\n", 242 | "AllData.notice(\"2-**:50-60\")\n", 243 | "```\n", 244 | "\n" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "----\n", 252 | "\n", 253 | "### Models\n", 254 | "\n", 255 | "#### Model With Multiple Data Groups\n", 256 | "\n", 257 | "When a model is defined and spectra are assigned to multiple data groups, PyXspec will generate a Model object copy for each data group (assuming the spectra also have responses attached). So if:\n" 258 | ] 259 | }, 260 | { 261 | "cell_type": "code", 262 | "execution_count": 67, 263 | "metadata": {}, 264 | "outputs": [], 265 | "source": [ 266 | "#\n", 267 | "# Load 2 spectra, spec.pha and spec_sim.pha, into 2 separate data groups\n", 268 | "#\n", 269 | "xspec.AllData.clear()\n", 270 | "xspec.AllData += \"data/spec.pha\" # read spectrum into first data group\n", 271 | "# Explicitly specify the response if necessary\n", 272 | "xspec.AllData(1).response = \"data/spec.rmf\" # this response include the effective area (ARF) information\n", 273 | "\n", 274 | "xspec.AllData(\"2:2 data/spec_sim.pha\") # read spectrum into data group 2\n", 275 | "# Explicitly specify the response, if necessary\n", 276 | "xspec.AllData(2).response = \"data/spec3.rmf\" # response includes the ARF already\n", 277 | "\n", 278 | "m1 = xspec.Model(\"tbabs*pow\")\n", 279 | "m2 = xspec.AllModels(2)\n", 280 | "\n" 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "then there are 2 Model objects for the model definition `tbabs*pow`. The variable `m1` is set to the object belonging to data group 1, and `m2` the object for data group 2, and `m1` and `m2` will each have the same set of Component and Parameter objects.\n" 288 | ] 289 | }, 290 | { 291 | "cell_type": "markdown", 292 | "metadata": {}, 293 | "source": [ 294 | "Parameters can be accessed directly by index from the Model objects, and these indices are numbered from 1 to nParameters for ALL data group copies. So for the \"Tbabs*pow\" example above:\n", 295 | "\n", 296 | "```\n", 297 | "p = m1(2) # Returns the 2nd parameter from m1, the model for data group 1.\n", 298 | "p = m2(2) # Returns the 2nd parameter from m2, the model for data group 2. \n", 299 | "```\n", 300 | "\n", 301 | "#### Defining Multiple Models\n", 302 | "\n", 303 | "Beginning with XSPEC12, it became possible to assign multiple sources to spectra, and each source may have its own model function definition. To keep track of multiple model definitions, XSPEC requires that you assign them names. In PyXspec, the model name and source number are supplied as additional arguments to the Model __init__ function.\n", 304 | "\n", 305 | "As with Standard XSPEC, to define a model for source numbers > 1 you first must load a detector response for the source. See \"Background, Response, and Arf\" in the previous section.\n", 306 | "\n", 307 | "\n" 308 | ] 309 | }, 310 | { 311 | "cell_type": "code", 312 | "execution_count": 80, 313 | "metadata": {}, 314 | "outputs": [], 315 | "source": [ 316 | "xspec.AllData.clear() # clear previously loaded data\n", 317 | "s1 = xspec.Spectrum(\"data/spec\")\n", 318 | "# Set a response for source 2\n", 319 | "s1.multiresponse[1] = \"data/spec.rmf\"\n", 320 | "# Define a model named \"alpha\" assigned to source 1\n", 321 | "m_1_1 = xspec.Model(\"wa*po\",\"alpha\")\n", 322 | "# Define a model named \"beta\" assigned to source 2\n", 323 | "m_2_1 = xspec.Model(\"tbabs*po\",\"beta\", sourceNum=2)\n", 324 | "# (In both of these cases, the returned object belongs to data group 1)\n" 325 | ] 326 | }, 327 | { 328 | "cell_type": "markdown", 329 | "metadata": {}, 330 | "source": [ 331 | "Note that in all previous examples in this tutorial, we have been using unnamed models which were assigned to source 1. Named models and source numbers may also be defined directly into the AllModels container by passing in a tuple:\n", 332 | "\n" 333 | ] 334 | }, 335 | { 336 | "cell_type": "code", 337 | "execution_count": 89, 338 | "metadata": {}, 339 | "outputs": [], 340 | "source": [ 341 | "xspec.AllModels.clear() # clear previous models\n", 342 | "# Define a model named \"defn1\" assigned to source 1\n", 343 | "xspec.AllModels += (\"wa*po\", \"defn1\")\n", 344 | "# Define a model named \"defn2\" assigned to source 2\n", 345 | "xspec.AllModels += (\"const*bbody\", \"defn2\", 2)\n", 346 | "# This replaces \"defn1\" with an unnamed model for source 1\n", 347 | "xspec.AllModels += \"wa*gaussian\"\n", 348 | "\n" 349 | ] 350 | }, 351 | { 352 | "cell_type": "markdown", 353 | "metadata": {}, 354 | "source": [ 355 | "and from which Model objects can be retrieved:" 356 | ] 357 | }, 358 | { 359 | "cell_type": "code", 360 | "execution_count": 106, 361 | "metadata": {}, 362 | "outputs": [ 363 | { 364 | "name": "stdout", 365 | "output_type": "stream", 366 | "text": [ 367 | "Model applied to data group 1, source 1='wabs*powerlaw'; Model applied to data group 2, source 2='constant*bbody'\n" 368 | ] 369 | } 370 | ], 371 | "source": [ 372 | "#\n", 373 | "# Load 2 spectra, spec.pha and spec_sim.pha, into 2 separate data groups\n", 374 | "#\n", 375 | "xspec.AllData.clear()\n", 376 | "s1 = xspec.Spectrum(\"data/spec\")\n", 377 | "# Set a response for source 2\n", 378 | "xspec.AllData(1).response = \"data/spec.rmf\" # this response include the effective area (ARF) information\n", 379 | "s1.multiresponse[1] = \"data/spec.rmf\"\n", 380 | "\n", 381 | "xspec.AllData(\"2:2 data/spec_sim.pha\") # read spectrum into data group 2\n", 382 | "# Explicitly specify the response, if necessary\n", 383 | "xspec.AllData(2).response = \"data/spec3.rmf\" # response includes the ARF already\n", 384 | "s2=xspec.AllData(2)\n", 385 | "s2.multiresponse[1] = \"data/spec3.rmf\"\n", 386 | "\n", 387 | "xspec.AllModels.clear() # clear previous models\n", 388 | "xspec.AllModels += (\"wa*po\", \"defn1\") # Define a model named \"defn1\" assigned to source 1\n", 389 | "xspec.AllModels += (\"const*bbody\", \"defn2\", 2) # Define a model named \"defn2\" assigned to source 2\n", 390 | "\n", 391 | "\n", 392 | "# Get the \"defn2\" Model object for data group 1\n", 393 | "m_2_1 = xspec.AllModels(1,\"defn1\")\n", 394 | "# ...and for data group 2\n", 395 | "m_2_2 = xspec.AllModels(2,\"defn2\")\n", 396 | "\n", 397 | "\n", 398 | "print \"Model applied to data group 1, source 1='{0}'; Model applied to data group 2, source 2='{1}'\".format(m_2_1.expression, m_2_2.expression)" 399 | ] 400 | }, 401 | { 402 | "cell_type": "markdown", 403 | "metadata": {}, 404 | "source": [ 405 | "To view all current source number and model assignments, see the AllModels.sources attribute, which displays a dictionary of the [source number]:[model name] pairs:\n", 406 | "\n" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 107, 412 | "metadata": {}, 413 | "outputs": [ 414 | { 415 | "data": { 416 | "text/plain": [ 417 | "{1: 'defn1', 2: 'defn2'}" 418 | ] 419 | }, 420 | "execution_count": 107, 421 | "metadata": {}, 422 | "output_type": "execute_result" 423 | } 424 | ], 425 | "source": [ 426 | "xspec.AllModels.sources" 427 | ] 428 | }, 429 | { 430 | "cell_type": "markdown", 431 | "metadata": {}, 432 | "source": [ 433 | "To remove model definitions:" 434 | ] 435 | }, 436 | { 437 | "cell_type": "code", 438 | "execution_count": 108, 439 | "metadata": {}, 440 | "outputs": [], 441 | "source": [ 442 | "# Remove all data group copies of \"defn2\"\n", 443 | "xspec.AllModels -= \"defn2\"\n", 444 | "# Remove all data group copies of the unnamed model (defined above as \"wa*gaussian\")\n", 445 | "#xspec.AllModels -= \"\"\n", 446 | "# Remove all copies of ALL model definitions\n", 447 | "xspec.AllModels.clear()\n", 448 | "\n" 449 | ] 450 | }, 451 | { 452 | "cell_type": "markdown", 453 | "metadata": {}, 454 | "source": [ 455 | "#### Component And Parameter Access Part 2\n", 456 | "\n", 457 | "When PyXspec constructs a Model object, it immediately adds to it an attribute of type Component for every component in the model expression. The attribute has the same (full) name as the component in the original expression, allowing you to access it as:\n", 458 | "\n", 459 | "\n" 460 | ] 461 | }, 462 | { 463 | "cell_type": "code", 464 | "execution_count": 112, 465 | "metadata": {}, 466 | "outputs": [ 467 | { 468 | "data": { 469 | "text/plain": [ 470 | "'powerlaw'" 471 | ] 472 | }, 473 | "execution_count": 112, 474 | "metadata": {}, 475 | "output_type": "execute_result" 476 | } 477 | ], 478 | "source": [ 479 | "m = xspec.Model(\"wa*pow\")\n", 480 | "c2 = m.powerlaw\n", 481 | "c2.name" 482 | ] 483 | }, 484 | { 485 | "cell_type": "raw", 486 | "metadata": {}, 487 | "source": [ 488 | "\n", 489 | "However when a model contains multiple copies of the same component, this type of access becomes ambiguous. So to distinguish among copies, for any component making its 2nd or more appearance (from left to right), PyXspec will append \"_n\" to the attribute name where n refers to the component's position in the expression (again from left to right). For example:\n", 490 | "\n" 491 | ] 492 | }, 493 | { 494 | "cell_type": "code", 495 | "execution_count": 114, 496 | "metadata": {}, 497 | "outputs": [], 498 | "source": [ 499 | "m = xspec.Model(\"wa*po + po\")\n", 500 | "# This gets the leftmost powerlaw component\n", 501 | "pow1 = m.powerlaw\n", 502 | "# This gets the rightmost, which is the 3rd component in the expression.\n", 503 | "pow2 = m.powerlaw_3\n", 504 | "\n" 505 | ] 506 | }, 507 | { 508 | "cell_type": "markdown", 509 | "metadata": {}, 510 | "source": [ 511 | "\n", 512 | "The Model object also stores an attribute which is a just a list of the names of its constituent Component attributes:\n", 513 | "\n" 514 | ] 515 | }, 516 | { 517 | "cell_type": "code", 518 | "execution_count": 115, 519 | "metadata": {}, 520 | "outputs": [ 521 | { 522 | "data": { 523 | "text/plain": [ 524 | "['wabs', 'powerlaw', 'powerlaw_3']" 525 | ] 526 | }, 527 | "execution_count": 115, 528 | "metadata": {}, 529 | "output_type": "execute_result" 530 | } 531 | ], 532 | "source": [ 533 | "m.componentNames" 534 | ] 535 | }, 536 | { 537 | "cell_type": "markdown", 538 | "metadata": {}, 539 | "source": [ 540 | "This may be useful, for example, if writing a loop to access each of a model's components. Similarly `Component` objects have a `parameterNames` attribute, listing the names of their constituent Parameter attributes:\n" 541 | ] 542 | }, 543 | { 544 | "cell_type": "code", 545 | "execution_count": 117, 546 | "metadata": {}, 547 | "outputs": [ 548 | { 549 | "data": { 550 | "text/plain": [ 551 | "['PhoIndex', 'norm']" 552 | ] 553 | }, 554 | "execution_count": 117, 555 | "metadata": {}, 556 | "output_type": "execute_result" 557 | } 558 | ], 559 | "source": [ 560 | "m.powerlaw.parameterNames" 561 | ] 562 | }, 563 | { 564 | "cell_type": "markdown", 565 | "metadata": {}, 566 | "source": [ 567 | "#### Gain Parameters (Response Models)\n", 568 | "\n", 569 | "Response Models differ from the regular kind in that they act on a Response rather than directly calculating a flux. At present there is only one kind of Response Model in Xspec, and this is `gain`. `gain` is a built-in attribute of all Response objects, and is of the class type `RModel`. It has 2 parameters for adjusting the energies of a Response: slope and offset. Gain parameters are initially off by default, but may be turned on simply by setting either one. For example:" 570 | ] 571 | }, 572 | { 573 | "cell_type": "code", 574 | "execution_count": 126, 575 | "metadata": {}, 576 | "outputs": [ 577 | { 578 | "name": "stdout", 579 | "output_type": "stream", 580 | "text": [ 581 | "The offset is 0.03 and the slope is 0.99\n" 582 | ] 583 | } 584 | ], 585 | "source": [ 586 | "s = xspec.Spectrum(\"data/spec\")\n", 587 | "s.response = \"data/spec.rmf\"\n", 588 | "\n", 589 | "# The spectrum's response has a gain attribute that is not in use,\n", 590 | "# which is the equivalent of having a slope fixed at 1.0 and offset = 0.0.\n", 591 | "\n", 592 | "r = s.response\n", 593 | "# Setting either the slope or offset turns the gain on for this response.\n", 594 | "# Both slope and offset will now be fit parameters.\n", 595 | "r.gain.slope = 1.05\n", 596 | "# The previous setting leaves the offset at 0.0. Now we'll change it.\n", 597 | "r.gain.offset = .05\n", 598 | "# You can set slope and offset at the same time using Response's setPars method.\n", 599 | "r.setPars(.99, .03)\n", 600 | "\n", 601 | "print \"The offset is {0} and the slope is {1}\".format(s.response.gain.offset.values[0],s.response.gain.slope.values[0])" 602 | ] 603 | }, 604 | { 605 | "cell_type": "code", 606 | "execution_count": 127, 607 | "metadata": {}, 608 | "outputs": [], 609 | "source": [ 610 | "# Modify the parameter's auxilliary values\n", 611 | "r.gain.offset = \".08,,.01,.01,.5,.5\"\n", 612 | "# Set a parameter link\n", 613 | "r.gain.offset.link = \".005*1\"\n", 614 | "\n" 615 | ] 616 | }, 617 | { 618 | "cell_type": "markdown", 619 | "metadata": {}, 620 | "source": [ 621 | "To remove the response fit parameters and return the Response back to its original state, call the gain.off() method:\n", 622 | "\n" 623 | ] 624 | }, 625 | { 626 | "cell_type": "code", 627 | "execution_count": 128, 628 | "metadata": { 629 | "collapsed": true 630 | }, 631 | "outputs": [], 632 | "source": [ 633 | "# This deletes the slope and offset parameters.\n", 634 | "# Any references to them become invalid.\n", 635 | "r.gain.off()\n", 636 | "\n" 637 | ] 638 | }, 639 | { 640 | "cell_type": "markdown", 641 | "metadata": {}, 642 | "source": [ 643 | "### Flux Calculations\n", 644 | "\n", 645 | "To perform a Standard XSPEC flux or lumin calculation, call the AllModels methods calcFlux or calcLumin respectively:\n" 646 | ] 647 | }, 648 | { 649 | "cell_type": "code", 650 | "execution_count": 129, 651 | "metadata": { 652 | "collapsed": true 653 | }, 654 | "outputs": [], 655 | "source": [ 656 | "xspec.AllModels.calcFlux(\".3 1.0\")\n", 657 | "xspec.AllModels.calcFlux(\".1 10.0 err\")\n", 658 | "xspec.AllModels.calcLumin(\".1 10. .05 err\")\n" 659 | ] 660 | }, 661 | { 662 | "cell_type": "markdown", 663 | "metadata": {}, 664 | "source": [ 665 | "As in Standard XSPEC the results will be stored with the currently loaded spectra:" 666 | ] 667 | }, 668 | { 669 | "cell_type": "code", 670 | "execution_count": 133, 671 | "metadata": {}, 672 | "outputs": [ 673 | { 674 | "name": "stdout", 675 | "output_type": "stream", 676 | "text": [ 677 | "Flux = (2.861965511334301e-08, 0.0, 0.0, 6.341347715278822, 0.0, 0.0)\n", 678 | "Luminosity = (1604.845391020328, 0.0, 0.0, 6.2919213498135145, 0.0, 0.0)\n" 679 | ] 680 | } 681 | ], 682 | "source": [ 683 | "s1 = xspec.AllData(1)\n", 684 | "print 'Flux = ',s1.flux\n", 685 | "print 'Luminosity =',s1.lumin\n", 686 | "\n" 687 | ] 688 | }, 689 | { 690 | "cell_type": "markdown", 691 | "metadata": {}, 692 | "source": [ 693 | "unless there are no spectra, in which case the results are stored with the model object:\n", 694 | "\n" 695 | ] 696 | }, 697 | { 698 | "cell_type": "code", 699 | "execution_count": 136, 700 | "metadata": {}, 701 | "outputs": [ 702 | { 703 | "name": "stdout", 704 | "output_type": "stream", 705 | "text": [ 706 | "Model Flux - (0.0, 0.0, 0.0, 0.0, 0.0, 0.0)\n" 707 | ] 708 | } 709 | ], 710 | "source": [ 711 | "xspec.AllData.clear()\n", 712 | "print \"Model Flux - \",xspec.AllModels(1).flux\n" 713 | ] 714 | }, 715 | { 716 | "cell_type": "markdown", 717 | "metadata": {}, 718 | "source": [ 719 | "----\n", 720 | "\n", 721 | "### Local Models in C/C++/Fortran\n", 722 | "\n", 723 | "In Standard XSPEC, local model libraries are built with the initpackage comamnd and then loaded with lmod. The AllModels container supplies both of these functions for doing the same thing in PyXspec:\n", 724 | "\n", 725 | "AllModels.initpackage(\"myLocalMods\",\"lmodel.dat\")\n", 726 | "AllModels.lmod(\"myLocalMods\")\n", 727 | "\n", 728 | "By default this looks in the directory set by the LOCAL_MODEL_DIRECTORY variable in your ~/.xspec/Xspec.init start-up file. You can override this by giving these functions an absolute or relative path as a dirPath keyword argument (see the Class guide for details).\n", 729 | "\n", 730 | "Local Models in Python\n", 731 | "\n", 732 | "You can also write model functions in Python and insert them into the XSPEC library with the AllModels addPyMod method. You simply define a function with 3 arguments for energies, parameters, and flux. For example a powerlaw model function might look like:\n" 733 | ] 734 | }, 735 | { 736 | "cell_type": "code", 737 | "execution_count": 137, 738 | "metadata": { 739 | "collapsed": true 740 | }, 741 | "outputs": [], 742 | "source": [ 743 | "def lpow(engs, params, flux):\n", 744 | " for i in range(len(engs)-1):\n", 745 | " pconst = 1.0 - params[0]\n", 746 | " val = math.pow(engs[i+1],pconst)/pconst - math.pow(engs[i],pconst)/pconst\n", 747 | " flux[i] = val\n", 748 | "\n" 749 | ] 750 | }, 751 | { 752 | "cell_type": "markdown", 753 | "metadata": {}, 754 | "source": [ 755 | "XSPEC will pass tuples containing the energy and parameter values to your function. For the flux array, it will pass a list pre-sized to nE-1, where nE is the size of the energies array. Your model function should fill in this list with the proper flux values. (For additional optional arguments to your model function, please see the documentation for the addPyMod function.)\n", 756 | "\n", 757 | "The second thing you must define is a tuple containing the parameters' information strings, one string for each parameter in your model. This is equivalent to the parameter strings you would define in a 'model.dat' file when adding local models in standard XSPEC, and it requires the same format. (See Appendix C of the XSPEC manual for more details.) So with the powerlaw function above which takes just 1 parameter, you might define a tuple as:\n", 758 | "\n", 759 | "`powInfo = (\"phoIndex \\\"\" 1.1 -3. -2. 9. 10. 0.01\",)`\n", 760 | "\n", 761 | "Note the need for the **trailing comma** when there's just one parameter string. This is to let Python know that powInfo is a tuple type and not a string.\n", 762 | "\n", 763 | "Once you've defined your function and parameter information, simply call:\n", 764 | "\n", 765 | "`AllModels.addPyMod(lpow, powInfo, 'add')`\n", 766 | "\n", 767 | "The 3rd argument tells XSPEC the type of your model function ('add', 'mul', or 'con'). After this call your function will be added to the list of available model components, which you can see by doing 'Model.showList()'. Your model will show up with the same name as your original Python function ('lpow'), and is ready for use in future Model definitions.\n", 768 | "\n", 769 | "\n" 770 | ] 771 | }, 772 | { 773 | "cell_type": "markdown", 774 | "metadata": {}, 775 | "source": [ 776 | "----\n", 777 | "\n", 778 | "### Fitting\n", 779 | "\n", 780 | "#### Error\n", 781 | "\n", 782 | "The error command is implemented through Fit, and the results are stored with the chosen Parameter object(s). The error attribute stores a tuple containing the low and high range values for the parameter, and the 9-letter status string to report problems incurred during the error calculation.\n", 783 | "\n", 784 | "```\n", 785 | "# Estimate the 90% confidence range for the 4th parameter\n", 786 | "xspec.Fit.error(\"2.706 4\")\n", 787 | "xspec.par4 = AllModels(1)(4)\n", 788 | "xspec.par4.error\n", 789 | "(0.11350354517707145, 0.14372981075906774, 'FFFFFFFFF')\n", 790 | "```" 791 | ] 792 | }, 793 | { 794 | "cell_type": "markdown", 795 | "metadata": {}, 796 | "source": [ 797 | "#### Query\n", 798 | "\n", 799 | "During an xspec.Fit.perform() operation, the default is to query the user whenever the fit has run the maximum number of iterations, as set by the Fit.nIterations attribute. You can change this behavior with the query attribute:\n" 800 | ] 801 | }, 802 | { 803 | "cell_type": "code", 804 | "execution_count": 140, 805 | "metadata": {}, 806 | "outputs": [], 807 | "source": [ 808 | "# When nIterations is reached, continue the fit without stopping to query.\n", 809 | "xspec.Fit.query = \"yes\"\n", 810 | "# Stop fit at nIterations and do not query.\n", 811 | "xspec.Fit.query = \"no\"\n", 812 | "# Query the user when nIterations is reached.\n", 813 | "xspec.Fit.query = \"on\"\n" 814 | ] 815 | }, 816 | { 817 | "cell_type": "markdown", 818 | "metadata": {}, 819 | "source": [ 820 | "\n", 821 | "#### Steppar\n", 822 | "\n", 823 | "The Standard XSPEC steppar command is also implemented through the global Fit object. You supply it with a string following the same steppar command syntax rules. For example:\n", 824 | "\n", 825 | "```\n", 826 | "# Step parameters 1 and 2 through the given range values\n", 827 | "# over a 10x10 2-D grid.\n", 828 | "Fit.steppar(\"1 20. 30. 10 2 .05 .08 10\")\n", 829 | "```\n", 830 | "\n", 831 | "### Fakeit\n", 832 | "\n", 833 | "PyXspec provides access to standard XSPEC's fakeit command, which is for creating spectra with simulated data. It is called through the AllData fakeit method:\n", 834 | "\n", 835 | "AllData.fakeit(nSpectra=1, settings=None, applyStats=True, filePrefix=\"\")\n", 836 | "\n", 837 | "NOTE: If AllData.fakeit is run when spectra are currently loaded, it will follow the same rules as the standard XSPEC fakeit function: It will REMOVE ALL pre-existing spectra and replace each one with a simulated spectrum (even if nSpectra is less than the number originally loaded).\n", 838 | "\n", 839 | "As those familiar with standard fakeit know, the user is normally prompted for quite a bit of additional information needed to generate the fakeit files. However the goal here is to have NO additional prompting, and that requires that all information must be entered as arguments to the AllData fakeit method call. This is done by passing objects of the FakeitSettings class to AllData.fakeit, as we'll show further below.\n", 840 | "\n", 841 | "NOTE: Unless stated otherwise, assume all spectra are OGIP type-1 (1 spectrum per file).\n", 842 | "\n", 843 | "For the simplest of cases, you don't need to create any FakeitSettings objects. Just pass in the number of fake spectra you'd like to create:\n", 844 | "\n" 845 | ] 846 | }, 847 | { 848 | "cell_type": "code", 849 | "execution_count": 141, 850 | "metadata": { 851 | "collapsed": true 852 | }, 853 | "outputs": [], 854 | "source": [ 855 | "# Create 3 fake spectra using only default settings.\n", 856 | "xspec.AllData.fakeit(3)" 857 | ] 858 | }, 859 | { 860 | "cell_type": "markdown", 861 | "metadata": {}, 862 | "source": [ 863 | "The fakeit function will then create a default `FakeitSettings` object for each of the 3 spectra. By default, a FakeitSettings object will have empty strings for all of its attributes, and these are handled differently depending on whether the fake spectrum is replacing a currently loaded spectrum, or creating one from scratch.\n", 864 | "\n", 865 | "#### From Existing Spectra\n", 866 | "\n", 867 | "When replacing an existing spectrum, FakeitSettings attributes with empty strings will simply take their value from the original spectrum. Also note that the response and arf settings for the original spectrum CANNOT be modified for the fakeit spectrum. If a name is filled in for either of these attributes, it will be ignored. If you wish to modify these, you can make the change to the original spectrum prior to calling fakeit. [The one exception is when the original spectrum has no response, in which case the response attribute MUST be filled in.] If the fileName attribute is empty, XSPEC will generate a default output name derived from the original file name.\n", 868 | "\n", 869 | "#### From Scratch\n", 870 | "\n", 871 | "When creating from scratch, an empty string implies \"none\" for the arf and background, 1.0 for exposure and correction, and XSPEC's default dummy response for the response attribute. If the fileName attribute is empty, XSPEC will generate a default output file name based on the response name, and it will include an auto-incremented index to prevent multiple output files from overwriting each other.\n", 872 | "\n", 873 | "FakeitSettings Objects\n", 874 | "\n", 875 | "To create a fake spectrum with anything other than default settings, you must supply a FakeitSettings object for that spectrum. The FakeitSettings attributes are: response, arf, background, exposure, correction, backExposure, and fileName. All are string types, though exposure, backExposure, and correction can also be entered as floats. Attributes can be set upon object construction, or anytime afterwards:\n", 876 | "\n", 877 | "fs1 = FakeitSettings(\"response1.rsp\", exposure = 1500.0)\n", 878 | "\n", 879 | "fs1.background = \"back1.pha\"\n", 880 | "\n", 881 | "A new FakeitSettings object can also be made by copying an existing one:\n", 882 | "\n", 883 | "fs2 = FakeitSettings(fs1)\n", 884 | "\n", 885 | "And now pass the objects to the fakeit method, either in a list, dictionary, or as a single object:\n", 886 | "\n", 887 | "```\n", 888 | "# Apply settings to fakeit spectra 1 and 2:\n", 889 | "AllData.fakeit(2,[fs1,fs2])\n", 890 | "# Apply setting to fakeit spectrum 1, use defaults for spectrum 2:\n", 891 | "AllData.fakeit(2, fs1)\n", 892 | "# Apply settings to fakeit spectra 2 and 4, use defaults for 1 and 3:\n", 893 | "settingsDict = {2:fs1, 4:fs2}\n", 894 | "AllData.fakeit(4, settingsDict)\n", 895 | "# Create 4 fakeit spectra from the same settings object:\n", 896 | "settingsList = 4*[fs1]\n", 897 | "AllData.fakeit(4, settingsList)\n", 898 | "```\n", 899 | "\n", 900 | "The remaining 2 arguments to the AllData.fakeit function are for choosing whether to apply statistical fluctuations (default = True), and whether to add an optional prefix string to the names of all output files.\n", 901 | "\n", 902 | "### OGIP Type-2 Files\n", 903 | "\n", 904 | "With OGIP type-2 files, multiple spectra may be placed in a single file. The important thing to recognize when generating type-2 fakeit files is that the exposure, correction, backExposure, and fileName attributes apply to the output files and not the individual spectra. Therefore these settings will be ignored for all but the first spectrum in a file. For example:\n", 905 | "\n", 906 | "```\n", 907 | "# Start with 4 spectra loaded, in 2 type-2 files:\n", 908 | "AllData(\"myDataFile1.pha{1-2} myDataFile2.pha{7-8}\")\n", 909 | "# Create settings for the 4 fake spectra that will be generated from these:\n", 910 | "fs1 = FakeitSettings(background=\"back1.pha\", exposure=250.) \n", 911 | "# The exposure setting in fs2 will be ignored!!!\n", 912 | "fs2 = FakeitSettings(background=\"back2.pha\", exposure 100.) \n", 913 | "fs3 = FakeitSettings(fileName=\"myFakeitFile_2.pha\")\n", 914 | "fs4 = FakeitSettings(fs3)\n", 915 | "# The following change will be ignored!!!\n", 916 | "fs4.fileName = \"myFakeitFile_3.pha\"\n", 917 | "# Now generate the fakeit files: AllData.fakeit(4, [fs1,fs2,fs3,fs4])\n", 918 | "```\n", 919 | "\n", 920 | "The above will generate 4 fakeit spectra, placed in 2 type-2 files. The exposure setting for spectrum 2 and the fileName setting for spectrum 4 will be ignored. Those values are only set by spectra 1 and 3.\n", 921 | "\n", 922 | "For more fakeit details and examples, please check:\n", 923 | "\n", 924 | "```\n", 925 | "help(FakeitSettings)\n", 926 | "help(DataManager.fakeit)\n", 927 | "```\n", 928 | "\n", 929 | "### Monte Carlo Markov Chains (MCMC)\n", 930 | "\n", 931 | "All MCMC operations are handled either by objects of class Chain, or the global AllChains container object. To create a new chain based on the current fit parameters, simply create a Chain object by passing it an output file name:\n", 932 | "\n", 933 | "`c1 = Chain(\"chain1.fits\")`\n", 934 | "\n", 935 | "The above call creates the file \"chain1.fits\", performs an MCMC run using the default burn, fileType, length, proposal, rand, and temperature values, and automatically places the new object in the AllChains container. These default settings are stored as attributes of AllChains:\n", 936 | "\n", 937 | "```\n", 938 | "# Ensure that new chains will burn the first 100 iterations, will\n", 939 | "# have length 1000, and will use the proposal \"gaussian fit\"\n", 940 | "AllChains.defBurn = 100\n", 941 | "AllChains.defLength = 1000\n", 942 | "AllChains.defProposal = \"gaussian fit\"\n", 943 | "c2 = Chain(\"chain2.fits\")\n", 944 | "```\n", 945 | "\n", 946 | "You can also override the AllChains default settings by passing additional arguments to Chain upon construction:\n", 947 | "\n", 948 | "```\n", 949 | "# Length will be 2000 for this chain, use defaults for all other settings.\n", 950 | "c3 = Chain(\"chain3.fits\", runLength = 2000)\n", 951 | "```\n", 952 | "\n", 953 | "The new chain objects will then store their own settings as attributes:\n", 954 | "\n", 955 | "```\n", 956 | "c2.burn\n", 957 | "100\n", 958 | "c2.runLength\n", 959 | "1000\n", 960 | "c3.runLength\n", 961 | "2000\n", 962 | "```\n", 963 | "\n", 964 | "All of a chain object's attributes will be displayed when calling its show() method.\n", 965 | "\n", 966 | "To append a new run to an existing chain object, call the object's run() method. The appending run will use the object's current attribute settings, and not the AllChains default settings:\n", 967 | "\n", 968 | "```\n", 969 | "# This will append a run of length 3000 to the c3 chain object, and with a\n", 970 | "# Metropolis-Hastings temperature of 50.0:\n", 971 | "c3.runLength = 3000\n", 972 | "c3.temperature = 50.0\n", 973 | "c3.run()\n", 974 | "\n", 975 | "c3.totalLength\n", 976 | "5000\n", 977 | "```\n", 978 | "To overwrite rather than append to an existing chain object, call run with its append argument set to False:\n", 979 | "\n", 980 | "```\n", 981 | "# This erases the results of any previous runs for object c3.\n", 982 | "c3.run(False)\n", 983 | "\n", 984 | "c3.totalLength\n", 985 | "3000\n", 986 | "```\n", 987 | "New chains are loaded into AllChains by default, but you can unload or reload them using the AllChains arithmetic operators:\n", 988 | "\n", 989 | "```\n", 990 | "# Chain c2 may be unloaded by passing its chain index number\n", 991 | "AllChains -= 2\n", 992 | "# OR by passing the object itself\n", 993 | "AllChains -= c2\n", 994 | "# 2 ways to remove ALL chains\n", 995 | "AllChains -= '*'\n", 996 | "AllChains.clear()\n", 997 | "\n", 998 | "\n", 999 | "# Reload an existing chain object\n", 1000 | "AllChains += c2\n", 1001 | "# Load a chain from an existing chain file\n", 1002 | "AllChains += \"earlierChain.fits\"\n", 1003 | "# Create a new chain, to be stored in file \"chain4.fits\"\n", 1004 | "AllChains += \"chain4.fits\"\n", 1005 | "```\n", 1006 | "\n", 1007 | "As with Standard XSPEC, unloading a chain will leave the chain's file intact. It merely removes the chain from XSPEC's calculations. To display information about the currently loaded chains, call AllChains.show().\n", 1008 | "\n", 1009 | "You may also get a chain object from the container at any time by passing it an index number:\n", 1010 | "\n", 1011 | "```\n", 1012 | "# Retrieve a chain object for the 4th chain in the container\n", 1013 | "c4 = AllChains(4)\n", 1014 | "```\n", 1015 | "\n", 1016 | "### Plotting\n", 1017 | "\n", 1018 | "All of the plotting options available in Standard XSPEC's setplot command are now implemented as attributes of the Plot object. Some of these are mentioned in the Quick Version of the tutorial, and please see the PlotManager class reference for the complete guide.\n", 1019 | "\n", 1020 | "One setting of particular interest is the commands attribute. This is a tuple of user-entered PLT command strings which are added to XSPEC's auto-generated commands when performing a plot, and is modified through Plot's addCommand and delCommand methods. For example, to enter a PLT command to place an additional label at the specified coordinates on the plot:\n", 1021 | "\n", 1022 | "`Plot.addCommand(\"label 1 pos 10 .05 \\\"Another Label\"\")`\n", 1023 | "\n", 1024 | "To view the currently loaded commands:\n", 1025 | "\n", 1026 | "`print Plot.commands`\n", 1027 | "\n", 1028 | "and to remove the 3rd command from the tuple:\n", 1029 | "\n", 1030 | "`Plot.delCommand(3)`\n", 1031 | "\n", 1032 | "### XSPEC Settings\n", 1033 | "\n", 1034 | "Most of the internal switches set through Standard XSPEC's xset command are now set through attributes of the global Xset object. Examples:\n", 1035 | "\n", 1036 | "```\n", 1037 | "Xset.abund = \"angr\"\n", 1038 | "Xset.cosmo = \"50 .5 0.\"\n", 1039 | "Xset.xsect = \"bcmc\"\n", 1040 | "```\n", 1041 | "\n", 1042 | "Xset also provides the methods `addModelString` and `delModelString` to set the `,` pairs which are used by certain models. The `` argument is case-insensitive.\n", 1043 | "\n", 1044 | "```\n", 1045 | "Xset.addModelString(\"APECROOT\",\"1.3.1\")\n", 1046 | "Xset.addModelString(\"APECTHERMAL\",\"yes\")\n", 1047 | "Xset.delModelString(\"neivers\")\n", 1048 | "```\n", 1049 | "\n", 1050 | "The entire collection of `,` pairs may be set or retrieved with the Xset.modelStrings attribute:\n", 1051 | "\n", 1052 | "```\n", 1053 | "# Replace all previous entries with a new dictionary\n", 1054 | "Xset.modelStrings = {\"neivers\":\"1.1\", \"apecroot\":\"1.3.1\"}\n", 1055 | "# Clear out all entries:\n", 1056 | "Xset.modelStrings = {}\n", 1057 | "```\n", 1058 | "\n", 1059 | "`Xset.show()` will display all of the current settings including the current `,` pairs.\n", 1060 | "\n", 1061 | "### Logging And XSPEC Output\n", 1062 | "\n", 1063 | "The Xset object provides attributes and methods for controlling output chatter level and for creating log files:\n", 1064 | "\n", 1065 | "```\n", 1066 | "# Get/Set the console chatter level\n", 1067 | "ch = Xset.chatter\n", 1068 | "Xset.chatter = 10\n", 1069 | "# Get/Set the log chatter level\n", 1070 | "lch = Xset.logChatter\n", 1071 | "Xset.logChatter = 20\n", 1072 | "\n", 1073 | "# Create and open a log file for XSPEC output\n", 1074 | "# This returns a Python file object\n", 1075 | "logFile = Xset.openLog(\"newLogFile.txt\")\n", 1076 | "# Get the Python file object for the currently opened log\n", 1077 | "logFile = Xset.log\n", 1078 | "# Close XSPEC's currently opened log file.\n", 1079 | "Xset.closeLog()\n", 1080 | "```\n", 1081 | "\n", 1082 | "### Exceptions And Error Handling\n", 1083 | "\n", 1084 | "PyXspec utilizes the standard Python try/except/raise mechanism for handling and reporting errors. In this early version, only exception objects of the class Exception are ever raised. In the future other (more specific) error classes may be used, but they should always be derived from Exception. So you can catch all PyXspec exceptions with code such as:\n", 1085 | "\n", 1086 | "```\n", 1087 | " try:\n", 1088 | " # Only 4 spectra are currently loaded\n", 1089 | " s = xspec.AllData(5)\n", 1090 | " except Exception, msg:\n", 1091 | " print msg \n", 1092 | "```\n", 1093 | "\n", 1094 | "which will print the error message:\n", 1095 | "\n", 1096 | "`Error: Spectrum index number is out of range: 5`\n", 1097 | "\n", 1098 | "PyXspec raises errors in a variety of situations, such as for invalid input argument syntax, or for input which is invalid within the context of the call (as in the example above). It can also raise exceptions if you try to rebind a class attribute when such modification is not permitted.\n", 1099 | "\n", 1100 | "### Adding Attributes To PyXspec Objects\n", 1101 | "\n", 1102 | "A particularly novel feature of Python (in comparison with say C++) is that it allows you to create new attributes \"on the fly\". The attributes don't have to have been part of the original class definition:\n", 1103 | "\n", 1104 | "```\n", 1105 | " class C:\n", 1106 | " pass\n", 1107 | "\n", 1108 | "\n", 1109 | " x = C()\n", 1110 | "x.pi = 3.1416\n", 1111 | "```\n", 1112 | "\n", 1113 | "The downside of course is that spelling or case sensitive errors become much harder to detect. For example, with PyXspec's Plot object:\n", 1114 | "\n", 1115 | "```\n", 1116 | "Plot.yLog = True # Correct\n", 1117 | "Plot.ylog = True # Wrong!\n", 1118 | "```\n", 1119 | "\n", 1120 | "In the second case, standard Python will simply add a new attribute named \"ylog\" to Plot, and this will have no effect on the actual plot since PyXspec is only looking at \"yLog\".\n", 1121 | "\n", 1122 | "So operating under the assumption that this downside outweighs the benefits, we've decided to disable the ability to add new attributes to PyXspec class objects. A misspelling or case error will instead raise an Exception object. And since some users may genuinely wish to add their own attributes to PyXspec classes, this default behavior may be overridden by toggling the Xset.allowNewAttributes flag:\n", 1123 | "\n", 1124 | "```\n", 1125 | "s = Spectrum(\"dataFile.pha\")\n", 1126 | "s.myNewIndex = 10 # Error: Will raise an exception\n", 1127 | "Xset.allowNewAttributes = True\n", 1128 | "s.myNewIndex = 10 # OK\n", 1129 | ".\n", 1130 | ". # Can add new attributes to any PyXspec object,\n", 1131 | ". # but attribute spelling errors will go undetected.\n", 1132 | ".\n", 1133 | "Xset.allowNewAttributes = False\n", 1134 | "```\n", 1135 | "\n", 1136 | "### Using With Other Packages\n", 1137 | "\n", 1138 | "One of the primary benefits of PyXspec is that it makes it much easier to use XSPEC data and results in 3rd party packages. For example you can bypass XSPEC's built-in plotting functions in favor of a Python plotting library such as Matplotlib:\n", 1139 | "\n", 1140 | "```\n", 1141 | "#!/usr/bin/python\n", 1142 | "\n", 1143 | "from xspec import *\n", 1144 | "import matplotlib.pyplot as plt\n", 1145 | "\n", 1146 | "# PyXspec operations:\n", 1147 | "s = Spectrum(\"file1.pha\")\n", 1148 | "m = Model(\"wa*po\")\n", 1149 | "Fit.perform()\n", 1150 | "\n", 1151 | "# Plot using Matplotlib:\n", 1152 | "plt.plot(s.noticed, s.values, 'ro', s.noticed, m.folded(1))\n", 1153 | "plt.xlabel('channels')\n", 1154 | "plt.ylabel('counts/cm^2/sec/chan')\n", 1155 | "plt.savefig('myplot')\n", 1156 | "```\n", 1157 | "\n", 1158 | "The above code produces a Matplotlib plot of the spectral data and folded model vs. channels (similar to what you get with Standard XSPEC's \"plot data\" command). It makes use of the Spectrum object's noticed attribute to pass a list of the channel numbers, and the values attribute (a tuple) to pass the spectral data values in counts/cm^2/s. The folded model values are obtained as a list by calling the Model object's folded method with a spectrum number argument." 1159 | ] 1160 | }, 1161 | { 1162 | "cell_type": "code", 1163 | "execution_count": null, 1164 | "metadata": { 1165 | "collapsed": true 1166 | }, 1167 | "outputs": [], 1168 | "source": [] 1169 | } 1170 | ], 1171 | "metadata": { 1172 | "kernelspec": { 1173 | "display_name": "Python 2", 1174 | "language": "python", 1175 | "name": "python2" 1176 | }, 1177 | "language_info": { 1178 | "codemirror_mode": { 1179 | "name": "ipython", 1180 | "version": 2 1181 | }, 1182 | "file_extension": ".py", 1183 | "mimetype": "text/x-python", 1184 | "name": "python", 1185 | "nbconvert_exporter": "python", 1186 | "pygments_lexer": "ipython2", 1187 | "version": "2.7.14" 1188 | }, 1189 | "nav_menu": {}, 1190 | "toc": { 1191 | "navigate_menu": true, 1192 | "number_sections": true, 1193 | "sideBar": true, 1194 | "threshold": 6, 1195 | "toc_cell": false, 1196 | "toc_section_display": "block", 1197 | "toc_window_display": true 1198 | } 1199 | }, 1200 | "nbformat": 4, 1201 | "nbformat_minor": 1 1202 | } 1203 | -------------------------------------------------------------------------------- /PyXspecUserGuide-QuickTutorial.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "*Some Standard Python Imports*\n" 8 | ] 9 | }, 10 | { 11 | "cell_type": "code", 12 | "execution_count": 1, 13 | "metadata": { 14 | "run_control": { 15 | "marked": true 16 | } 17 | }, 18 | "outputs": [], 19 | "source": [ 20 | "%matplotlib inline\n", 21 | "\n", 22 | "import matplotlib\n", 23 | "import numpy as np\n", 24 | "import matplotlib.pyplot as plt" 25 | ] 26 | }, 27 | { 28 | "cell_type": "markdown", 29 | "metadata": {}, 30 | "source": [ 31 | "# ``PyXspec`` Tutorial - Quick Version\n", 32 | "\n", 33 | "This assumes the user already has a basic familiarity with both ``XSPEC`` and Python. Everything in ``PyXspec`` is accessible by importing the package xspec into your Python script.\n", 34 | "\n", 35 | "``PyXspec`` can be utilized in a Python script or from the command line of the plain interactive Python interpreter. ``PyXspec`` does not implement its own command handler, so it is NOT intended to be run as the Python equivalent of a traditional interactive XSPEC session (which is really an enhanced interactive Tcl interpreter). In other words you launch an interactive PyXspec session with:\n", 36 | "\n", 37 | "```\n", 38 | "UNIX>python\n", 39 | ">>> import xspec\n", 40 | ">>>\n", 41 | "\n", 42 | "rather than:\n", 43 | "\n", 44 | "UNIX>xspec\n", 45 | "XSPEC12>\n", 46 | "```\n", 47 | "\n", 48 | "**A Note on Nomenclature**: While the python version of ``xspec`` is sometimes referred to as ``Pyxspec``, the actual python package name is ``xspec``. ``XSPEC`` refers to the standard (non-Python) command-line ``XSPEC`` software analysis suite.\n", 49 | "\n", 50 | "**A Note on the Sample Data**: To run through the examples in this Notebook, the data should files should be stored in a ``data`` subdirectory of the directory where the Notebook is located. Note that the spectrum files are based on simulated data and are not scientifically useful. \n" 51 | ] 52 | }, 53 | { 54 | "cell_type": "markdown", 55 | "metadata": {}, 56 | "source": [ 57 | "# Importing the ``xspec`` package" 58 | ] 59 | }, 60 | { 61 | "cell_type": "code", 62 | "execution_count": 3, 63 | "metadata": { 64 | "run_control": { 65 | "marked": true 66 | } 67 | }, 68 | "outputs": [], 69 | "source": [ 70 | "import xspec" 71 | ] 72 | }, 73 | { 74 | "cell_type": "markdown", 75 | "metadata": {}, 76 | "source": [ 77 | "## Notes on Running ``PyXspec`` in a Jupyter Notebook\n", 78 | " \n", 79 | "As noted above, PyXspec does not implement its own command handler. This has implications when\n", 80 | "running the ``xspec`` package in a ``Jupyter notebook`` (like this one). When running an ``xspec`` session in a notebook, the output from the python xspec package is by\n", 81 | "default written to the terminal window from which you\n", 82 | "opened the notebook. A work-around is to use the ``sys_pipes()`` function from the ``wurlitzer`` Python package, which will capture information being written to ``STDOUT`` (i.e. the terminal) and re-direct it to display in the notebook.\n", 83 | "\n", 84 | "In addition, interactive prompts are not handled correctly. To avoid\n", 85 | "the problem with interactive ``xspec`` prompts, you should turn off prompting by setting \n", 86 | "\n", 87 | "``xspec.Xset.allowPrompting = False``\n", 88 | "\n", 89 | "(note that you do not need to set ``xspec.Xset.allowPrompting = False`` if you are using ``pyxspec`` from the command line in a terminal window.)" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "execution_count": 4, 95 | "metadata": { 96 | "run_control": { 97 | "marked": true 98 | } 99 | }, 100 | "outputs": [], 101 | "source": [ 102 | "xspec.Xset.allowPrompting = False # keeps pyxspec from hanging, waiting for a response to a prompt" 103 | ] 104 | }, 105 | { 106 | "cell_type": "markdown", 107 | "metadata": {}, 108 | "source": [ 109 | "----\n", 110 | "## Jumping In - The Really Quick Version\n", 111 | "\n", 112 | "A simple Xspec load-fit-plot Python script may look something like this:\n", 113 | "```\n", 114 | "#!/usr/bin/python\n", 115 | "from xspec import *\n", 116 | "\n", 117 | "Spectrum(\"file1.pha\")\n", 118 | "Model(\"wabs*pow\")\n", 119 | "Fit.perform()\n", 120 | "Plot.device =\"/xs\"\n", 121 | "Plot(\"data\")\n", 122 | "```\n", 123 | "\n", 124 | "Keeping this template in mind, we'll proceed to fill in the details..." 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "metadata": {}, 130 | "source": [ 131 | "# Some Details\n", 132 | "\n", 133 | "## Terminology\n", 134 | "\n", 135 | "This description uses the standard Python object-oriented terminology, distinguishing between classes and objects. Class is used when referring to the type or definition of an object. An object refers to a specific instance of a class and is normally assigned to a variable. For example a user may load 3 data files by creating 3 spectral data objects s1, s2, and s3, which are all instances of the class `Spectrum`.\n", 136 | "\n", 137 | "The functions and stored data members that make up the definition of a class are referred to as methods and attributes respectively.\n", 138 | "\n", 139 | "The term Standard XSPEC refers to the traditional ways of using XSPEC, either with a Tcl script or an interactive, command-line XSPEC session.\n", 140 | "\n", 141 | "## The 6 Global Objects\n", 142 | "\n", 143 | "An ``XSPEC`` session fundamentally consists of loading data, fitting that data to a model, and plotting the results. To manage these operations, ``PyXspec`` offers the user 6 global objects: ``AllChains``, ``AllData``, ``AllModels``, ``Fit``, ``Plot``, and ``Xset``. Note that these are NOT the names of classes. They are instantiated objects of the class types shown in Table 1.\n", 144 | "\n", 145 | "\n", 146 | "\n", 147 | "\n", 148 | "\n", 149 | "\n", 150 | "\n", 151 | "\n", 152 | "\n", 153 | "\n", 154 | "\n", 155 | "\n", 156 | "\n", 157 | "\n", 158 | "\n", 159 | "\n", 160 | "\n", 161 | "\n", 162 | "
Table 1. PyXspec global objects
Object Name Class Role
AllChains ChainManager Monte Carlo Markov Chain container
AllData DataManager Container for all loaded data sets (objects of class Spectrum)
AllModels ModelManager Container for all Model objects
Fit FitManager Manager class for setting properties and running a fit
Plot PlotManager Manager class for performing XSPEC plots
Xset XspecSettings Storage class for Xspec settings
\n", 163 | "\n", 164 | "``PyXspec`` instantiates these objects immediately upon the importing of the ``xspec`` package. You cannot create any other objects of these class types, as they each allow only 1 instance of their type. (They are *singletons* in the language of design patterns.)\n", 165 | "\n", 166 | "Operations involving these should ALWAYS be performed through the objects and NOT their class names. These class names should never appear in your code.\n", 167 | "\n", 168 | "## A Note about indexing\n", 169 | "\n", 170 | "True to its Fortran roots, ``Pyxspec`` uses a 1-based indexing when referring to model and data components. Python uses a 0-based indexing (i.e. Python arrays start at 0). So ``Pyxspec`` numbers the first spectrum in a group as spectrum 1, not spectrum 0. Users should make note of this! \n", 171 | "\n", 172 | "## Getting Help\n", 173 | "\n", 174 | "There are two ways to get help for programming with PyXspec classes. The first is by viewing the Classes section of this manual. The Classes:Class List subsection is particularly useful as an entry point, as it contains hyperlinks to descriptions of every PyXspec class that is part of the public interface. The second way is to call Python's built-in help([class]) function from the interactive Python shell. Both methods will display essentially the same information, which originates in the class docstrings in the code files.\n", 175 | "\n", 176 | "\n", 177 | "---\n", 178 | "\n", 179 | "Those are some of the under-the-hood details. We'll next cover how to load spectra, define a model, fit data, plot data, and simulate spectra.\n", 180 | "\n", 181 | "----\n", 182 | "# Loading And Removing Data\n", 183 | "\n", 184 | "Spectral data files can be loaded in several ways. You can create an object of the `Spectrum` class by passing it the data file name. For example, suppose you had a spectrum in a pha file called spec.pha in a subdirectory `data` of your current working directory. To create a `Spectrum` object, do:" 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": 5, 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "xspec.AllData.clear() # clear out any previously loaded dataset\n", 194 | "s1 = xspec.Spectrum(\"data/spec.pha\")" 195 | ] 196 | }, 197 | { 198 | "cell_type": "markdown", 199 | "metadata": {}, 200 | "source": [ 201 | "Creating a `Spectrum` object in this way also adds the new object `s1` to the `AllData` container. Alternatively, you can simply add the new file directly to the container without retrieving a `Spectrum` object:" 202 | ] 203 | }, 204 | { 205 | "cell_type": "code", 206 | "execution_count": 5, 207 | "metadata": {}, 208 | "outputs": [], 209 | "source": [ 210 | "# add second spectrum to the container\n", 211 | "xspec.AllData += \"data/spec2.pha\" # then add it to the AllData Container" 212 | ] 213 | }, 214 | { 215 | "cell_type": "markdown", 216 | "metadata": {}, 217 | "source": [ 218 | "Later you can always obtain a ``Spectrum`` object reference to any of the loaded spectra by passing AllData an integer:" 219 | ] 220 | }, 221 | { 222 | "cell_type": "code", 223 | "execution_count": 6, 224 | "metadata": {}, 225 | "outputs": [], 226 | "source": [ 227 | "s2 = xspec.AllData(2) # s2 is a reference to the 2nd loaded spectrum" 228 | ] 229 | }, 230 | { 231 | "cell_type": "markdown", 232 | "metadata": {}, 233 | "source": [ 234 | "In some cases (like the examples above) the response file (``rmf``), and optionally, the ancillary response file (``arf``) is hard-coded in the pha file FITS header. You can also set the response and ancillary response file for a loaded spectrum manually:" 235 | ] 236 | }, 237 | { 238 | "cell_type": "code", 239 | "execution_count": 7, 240 | "metadata": {}, 241 | "outputs": [], 242 | "source": [ 243 | "s1.response = \"data/spec.rmf\"\n", 244 | "s1.response.arf = \"https://heasarc.gsfc.nasa.gov/FTP/caldb/data/nicer/xti/cpf/arf/nixtiaveonaxis20170601v001.arf\"" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "metadata": {}, 250 | "source": [ 251 | "Note that, in order to load an ancillary response file, you must first load a response file. Also note that **``PyXspec`` is able to load files stored on an FTP server**. \n", 252 | "\n", 253 | "For more complicated data loading, you have access to the same functionality in ``XSPEC``'s ``data`` command. pass a string to ``AllData``:" 254 | ] 255 | }, 256 | { 257 | "cell_type": "code", 258 | "execution_count": 8, 259 | "metadata": {}, 260 | "outputs": [], 261 | "source": [ 262 | "xspec.AllData.clear() # remove previously loaded file\n", 263 | "xspec.AllData(\"data/spec data/spec2 2:3 data/spec3\") # spec and spec2 are in data group 1, and spec3 is in data group 3\n" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "Note that only the last example allows you to assign multiple data groups, the 3rd spectrum being assigned to data group 2. Also note that in the last example any previously loaded data sets are removed, thus reproducing the behavior of standard ``XSPEC``'s ``data`` command.\n", 271 | "\n", 272 | "In addition to the ``AllData.clear()`` method, other ways of removing ``Spectrum`` objects (ie. data sets) from the container are shown below.\n", 273 | "\n", 274 | "First let's load some spectral data:" 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 9, 280 | "metadata": {}, 281 | "outputs": [], 282 | "source": [ 283 | "xspec.AllData.clear() # remove previously loaded files\n", 284 | "xspec.AllData(\"data/spec data/spec2 2:3 data/spec3\") # load some data into 2 groups\n", 285 | "s1 = xspec.AllData(1) # define spectrum s1\n", 286 | "\n" 287 | ] 288 | }, 289 | { 290 | "cell_type": "markdown", 291 | "metadata": {}, 292 | "source": [ 293 | "... and then remove some of the previously-loaded data:" 294 | ] 295 | }, 296 | { 297 | "cell_type": "code", 298 | "execution_count": 10, 299 | "metadata": {}, 300 | "outputs": [], 301 | "source": [ 302 | "xspec.AllData -= 3 # Removes the 3rd Spectrum object (the spectrum with index number 3) from the container.\n", 303 | "xspec.AllData -= s1 # Removes the Spectrum object s1.\n", 304 | "xspec.AllData -= \"*\" # Removes all Spectrum objects.\n", 305 | "\n" 306 | ] 307 | }, 308 | { 309 | "cell_type": "markdown", 310 | "metadata": {}, 311 | "source": [ 312 | "You can check the current state of the AllData container at any time by doing:\n" 313 | ] 314 | }, 315 | { 316 | "cell_type": "code", 317 | "execution_count": 11, 318 | "metadata": {}, 319 | "outputs": [], 320 | "source": [ 321 | "xspec.AllData(\"data/spec data/spec2 2:3 data/spec3\") # load some data, as above\n", 322 | "xspec.AllData.show() # this will print in your terminal window if using an ipython/jupyter notebook" 323 | ] 324 | }, 325 | { 326 | "cell_type": "markdown", 327 | "metadata": {}, 328 | "source": [ 329 | "Similarly, to view information about a single Spectrum object:\n", 330 | "\n" 331 | ] 332 | }, 333 | { 334 | "cell_type": "code", 335 | "execution_count": 12, 336 | "metadata": {}, 337 | "outputs": [], 338 | "source": [ 339 | "s3 = xspec.AllData(3)\n", 340 | "s3.show()" 341 | ] 342 | }, 343 | { 344 | "cell_type": "markdown", 345 | "metadata": {}, 346 | "source": [ 347 | "----\n", 348 | "\n", 349 | "# Defining Models\n", 350 | "\n", 351 | "The basic way of defining an ``XSPEC`` model is to create an object of the ``PyXspec`` class `Model`. Simply pass in a string containing a combination of 1 or more ``XSPEC`` model components. Since this uses the same syntax as ``XSPEC``'s ``model`` command, component abbreviations are allowed.\n", 352 | "\n", 353 | "\n", 354 | "To get a list of currently-defined models:" 355 | ] 356 | }, 357 | { 358 | "cell_type": "code", 359 | "execution_count": 13, 360 | "metadata": {}, 361 | "outputs": [], 362 | "source": [ 363 | "xspec.Model.showList()" 364 | ] 365 | }, 366 | { 367 | "cell_type": "markdown", 368 | "metadata": {}, 369 | "source": [ 370 | "Use the standard ``XSPEC`` syntax to define a model. Component abbreviations are allowed:" 371 | ] 372 | }, 373 | { 374 | "cell_type": "code", 375 | "execution_count": 14, 376 | "metadata": {}, 377 | "outputs": [], 378 | "source": [ 379 | "m1 = xspec.Model(\"wa*po + ga\")" 380 | ] 381 | }, 382 | { 383 | "cell_type": "markdown", 384 | "metadata": {}, 385 | "source": [ 386 | "\n", 387 | "\n", 388 | "\n", 389 | "When you define a model like this, PyXspec also automatically adds the new object to the global AllModels container. If the model is applied to multiple data groups, object copies are added to the container for each data group.\n", 390 | "\n", 391 | "Similar to the case of spectral data, you can also load models directly into the global container:\n", 392 | "\n" 393 | ] 394 | }, 395 | { 396 | "cell_type": "code", 397 | "execution_count": 15, 398 | "metadata": {}, 399 | "outputs": [], 400 | "source": [ 401 | "# Another way to define a new model and create an object for each data group.\n", 402 | "xspec.AllModels += \"wa*po + ga\"\n", 403 | "xspec.AllModels += \"wa*(apec + pow)\"\n", 404 | "\n", 405 | "# Retrieve the model object assigned to data group 1.\n", 406 | "m1 = xspec.AllModels(1)\n" 407 | ] 408 | }, 409 | { 410 | "cell_type": "code", 411 | "execution_count": 16, 412 | "metadata": {}, 413 | "outputs": [], 414 | "source": [ 415 | "# Various ways to remove all model objects from the container.\n", 416 | "xspec.AllModels.clear()\n", 417 | "xspec.AllModels -= \"*\"" 418 | ] 419 | }, 420 | { 421 | "cell_type": "markdown", 422 | "metadata": {}, 423 | "source": [ 424 | "So let's define a model:" 425 | ] 426 | }, 427 | { 428 | "cell_type": "code", 429 | "execution_count": 17, 430 | "metadata": {}, 431 | "outputs": [], 432 | "source": [ 433 | "\n", 434 | "xspec.AllModels.clear() # clear previously defined models\n", 435 | "xspec.AllModels += \"wa*po + ga\"" 436 | ] 437 | }, 438 | { 439 | "cell_type": "markdown", 440 | "metadata": {}, 441 | "source": [ 442 | "To display models and their parameters:" 443 | ] 444 | }, 445 | { 446 | "cell_type": "code", 447 | "execution_count": 18, 448 | "metadata": {}, 449 | "outputs": [], 450 | "source": [ 451 | "m1=xspec.AllModels(1)\n", 452 | "m1.show()" 453 | ] 454 | }, 455 | { 456 | "cell_type": "markdown", 457 | "metadata": {}, 458 | "source": [ 459 | "Show the defined model and all the current parameter values:" 460 | ] 461 | }, 462 | { 463 | "cell_type": "code", 464 | "execution_count": 19, 465 | "metadata": {}, 466 | "outputs": [], 467 | "source": [ 468 | "xspec.AllModels.show()" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 20, 474 | "metadata": {}, 475 | "outputs": [], 476 | "source": [ 477 | "# While this displays just parameters 1,2,3 and 5:\n", 478 | "xspec.AllModels.show(\"1-3, 5\")" 479 | ] 480 | }, 481 | { 482 | "cell_type": "markdown", 483 | "metadata": {}, 484 | "source": [ 485 | "If you have multiple data groups assigned, you can display the model parameters for each group. For example suppose we have 3 spectra, two in group one and the third in group 2. You can load the data, define a model to be applied to each group, and show the parameter values for the groups as follows:" 486 | ] 487 | }, 488 | { 489 | "cell_type": "code", 490 | "execution_count": 21, 491 | "metadata": {}, 492 | "outputs": [], 493 | "source": [ 494 | "xspec.AllData.clear() # remove previously loaded files\n", 495 | "xspec.AllData(\"data/spec data/spec2 2:3 data/spec3\") # load some data into 2 groups\n", 496 | "\n", 497 | "xspec.AllModels += \"Tbabs*apec\" # define a model to be applied to each group\n", 498 | "m1 = xspec.AllModels(1) # the model defined for group 1\n", 499 | "m2 = xspec.AllModels(2) # the model defined for group 2\n", 500 | "m1.show() # show parameters for m1\n", 501 | "m2.show() # show parameters for m2" 502 | ] 503 | }, 504 | { 505 | "cell_type": "markdown", 506 | "metadata": {}, 507 | "source": [ 508 | "Once a fit is performed, non-linked parameters in the two model groups will have different values, in general. For defining mulitple (or named) models and assigning multiple sources, please see the ``Extended Tutorial``.\n", 509 | "\n", 510 | "## Component and Parameter Objects\n", 511 | "\n", 512 | "Model objects contain Component objects and Component objects contain Parameter objects. There are several ways to access and set components and parameters individually (and if you want to change many parameter values at once, it may be faster to use the Model or AllModels setPars methods described in the next section). Examples of individual Component and Parameter object access are shown below.\n", 513 | "\n" 514 | ] 515 | }, 516 | { 517 | "cell_type": "markdown", 518 | "metadata": {}, 519 | "source": [ 520 | "Accessing components by name:" 521 | ] 522 | }, 523 | { 524 | "cell_type": "code", 525 | "execution_count": 22, 526 | "metadata": {}, 527 | "outputs": [ 528 | { 529 | "name": "stdout", 530 | "output_type": "stream", 531 | "text": [ 532 | "['PhoIndex', 'norm']\n" 533 | ] 534 | } 535 | ], 536 | "source": [ 537 | "# Component objects are accessible-by-name as Model object attributes:\n", 538 | "\n", 539 | "xspec.AllModels.clear()\n", 540 | "xspec.AllModels += \"wabs*pow + gauss\" # define a model to be applied to each group\n", 541 | "m1 = xspec.AllModels(1) # the model defined for group 1\n", 542 | "m2 = xspec.AllModels(2) # the model defined for group 2\n", 543 | "\n", 544 | "\n", 545 | "comp1 = m1.wabs\n", 546 | "comp2 = m1.powerlaw\n", 547 | "print comp2.parameterNames" 548 | ] 549 | }, 550 | { 551 | "cell_type": "markdown", 552 | "metadata": {}, 553 | "source": [ 554 | "Accessing component parameters by name:" 555 | ] 556 | }, 557 | { 558 | "cell_type": "code", 559 | "execution_count": 23, 560 | "metadata": {}, 561 | "outputs": [ 562 | { 563 | "name": "stdout", 564 | "output_type": "stream", 565 | "text": [ 566 | "Photon Index currently set to 1.0\n" 567 | ] 568 | } 569 | ], 570 | "source": [ 571 | "# Parameter objects are accessible-by-name as Component object attributes:\n", 572 | "par6 = m1.powerlaw.PhoIndex\n", 573 | "par6orig = par6.values[0]\n", 574 | "print \"Photon Index currently set to {0}\".format(par6.values[0])" 575 | ] 576 | }, 577 | { 578 | "cell_type": "markdown", 579 | "metadata": {}, 580 | "source": [ 581 | "Modifying parameter values" 582 | ] 583 | }, 584 | { 585 | "cell_type": "code", 586 | "execution_count": 24, 587 | "metadata": {}, 588 | "outputs": [ 589 | { 590 | "name": "stdout", 591 | "output_type": "stream", 592 | "text": [ 593 | "Photon Index was 1.0, now set to 3.5\n" 594 | ] 595 | } 596 | ], 597 | "source": [ 598 | "# ...and we can modify their values:\n", 599 | "par6.values = 3.5\n", 600 | "print \"Photon Index was {0}, now set to {1}\".format(par6orig, par6.values[0])\n", 601 | "m1.wabs.nH = 5.0\n", 602 | "comp2.PhoIndex = 1.5" 603 | ] 604 | }, 605 | { 606 | "cell_type": "markdown", 607 | "metadata": {}, 608 | "source": [ 609 | "You can also get a Parameter object directly from a Model, without going through a Component.\n", 610 | "Just pass the Model the Parameter index number:" 611 | ] 612 | }, 613 | { 614 | "cell_type": "code", 615 | "execution_count": 25, 616 | "metadata": {}, 617 | "outputs": [ 618 | { 619 | "name": "stdout", 620 | "output_type": "stream", 621 | "text": [ 622 | "Parameter 5 name = 'Sigma'. Hi Sigma!\n" 623 | ] 624 | } 625 | ], 626 | "source": [ 627 | "par5 = m1(5)\n", 628 | "print \"Parameter 5 name = '{0}'. Hi {0}!\".format(par5.name)" 629 | ] 630 | }, 631 | { 632 | "cell_type": "markdown", 633 | "metadata": {}, 634 | "source": [ 635 | "Some examples of numerical operations allowed with Parameter objects:" 636 | ] 637 | }, 638 | { 639 | "cell_type": "code", 640 | "execution_count": 26, 641 | "metadata": {}, 642 | "outputs": [], 643 | "source": [ 644 | "par4 = m1(4)\n", 645 | "par4 += 0.75 # increment parameter 4 by 0.75\n", 646 | "par4 *= 2.0 # multiply parameter 4 value by 2.0\n", 647 | "y1 = m1.wabs.nH*100.0 # set y1 to 100x the column density of model m1\n", 648 | "y2 = par4 + par5 # set y2 to the sum of par4 + par 5" 649 | ] 650 | }, 651 | { 652 | "cell_type": "code", 653 | "execution_count": 27, 654 | "metadata": {}, 655 | "outputs": [ 656 | { 657 | "data": { 658 | "text/plain": [ 659 | "[14.5, 0.145, 0.0, 0.0, 1000000.0, 1000000.0]" 660 | ] 661 | }, 662 | "execution_count": 27, 663 | "metadata": {}, 664 | "output_type": "execute_result" 665 | } 666 | ], 667 | "source": [ 668 | "par4.values" 669 | ] 670 | }, 671 | { 672 | "cell_type": "markdown", 673 | "metadata": {}, 674 | "source": [ 675 | "For models with duplicate copies of components, see the ``Extended Tutorial`` for accessing Component objects by name.\n", 676 | "\n", 677 | "Note that in the above examples, only the parameter's value is being accessed or modified. To change all or part of its FULL list of settings (including auxiliary values: value, fit delta, min, bot, top, max), you can set its values attribute to a tuple or list of size 1-6:\n" 678 | ] 679 | }, 680 | { 681 | "cell_type": "code", 682 | "execution_count": 28, 683 | "metadata": {}, 684 | "outputs": [], 685 | "source": [ 686 | "par4.values = 4.3, .01, 1e-3\n", 687 | "par4.values = [4.3, .01, 1e-3, 1e-2, 100, 200]" 688 | ] 689 | }, 690 | { 691 | "cell_type": "markdown", 692 | "metadata": {}, 693 | "source": [ 694 | "Or for greater flexibility you can set it to a string using Standard XSPEC's newpar command syntax:" 695 | ] 696 | }, 697 | { 698 | "cell_type": "code", 699 | "execution_count": 29, 700 | "metadata": {}, 701 | "outputs": [], 702 | "source": [ 703 | "# This allows you to set new values non-consecutively.\n", 704 | "par4.values = \"1.0, -.01,,,,150\"" 705 | ] 706 | }, 707 | { 708 | "cell_type": "markdown", 709 | "metadata": {}, 710 | "source": [ 711 | "A quick way to freeze or thaw a parameter is to toggle its frozen attribute:\n", 712 | "\n", 713 | "\n" 714 | ] 715 | }, 716 | { 717 | "cell_type": "code", 718 | "execution_count": 30, 719 | "metadata": {}, 720 | "outputs": [], 721 | "source": [ 722 | "par4.frozen = False\n", 723 | "par5.frozen = True" 724 | ] 725 | }, 726 | { 727 | "cell_type": "markdown", 728 | "metadata": {}, 729 | "source": [ 730 | "To link a parameter to one or more others, set its link attribute to a link expression string as you would have with the newpar command. To remove the link, set link to an empty string or call the parameter's untie method.\n", 731 | "\n", 732 | "\n" 733 | ] 734 | }, 735 | { 736 | "cell_type": "code", 737 | "execution_count": 31, 738 | "metadata": {}, 739 | "outputs": [], 740 | "source": [ 741 | "par5.link = \"2.3 * 4\" # Link par 5 to par 4 with a multiplicative constant.\n", 742 | "par5.link = \"\" # Removes the link.\n", 743 | "par5.untie() # Also removes the link.\n" 744 | ] 745 | }, 746 | { 747 | "cell_type": "markdown", 748 | "metadata": {}, 749 | "source": [ 750 | "Also ALL linked parameters in a model object can be untied with a single call to the Model class untie method, as show below." 751 | ] 752 | }, 753 | { 754 | "cell_type": "code", 755 | "execution_count": 32, 756 | "metadata": {}, 757 | "outputs": [], 758 | "source": [ 759 | "m1.untie()" 760 | ] 761 | }, 762 | { 763 | "cell_type": "markdown", 764 | "metadata": {}, 765 | "source": [ 766 | "To display a parameter's full set of values (including auxiliary values), just print its values attribute:" 767 | ] 768 | }, 769 | { 770 | "cell_type": "code", 771 | "execution_count": 33, 772 | "metadata": {}, 773 | "outputs": [ 774 | { 775 | "name": "stdout", 776 | "output_type": "stream", 777 | "text": [ 778 | "The value of Parameter 4 and its auxiliary values are: [1.0, 0.01, 0.001, 0.01, 100.0, 150.0]\n", 779 | "\n", 780 | "Current value = 1.0\n", 781 | "Current delta = 0.01\n", 782 | "Current soft minimum = 0.001\n", 783 | "Current hard minimum = 0.01\n", 784 | "Current soft maximum = 100.0\n", 785 | "Current hard maximum = 150.0\n" 786 | ] 787 | } 788 | ], 789 | "source": [ 790 | "print \"The value of Parameter 4 and its auxiliary values are: {0}\".format(par4.values)\n", 791 | "print \"\\nCurrent value = {0}\".format(par4.values[0])\n", 792 | "print \"Current delta = {0}\".format(par4.values[1])\n", 793 | "print \"Current soft minimum = {0}\".format(par4.values[2])\n", 794 | "print \"Current hard minimum = {0}\".format(par4.values[3])\n", 795 | "print \"Current soft maximum = {0}\".format(par4.values[4])\n", 796 | "print \"Current hard maximum = {0}\".format(par4.values[5])" 797 | ] 798 | }, 799 | { 800 | "cell_type": "markdown", 801 | "metadata": {}, 802 | "source": [ 803 | "## Setting Multiple Parameters At A Time\n", 804 | "\n", 805 | "You can set multiple parameter values with a single call using the Model or AllModels setPars methods. This may be considerably faster than setting parameters one at a time through the individual Parameter objects as shown in the previous section. With setPars, the model will be recalculated just ONCE after all the changes have been made. But when setting through individual Parameter objects, the model will be recalculated after EACH parameter change.\n", 806 | "\n", 807 | "\n" 808 | ] 809 | }, 810 | { 811 | "cell_type": "code", 812 | "execution_count": 34, 813 | "metadata": {}, 814 | "outputs": [], 815 | "source": [ 816 | "# For Model object m1, supply 1 or more new parameter values in consecutive order:\n", 817 | "m1.setPars(2.5, 1.4, 1.0e3) # This changes pars 1, 2, and 3.\n" 818 | ] 819 | }, 820 | { 821 | "cell_type": "code", 822 | "execution_count": 35, 823 | "metadata": {}, 824 | "outputs": [], 825 | "source": [ 826 | "# Can also change paramater auxiliary values by passing a string using the same\n", 827 | "# syntax as with Standard XSPEC's newpar command:\n", 828 | "m1.setPars(.95, \"1.8,,-5,-4,10,10\")" 829 | ] 830 | }, 831 | { 832 | "cell_type": "code", 833 | "execution_count": 36, 834 | "metadata": {}, 835 | "outputs": [], 836 | "source": [ 837 | "# Now set parameters NON-CONSECUTIVELY by passing a Python dictionary object.\n", 838 | "# This example changes pars 1, 2, 4, and 6:\n", 839 | "m1.setPars(.95, 1.2, {4:9.8, 6:2.0})\n" 840 | ] 841 | }, 842 | { 843 | "cell_type": "markdown", 844 | "metadata": {}, 845 | "source": [ 846 | "Parameters can also be initialized by passing values to the Model object constructor. You do this by setting the Model constructor's setPars keyword argument to a tuple, list, or dictionary (or just a single value or string if only setting the first parameter):" 847 | ] 848 | }, 849 | { 850 | "cell_type": "code", 851 | "execution_count": 37, 852 | "metadata": {}, 853 | "outputs": [], 854 | "source": [ 855 | "# Supply values for parameters 1 and 3, use defaults for the rest.\n", 856 | "m = xspec.Model(\"wa*ga\", setPars={1:1.5, 3:.2})" 857 | ] 858 | }, 859 | { 860 | "cell_type": "code", 861 | "execution_count": 38, 862 | "metadata": {}, 863 | "outputs": [], 864 | "source": [ 865 | "# Supply values for 1 and 2, use defaults for the rest.\n", 866 | "m = xspec.Model(\"wa*ga\", setPars=(1.5, 0.7))" 867 | ] 868 | }, 869 | { 870 | "cell_type": "code", 871 | "execution_count": 39, 872 | "metadata": {}, 873 | "outputs": [], 874 | "source": [ 875 | "# Supply value only for 1.\n", 876 | "m = xspec.Model(\"wa*ga\", setPars=1.5)" 877 | ] 878 | }, 879 | { 880 | "cell_type": "markdown", 881 | "metadata": {}, 882 | "source": [ 883 | "Finally, if you wish to set multiple parameters that belong to different model objects, you must use the AllModels container's `setPars` method. This is a quick way to change multiple parameter values at a time\n", 884 | "since only a **SINGLE** recalculation will be performed at the end.\n", 885 | "In contrast, when parameter values are changed through the individual \n", 886 | "parameter objects, the model is recalculated after EACH parameter\n", 887 | "change. (If all the parameters belong to a single model object,\n", 888 | "you can also use the Model.setPars() function.)This follows the same syntax rules as the single Model setPars, except that you also supply the Model objects as arguments:\n", 889 | "\n" 890 | ] 891 | }, 892 | { 893 | "cell_type": "code", 894 | "execution_count": 40, 895 | "metadata": {}, 896 | "outputs": [ 897 | { 898 | "name": "stdout", 899 | "output_type": "stream", 900 | "text": [ 901 | "Value of Parameter 1 in m1 = 6.40, and in m2 = 6.70\n", 902 | "Value of Parameter 3 in m1 = 1.78, and in m2 = 1.00\n" 903 | ] 904 | } 905 | ], 906 | "source": [ 907 | "#\n", 908 | "# Load 2 spectra into 2 separate data groups\n", 909 | "#\n", 910 | "xspec.AllData.clear()\n", 911 | "xspec.AllData += \"data/spec.pha\" # read spectrum into first data group\n", 912 | "# Explicitly specify the response if necessary\n", 913 | "xspec.AllData(1).response = \"data/spec.rmf\" # this response include the effective area (ARF) information\n", 914 | "\n", 915 | "xspec.AllData(\"2:2 data/spec_sim.pha\") # read spectrum into data group 2\n", 916 | "# Explicitly specify the response, if necessary\n", 917 | "xspec.AllData(2).response = \"data/spec3.rmf\" # response includes the ARF already\n", 918 | "\n", 919 | "#\n", 920 | "# use AllModels.setPars to Change pars 1 and 3 in m1, and pars 1 and 2 in m2\n", 921 | "#\n", 922 | "xspec.AllModels.clear() # clear previous models\n", 923 | "xspec.AllModels += \"gauss + pow\"\n", 924 | "xspec.AllModels += \"TBabs*apec\"\n", 925 | "m1 = xspec.AllModels(1)\n", 926 | "m2 = xspec.AllModels(2)\n", 927 | "xspec.AllModels.setPars(m1, {1:6.4, 3:1.78}, m2, {1:6.7, 3:5.5})\n", 928 | "print \"Value of Parameter 1 in m1 = {0:3.2f}, and in m2 = {1:3.2f}\".format(m1(1).values[0], m2(1).values[0])\n", 929 | "print \"Value of Parameter 3 in m1 = {0:3.2f}, and in m2 = {1:3.2f}\".format(m1(3).values[0], m2(3).values[0])" 930 | ] 931 | }, 932 | { 933 | "cell_type": "markdown", 934 | "metadata": {}, 935 | "source": [ 936 | "----\n", 937 | "\n", 938 | "# Fitting\n", 939 | "\n", 940 | "Once data and models are loaded, you can fit the model to the data usint the Fit object. First you probably want to adjust the fitting parameters:\n", 941 | "\n", 942 | "\n", 943 | "\n" 944 | ] 945 | }, 946 | { 947 | "cell_type": "code", 948 | "execution_count": 41, 949 | "metadata": {}, 950 | "outputs": [], 951 | "source": [ 952 | "xspec.Fit.nIterations = 100" 953 | ] 954 | }, 955 | { 956 | "cell_type": "markdown", 957 | "metadata": {}, 958 | "source": [ 959 | "You can set an appropriate fit statistic (``cstat``, ``chi``, etc) by assigning a value to ``xspec.Fit.statMethod``. Below we use the ``cstat`` statistic" 960 | ] 961 | }, 962 | { 963 | "cell_type": "code", 964 | "execution_count": 42, 965 | "metadata": {}, 966 | "outputs": [], 967 | "source": [ 968 | "xspec.Fit.statMethod = \"cstat\"" 969 | ] 970 | }, 971 | { 972 | "cell_type": "markdown", 973 | "metadata": {}, 974 | "source": [ 975 | "Fitting is performed by calling the perform method of the Fit global object:" 976 | ] 977 | }, 978 | { 979 | "cell_type": "code", 980 | "execution_count": 43, 981 | "metadata": {}, 982 | "outputs": [], 983 | "source": [ 984 | "xspec.Fit.perform()" 985 | ] 986 | }, 987 | { 988 | "cell_type": "markdown", 989 | "metadata": {}, 990 | "source": [ 991 | "To display the fit results:" 992 | ] 993 | }, 994 | { 995 | "cell_type": "code", 996 | "execution_count": 44, 997 | "metadata": {}, 998 | "outputs": [], 999 | "source": [ 1000 | "xspec.Fit.show()" 1001 | ] 1002 | }, 1003 | { 1004 | "cell_type": "markdown", 1005 | "metadata": {}, 1006 | "source": [ 1007 | "Please see the class reference guide and the ``Extended Tutorial`` for `Fit`'s complete functionality." 1008 | ] 1009 | }, 1010 | { 1011 | "cell_type": "markdown", 1012 | "metadata": {}, 1013 | "source": [ 1014 | "____\n", 1015 | "\n", 1016 | "# Plotting\n", 1017 | "\n", 1018 | "In Standard XSPEC, plot settings are adjusted using the ``setplot`` command while the plot is displayed through the plot command. In PyXspec, all plot settings and functionality is handled through the global Plot object. A device must be set before any plots can be displayed, and this done through the device attribute:\n", 1019 | "\n", 1020 | "`xspec.Plot.device = \"/xs\"`\n", 1021 | "\n", 1022 | "The device can also be set to print to an output file in several formats. The list of possible devices is given by the ``cpd`` command in the XSPEC manual.\n", 1023 | "\n", 1024 | "A typical setting to adjust is the X-axis units. You can choose to plot channel numbers, or select from various energy and wavelength units. The strings can also be abbreviated. Examples:\n", 1025 | "\n", 1026 | "```\n", 1027 | "xspec.Plot.xAxis = \"channel\"\n", 1028 | "xspec.Plot.xAxis = \"MeV\"\n", 1029 | "xspec.Plot.xAxis = \"Hz\"\n", 1030 | "xspec.Plot.xAxis = \"angstrom\"\n", 1031 | "```\n", 1032 | "\n", 1033 | "The displays of individual additive components or background spectra is toggled by setting their attributes to a bool:\n", 1034 | "\n", 1035 | "```\n", 1036 | "xspec.Plot.add = True\n", 1037 | "xspec.Plot.background = False\n", 1038 | "```\n", 1039 | "\n", 1040 | "Similarly log/linear settings for data plots (when using energy or wavelength units):\n", 1041 | "\n", 1042 | "```\n", 1043 | "xspec.Plot.xLog = True\n", 1044 | "xspec.Plot.yLog = False\n", 1045 | "```\n", 1046 | "\n", 1047 | "The current plot settings are displayed with:\n", 1048 | "\n", 1049 | "`xspec.Plot.show()`\n", 1050 | "\n", 1051 | "To actually display a plot, send 1 or more string arguments to ``xspec.Plot``. The standard ``XSPEC`` plot types are all allowed. Some common plot types are:\n", 1052 | "* ``data`` - a plot of the data (normalized cts s$^{-1}$ keV$^{-1}$\n", 1053 | "* ``ldata`` - data plotted logaritmically\n", 1054 | "* ``ufs`` - \"unfolded\" spectra (photons instead of counts)\n", 1055 | "* ``model`` - a plot of the defined model\n", 1056 | "* ``background`` - plot the background spectrum\n", 1057 | "\n", 1058 | "The full list of plot types:\n", 1059 | "```\n", 1060 | "\tbackground chain chisq contour counts\n", 1061 | "\tintegprob data delchi dem emodel\n", 1062 | "\teemodel efficiency eqw eufspec eeufspec\n", 1063 | "\tfoldmodel goodness icounts insensitivity lcounts\n", 1064 | "\tldata margin model ratio residuals\n", 1065 | "\tsensitivity sum ufspec\n", 1066 | "```\n", 1067 | "\n", 1068 | "Some examples:\n" 1069 | ] 1070 | }, 1071 | { 1072 | "cell_type": "markdown", 1073 | "metadata": {}, 1074 | "source": [ 1075 | "* Single panel plots vs. Energy in keV:" 1076 | ] 1077 | }, 1078 | { 1079 | "cell_type": "code", 1080 | "execution_count": 45, 1081 | "metadata": {}, 1082 | "outputs": [], 1083 | "source": [ 1084 | "xspec.Plot.xAxis = \"keV\"\n", 1085 | "xspec.Plot.device = \"/xs\"\n", 1086 | "xspec.Plot.setRebin = \"3., 10\" # rebin the data in the plot \n", 1087 | "xspec.Plot(\"ldata\")" 1088 | ] 1089 | }, 1090 | { 1091 | "cell_type": "markdown", 1092 | "metadata": {}, 1093 | "source": [ 1094 | "* plot the model to a single panel" 1095 | ] 1096 | }, 1097 | { 1098 | "cell_type": "code", 1099 | "execution_count": 46, 1100 | "metadata": {}, 1101 | "outputs": [], 1102 | "source": [ 1103 | "xspec.Plot(\"model\")" 1104 | ] 1105 | }, 1106 | { 1107 | "cell_type": "markdown", 1108 | "metadata": {}, 1109 | "source": [ 1110 | "* plot the unfolded spectrum" 1111 | ] 1112 | }, 1113 | { 1114 | "cell_type": "code", 1115 | "execution_count": 47, 1116 | "metadata": {}, 1117 | "outputs": [], 1118 | "source": [ 1119 | "xspec.Plot(\"ufspec\")" 1120 | ] 1121 | }, 1122 | { 1123 | "cell_type": "markdown", 1124 | "metadata": {}, 1125 | "source": [ 1126 | "For multi-panel plots, simply add another plot type to the call to ``xspec.Plot``:" 1127 | ] 1128 | }, 1129 | { 1130 | "cell_type": "code", 1131 | "execution_count": 48, 1132 | "metadata": {}, 1133 | "outputs": [], 1134 | "source": [ 1135 | "# Multi panel plots\n", 1136 | "xspec.Plot(\"data chisq\")\n" 1137 | ] 1138 | }, 1139 | { 1140 | "cell_type": "code", 1141 | "execution_count": 49, 1142 | "metadata": {}, 1143 | "outputs": [], 1144 | "source": [ 1145 | "xspec.Plot(\"data\",\"model\",\"resid\")" 1146 | ] 1147 | }, 1148 | { 1149 | "cell_type": "markdown", 1150 | "metadata": {}, 1151 | "source": [ 1152 | "* Calling ``xspec.Plot()`` with no arguments repeats the previous plot command" 1153 | ] 1154 | }, 1155 | { 1156 | "cell_type": "code", 1157 | "execution_count": 50, 1158 | "metadata": {}, 1159 | "outputs": [], 1160 | "source": [ 1161 | "xspec.Plot()" 1162 | ] 1163 | }, 1164 | { 1165 | "cell_type": "markdown", 1166 | "metadata": {}, 1167 | "source": [ 1168 | "After displaying a plot, you can get an array of the plotted values by calling one of ``xspec.Plot``'s retrieval methods. All of these functions take an optional plot group number argument for the case of multiple plot groups, and all return the plot values in a Python list." 1169 | ] 1170 | }, 1171 | { 1172 | "cell_type": "code", 1173 | "execution_count": 51, 1174 | "metadata": {}, 1175 | "outputs": [ 1176 | { 1177 | "data": { 1178 | "text/plain": [ 1179 | "[]" 1180 | ] 1181 | }, 1182 | "execution_count": 51, 1183 | "metadata": {}, 1184 | "output_type": "execute_result" 1185 | }, 1186 | { 1187 | "data": { 1188 | "image/png": "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\n", 1189 | "text/plain": [ 1190 | "
" 1191 | ] 1192 | }, 1193 | "metadata": {}, 1194 | "output_type": "display_data" 1195 | } 1196 | ], 1197 | "source": [ 1198 | "xspec.Plot(\"data\")\n", 1199 | "xVals = xspec.Plot.x()\n", 1200 | "yVals = xspec.Plot.y()\n", 1201 | "yVals2 = xspec.Plot.y(1) # Gets values for data in the first plot group\n", 1202 | "modVals = xspec.Plot.model()\n", 1203 | "plt.plot(xVals, yVals)" 1204 | ] 1205 | }, 1206 | { 1207 | "cell_type": "markdown", 1208 | "metadata": {}, 1209 | "source": [ 1210 | "You can get the background array for plotting but you need to set the ``xspec.Plot.background`` attribute to True first:" 1211 | ] 1212 | }, 1213 | { 1214 | "cell_type": "code", 1215 | "execution_count": 52, 1216 | "metadata": {}, 1217 | "outputs": [], 1218 | "source": [ 1219 | "xspec.Plot.background = True\n", 1220 | "xspec.Plot(\"data\")\n", 1221 | "bkg = xspec.Plot.backgroundVals()" 1222 | ] 1223 | }, 1224 | { 1225 | "cell_type": "markdown", 1226 | "metadata": {}, 1227 | "source": [ 1228 | "You can also get the error array values for the X and Y axes:" 1229 | ] 1230 | }, 1231 | { 1232 | "cell_type": "code", 1233 | "execution_count": 53, 1234 | "metadata": {}, 1235 | "outputs": [], 1236 | "source": [ 1237 | "# Retrieve error arrays\n", 1238 | "xErrs = xspec.Plot.xErr()\n", 1239 | "yErrs = xspec.Plot.yErr()" 1240 | ] 1241 | }, 1242 | { 1243 | "cell_type": "markdown", 1244 | "metadata": {}, 1245 | "source": [ 1246 | "----\n", 1247 | "\n", 1248 | "# Simulating Spectra\n", 1249 | "\n", 1250 | "You can also create simulated spectra with PyXspec just as in the non-Python version. The steps are very similar: define a model; read in an instrument response; then convolve the model through the response using the ``AllData`` container's ``Fakeit`` method " 1251 | ] 1252 | }, 1253 | { 1254 | "cell_type": "markdown", 1255 | "metadata": {}, 1256 | "source": [ 1257 | "## Clear any previously loaded data and models" 1258 | ] 1259 | }, 1260 | { 1261 | "cell_type": "code", 1262 | "execution_count": 54, 1263 | "metadata": {}, 1264 | "outputs": [], 1265 | "source": [ 1266 | "#\n", 1267 | "# create simulated spectrum; first clear any previously loaded data and models\n", 1268 | "#\n", 1269 | "xspec.AllData.clear() \n", 1270 | "xspec.AllModels.clear()" 1271 | ] 1272 | }, 1273 | { 1274 | "cell_type": "markdown", 1275 | "metadata": {}, 1276 | "source": [ 1277 | "## Define A Model" 1278 | ] 1279 | }, 1280 | { 1281 | "cell_type": "code", 1282 | "execution_count": 55, 1283 | "metadata": {}, 1284 | "outputs": [], 1285 | "source": [ 1286 | "mo = xspec.Model(\"tbabs*(apec + gauss + pow)\")\n", 1287 | "# set parameter 1 (NH), 2 (kT), 5 (norm), 7 (sigma) 8 (line norm) and 10 (power law norm) to reasonable cosmic values\n", 1288 | "mo.setPars({1:4}, {2:50}, {5:0.01}, {7:0.01}, {8:1e-2}, {10:.1}) " 1289 | ] 1290 | }, 1291 | { 1292 | "cell_type": "markdown", 1293 | "metadata": {}, 1294 | "source": [ 1295 | "## Run ``xspec.AllData.fakeit()``" 1296 | ] 1297 | }, 1298 | { 1299 | "cell_type": "code", 1300 | "execution_count": 56, 1301 | "metadata": {}, 1302 | "outputs": [], 1303 | "source": [ 1304 | "expo = 1e5 # use an exposure time of 100,000 seconds\n", 1305 | "fs = xspec.FakeitSettings(response = 'data/spec3.rmf', background='data/spec3_bkg.pha', exposure=str(expo), \n", 1306 | " fileName='data/spec_sim.pha')\n", 1307 | "xspec.AllData.fakeit(1,fs)" 1308 | ] 1309 | }, 1310 | { 1311 | "cell_type": "markdown", 1312 | "metadata": {}, 1313 | "source": [ 1314 | "## Plot the Data\n", 1315 | "\n", 1316 | "Let's plot the simulated data in Python" 1317 | ] 1318 | }, 1319 | { 1320 | "cell_type": "code", 1321 | "execution_count": 57, 1322 | "metadata": {}, 1323 | "outputs": [ 1324 | { 1325 | "data": { 1326 | "text/plain": [ 1327 | "[]" 1328 | ] 1329 | }, 1330 | "execution_count": 57, 1331 | "metadata": {}, 1332 | "output_type": "execute_result" 1333 | }, 1334 | { 1335 | "data": { 1336 | "image/png": "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\n", 1337 | "text/plain": [ 1338 | "
" 1339 | ] 1340 | }, 1341 | "metadata": {}, 1342 | "output_type": "display_data" 1343 | } 1344 | ], 1345 | "source": [ 1346 | "pha = xspec.AllData(1)\n", 1347 | "xspec.Plot.device=\"/null\"\n", 1348 | "xspec.Plot.setRebin = \"3., 10\"\n", 1349 | "xspec.Plot.xAxis = 'keV'\n", 1350 | "xspec.Plot('data')\n", 1351 | "yscale('log')\n", 1352 | "ylim(0.0001,1)\n", 1353 | "xlabel('Energy (keV)')\n", 1354 | "ylabel('Normalized Cts/s/keV')\n", 1355 | "plot(xspec.Plot.x(1), xspec.Plot.y(1))" 1356 | ] 1357 | }, 1358 | { 1359 | "cell_type": "code", 1360 | "execution_count": null, 1361 | "metadata": {}, 1362 | "outputs": [], 1363 | "source": [] 1364 | } 1365 | ], 1366 | "metadata": { 1367 | "kernelspec": { 1368 | "display_name": "Python 2", 1369 | "language": "python", 1370 | "name": "python2" 1371 | }, 1372 | "language_info": { 1373 | "codemirror_mode": { 1374 | "name": "ipython", 1375 | "version": 2 1376 | }, 1377 | "file_extension": ".py", 1378 | "mimetype": "text/x-python", 1379 | "name": "python", 1380 | "nbconvert_exporter": "python", 1381 | "pygments_lexer": "ipython2", 1382 | "version": "2.7.16" 1383 | }, 1384 | "nav_menu": { 1385 | "height": "229px", 1386 | "width": "265px" 1387 | }, 1388 | "toc": { 1389 | "navigate_menu": true, 1390 | "number_sections": false, 1391 | "sideBar": true, 1392 | "threshold": 6, 1393 | "toc_cell": false, 1394 | "toc_section_display": "block", 1395 | "toc_window_display": true 1396 | } 1397 | }, 1398 | "nbformat": 4, 1399 | "nbformat_minor": 1 1400 | } 1401 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pyxspec-tutorial 2 | jupyter notebook version of the pxspec tutorials. The original pdf versions of the pyxspec tutorials can be found at 3 | 4 | https://heasarc.gsfc.nasa.gov/xanadu/xspec/python/html/quick.html 5 | 6 | and 7 | 8 | https://heasarc.gsfc.nasa.gov/xanadu/xspec/python/html/extended.html 9 | 10 | -------------------------------------------------------------------------------- /data/spec.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec.pha -------------------------------------------------------------------------------- /data/spec.rmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec.rmf -------------------------------------------------------------------------------- /data/spec2.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec2.pha -------------------------------------------------------------------------------- /data/spec2_bkg.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec2_bkg.pha -------------------------------------------------------------------------------- /data/spec3.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec3.pha -------------------------------------------------------------------------------- /data/spec3.rmf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec3.rmf -------------------------------------------------------------------------------- /data/spec3_bkg.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec3_bkg.pha -------------------------------------------------------------------------------- /data/spec_bkg.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec_bkg.pha -------------------------------------------------------------------------------- /data/spec_sim.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec_sim.pha -------------------------------------------------------------------------------- /data/spec_sim_bkg.pha: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mfacorcoran/pyxspec-tutorial/5bccaea478def1b00b367c194729d0b56a42ded7/data/spec_sim_bkg.pha --------------------------------------------------------------------------------