{"action":"created","comment":{"url":"https://api.github.com/repos/XENON1T/hax/pulls/comments/54595795","id":54595795,"diff_hunk":"@@ -0,0 +1,154 @@\n+##\n+## Plot some data on the PMT arrays\n+##\n+## Jelle, February 2016\n+## May go into hax soon...\n+##\n+## Known issue's I'm to lazy to fix right now:\n+##  - on physical layout, color and/or size probably not on same scale in two subplots \n+##    unless vmin&vmax are specified explicitly.\n+##  - Have categorical labels event if _channel present. Make digitizer obey _channel suffix convention.\n+\n+import numpy as np\n+import matplotlib\n+import matplotlib.pyplot as plt\n+import pandas as pd\n+\n+from pax import units\n+from pax.configuration import load_configuration\n+\n+from hax.utils import flatten_dict\n+\n+##\n+# Load the PMT data from the pax configuration\n+##\n+\n+# Convert PMT/channel map to record array\n+config = load_configuration('XENON1T')\n+\n+pmt_data = pd.DataFrame([flatten_dict(info, sep='_') for info in config['DEFAULT']['pmts']])\n+\n+pmt_data['PMT'] = pmt_data['pmt_position']\n+del pmt_data['pmt_position']\n+\n+# Split connector + channel information into separate fields\n+# Note to anyone reading this: always make separate fields for separate information\n+for keyname in ('high_voltage_connector', 'signal_connector'):\n+    main = [int(q.split('.')[0]) for q in pmt_data[keyname]]\n+    channel = [int(q.split('.')[1]) for q in pmt_data[keyname]]\n+    pmt_data[keyname] = main\n+    pmt_data[keyname + '_channel'] = channel\n+        \n+pmt_numbering_start = pmt_data['PMT'].min()\n+\n+##\n+# Plotting functions\n+##\n+\n+def _plot_pmts(ax, pmt_selection, \n+               xkey, ykey=None, \n+               color=None, size=None, tight_limits=False, \n+               **kwargs):\n+    \"\"\"Makes a scatter plot of pmts for which pmt_selection is True on axes, using xkey and ykey for x, y.\n+    Reliese on pmt_data being present as global.\n+    Returns the return value of plt.scatter (useful to define a color bar)\n+    \"\"\"\n+    global pmt_data\n+    if ykey is not None:\n+        x, y, pmt_numbers = pmt_data[pmt_selection][[xkey, ykey, 'PMT']].as_matrix().T\n+        xlabel = xkey\n+        ylabel = ykey\n+    else:\n+        plot_keys, pmt_numbers = pmt_data[pmt_selection][[xkey, 'PMT']].as_matrix().T\n+        \n+        labels = sorted(list(set(plot_keys)))\n+        from collections import defaultdict\n+        n_occs = defaultdict(float)\n+        y = []\n+        x = []\n+        for i, k in enumerate(plot_keys):\n+            x.append(labels.index(k))\n+            y.append(n_occs[k])\n+            n_occs[k] += 1\n+            \n+        xlabel=xkey\n+        ylabel=''\n+    \n+    # Plot the PMT as circles with specified colors and sizes\n+    sc = ax.scatter(x, y, \n+                    c=color[pmt_selection], s=size[pmt_selection], \n+                    **kwargs)\n+    \n+    # Show the PMT id texts\n+    for i in range(len(x)):\n+        ax.text(x[i], y[i], int(pmt_numbers[i]),\n+                fontsize=8, va='center', ha='center')\n+                   \n+    # Set limits and labels\n+    lim_scale = 1.3\n+    if tight_limits:\n+        ax.set_xlim(x.min() * lim_scale, x.max() * lim_scale)\n+        ax.set_ylim(y.min() * lim_scale, y.max() * lim_scale)\n+    if ykey is None:\n+        plt.xticks(np.arange(len(labels)), labels, rotation='vertical')\n+        #ax.set_xticks(x)\n+        #ax.set_xticklabels(labels, rotation='vertical')\n+    ax.set_xlabel(xlabel)\n+    ax.set_ylabel(ylabel)   \n+                   \n+    return sc\n+\n+\n+def plot_on_pmt_arrays(color=None, size=None,\n+                       geometry='physical',\n+                       textcolor='white', fontsize=8,\n+                       scatter_kwargs=None, colorbar_kwargs=None):\n+    \"\"\"Plot a scatter plot of PMTs in a specified geometry, with a specified color and size of the markers.\n+        scatter_kwargs will be passed to plt.scatter\n+        colorbar_kwargs will be passed to plt.colorbar\n+        geometry can be 'physical', or any key from pmt_data\n+    Relies on 'pmt_data' being present as a global\n+    \"\"\"\n+    if scatter_kwargs is None:\n+        scatter_kwargs = dict()\n+    if colorbar_kwargs is None:\n+        colorbar_kwargs = dict()\n+    if size is None:\n+        if color is None:\n+            raise ValueError(\"Give me at least size or color\")\n+        size = 1000 * color/np.nanmean(color)\n+    if color is None:\n+        color = 'blue'\n+        \n+    if geometry == 'physical':\n+        # For the physical geometry, plot the top and bottom arrays side-by-side.\n+        _, (ax1, ax2) = plt.subplots(1, 2, sharey=True, figsize=(20, 7))\n+                   \n+        for array_name, ax in (('top', ax1), ('bottom', ax2)):\n+            sc = _plot_pmts(ax=ax, \n+                            pmt_selection=(pmt_data['array'] == array_name).as_matrix(), \n+                            xkey='position_x', ykey='position_y', \n+                            color=color, size=size, \n+                            tight_limits=True, **scatter_kwargs)\n+            ax.set_title('%s array' % array_name.capitalize())\n+                   \n+        cax, _ = matplotlib.colorbar.make_axes([ax1, ax2])\n+        plt.colorbar(sc, cax=cax, **colorbar_kwargs)\n+            \n+    else:\n+        plt.figure(figsize=(20, 8))\n+        if geometry + '_channel' in pmt_data.columns:\n+            sc = _plot_pmts(ax=plt.gca(), \n+                            pmt_selection=slice(None), \n+                            xkey=geometry, ykey=geometry + '_channel',\n+                            color=color, size=size,\n+                            **scatter_kwargs)\n+            plt.colorbar(sc, **colorbar_kwargs)\n+            \n+        else:\n+            sc = _plot_pmts(ax=plt.gca(), \n+                            pmt_selection=slice(None), ","path":"hax/pmt_plot.py","position":150,"original_position":150,"commit_id":"4f1d7868ad55b2bf110f136a73e90c8b94c77e2d","original_commit_id":"4f1d7868ad55b2bf110f136a73e90c8b94c77e2d","user":{"login":"tunnell","id":2406627,"avatar_url":"https://avatars.githubusercontent.com/u/2406627?v=3","gravatar_id":"","url":"https://api.github.com/users/tunnell","html_url":"https://github.com/tunnell","followers_url":"https://api.github.com/users/tunnell/followers","following_url":"https://api.github.com/users/tunnell/following{/other_user}","gists_url":"https://api.github.com/users/tunnell/gists{/gist_id}","starred_url":"https://api.github.com/users/tunnell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/tunnell/subscriptions","organizations_url":"https://api.github.com/users/tunnell/orgs","repos_url":"https://api.github.com/users/tunnell/repos","events_url":"https://api.github.com/users/tunnell/events{/privacy}","received_events_url":"https://api.github.com/users/tunnell/received_events","type":"User","site_admin":false},"body":"__[flake8]__\n* [W291] trailing whitespace","created_at":"2016-03-01T16:45:53Z","updated_at":"2016-03-01T16:45:53Z","html_url":"https://github.com/XENON1T/hax/pull/6#discussion_r54595795","pull_request_url":"https://api.github.com/repos/XENON1T/hax/pulls/6","_links":{"self":{"href":"https://api.github.com/repos/XENON1T/hax/pulls/comments/54595795"},"html":{"href":"https://github.com/XENON1T/hax/pull/6#discussion_r54595795"},"pull_request":{"href":"https://api.github.com/repos/XENON1T/hax/pulls/6"}}},"pull_request":{"url":"https://api.github.com/repos/XENON1T/hax/pulls/6","id":61270614,"html_url":"https://github.com/XENON1T/hax/pull/6","diff_url":"https://github.com/XENON1T/hax/pull/6.diff","patch_url":"https://github.com/XENON1T/hax/pull/6.patch","issue_url":"https://api.github.com/repos/XENON1T/hax/issues/6","number":6,"state":"open","locked":false,"title":"Hax version 0.1","user":{"login":"JelleAalbers","id":4354311,"avatar_url":"https://avatars.githubusercontent.com/u/4354311?v=3","gravatar_id":"","url":"https://api.github.com/users/JelleAalbers","html_url":"https://github.com/JelleAalbers","followers_url":"https://api.github.com/users/JelleAalbers/followers","following_url":"https://api.github.com/users/JelleAalbers/following{/other_user}","gists_url":"https://api.github.com/users/JelleAalbers/gists{/gist_id}","starred_url":"https://api.github.com/users/JelleAalbers/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JelleAalbers/subscriptions","organizations_url":"https://api.github.com/users/JelleAalbers/orgs","repos_url":"https://api.github.com/users/JelleAalbers/repos","events_url":"https://api.github.com/users/JelleAalbers/events{/privacy}","received_events_url":"https://api.github.com/users/JelleAalbers/received_events","type":"User","site_admin":false},"body":"This is an update / refactor of hax:\r\n\r\n * Additional tools for raw data analysis, such as helper functions to spawn a raw data iterator or processor. What used to be in hax.waveforms (event inspection) is now also in hax.raw_data.\r\n * Rename hax.looproot to hax.paxroot, and support for data from new pax versions, which have the event class embedded in the root file;\r\n * Begin XENON1T support by introducing the 'experiment' config option and support for loading in XENON1T raw data.\r\n * Add the pmt_plot module for making plots of the XENON1T PMT array.\r\n * Bump version to 0.1, add bumpversion config (see #1).\r\n * Restructure various things in the package. Most importantly, hax now has an init (see #5). This means you need to do:\r\n\r\n    hax.init()\r\n\r\njust after importing hax. This odious labour gets you the ability to specify different hax.ini files, or override any option for hax by specifying keyword arguments.\r\n\r\nThe tutorials have been updated.\r\n\r\n","created_at":"2016-03-01T16:41:46Z","updated_at":"2016-03-01T16:45:53Z","closed_at":null,"merged_at":null,"merge_commit_sha":"aff903a9819a9b63996363ab663f3a7eb3d1f9d6","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/XENON1T/hax/pulls/6/commits","review_comments_url":"https://api.github.com/repos/XENON1T/hax/pulls/6/comments","review_comment_url":"https://api.github.com/repos/XENON1T/hax/pulls/comments{/number}","comments_url":"https://api.github.com/repos/XENON1T/hax/issues/6/comments","statuses_url":"https://api.github.com/repos/XENON1T/hax/statuses/4f1d7868ad55b2bf110f136a73e90c8b94c77e2d","head":{"label":"XENON1T:refactor","ref":"refactor","sha":"4f1d7868ad55b2bf110f136a73e90c8b94c77e2d","user":{"login":"XENON1T","id":6840852,"avatar_url":"https://avatars.githubusercontent.com/u/6840852?v=3","gravatar_id":"","url":"https://api.github.com/users/XENON1T","html_url":"https://github.com/XENON1T","followers_url":"https://api.github.com/users/XENON1T/followers","following_url":"https://api.github.com/users/XENON1T/following{/other_user}","gists_url":"https://api.github.com/users/XENON1T/gists{/gist_id}","starred_url":"https://api.github.com/users/XENON1T/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/XENON1T/subscriptions","organizations_url":"https://api.github.com/users/XENON1T/orgs","repos_url":"https://api.github.com/users/XENON1T/repos","events_url":"https://api.github.com/users/XENON1T/events{/privacy}","received_events_url":"https://api.github.com/users/XENON1T/received_events","type":"Organization","site_admin":false},"repo":{"id":50927571,"name":"hax","full_name":"XENON1T/hax","owner":{"login":"XENON1T","id":6840852,"avatar_url":"https://avatars.githubusercontent.com/u/6840852?v=3","gravatar_id":"","url":"https://api.github.com/users/XENON1T","html_url":"https://github.com/XENON1T","followers_url":"https://api.github.com/users/XENON1T/followers","following_url":"https://api.github.com/users/XENON1T/following{/other_user}","gists_url":"https://api.github.com/users/XENON1T/gists{/gist_id}","starred_url":"https://api.github.com/users/XENON1T/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/XENON1T/subscriptions","organizations_url":"https://api.github.com/users/XENON1T/orgs","repos_url":"https://api.github.com/users/XENON1T/repos","events_url":"https://api.github.com/users/XENON1T/events{/privacy}","received_events_url":"https://api.github.com/users/XENON1T/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/XENON1T/hax","description":"Handy Analysis for XENON","fork":false,"url":"https://api.github.com/repos/XENON1T/hax","forks_url":"https://api.github.com/repos/XENON1T/hax/forks","keys_url":"https://api.github.com/repos/XENON1T/hax/keys{/key_id}","collaborators_url":"https://api.github.com/repos/XENON1T/hax/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/XENON1T/hax/teams","hooks_url":"https://api.github.com/repos/XENON1T/hax/hooks","issue_events_url":"https://api.github.com/repos/XENON1T/hax/issues/events{/number}","events_url":"https://api.github.com/repos/XENON1T/hax/events","assignees_url":"https://api.github.com/repos/XENON1T/hax/assignees{/user}","branches_url":"https://api.github.com/repos/XENON1T/hax/branches{/branch}","tags_url":"https://api.github.com/repos/XENON1T/hax/tags","blobs_url":"https://api.github.com/repos/XENON1T/hax/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/XENON1T/hax/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/XENON1T/hax/git/refs{/sha}","trees_url":"https://api.github.com/repos/XENON1T/hax/git/trees{/sha}","statuses_url":"https://api.github.com/repos/XENON1T/hax/statuses/{sha}","languages_url":"https://api.github.com/repos/XENON1T/hax/languages","stargazers_url":"https://api.github.com/repos/XENON1T/hax/stargazers","contributors_url":"https://api.github.com/repos/XENON1T/hax/contributors","subscribers_url":"https://api.github.com/repos/XENON1T/hax/subscribers","subscription_url":"https://api.github.com/repos/XENON1T/hax/subscription","commits_url":"https://api.github.com/repos/XENON1T/hax/commits{/sha}","git_commits_url":"https://api.github.com/repos/XENON1T/hax/git/commits{/sha}","comments_url":"https://api.github.com/repos/XENON1T/hax/comments{/number}","issue_comment_url":"https://api.github.com/repos/XENON1T/hax/issues/comments{/number}","contents_url":"https://api.github.com/repos/XENON1T/hax/contents/{+path}","compare_url":"https://api.github.com/repos/XENON1T/hax/compare/{base}...{head}","merges_url":"https://api.github.com/repos/XENON1T/hax/merges","archive_url":"https://api.github.com/repos/XENON1T/hax/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/XENON1T/hax/downloads","issues_url":"https://api.github.com/repos/XENON1T/hax/issues{/number}","pulls_url":"https://api.github.com/repos/XENON1T/hax/pulls{/number}","milestones_url":"https://api.github.com/repos/XENON1T/hax/milestones{/number}","notifications_url":"https://api.github.com/repos/XENON1T/hax/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/XENON1T/hax/labels{/name}","releases_url":"https://api.github.com/repos/XENON1T/hax/releases{/id}","deployments_url":"https://api.github.com/repos/XENON1T/hax/deployments","created_at":"2016-02-02T14:50:29Z","updated_at":"2016-02-03T10:59:36Z","pushed_at":"2016-03-01T16:41:46Z","git_url":"git://github.com/XENON1T/hax.git","ssh_url":"git@github.com:XENON1T/hax.git","clone_url":"https://github.com/XENON1T/hax.git","svn_url":"https://github.com/XENON1T/hax","homepage":null,"size":8487,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":1,"default_branch":"master"}},"base":{"label":"XENON1T:master","ref":"master","sha":"01353a10b0176048cb9570024597ff3d885d9a61","user":{"login":"XENON1T","id":6840852,"avatar_url":"https://avatars.githubusercontent.com/u/6840852?v=3","gravatar_id":"","url":"https://api.github.com/users/XENON1T","html_url":"https://github.com/XENON1T","followers_url":"https://api.github.com/users/XENON1T/followers","following_url":"https://api.github.com/users/XENON1T/following{/other_user}","gists_url":"https://api.github.com/users/XENON1T/gists{/gist_id}","starred_url":"https://api.github.com/users/XENON1T/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/XENON1T/subscriptions","organizations_url":"https://api.github.com/users/XENON1T/orgs","repos_url":"https://api.github.com/users/XENON1T/repos","events_url":"https://api.github.com/users/XENON1T/events{/privacy}","received_events_url":"https://api.github.com/users/XENON1T/received_events","type":"Organization","site_admin":false},"repo":{"id":50927571,"name":"hax","full_name":"XENON1T/hax","owner":{"login":"XENON1T","id":6840852,"avatar_url":"https://avatars.githubusercontent.com/u/6840852?v=3","gravatar_id":"","url":"https://api.github.com/users/XENON1T","html_url":"https://github.com/XENON1T","followers_url":"https://api.github.com/users/XENON1T/followers","following_url":"https://api.github.com/users/XENON1T/following{/other_user}","gists_url":"https://api.github.com/users/XENON1T/gists{/gist_id}","starred_url":"https://api.github.com/users/XENON1T/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/XENON1T/subscriptions","organizations_url":"https://api.github.com/users/XENON1T/orgs","repos_url":"https://api.github.com/users/XENON1T/repos","events_url":"https://api.github.com/users/XENON1T/events{/privacy}","received_events_url":"https://api.github.com/users/XENON1T/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/XENON1T/hax","description":"Handy Analysis for XENON","fork":false,"url":"https://api.github.com/repos/XENON1T/hax","forks_url":"https://api.github.com/repos/XENON1T/hax/forks","keys_url":"https://api.github.com/repos/XENON1T/hax/keys{/key_id}","collaborators_url":"https://api.github.com/repos/XENON1T/hax/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/XENON1T/hax/teams","hooks_url":"https://api.github.com/repos/XENON1T/hax/hooks","issue_events_url":"https://api.github.com/repos/XENON1T/hax/issues/events{/number}","events_url":"https://api.github.com/repos/XENON1T/hax/events","assignees_url":"https://api.github.com/repos/XENON1T/hax/assignees{/user}","branches_url":"https://api.github.com/repos/XENON1T/hax/branches{/branch}","tags_url":"https://api.github.com/repos/XENON1T/hax/tags","blobs_url":"https://api.github.com/repos/XENON1T/hax/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/XENON1T/hax/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/XENON1T/hax/git/refs{/sha}","trees_url":"https://api.github.com/repos/XENON1T/hax/git/trees{/sha}","statuses_url":"https://api.github.com/repos/XENON1T/hax/statuses/{sha}","languages_url":"https://api.github.com/repos/XENON1T/hax/languages","stargazers_url":"https://api.github.com/repos/XENON1T/hax/stargazers","contributors_url":"https://api.github.com/repos/XENON1T/hax/contributors","subscribers_url":"https://api.github.com/repos/XENON1T/hax/subscribers","subscription_url":"https://api.github.com/repos/XENON1T/hax/subscription","commits_url":"https://api.github.com/repos/XENON1T/hax/commits{/sha}","git_commits_url":"https://api.github.com/repos/XENON1T/hax/git/commits{/sha}","comments_url":"https://api.github.com/repos/XENON1T/hax/comments{/number}","issue_comment_url":"https://api.github.com/repos/XENON1T/hax/issues/comments{/number}","contents_url":"https://api.github.com/repos/XENON1T/hax/contents/{+path}","compare_url":"https://api.github.com/repos/XENON1T/hax/compare/{base}...{head}","merges_url":"https://api.github.com/repos/XENON1T/hax/merges","archive_url":"https://api.github.com/repos/XENON1T/hax/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/XENON1T/hax/downloads","issues_url":"https://api.github.com/repos/XENON1T/hax/issues{/number}","pulls_url":"https://api.github.com/repos/XENON1T/hax/pulls{/number}","milestones_url":"https://api.github.com/repos/XENON1T/hax/milestones{/number}","notifications_url":"https://api.github.com/repos/XENON1T/hax/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/XENON1T/hax/labels{/name}","releases_url":"https://api.github.com/repos/XENON1T/hax/releases{/id}","deployments_url":"https://api.github.com/repos/XENON1T/hax/deployments","created_at":"2016-02-02T14:50:29Z","updated_at":"2016-02-03T10:59:36Z","pushed_at":"2016-03-01T16:41:46Z","git_url":"git://github.com/XENON1T/hax.git","ssh_url":"git@github.com:XENON1T/hax.git","clone_url":"https://github.com/XENON1T/hax.git","svn_url":"https://github.com/XENON1T/hax","homepage":null,"size":8487,"stargazers_count":1,"watchers_count":1,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":3,"forks":0,"open_issues":3,"watchers":1,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/XENON1T/hax/pulls/6"},"html":{"href":"https://github.com/XENON1T/hax/pull/6"},"issue":{"href":"https://api.github.com/repos/XENON1T/hax/issues/6"},"comments":{"href":"https://api.github.com/repos/XENON1T/hax/issues/6/comments"},"review_comments":{"href":"https://api.github.com/repos/XENON1T/hax/pulls/6/comments"},"review_comment":{"href":"https://api.github.com/repos/XENON1T/hax/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/XENON1T/hax/pulls/6/commits"},"statuses":{"href":"https://api.github.com/repos/XENON1T/hax/statuses/4f1d7868ad55b2bf110f136a73e90c8b94c77e2d"}}}}