def donut_segments(self) -> List[go.Scatter]: [burn_in, remaining] = self.data.slcs x_axis = Axis((0, 1), DialPlot.angular_domain) return [ DialPlot.donut_segment(x_axis.map_domain(burn_in), self.theme.burn_in_segment), DialPlot.donut_segment(x_axis.map_domain(remaining), self.theme.remaining_segment) ]
def spiral_plot( xs: Sequence[float], ys: Sequence[float], x_axis: Axis, y_axis: Axis, b: float, ) -> Tuple[List[float], List[float]]: """Plot along arithmetic spiral r = a + b * theta, via the supplied axes. 12 o'clock = 0.5 * pi.""" assert len(xs) == len(ys) thetas = x_axis.map(xs) ys_radial = [y + b * theta for theta, y in zip(thetas, y_axis.map(ys))] rs_thetas: List[Tuple[float, float]] = [(cos(theta) * y, sin(theta) * y) for theta, y in zip(thetas, ys_radial)] return [r for r, _ in rs_thetas], [theta for _, theta in rs_thetas]
def spiral_plot(self) -> go.Scatter: chain: List[float] = self.data.variance(self.n_chain, self.step) xs: List[int] = [*range(0, self.data.n_iter)] y_range: Domain = min(chain), max(chain) # plot variance (which is always positive) and its negation in the same plot, and close into a polygon xs1, ys1 = spiral_plot(xs, chain, self.angular_axis, Axis(y_range, (0.5, 1)), 1 / (2 * pi)) xs2, ys2 = spiral_plot(xs, chain, self.angular_axis, Axis(y_range, (0.5, 0)), 1 / (2 * pi)) return go.Scatter( x=xs1 + xs2[::-1], y=ys1 + ys2[::-1], fill='toself', fillcolor=alpha(self.theme.palette[self.n_chain], 0.5), line=dict(width=0.5, color=self.theme.palette[self.n_chain]), xaxis='x' + self.axis_id, yaxis='y' + self.axis_id, )
def radial_ticks(self, xs: Sequence[float], tick_size: Tuple[float, float], colour: str) -> go.Scatter: """Ticks at supplied angular positions, sized relative to radial_domain.""" top, bottom = tick_size y_axis: Axis = Axis((0, 1), DialPlot.radial_domain) x1, y1 = polar_plot(xs, [top] * len(xs), self.angular_axis, y_axis) x2, y2 = polar_plot(xs, [bottom] * len(xs), self.angular_axis, y_axis) x = [x for p in zip(x1, x2, x2) for x in p] y = [y for p in zip(y1, y2, [nan] * len(x2)) for y in p] # nan to avoid joining all points return go.Scatter(x=x, y=y, mode='lines', line=dict(width=1, color=colour))
def angular_axis(self) -> Axis: return Axis((0, self.data.n_iter), (0.5 * pi, 2 * pi * 3))
def radial_axis(self) -> Axis: return Axis((self.data.min_sample, self.data.max_sample), DialPlot.radial_domain)
def angular_axis(self) -> Axis: return Axis((0, self.data.n_iter), DialPlot.angular_domain)
def arc(x_size: Domain, y: float, n_steps: int) -> Tuple[List[float], List[float]]: """Arc at distance y from (0,0) with angular extent x_domain.""" xs = [*range(0, n_steps)] ys = [y] * n_steps return polar_plot(xs, ys, Axis((0, n_steps - 1), x_size), Axis((0, 1), DialPlot.radial_domain))
def tick_labels(self, xs: Sequence[float], tick_bottom: float) -> go.Scatter: y_axis: Axis = Axis((0, 1), DialPlot.radial_domain) x, y = polar_plot(xs, [tick_bottom - 0.05] * len(xs), self.angular_axis, y_axis) return go.Scatter(x=x, y=y, text=[str(x) for x in xs], mode='text', textposition='middle left')