<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def plot_objective(ensemble, partition='train', ax=None, jitter=0.1, scatter_kw=dict(), line_kw=dict()):
 """Plots objective function as a function of model rank. Parameters ensemble : Ensemble object holds optimization results across a range of model ranks partition : string, one of: {'train', 'test'} specifies whether to plot the objective function on the training data or the held-out test set. ax : matplotlib axis (optional) axis to plot on (defaults to current axis object) jitter : float (optional) amount of horizontal jitter added to scatterpoints (default=0.1) scatter_kw : dict (optional) keyword arguments for styling the scatterpoints line_kw : dict (optional) keyword arguments for styling the line """


    if ax is None:
        ax = plt.gca()

    if partition == 'train':
        pass
    elif partition == 'test':
        raise NotImplementedError('Cross-validation is on the TODO list.')
    else:
        raise ValueError("partition must be 'train' or 'test'.")

    # compile statistics for plotting
    x, obj, min_obj = [], [], []
    for rank in sorted(ensemble.results):
        # reconstruction errors for rank-r models
        o = ensemble.objectives(rank)
        obj.extend(o)
        x.extend(np.full(len(o), rank))
        min_obj.append(min(o))

    # add horizontal jitter
    ux = np.unique(x)
    x = np.array(x) + (np.random.rand(len(x))-0.5)*jitter

    # make plot
    ax.scatter(x, obj, **scatter_kw)
    ax.plot(ux, min_obj, **line_kw)
    ax.set_xlabel('model rank')
    ax.set_ylabel('objective')

    return ax