def plot_results(<EOL>allresults, *,<EOL>xy_fn=default_xy_fn,<EOL>split_fn=default_split_fn,<EOL>group_fn=default_split_fn,<EOL>average_group=False,<EOL>shaded_std=True,<EOL>shaded_err=True,<EOL>figsize=None,<EOL>legend_outside=False,<EOL>resample=<NUM_LIT:0>,<EOL>smooth_step=<NUM_LIT:1.0><EOL>):
if split_fn is None: split_fn = lambda _ : '<STR_LIT>'<EOL>if group_fn is None: group_fn = lambda _ : '<STR_LIT>'<EOL>sk2r = defaultdict(list) <EOL>for result in allresults:<EOL><INDENT>splitkey = split_fn(result)<EOL>sk2r[splitkey].append(result)<EOL><DEDENT>assert len(sk2r) > <NUM_LIT:0><EOL>assert isinstance(resample, int), "<STR_LIT>"<EOL>nrows = len(sk2r)<EOL>ncols = <NUM_LIT:1><EOL>figsize = figsize or (<NUM_LIT:6>, <NUM_LIT:6> * nrows)<EOL>f, axarr = plt.subplots(nrows, ncols, sharex=False, squeeze=False, figsize=figsize)<EOL>groups = list(set(group_fn(result) for result in allresults))<EOL>default_samples = <NUM_LIT><EOL>if average_group:<EOL><INDENT>resample = resample or default_samples<EOL><DEDENT>for (isplit, sk) in enumerate(sorted(sk2r.keys())):<EOL><INDENT>g2l = {}<EOL>g2c = defaultdict(int)<EOL>sresults = sk2r[sk]<EOL>gresults = defaultdict(list)<EOL>ax = axarr[isplit][<NUM_LIT:0>]<EOL>for result in sresults:<EOL><INDENT>group = group_fn(result)<EOL>g2c[group] += <NUM_LIT:1><EOL>x, y = xy_fn(result)<EOL>if x is None: x = np.arange(len(y))<EOL>x, y = map(np.asarray, (x, y))<EOL>if average_group:<EOL><INDENT>gresults[group].append((x,y))<EOL><DEDENT>else:<EOL><INDENT>if resample:<EOL><INDENT>x, y, counts = symmetric_ema(x, y, x[<NUM_LIT:0>], x[-<NUM_LIT:1>], resample, decay_steps=smooth_step)<EOL><DEDENT>l, = ax.plot(x, y, color=COLORS[groups.index(group) % len(COLORS)])<EOL>g2l[group] = l<EOL><DEDENT><DEDENT>if average_group:<EOL><INDENT>for group in sorted(groups):<EOL><INDENT>xys = gresults[group]<EOL>if not any(xys):<EOL><INDENT>continue<EOL><DEDENT>color = COLORS[groups.index(group) % len(COLORS)]<EOL>origxs = [xy[<NUM_LIT:0>] for xy in xys]<EOL>minxlen = min(map(len, origxs))<EOL>def allequal(qs):<EOL><INDENT>return all((q==qs[<NUM_LIT:0>]).all() for q in qs[<NUM_LIT:1>:])<EOL><DEDENT>if resample:<EOL><INDENT>low  = max(x[<NUM_LIT:0>] for x in origxs)<EOL>high = min(x[-<NUM_LIT:1>] for x in origxs)<EOL>usex = np.linspace(low, high, resample)<EOL>ys = []<EOL>for (x, y) in xys:<EOL><INDENT>ys.append(symmetric_ema(x, y, low, high, resample, decay_steps=smooth_step)[<NUM_LIT:1>])<EOL><DEDENT><DEDENT>else:<EOL><INDENT>assert allequal([x[:minxlen] for x in origxs]),'<STR_LIT>'<EOL>usex = origxs[<NUM_LIT:0>]<EOL>ys = [xy[<NUM_LIT:1>][:minxlen] for xy in xys]<EOL><DEDENT>ymean = np.mean(ys, axis=<NUM_LIT:0>)<EOL>ystd = np.std(ys, axis=<NUM_LIT:0>)<EOL>ystderr = ystd / np.sqrt(len(ys))<EOL>l, = axarr[isplit][<NUM_LIT:0>].plot(usex, ymean, color=color)<EOL>g2l[group] = l<EOL>if shaded_err:<EOL><INDENT>ax.fill_between(usex, ymean - ystderr, ymean + ystderr, color=color, alpha=<NUM_LIT>)<EOL><DEDENT>if shaded_std:<EOL><INDENT>ax.fill_between(usex, ymean - ystd,    ymean + ystd,    color=color, alpha=<NUM_LIT>)<EOL><DEDENT><DEDENT><DEDENT>plt.tight_layout()<EOL>if any(g2l.keys()):<EOL><INDENT>ax.legend(<EOL>g2l.values(),<EOL>['<STR_LIT>'%(g, g2c[g]) for g in g2l] if average_group else g2l.keys(),<EOL>loc=<NUM_LIT:2> if legend_outside else None,<EOL>bbox_to_anchor=(<NUM_LIT:1>,<NUM_LIT:1>) if legend_outside else None)<EOL><DEDENT>ax.set_title(sk)<EOL><DEDENT>return f, axarr<EOL>
Plot multiple Results objects

xy_fn: function Result -> x,y           - function that converts results objects into tuple of x and y values.
                                          By default, x is cumsum of episode lengths, and y is episode rewards

split_fn: function Result -> hashable   - function that converts results objects into keys to split curves into sub-panels by.
                                          That is, the results r for which split_fn(r) is different will be put on different sub-panels.
                                          By default, the portion of r.dirname between last / and -<digits> is returned. The sub-panels are
                                          stacked vertically in the figure.

group_fn: function Result -> hashable   - function that converts results objects into keys to group curves by.
                                          That is, the results r for which group_fn(r) is the same will be put into the same group.
                                          Curves in the same group have the same color (if average_group is False), or averaged over
                                          (if average_group is True). The default value is the same as default value for split_fn

average_group: bool                     - if True, will average the curves in the same group and plot the mean. Enables resampling
                                          (if resample = 0, will use 512 steps)

shaded_std: bool                        - if True (default), the shaded region corresponding to standard deviation of the group of curves will be
                                          shown (only applicable if average_group = True)

shaded_err: bool                        - if True (default), the shaded region corresponding to error in mean estimate of the group of curves
                                          (that is, standard deviation divided by square root of number of curves) will be
                                          shown (only applicable if average_group = True)

figsize: tuple or None                  - size of the resulting figure (including sub-panels). By default, width is 6 and height is 6 times number of
                                          sub-panels.


legend_outside: bool                    - if True, will place the legend outside of the sub-panels.

resample: int                           - if not zero, size of the uniform grid in x direction to resample onto. Resampling is performed via symmetric
                                          EMA smoothing (see the docstring for symmetric_ema).
                                          Default is zero (no resampling). Note that if average_group is True, resampling is necessary; in that case, default
                                          value is 512.

smooth_step: float                      - when resampling (i.e. when resample > 0 or average_group is True), use this EMA decay parameter (in units of the new grid step).
                                          See docstrings for decay_steps in symmetric_ema or one_sided_ema functions.