{"action":"created","comment":{"url":"https://api.github.com/repos/xray/xray/pulls/comments/38710955","id":38710955,"diff_hunk":"@@ -0,0 +1,384 @@\n+from __future__ import division\n+\n+import warnings\n+import itertools\n+import functools\n+\n+import numpy as np\n+import pandas as pd\n+\n+from ..core.formatting import format_item\n+from .plot import _determine_cmap_params\n+\n+\n+# Overrides axes.labelsize, xtick.major.size, ytick.major.size\n+# from mpl.rcParams\n+_FONTSIZE = 'small'\n+# For major ticks on x, y axes\n+_NTICKS = 5\n+\n+\n+def _nicetitle(coord, value, maxchar, template):\n+    '''\n+    Put coord, value in template and truncate at maxchar\n+    '''\n+    prettyvalue = format_item(value)\n+    title = template.format(coord=coord, value=prettyvalue)\n+\n+    if len(title) > maxchar:\n+        title = title[:(maxchar - 3)] + '...'\n+\n+    return title\n+\n+\n+class FacetGrid(object):\n+    '''\n+    Initialize the matplotlib figure and FacetGrid object.\n+\n+    The :class:`FacetGrid` is an object that links a xray DataArray to\n+    a matplotlib figure with a particular structure.\n+\n+    In particular, :class:`FacetGrid` is used to draw plots with multiple\n+    Axes where each Axes shows the same relationship conditioned on\n+    different levels of some dimension. It's possible to condition on up to\n+    two variables by assigning variables to the rows and columns of the\n+    grid.\n+\n+    The general approach to plotting here is called \"small multiples\",\n+    where the same kind of plot is repeated multiple times, and the\n+    specific use of small multiples to display the same relationship\n+    conditioned on one ore more other variables is often called a \"trellis\n+    plot\".\n+\n+    The basic workflow is to initialize the :class:`FacetGrid` object with\n+    the DataArray and the variable names that are used to structure the grid. Then\n+    one or more plotting functions can be applied to each subset by calling\n+    :meth:`FacetGrid.map_dataarray` or :meth:`FacetGrid.map`.\n+\n+    Attributes\n+    ----------\n+    axes : numpy object array\n+        Contains axes in corresponding position, as returned from\n+        plt.subplots\n+    fig : matplotlib.Figure\n+        The figure containing all the axes\n+    name_dicts : numpy object array\n+        Contains dictionaries mapping coordinate names to values. None is\n+        used as a sentinel value for axes which should remain empty, ie.\n+        sometimes the bottom right grid\n+\n+    '''\n+\n+    def __init__(self, darray, col=None, row=None, col_wrap=None,\n+            aspect=1, size=3, margin_titles=True):\n+        '''\n+        Parameters\n+        ----------\n+        darray : DataArray\n+            xray DataArray to be plotted\n+        row, col : strings\n+            Dimesion names that define subsets of the data, which will be drawn on\n+            separate facets in the grid.\n+        col_wrap : int, optional\n+            \"Wrap\" the column variable at this width, so that the column facets\n+        aspect : scalar, optional\n+            Aspect ratio of each facet, so that ``aspect * size`` gives the width\n+            of each facet in inches\n+        size : scalar, optional\n+            Height (in inches) of each facet. See also: ``aspect``\n+        margin_titles : bool, optional\n+            If ``True``, the titles for the row variable are drawn to the right of\n+            the last column. This option is experimental and may not work in all\n+            cases.\n+\n+        '''\n+\n+        import matplotlib.pyplot as plt\n+\n+        # Handle corner case of nonunique coordinates\n+        rep_col = col is not None and not darray[col].to_index().is_unique\n+        rep_row = row is not None and not darray[row].to_index().is_unique\n+        if rep_col or rep_row:\n+            raise ValueError('Coordinates used for faceting cannot '\n+                             'contain repeated (nonunique) values.')\n+\n+        # self._single_group is the grouping variable, if there is exactly one\n+        if col and row:\n+            self._single_group = False\n+            self._nrow = len(darray[row])\n+            self._ncol = len(darray[col])\n+            self.nfacet = self._nrow * self._ncol\n+            if col_wrap is not None:\n+                warnings.warn('Ignoring col_wrap since both col and row '\n+                              'were passed')\n+        elif row and not col:\n+            self._single_group = row\n+        elif not row and col:\n+            self._single_group = col\n+        else:\n+            raise ValueError('Pass a coordinate name as an argument for row or col')\n+\n+        # Compute grid shape\n+        if self._single_group:\n+            self.nfacet = len(darray[self._single_group])\n+            if col:\n+                # idea - could add heuristic for nice shapes like 3x4\n+                self._ncol = self.nfacet\n+                margin_titles = False\n+            if row:\n+                self._ncol = 1\n+            if col_wrap is not None:\n+                # Overrides previous settings\n+                self._ncol = col_wrap\n+            self._nrow = int(np.ceil(self.nfacet / self._ncol))\n+\n+        # Calculate the base figure size with extra horizontal space for a colorbar\n+        self._cbar_space = 1\n+        figsize = (self._ncol * size * aspect + self._cbar_space, self._nrow * size)\n+\n+        self.fig, self.axes = plt.subplots(self._nrow, self._ncol,\n+                sharex=True, sharey=True, squeeze=False, figsize=figsize)\n+\n+        # Set up the lists of names for the row and column facet variables\n+        col_names = list(darray[col].values) if col else []\n+        row_names = list(darray[row].values) if row else []\n+\n+        if self._single_group:\n+            full = [{self._single_group: x} for x in\n+                      darray[self._single_group].values]\n+            empty = [None for x in range(self._nrow * self._ncol - len(full))]\n+            name_dicts = full + empty\n+        else:\n+            rowcols = itertools.product(row_names, col_names)\n+            name_dicts = [{row: r, col: c} for r, c in rowcols]\n+\n+        self.name_dicts = np.array(name_dicts).reshape(self._nrow, self._ncol)\n+\n+        self.row_names = row_names\n+        self.col_names = col_names\n+        self.darray = darray\n+        self.row = row\n+        self.col = col\n+        self.col_wrap = col_wrap\n+\n+        # Next the private variables\n+        self._margin_titles = margin_titles\n+        self._row_var = row\n+        self._col_var = col\n+        self._col_wrap = col_wrap\n+\n+        self.set_titles()\n+\n+    def __iter__(self):\n+        return self.axes.flat\n+\n+    def map_dataarray(self, plotfunc, x, y, max_xticks=4, max_yticks=4,\n+            fontsize=_FONTSIZE, **kwargs):\n+        '''\n+        Apply a plotting function to a 2d facet's subset of the data.\n+\n+        This is more convenient and less general than ``FacetGrid.map``\n+\n+        Parameters\n+        ----------\n+        plotfunc : callable\n+            A plotting function with the same signature as a 2d xray\n+            plotting method such as `xray.plot.imshow`\n+        x, y : string\n+            Names of the coordinates to plot on x, y axes\n+        max_xticks, max_yticks : int, optional\n+            Maximum number of labeled ticks to plot on x, y axes\n+        max_yticks : int\n+            Maximum number of tick marks to place on y axis\n+        fontsize : string or int\n+            Font size as used by matplotlib text\n+        kwargs :\n+            additional keyword arguments to plotfunc\n+\n+        Returns\n+        -------\n+        self : FacetGrid object\n+\n+        '''\n+        import matplotlib.pyplot as plt\n+\n+        # These should be consistent with xray.plot._plot2d\n+        cmap_kwargs = {'plot_data': self.darray.values,\n+                'vmin': None,\n+                'vmax': None,\n+                'cmap': None,\n+                'center': None,\n+                'robust': False,\n+                'extend': None,\n+                'levels': 7 if 'contour' in plotfunc.__name__ else None, # MPL default\n+                'filled': plotfunc.__name__ != 'contour',\n+                }\n+\n+        # Allow kwargs to override these defaults\n+        for param in kwargs:\n+            if param in cmap_kwargs:\n+                cmap_kwargs[param] = kwargs[param]\n+\n+        # colormap inference has to happen here since all the data in self.darray\n+        # is required to make the right choice\n+        cmap_params = _determine_cmap_params(**cmap_kwargs)\n+\n+        if 'contour' in plotfunc.__name__:\n+            # extend is a keyword argument only for contour and contourf, but\n+            # passing it to the colorbar is sufficient for imshow and\n+            # pcolormesh\n+            kwargs['extend'] = cmap_params['extend']\n+            kwargs['levels'] = cmap_params['levels']\n+\n+        defaults = {\n+                'add_colorbar': False,\n+                'add_labels': False,\n+                'norm': cmap_params.pop('cnorm'),\n+                }\n+\n+        # Order is important\n+        defaults.update(cmap_params)\n+        defaults.update(kwargs)\n+\n+        for d, ax in zip(self.name_dicts.flat, self.axes.flat):\n+            # None is the sentinel value\n+            if d is not None:\n+                subset = self.darray.loc[d]\n+                mappable = plotfunc(subset, x, y, ax=ax, **defaults)\n+\n+        self.x = x\n+        self.y = y\n+\n+        # Left side labels\n+        for ax in self.axes[:, 0]:\n+            ax.set_ylabel(self.y)\n+\n+        # Bottom labels\n+        for ax in self.axes[-1, :]:\n+            ax.set_xlabel(self.x)\n+\n+        self.fig.tight_layout()\n+\n+        if self._single_group:\n+            for d, ax in zip(self.name_dicts.flat, self.axes.flat):\n+                if d is None:\n+                    ax.set_visible(False)\n+\n+        # colorbar\n+        if kwargs.get('add_colorbar', True):\n+            cbar = self.fig.colorbar(mappable,\n+                                     ax=list(self.axes.flat),\n+                                     extend=cmap_params['extend'])\n+\n+            if self.darray.name:\n+                cbar.set_label(self.darray.name, rotation=270,\n+                        verticalalignment='bottom')\n+\n+        # This happens here rather than __init__ since FacetGrid.map should\n+        # use default ticks\n+        self.set_ticks(max_xticks, max_yticks, fontsize)\n+\n+        return self\n+\n+    def set_titles(self, template=\"{coord} = {value}\", maxchar=30,\n+            fontsize=_FONTSIZE, **kwargs):\n+        '''\n+        Draw titles either above each facet or on the grid margins.\n+\n+        Parameters\n+        ----------\n+        template : string\n+            Template for plot titles containing {coord} and {value}\n+        maxchar : int\n+            Truncate titles at maxchar\n+        fontsize : string or int\n+            Passed to matplotlib.text\n+        kwargs : keyword args\n+            additional arguments to matplotlib.text\n+\n+        Returns\n+        -------\n+        self: FacetGrid object\n+\n+        '''\n+\n+        import matplotlib as mpl\n+\n+        kwargs['fontsize'] = fontsize\n+\n+        nicetitle = functools.partial(_nicetitle, maxchar=maxchar,\n+                template=template)\n+\n+        if self._single_group:\n+            for d, ax in zip(self.name_dicts.flat, self.axes.flat):\n+                # Only label the ones with data\n+                if d is not None:\n+                    coord, value = list(d.items()).pop()\n+                    title = nicetitle(coord, value, maxchar=maxchar)\n+                    ax.set_title(title, **kwargs)\n+        else:\n+            # The row titles on the right edge of the grid\n+            if self._margin_titles:\n+                for ax, row_name in zip(self.axes[:, -1], self.row_names):\n+                    title = nicetitle(coord=self.row, value=row_name, maxchar=maxchar)\n+                    ax.annotate(title, xy=(1.02, .5), xycoords=\"axes fraction\",\n+                                rotation=270, ha=\"left\", va=\"center\", **kwargs)\n+\n+            # The column titles on the top row\n+            for ax, col_name in zip(self.axes[0, :], self.col_names):\n+                title = nicetitle(coord=self.col, value=col_name, maxchar=maxchar)\n+                ax.set_title(title, **kwargs)\n+\n+        return self\n+\n+    def set_ticks(self, max_xticks=_NTICKS, max_yticks=_NTICKS, fontsize=_FONTSIZE):\n+        '''\n+        Sets tick behavior.\n+\n+        Refer to documentation in :meth:`FacetGrid.map_dataarray`\n+        '''\n+        from matplotlib.ticker import MaxNLocator\n+\n+        # Both are necessary\n+        x_major_locator = MaxNLocator(nbins=max_xticks)\n+        y_major_locator = MaxNLocator(nbins=max_yticks)\n+\n+        for ax in self.axes.flat:\n+            ax.xaxis.set_major_locator(x_major_locator)\n+            ax.yaxis.set_major_locator(y_major_locator)\n+            for tick in itertools.chain(ax.xaxis.get_major_ticks(),\n+                    ax.yaxis.get_major_ticks()):\n+                tick.label.set_fontsize(fontsize)","path":"xray/plot/facetgrid.py","position":351,"original_position":351,"commit_id":"1043bd29068c11f7cf65d7c92289e6315b0194e5","original_commit_id":"1043bd29068c11f7cf65d7c92289e6315b0194e5","user":{"login":"shoyer","id":1217238,"avatar_url":"https://avatars.githubusercontent.com/u/1217238?v=3","gravatar_id":"","url":"https://api.github.com/users/shoyer","html_url":"https://github.com/shoyer","followers_url":"https://api.github.com/users/shoyer/followers","following_url":"https://api.github.com/users/shoyer/following{/other_user}","gists_url":"https://api.github.com/users/shoyer/gists{/gist_id}","starred_url":"https://api.github.com/users/shoyer/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/shoyer/subscriptions","organizations_url":"https://api.github.com/users/shoyer/orgs","repos_url":"https://api.github.com/users/shoyer/repos","events_url":"https://api.github.com/users/shoyer/events{/privacy}","received_events_url":"https://api.github.com/users/shoyer/received_events","type":"User","site_admin":false},"body":"should `return self` like the other set methods","created_at":"2015-09-04T00:10:01Z","updated_at":"2015-09-04T00:10:01Z","html_url":"https://github.com/xray/xray/pull/527#discussion_r38710955","pull_request_url":"https://api.github.com/repos/xray/xray/pulls/527","_links":{"self":{"href":"https://api.github.com/repos/xray/xray/pulls/comments/38710955"},"html":{"href":"https://github.com/xray/xray/pull/527#discussion_r38710955"},"pull_request":{"href":"https://api.github.com/repos/xray/xray/pulls/527"}}},"pull_request":{"url":"https://api.github.com/repos/xray/xray/pulls/527","id":42295340,"html_url":"https://github.com/xray/xray/pull/527","diff_url":"https://github.com/xray/xray/pull/527.diff","patch_url":"https://github.com/xray/xray/pull/527.patch","issue_url":"https://api.github.com/repos/xray/xray/issues/527","number":527,"state":"open","locked":false,"title":"faceted plots","user":{"login":"clarkfitzg","id":5356122,"avatar_url":"https://avatars.githubusercontent.com/u/5356122?v=3","gravatar_id":"","url":"https://api.github.com/users/clarkfitzg","html_url":"https://github.com/clarkfitzg","followers_url":"https://api.github.com/users/clarkfitzg/followers","following_url":"https://api.github.com/users/clarkfitzg/following{/other_user}","gists_url":"https://api.github.com/users/clarkfitzg/gists{/gist_id}","starred_url":"https://api.github.com/users/clarkfitzg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clarkfitzg/subscriptions","organizations_url":"https://api.github.com/users/clarkfitzg/orgs","repos_url":"https://api.github.com/users/clarkfitzg/repos","events_url":"https://api.github.com/users/clarkfitzg/events{/privacy}","received_events_url":"https://api.github.com/users/clarkfitzg/received_events","type":"User","site_admin":false},"body":"Opening this to provide visibility as I work on this PR.\r\n\r\nCurrently this has `x` and `y` string arguments for 2d plot working, but everything else still needs lots of work. I'll let people know when it's ready for review.","created_at":"2015-08-12T22:12:12Z","updated_at":"2015-09-04T00:10:01Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6f28aebf622f7cd9c7f2ff57a0635650234ed7c4","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/xray/xray/pulls/527/commits","review_comments_url":"https://api.github.com/repos/xray/xray/pulls/527/comments","review_comment_url":"https://api.github.com/repos/xray/xray/pulls/comments{/number}","comments_url":"https://api.github.com/repos/xray/xray/issues/527/comments","statuses_url":"https://api.github.com/repos/xray/xray/statuses/1043bd29068c11f7cf65d7c92289e6315b0194e5","head":{"label":"clarkfitzg:facet2","ref":"facet2","sha":"1043bd29068c11f7cf65d7c92289e6315b0194e5","user":{"login":"clarkfitzg","id":5356122,"avatar_url":"https://avatars.githubusercontent.com/u/5356122?v=3","gravatar_id":"","url":"https://api.github.com/users/clarkfitzg","html_url":"https://github.com/clarkfitzg","followers_url":"https://api.github.com/users/clarkfitzg/followers","following_url":"https://api.github.com/users/clarkfitzg/following{/other_user}","gists_url":"https://api.github.com/users/clarkfitzg/gists{/gist_id}","starred_url":"https://api.github.com/users/clarkfitzg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clarkfitzg/subscriptions","organizations_url":"https://api.github.com/users/clarkfitzg/orgs","repos_url":"https://api.github.com/users/clarkfitzg/repos","events_url":"https://api.github.com/users/clarkfitzg/events{/privacy}","received_events_url":"https://api.github.com/users/clarkfitzg/received_events","type":"User","site_admin":false},"repo":{"id":37937560,"name":"xray","full_name":"clarkfitzg/xray","owner":{"login":"clarkfitzg","id":5356122,"avatar_url":"https://avatars.githubusercontent.com/u/5356122?v=3","gravatar_id":"","url":"https://api.github.com/users/clarkfitzg","html_url":"https://github.com/clarkfitzg","followers_url":"https://api.github.com/users/clarkfitzg/followers","following_url":"https://api.github.com/users/clarkfitzg/following{/other_user}","gists_url":"https://api.github.com/users/clarkfitzg/gists{/gist_id}","starred_url":"https://api.github.com/users/clarkfitzg/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/clarkfitzg/subscriptions","organizations_url":"https://api.github.com/users/clarkfitzg/orgs","repos_url":"https://api.github.com/users/clarkfitzg/repos","events_url":"https://api.github.com/users/clarkfitzg/events{/privacy}","received_events_url":"https://api.github.com/users/clarkfitzg/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/clarkfitzg/xray","description":"N-D labeled arrays and datasets in Python","fork":true,"url":"https://api.github.com/repos/clarkfitzg/xray","forks_url":"https://api.github.com/repos/clarkfitzg/xray/forks","keys_url":"https://api.github.com/repos/clarkfitzg/xray/keys{/key_id}","collaborators_url":"https://api.github.com/repos/clarkfitzg/xray/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/clarkfitzg/xray/teams","hooks_url":"https://api.github.com/repos/clarkfitzg/xray/hooks","issue_events_url":"https://api.github.com/repos/clarkfitzg/xray/issues/events{/number}","events_url":"https://api.github.com/repos/clarkfitzg/xray/events","assignees_url":"https://api.github.com/repos/clarkfitzg/xray/assignees{/user}","branches_url":"https://api.github.com/repos/clarkfitzg/xray/branches{/branch}","tags_url":"https://api.github.com/repos/clarkfitzg/xray/tags","blobs_url":"https://api.github.com/repos/clarkfitzg/xray/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/clarkfitzg/xray/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/clarkfitzg/xray/git/refs{/sha}","trees_url":"https://api.github.com/repos/clarkfitzg/xray/git/trees{/sha}","statuses_url":"https://api.github.com/repos/clarkfitzg/xray/statuses/{sha}","languages_url":"https://api.github.com/repos/clarkfitzg/xray/languages","stargazers_url":"https://api.github.com/repos/clarkfitzg/xray/stargazers","contributors_url":"https://api.github.com/repos/clarkfitzg/xray/contributors","subscribers_url":"https://api.github.com/repos/clarkfitzg/xray/subscribers","subscription_url":"https://api.github.com/repos/clarkfitzg/xray/subscription","commits_url":"https://api.github.com/repos/clarkfitzg/xray/commits{/sha}","git_commits_url":"https://api.github.com/repos/clarkfitzg/xray/git/commits{/sha}","comments_url":"https://api.github.com/repos/clarkfitzg/xray/comments{/number}","issue_comment_url":"https://api.github.com/repos/clarkfitzg/xray/issues/comments{/number}","contents_url":"https://api.github.com/repos/clarkfitzg/xray/contents/{+path}","compare_url":"https://api.github.com/repos/clarkfitzg/xray/compare/{base}...{head}","merges_url":"https://api.github.com/repos/clarkfitzg/xray/merges","archive_url":"https://api.github.com/repos/clarkfitzg/xray/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/clarkfitzg/xray/downloads","issues_url":"https://api.github.com/repos/clarkfitzg/xray/issues{/number}","pulls_url":"https://api.github.com/repos/clarkfitzg/xray/pulls{/number}","milestones_url":"https://api.github.com/repos/clarkfitzg/xray/milestones{/number}","notifications_url":"https://api.github.com/repos/clarkfitzg/xray/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/clarkfitzg/xray/labels{/name}","releases_url":"https://api.github.com/repos/clarkfitzg/xray/releases{/id}","created_at":"2015-06-23T18:35:23Z","updated_at":"2015-06-23T18:35:24Z","pushed_at":"2015-09-03T23:22:55Z","git_url":"git://github.com/clarkfitzg/xray.git","ssh_url":"git@github.com:clarkfitzg/xray.git","clone_url":"https://github.com/clarkfitzg/xray.git","svn_url":"https://github.com/clarkfitzg/xray","homepage":"http://xray.readthedocs.org","size":5061,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"xray:master","ref":"master","sha":"04f4e88bbae14d8c4c8e5d7b3f866751ead90a6c","user":{"login":"xray","id":7505795,"avatar_url":"https://avatars.githubusercontent.com/u/7505795?v=3","gravatar_id":"","url":"https://api.github.com/users/xray","html_url":"https://github.com/xray","followers_url":"https://api.github.com/users/xray/followers","following_url":"https://api.github.com/users/xray/following{/other_user}","gists_url":"https://api.github.com/users/xray/gists{/gist_id}","starred_url":"https://api.github.com/users/xray/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xray/subscriptions","organizations_url":"https://api.github.com/users/xray/orgs","repos_url":"https://api.github.com/users/xray/repos","events_url":"https://api.github.com/users/xray/events{/privacy}","received_events_url":"https://api.github.com/users/xray/received_events","type":"Organization","site_admin":false},"repo":{"id":13221727,"name":"xray","full_name":"xray/xray","owner":{"login":"xray","id":7505795,"avatar_url":"https://avatars.githubusercontent.com/u/7505795?v=3","gravatar_id":"","url":"https://api.github.com/users/xray","html_url":"https://github.com/xray","followers_url":"https://api.github.com/users/xray/followers","following_url":"https://api.github.com/users/xray/following{/other_user}","gists_url":"https://api.github.com/users/xray/gists{/gist_id}","starred_url":"https://api.github.com/users/xray/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/xray/subscriptions","organizations_url":"https://api.github.com/users/xray/orgs","repos_url":"https://api.github.com/users/xray/repos","events_url":"https://api.github.com/users/xray/events{/privacy}","received_events_url":"https://api.github.com/users/xray/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/xray/xray","description":"N-D labeled arrays and datasets in Python","fork":false,"url":"https://api.github.com/repos/xray/xray","forks_url":"https://api.github.com/repos/xray/xray/forks","keys_url":"https://api.github.com/repos/xray/xray/keys{/key_id}","collaborators_url":"https://api.github.com/repos/xray/xray/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/xray/xray/teams","hooks_url":"https://api.github.com/repos/xray/xray/hooks","issue_events_url":"https://api.github.com/repos/xray/xray/issues/events{/number}","events_url":"https://api.github.com/repos/xray/xray/events","assignees_url":"https://api.github.com/repos/xray/xray/assignees{/user}","branches_url":"https://api.github.com/repos/xray/xray/branches{/branch}","tags_url":"https://api.github.com/repos/xray/xray/tags","blobs_url":"https://api.github.com/repos/xray/xray/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/xray/xray/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/xray/xray/git/refs{/sha}","trees_url":"https://api.github.com/repos/xray/xray/git/trees{/sha}","statuses_url":"https://api.github.com/repos/xray/xray/statuses/{sha}","languages_url":"https://api.github.com/repos/xray/xray/languages","stargazers_url":"https://api.github.com/repos/xray/xray/stargazers","contributors_url":"https://api.github.com/repos/xray/xray/contributors","subscribers_url":"https://api.github.com/repos/xray/xray/subscribers","subscription_url":"https://api.github.com/repos/xray/xray/subscription","commits_url":"https://api.github.com/repos/xray/xray/commits{/sha}","git_commits_url":"https://api.github.com/repos/xray/xray/git/commits{/sha}","comments_url":"https://api.github.com/repos/xray/xray/comments{/number}","issue_comment_url":"https://api.github.com/repos/xray/xray/issues/comments{/number}","contents_url":"https://api.github.com/repos/xray/xray/contents/{+path}","compare_url":"https://api.github.com/repos/xray/xray/compare/{base}...{head}","merges_url":"https://api.github.com/repos/xray/xray/merges","archive_url":"https://api.github.com/repos/xray/xray/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/xray/xray/downloads","issues_url":"https://api.github.com/repos/xray/xray/issues{/number}","pulls_url":"https://api.github.com/repos/xray/xray/pulls{/number}","milestones_url":"https://api.github.com/repos/xray/xray/milestones{/number}","notifications_url":"https://api.github.com/repos/xray/xray/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/xray/xray/labels{/name}","releases_url":"https://api.github.com/repos/xray/xray/releases{/id}","created_at":"2013-09-30T17:21:10Z","updated_at":"2015-09-03T00:32:30Z","pushed_at":"2015-09-04T00:03:40Z","git_url":"git://github.com/xray/xray.git","ssh_url":"git@github.com:xray/xray.git","clone_url":"https://github.com/xray/xray.git","svn_url":"https://github.com/xray/xray","homepage":"http://xray.readthedocs.org","size":8356,"stargazers_count":246,"watchers_count":246,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":64,"mirror_url":null,"open_issues_count":74,"forks":64,"open_issues":74,"watchers":246,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/xray/xray/pulls/527"},"html":{"href":"https://github.com/xray/xray/pull/527"},"issue":{"href":"https://api.github.com/repos/xray/xray/issues/527"},"comments":{"href":"https://api.github.com/repos/xray/xray/issues/527/comments"},"review_comments":{"href":"https://api.github.com/repos/xray/xray/pulls/527/comments"},"review_comment":{"href":"https://api.github.com/repos/xray/xray/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/xray/xray/pulls/527/commits"},"statuses":{"href":"https://api.github.com/repos/xray/xray/statuses/1043bd29068c11f7cf65d7c92289e6315b0194e5"}}}}