|
| 1 | +""" |
| 2 | +Unit circle |
| 3 | +=========== |
| 4 | +
|
| 5 | +Example with linear selectors on a sine and cosine function that demonstrates the unit circle. |
| 6 | +
|
| 7 | +This shows how fastplotlib supports bidirectional events, drag the linear selector on the sine |
| 8 | +or cosine function and they will both move together. |
| 9 | +
|
| 10 | +Click on the sine or cosine function to set the colormap transform to illustrate the sine or |
| 11 | +cosine function output values on the unit circle. |
| 12 | +""" |
| 13 | + |
| 14 | +# test_example = false |
| 15 | +# sphinx_gallery_pygfx_docs = 'screenshot' |
| 16 | + |
| 17 | + |
| 18 | +import numpy as np |
| 19 | +import fastplotlib as fpl |
| 20 | + |
| 21 | + |
| 22 | +# helper function to make a cirlce |
| 23 | +def make_circle(center, radius: float, n_points: int) -> np.ndarray: |
| 24 | + theta = np.linspace(0, 2 * np.pi, n_points) |
| 25 | + xs = radius * np.cos(theta) |
| 26 | + ys = radius * np.sin(theta) |
| 27 | + |
| 28 | + return np.column_stack([xs, ys]) + center |
| 29 | + |
| 30 | + |
| 31 | +# create a figure with 3 subplots |
| 32 | +figure = fpl.Figure((3, 1), names=["unit circle", "sin(x)", "cos(x)"], size=(700, 1024)) |
| 33 | + |
| 34 | +# set the axes to intersect at (0, 0, 0) to better illustrate the unit circle |
| 35 | +for subplot in figure: |
| 36 | + subplot.axes.intersection = (0, 0, 0) |
| 37 | + |
| 38 | +figure["sin(x)"].camera.maintain_aspect = False |
| 39 | +figure["cos(x)"].camera.maintain_aspect = False |
| 40 | + |
| 41 | +# create sine and cosine data |
| 42 | +xs = np.linspace(0, 2 * np.pi, 360) |
| 43 | +sine = np.sin(xs) |
| 44 | +cosine = np.cos(xs) |
| 45 | + |
| 46 | +# circle data |
| 47 | +circle_data = make_circle(center=(0, 0), radius=1, n_points=360) |
| 48 | + |
| 49 | +# make the circle line graphic, set the cmap transform using the sine function |
| 50 | +circle_graphic = figure["unit circle"].add_line( |
| 51 | + circle_data, thickness=4, cmap="bwr", cmap_transform=sine |
| 52 | +) |
| 53 | + |
| 54 | +# line to show the circle radius |
| 55 | +# use it to indicate the current position of the sine and cosine selctors (below) |
| 56 | +radius_data = np.array([[0, 0, 0], [*circle_data[0], 0]]) |
| 57 | +circle_radius = figure["unit circle"].add_line( |
| 58 | + radius_data, thickness=6, colors="magenta" |
| 59 | +) |
| 60 | + |
| 61 | +# sine line graphic, cmap transform set from the sine function |
| 62 | +sine_graphic = figure["sin(x)"].add_line( |
| 63 | + sine, thickness=10, cmap="bwr", cmap_transform=sine |
| 64 | +) |
| 65 | + |
| 66 | +# cosine line graphic, cmap transform set from the sine function |
| 67 | +# illustrates the sine function values on the cosine graphic |
| 68 | +cosine_graphic = figure["cos(x)"].add_line( |
| 69 | + cosine, thickness=10, cmap="bwr", cmap_transform=sine |
| 70 | +) |
| 71 | + |
| 72 | +# add linear selectors to the sine and cosine line graphics |
| 73 | +sine_selector = sine_graphic.add_linear_selector() |
| 74 | +cosine_selector = cosine_graphic.add_linear_selector() |
| 75 | + |
| 76 | +def set_circle_cmap(ev): |
| 77 | + # sets the cmap transforms |
| 78 | + |
| 79 | + cmap_transform = ev.graphic.data[:, 1] # y-val data of the sine or cosine graphic |
| 80 | + for g in [sine_graphic, cosine_graphic]: |
| 81 | + g.cmap.transform = cmap_transform |
| 82 | + |
| 83 | + # set circle cmap transform |
| 84 | + circle_graphic.cmap.transform = cmap_transform |
| 85 | + |
| 86 | +# when the sine or cosine graphic is clicked, the cmap_transform |
| 87 | +# of the sine, cosine and circle line graphics are all set from |
| 88 | +# the y-values of the clicked line |
| 89 | +sine_graphic.add_event_handler(set_circle_cmap, "click") |
| 90 | +cosine_graphic.add_event_handler(set_circle_cmap, "click") |
| 91 | + |
| 92 | + |
| 93 | +def set_x_val(ev): |
| 94 | + # used to sync the two selectors |
| 95 | + value = ev.info["value"] |
| 96 | + index = ev.get_selected_index() |
| 97 | + |
| 98 | + sine_selector.selection = value |
| 99 | + cosine_selector.selection = value |
| 100 | + |
| 101 | + circle_radius.data[1, :-1] = circle_data[index] |
| 102 | + |
| 103 | +# add same event handler to both graphics |
| 104 | +sine_selector.add_event_handler(set_x_val, "selection") |
| 105 | +cosine_selector.add_event_handler(set_x_val, "selection") |
| 106 | + |
| 107 | +figure.show() |
| 108 | + |
| 109 | + |
| 110 | +# NOTE: `if __name__ == "__main__"` is NOT how to use fastplotlib interactively |
| 111 | +# please see our docs for using fastplotlib interactively in ipython and jupyter |
| 112 | +if __name__ == "__main__": |
| 113 | + print(__doc__) |
| 114 | + fpl.loop.run() |
0 commit comments