class LightCurve(widgets.HBox):
    def __init__(self, t, flux, P=1.0, t0=8468.287, dP=1e-3):
        super().__init__()
        output = widgets.Output()

        self.t = t
        self.flux = flux

        self._t0 = t0
        self._P = P

        # Display phases between -0.25 and 0.75
        phi = phase(t, self._t0, self._P)
        phi[phi > 0.75] -= 1

        # Draw data points and initial fits
        with output:
            self.fig, self.ax = plt.subplots(constrained_layout=True,
                                             figsize=(6, 4))

        # Sort the phases so we can draw the lines
        idx = np.argsort(phi)
        self.lc, = plt.plot(phi[idx],
                            self.flux[idx],
                            'o-',
                            ms=2,
                            color='#AAAAAA',
                            mfc='k',
                            mec='k')
        plt.xlim(-0.25, 0.75)
        plt.xlabel('Phase')
        plt.ylabel('Flux (normalised)')
        plt.title('$TESS$ phased light curve')
        self.fig.canvas.toolbar_position = 'left'
        self.fig.set_label(' ')
        # Calculate initial string length
        str_len = string_length(phi, flux)
        self.str_len = AnchoredText('String length = %.2f' % str_len,
                                    loc='lower right',
                                    prop=dict(color='w'))
        self.str_len.patch.set(facecolor='tab:red', alpha=0.5)
        self.ax.add_artist(self.str_len)
        self.lc.set_linestyle('None')  # make invisible initially
        self.str_len.set_visible(False)

        # Define widgets
        self.P = widgets.FloatText(value=self._P,
                                   description='Period (d)',
                                   step=dP,
                                   style={'description_width': '10em'})
        self.t0 = widgets.FloatText(value=self._t0,
                                    min=self._t0 - 1,
                                    max=self._t0 + 1,
                                    description='$t_{0}$ (BJD $-$ 2450000)',
                                    step=1e-3,
                                    style={'description_width': '10em'})
        self.show_string = widgets.Checkbox(
            description='Show string',
            value=False,
            style={'description_width': '10em'})
        self.show_grid = widgets.Checkbox(description='Show grid',
                                          value=False,
                                          style={'description_width': '10em'})

        # Monitor for updates
        self.P.observe(self.update_points, 'value')
        self.t0.observe(self.update_points, 'value')
        self.show_string.observe(self.update_show_string, 'value')
        self.show_grid.observe(self.update_show_grid, 'value')

        controls = widgets.VBox(
            [self.P, self.t0, self.show_string, self.show_grid])

        # Add to children
        self.children = [output, controls]

    def update_points(self, change):
        phi = phase(self.t, self.t0.value, self.P.value)
        phi[phi > 0.75] -= 1
        idx = np.argsort(phi)
        self.lc.set_xdata(phi[idx])
        self.lc.set_ydata(self.flux[idx])
        # Update the string length
        self.str_len.txt.set_text('String length = %.2f' %
                                  string_length(phi, self.flux))

    def update_show_string(self, change):
        self.str_len.set_visible(change.new)
        ls = '-' if change.new else 'None'
        self.lc.set_linestyle(ls)

    def update_show_grid(self, change):
        self.ax.grid(change.new)