{"action":"created","comment":{"url":"https://api.github.com/repos/Code4SA/umibukela/pulls/comments/51427751","id":51427751,"diff_hunk":"@@ -0,0 +1,191 @@\n+\"\"\"\n+survey response summary calculation\n+\"\"\"\n+\n+\n+def count_submissions(submissions):\n+    results = {}\n+    # per-gender counts\n+    cols = ['facility', 'demographics_group/gender']\n+    question_table = submissions.loc[:, cols]\n+    gender_counts = question_table.groupby(\n+        ['demographics_group/gender']\n+    ).count()\n+    for gender in ['female', 'male']:\n+        results = deep_dict_set(\n+            results,\n+            int(gender_counts.loc[gender]),\n+            [gender]\n+        )\n+\n+    # total count\n+    results = deep_dict_set(\n+        results,\n+        int(submissions.loc[:, ['facility']].count()),\n+        ['total']\n+    )\n+    return results\n+\n+\n+def count_options(\n+        submissions,\n+        children,\n+        path=None,\n+        question_results=None,\n+        current_option_counts=None):\n+    \"\"\"\n+    returns nested dicts where the keys are the names of the XForm element\n+    branches to each question and each option of a question. Only multiple\n+    choice questions are supported.\n+    \"\"\"\n+    path = path or []\n+    question_results = question_results or {}\n+    idx = 0  # The index of the child in the form in its array of siblings\n+    for child in children:\n+        deeper_path = path + [child['name']]\n+        if deeper_path in [['facility'], ['demographics_group', 'gender']]:\n+            pass\n+        elif child_is_type(child, 'group') and child['name'] == 'meta':\n+            pass\n+        elif child_is_type(child, 'group'):\n+            question_results = count_options(\n+                submissions,\n+                child['children'],\n+                deeper_path,\n+                question_results,\n+                None)\n+        elif (child_is_type(child, 'select one')\n+              or child_is_type(child, 'select all that apply')):\n+            # multiple choice questions\n+            current_option_counts = count_question_options(\n+                submissions,\n+                deeper_path\n+            )\n+            question_results = deep_dict_set(\n+                question_results,\n+                child['label'],\n+                [pathstr(deeper_path), 'label']\n+            )\n+            question_results = count_options(\n+                submissions,\n+                child['children'],\n+                deeper_path,\n+                question_results,\n+                current_option_counts\n+            )\n+        elif ('type' not in child):\n+            # option in multiple choice question\n+            question_results = deep_dict_set(\n+                question_results,\n+                child['label'],\n+                [pathstr(path), 'options', child['name'], 'label']\n+            )\n+            question_results = deep_dict_set(\n+                question_results,\n+                idx,\n+                [pathstr(path), 'options', child['name'], 'idx']\n+            )\n+            question_results = set_option_counts(\n+                path,\n+                child['name'],\n+                question_results,\n+                current_option_counts\n+            )\n+        else:\n+            pass\n+        idx += 1\n+    return question_results\n+\n+\n+def child_is_type(child, type):\n+    return ('type' in child) and child['type'] == type\n+\n+\n+def count_question_options(site_submissions, path):\n+    cols = ['facility', 'demographics_group/gender', pathstr(path)]\n+    question_table = site_submissions.loc[:, cols]\n+    question_counts = question_table.groupby(\n+        ['demographics_group/gender', pathstr(path)]\n+    ).count()\n+    return question_counts\n+\n+\n+def set_option_counts(path, option_name, results, current_option_counts):\n+    for gender in ['male', 'female']:\n+        option_table = current_option_counts\n+\n+        try:\n+            val = int(option_table.loc[gender, option_name])\n+        except KeyError:\n+            # values that aren't counted because they don't occur in the\n+            # results for this question won't be indexes in the counts\n+            print(\"########################################\")\n+            print(path, gender, option_name_as_idx)\n+            print(option_table)\n+            val = 0\n+\n+        results = deep_dict_set(\n+            results,\n+            val,\n+            [pathstr(path), 'options', option_name, 'count', gender]\n+        )\n+    return results\n+\n+\n+def pathstr(path):\n+    \"\"\" / separated path from array of strings\"\"\"\n+    return '/'.join(path)\n+\n+\n+def deep_dict_set(deep_dict, value, layers):\n+    layer = layers[0]\n+    if layers[1:]:\n+        if layer in deep_dict:\n+            deep_dict[layer] = deep_dict_set(\n+                deep_dict[layer],\n+                value,\n+                layers[1:]\n+            )\n+        else:\n+            deep_dict[layer] = deep_dict_set({}, value, layers[1:])\n+    else:\n+        deep_dict[layer] = value\n+\n+    return deep_dict\n+\n+\n+def questions_dict_to_array(question_dict):\n+    \"\"\"\n+    Turn the question-name-keyed dict into an array of questions and options\n+    \"\"\"\n+    questions = []\n+    for q_key in question_dict.keys():\n+        question = question_dict[q_key]\n+        options_dict = question['options']\n+        options = [None] * len(options_dict)\n+        for o_key in options_dict.keys():\n+            option = options_dict[o_key]\n+            option['key'] = o_key\n+            options[option['idx']] = option\n+        question['options'] = options  # overwrite\n+        question['key'] = q_key\n+        questions.append(question)\n+    return questions\n+\n+\n+def calc_q_percents(questions, site_totals):","path":"umibukela/results.py","position":176,"original_position":176,"commit_id":"0e8e3b70aa5335027680334cb885953cd1104fc3","original_commit_id":"0e8e3b70aa5335027680334cb885953cd1104fc3","user":{"login":"longhotsummer","id":4178542,"avatar_url":"https://avatars.githubusercontent.com/u/4178542?v=3","gravatar_id":"","url":"https://api.github.com/users/longhotsummer","html_url":"https://github.com/longhotsummer","followers_url":"https://api.github.com/users/longhotsummer/followers","following_url":"https://api.github.com/users/longhotsummer/following{/other_user}","gists_url":"https://api.github.com/users/longhotsummer/gists{/gist_id}","starred_url":"https://api.github.com/users/longhotsummer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/longhotsummer/subscriptions","organizations_url":"https://api.github.com/users/longhotsummer/orgs","repos_url":"https://api.github.com/users/longhotsummer/repos","events_url":"https://api.github.com/users/longhotsummer/events{/privacy}","received_events_url":"https://api.github.com/users/longhotsummer/received_events","type":"User","site_admin":false},"body":"As discussed, feels like we could do this when building up the counts, *and* using the local total number, not the global total number.","created_at":"2016-02-01T15:02:13Z","updated_at":"2016-02-01T15:02:13Z","html_url":"https://github.com/Code4SA/umibukela/pull/23#discussion_r51427751","pull_request_url":"https://api.github.com/repos/Code4SA/umibukela/pulls/23","_links":{"self":{"href":"https://api.github.com/repos/Code4SA/umibukela/pulls/comments/51427751"},"html":{"href":"https://github.com/Code4SA/umibukela/pull/23#discussion_r51427751"},"pull_request":{"href":"https://api.github.com/repos/Code4SA/umibukela/pulls/23"}}},"pull_request":{"url":"https://api.github.com/repos/Code4SA/umibukela/pulls/23","id":57376590,"html_url":"https://github.com/Code4SA/umibukela/pull/23","diff_url":"https://github.com/Code4SA/umibukela/pull/23.diff","patch_url":"https://github.com/Code4SA/umibukela/pull/23.patch","issue_url":"https://api.github.com/repos/Code4SA/umibukela/issues/23","number":23,"state":"open","locked":false,"title":"display survey results calculated on the fly from data in the DB","user":{"login":"jbothma","id":235801,"avatar_url":"https://avatars.githubusercontent.com/u/235801?v=3","gravatar_id":"","url":"https://api.github.com/users/jbothma","html_url":"https://github.com/jbothma","followers_url":"https://api.github.com/users/jbothma/followers","following_url":"https://api.github.com/users/jbothma/following{/other_user}","gists_url":"https://api.github.com/users/jbothma/gists{/gist_id}","starred_url":"https://api.github.com/users/jbothma/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jbothma/subscriptions","organizations_url":"https://api.github.com/users/jbothma/orgs","repos_url":"https://api.github.com/users/jbothma/repos","events_url":"https://api.github.com/users/jbothma/events{/privacy}","received_events_url":"https://api.github.com/users/jbothma/received_events","type":"User","site_admin":false},"body":"known bugs:\r\n- options whose name are ints aren't tallied right now\r\n  - was fixed, regressed, tests FTW.\r\n- \"how long did it take\" is missing from some question labels\r\n  - it probably comes with the group and is easy to fix\r\n\r\n![screenshot_2016-01-27_17-39-40_charts_from_db](https://cloud.githubusercontent.com/assets/235801/12618620/51525588-c51d-11e5-84f4-730b7816bb43.png)\r\n","created_at":"2016-01-27T15:37:52Z","updated_at":"2016-02-01T15:02:13Z","closed_at":null,"merged_at":null,"merge_commit_sha":"968e359218ca7c04a59f72a4cbf8b882806e454d","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/Code4SA/umibukela/pulls/23/commits","review_comments_url":"https://api.github.com/repos/Code4SA/umibukela/pulls/23/comments","review_comment_url":"https://api.github.com/repos/Code4SA/umibukela/pulls/comments{/number}","comments_url":"https://api.github.com/repos/Code4SA/umibukela/issues/23/comments","statuses_url":"https://api.github.com/repos/Code4SA/umibukela/statuses/0e8e3b70aa5335027680334cb885953cd1104fc3","head":{"label":"Code4SA:models-for-survey-responses","ref":"models-for-survey-responses","sha":"0e8e3b70aa5335027680334cb885953cd1104fc3","user":{"login":"Code4SA","id":4387576,"avatar_url":"https://avatars.githubusercontent.com/u/4387576?v=3","gravatar_id":"","url":"https://api.github.com/users/Code4SA","html_url":"https://github.com/Code4SA","followers_url":"https://api.github.com/users/Code4SA/followers","following_url":"https://api.github.com/users/Code4SA/following{/other_user}","gists_url":"https://api.github.com/users/Code4SA/gists{/gist_id}","starred_url":"https://api.github.com/users/Code4SA/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Code4SA/subscriptions","organizations_url":"https://api.github.com/users/Code4SA/orgs","repos_url":"https://api.github.com/users/Code4SA/repos","events_url":"https://api.github.com/users/Code4SA/events{/privacy}","received_events_url":"https://api.github.com/users/Code4SA/received_events","type":"Organization","site_admin":false},"repo":{"id":47106932,"name":"umibukela","full_name":"Code4SA/umibukela","owner":{"login":"Code4SA","id":4387576,"avatar_url":"https://avatars.githubusercontent.com/u/4387576?v=3","gravatar_id":"","url":"https://api.github.com/users/Code4SA","html_url":"https://github.com/Code4SA","followers_url":"https://api.github.com/users/Code4SA/followers","following_url":"https://api.github.com/users/Code4SA/following{/other_user}","gists_url":"https://api.github.com/users/Code4SA/gists{/gist_id}","starred_url":"https://api.github.com/users/Code4SA/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Code4SA/subscriptions","organizations_url":"https://api.github.com/users/Code4SA/orgs","repos_url":"https://api.github.com/users/Code4SA/repos","events_url":"https://api.github.com/users/Code4SA/events{/privacy}","received_events_url":"https://api.github.com/users/Code4SA/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Code4SA/umibukela","description":"Community-Based Monitoring advocacy and reporting platform","fork":false,"url":"https://api.github.com/repos/Code4SA/umibukela","forks_url":"https://api.github.com/repos/Code4SA/umibukela/forks","keys_url":"https://api.github.com/repos/Code4SA/umibukela/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Code4SA/umibukela/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Code4SA/umibukela/teams","hooks_url":"https://api.github.com/repos/Code4SA/umibukela/hooks","issue_events_url":"https://api.github.com/repos/Code4SA/umibukela/issues/events{/number}","events_url":"https://api.github.com/repos/Code4SA/umibukela/events","assignees_url":"https://api.github.com/repos/Code4SA/umibukela/assignees{/user}","branches_url":"https://api.github.com/repos/Code4SA/umibukela/branches{/branch}","tags_url":"https://api.github.com/repos/Code4SA/umibukela/tags","blobs_url":"https://api.github.com/repos/Code4SA/umibukela/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Code4SA/umibukela/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Code4SA/umibukela/git/refs{/sha}","trees_url":"https://api.github.com/repos/Code4SA/umibukela/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Code4SA/umibukela/statuses/{sha}","languages_url":"https://api.github.com/repos/Code4SA/umibukela/languages","stargazers_url":"https://api.github.com/repos/Code4SA/umibukela/stargazers","contributors_url":"https://api.github.com/repos/Code4SA/umibukela/contributors","subscribers_url":"https://api.github.com/repos/Code4SA/umibukela/subscribers","subscription_url":"https://api.github.com/repos/Code4SA/umibukela/subscription","commits_url":"https://api.github.com/repos/Code4SA/umibukela/commits{/sha}","git_commits_url":"https://api.github.com/repos/Code4SA/umibukela/git/commits{/sha}","comments_url":"https://api.github.com/repos/Code4SA/umibukela/comments{/number}","issue_comment_url":"https://api.github.com/repos/Code4SA/umibukela/issues/comments{/number}","contents_url":"https://api.github.com/repos/Code4SA/umibukela/contents/{+path}","compare_url":"https://api.github.com/repos/Code4SA/umibukela/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Code4SA/umibukela/merges","archive_url":"https://api.github.com/repos/Code4SA/umibukela/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Code4SA/umibukela/downloads","issues_url":"https://api.github.com/repos/Code4SA/umibukela/issues{/number}","pulls_url":"https://api.github.com/repos/Code4SA/umibukela/pulls{/number}","milestones_url":"https://api.github.com/repos/Code4SA/umibukela/milestones{/number}","notifications_url":"https://api.github.com/repos/Code4SA/umibukela/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Code4SA/umibukela/labels{/name}","releases_url":"https://api.github.com/repos/Code4SA/umibukela/releases{/id}","deployments_url":"https://api.github.com/repos/Code4SA/umibukela/deployments","created_at":"2015-11-30T09:03:27Z","updated_at":"2016-01-13T10:20:12Z","pushed_at":"2016-01-27T16:50:32Z","git_url":"git://github.com/Code4SA/umibukela.git","ssh_url":"git@github.com:Code4SA/umibukela.git","clone_url":"https://github.com/Code4SA/umibukela.git","svn_url":"https://github.com/Code4SA/umibukela","homepage":"http://cbm.code4sa.org","size":3417,"stargazers_count":0,"watchers_count":0,"language":"HTML","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"Code4SA:master","ref":"master","sha":"a5e582cb1dd6edf8cecdad42a47ad86af0ae2bf5","user":{"login":"Code4SA","id":4387576,"avatar_url":"https://avatars.githubusercontent.com/u/4387576?v=3","gravatar_id":"","url":"https://api.github.com/users/Code4SA","html_url":"https://github.com/Code4SA","followers_url":"https://api.github.com/users/Code4SA/followers","following_url":"https://api.github.com/users/Code4SA/following{/other_user}","gists_url":"https://api.github.com/users/Code4SA/gists{/gist_id}","starred_url":"https://api.github.com/users/Code4SA/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Code4SA/subscriptions","organizations_url":"https://api.github.com/users/Code4SA/orgs","repos_url":"https://api.github.com/users/Code4SA/repos","events_url":"https://api.github.com/users/Code4SA/events{/privacy}","received_events_url":"https://api.github.com/users/Code4SA/received_events","type":"Organization","site_admin":false},"repo":{"id":47106932,"name":"umibukela","full_name":"Code4SA/umibukela","owner":{"login":"Code4SA","id":4387576,"avatar_url":"https://avatars.githubusercontent.com/u/4387576?v=3","gravatar_id":"","url":"https://api.github.com/users/Code4SA","html_url":"https://github.com/Code4SA","followers_url":"https://api.github.com/users/Code4SA/followers","following_url":"https://api.github.com/users/Code4SA/following{/other_user}","gists_url":"https://api.github.com/users/Code4SA/gists{/gist_id}","starred_url":"https://api.github.com/users/Code4SA/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Code4SA/subscriptions","organizations_url":"https://api.github.com/users/Code4SA/orgs","repos_url":"https://api.github.com/users/Code4SA/repos","events_url":"https://api.github.com/users/Code4SA/events{/privacy}","received_events_url":"https://api.github.com/users/Code4SA/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/Code4SA/umibukela","description":"Community-Based Monitoring advocacy and reporting platform","fork":false,"url":"https://api.github.com/repos/Code4SA/umibukela","forks_url":"https://api.github.com/repos/Code4SA/umibukela/forks","keys_url":"https://api.github.com/repos/Code4SA/umibukela/keys{/key_id}","collaborators_url":"https://api.github.com/repos/Code4SA/umibukela/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/Code4SA/umibukela/teams","hooks_url":"https://api.github.com/repos/Code4SA/umibukela/hooks","issue_events_url":"https://api.github.com/repos/Code4SA/umibukela/issues/events{/number}","events_url":"https://api.github.com/repos/Code4SA/umibukela/events","assignees_url":"https://api.github.com/repos/Code4SA/umibukela/assignees{/user}","branches_url":"https://api.github.com/repos/Code4SA/umibukela/branches{/branch}","tags_url":"https://api.github.com/repos/Code4SA/umibukela/tags","blobs_url":"https://api.github.com/repos/Code4SA/umibukela/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/Code4SA/umibukela/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/Code4SA/umibukela/git/refs{/sha}","trees_url":"https://api.github.com/repos/Code4SA/umibukela/git/trees{/sha}","statuses_url":"https://api.github.com/repos/Code4SA/umibukela/statuses/{sha}","languages_url":"https://api.github.com/repos/Code4SA/umibukela/languages","stargazers_url":"https://api.github.com/repos/Code4SA/umibukela/stargazers","contributors_url":"https://api.github.com/repos/Code4SA/umibukela/contributors","subscribers_url":"https://api.github.com/repos/Code4SA/umibukela/subscribers","subscription_url":"https://api.github.com/repos/Code4SA/umibukela/subscription","commits_url":"https://api.github.com/repos/Code4SA/umibukela/commits{/sha}","git_commits_url":"https://api.github.com/repos/Code4SA/umibukela/git/commits{/sha}","comments_url":"https://api.github.com/repos/Code4SA/umibukela/comments{/number}","issue_comment_url":"https://api.github.com/repos/Code4SA/umibukela/issues/comments{/number}","contents_url":"https://api.github.com/repos/Code4SA/umibukela/contents/{+path}","compare_url":"https://api.github.com/repos/Code4SA/umibukela/compare/{base}...{head}","merges_url":"https://api.github.com/repos/Code4SA/umibukela/merges","archive_url":"https://api.github.com/repos/Code4SA/umibukela/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/Code4SA/umibukela/downloads","issues_url":"https://api.github.com/repos/Code4SA/umibukela/issues{/number}","pulls_url":"https://api.github.com/repos/Code4SA/umibukela/pulls{/number}","milestones_url":"https://api.github.com/repos/Code4SA/umibukela/milestones{/number}","notifications_url":"https://api.github.com/repos/Code4SA/umibukela/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/Code4SA/umibukela/labels{/name}","releases_url":"https://api.github.com/repos/Code4SA/umibukela/releases{/id}","deployments_url":"https://api.github.com/repos/Code4SA/umibukela/deployments","created_at":"2015-11-30T09:03:27Z","updated_at":"2016-01-13T10:20:12Z","pushed_at":"2016-01-27T16:50:32Z","git_url":"git://github.com/Code4SA/umibukela.git","ssh_url":"git@github.com:Code4SA/umibukela.git","clone_url":"https://github.com/Code4SA/umibukela.git","svn_url":"https://github.com/Code4SA/umibukela","homepage":"http://cbm.code4sa.org","size":3417,"stargazers_count":0,"watchers_count":0,"language":"HTML","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/Code4SA/umibukela/pulls/23"},"html":{"href":"https://github.com/Code4SA/umibukela/pull/23"},"issue":{"href":"https://api.github.com/repos/Code4SA/umibukela/issues/23"},"comments":{"href":"https://api.github.com/repos/Code4SA/umibukela/issues/23/comments"},"review_comments":{"href":"https://api.github.com/repos/Code4SA/umibukela/pulls/23/comments"},"review_comment":{"href":"https://api.github.com/repos/Code4SA/umibukela/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/Code4SA/umibukela/pulls/23/commits"},"statuses":{"href":"https://api.github.com/repos/Code4SA/umibukela/statuses/0e8e3b70aa5335027680334cb885953cd1104fc3"}}}}