-
Notifications
You must be signed in to change notification settings - Fork 128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Geomedian notebook #1148
Geomedian notebook #1148
Changes from all commits
2e4221d
005ec26
36a24fe
2a6975f
edd03c5
cb424ef
38c1177
e2d0fa4
bf1ce5d
555e3e9
c3651fc
02ed2dc
b4b992a
09d81c7
6025419
1e69dc2
ddf6b7c
cf4f524
0cf8ac8
b956e10
65ba42e
2b0fdf7
3a8233a
14d2302
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
""" | ||
Geomedian widget: generates an interactive visualisation of | ||
the geomedian summary statistic. | ||
""" | ||
|
||
# Load modules | ||
import ipywidgets as widgets | ||
import matplotlib.pyplot as plt | ||
from mpl_toolkits.mplot3d import Axes3D | ||
import numpy as np | ||
import xarray as xr | ||
from odc.algo import xr_geomedian | ||
|
||
def run_app(): | ||
|
||
""" | ||
An interactive app that allows users to visualise the difference between the median and geomedian time-series summary statistics. By modifying the red-green-blue values of three timesteps for a given pixel, the user changes the output summary statistics. | ||
|
||
This allows a visual representation of the difference through the output values, RGB colour, as well as showing values plotted as a vector on a 3-dimensional space. | ||
|
||
Last modified: December 2021 | ||
""" | ||
|
||
# Define the red-green-blue sliders for timestep 1 | ||
p1r = widgets.IntSlider(description='Red', max=255, value=58) | ||
p1g = widgets.IntSlider(description='Green', max=255, value=153) | ||
p1b = widgets.IntSlider(description='Blue', max=255, value=68) | ||
|
||
# Define the red-green-blue sliders for timestep 2 | ||
p2r = widgets.IntSlider(description='Red', max=255, value=208) | ||
p2g = widgets.IntSlider(description='Green', max=255, value=221) | ||
p2b = widgets.IntSlider(description='Blue', max=255, value=203) | ||
|
||
# Define the red-green-blue sliders for timestep 3 | ||
p3r = widgets.IntSlider(description='Red', max=255, value=202) | ||
p3g = widgets.IntSlider(description='Green', max=255, value=82) | ||
p3b = widgets.IntSlider(description='Blue', max=255, value=33) | ||
|
||
# Define the median calculation for the timesteps | ||
def f(p1r, p1g, p1b, p2r, p2g, p2b, p3r, p3g, p3b): | ||
print('Red Median = {}'.format(np.median([p1r, p2r, p3r]))) | ||
print('Green Median = {}'.format(np.median([p1g, p2g, p3g]))) | ||
print('Blue Median = {}'.format(np.median([p1b, p2b, p3b]))) | ||
|
||
# Define the geomedian calculation for the timesteps | ||
def g(p1r, p1g, p1b, p2r, p2g, p2b, p3r, p3g, p3b): | ||
print('Red Geomedian = {:.2f}'.format(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).red.values.ravel()[0])) | ||
print('Green Geomedian = {:.2f}'.format(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).green.values.ravel()[0])) | ||
print('Blue Geomedian = {:.2f}'.format(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).blue.values.ravel()[0])) | ||
|
||
# Define the Timestep 1 box colour | ||
def h(p1r, p1g, p1b): | ||
fig1, axes1 = plt.subplots(figsize=(2,2)) | ||
fig1 = plt.imshow([[(p1r, p1g, p1b)]]) | ||
axes1.set_title('Timestep 1') | ||
axes1.axis('off') | ||
plt.show(fig1) | ||
|
||
# Define the Timestep 2 box colour | ||
def hh(p2r, p2g, p2b): | ||
fig2, axes2 = plt.subplots(figsize=(2,2)) | ||
fig2 = plt.imshow([[(p2r, p2g, p2b)]]) | ||
axes2.set_title('Timestep 2') | ||
axes2.axis('off') | ||
plt.show(fig2) | ||
|
||
# Define the Timestep 3 box colour | ||
def hhh(p3r, p3g, p3b): | ||
fig3, axes3 = plt.subplots(figsize=(2,2)) | ||
fig3 = plt.imshow([[(p3r, p3g, p3b)]]) | ||
axes3.set_title('Timestep 3') | ||
axes3.axis('off') | ||
plt.show(fig3) | ||
|
||
# Define the Median RGB colour box | ||
def i(p1r, p1g, p1b, p2r, p2g, p2b, p3r, p3g, p3b): | ||
fig4, axes4 = plt.subplots(figsize=(3,3)) | ||
fig4 = plt.imshow([[(int(np.median([p1r, p2r, p3r])), int(np.median([p1g, p2g, p3g])), int(np.median([p1b, p2b, p3b])))]]) | ||
axes4.set_title('Median RGB - All timesteps') | ||
axes4.axis('off') | ||
plt.show(fig4) | ||
|
||
# Define the Geomedian RGB colour box | ||
def ii(p1r, p1g, p1b, p2r, p2g, p2b, p3r, p3g, p3b): | ||
fig5, axes5 = plt.subplots(figsize=(3,3)) | ||
fig5 = plt.imshow([[(int(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).red.values.ravel()[0]), int(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).green.values.ravel()[0]), int(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).blue.values.ravel()[0]))]]) | ||
axes5.set_title('Geomedian RGB - All timesteps') | ||
axes5.axis('off') | ||
plt.show(fig5) | ||
|
||
# Define 3-D axis to display vectors on | ||
def j(p1r, p1g, p1b, p2r, p2g, p2b, p3r, p3g, p3b): | ||
fig6 = plt.figure() | ||
axes6 = fig6.add_subplot(111, projection='3d') | ||
x = [p1r, p2r, p3r, int(np.median([p1r, p2r, p3r])), int(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).red.values.ravel()[0])] | ||
y = [p1g, p2g, p3g, int(np.median([p1g, p2g, p3g])), int(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).green.values.ravel()[0])] | ||
z = [p1b, p2b, p3b, int(np.median([p1b, p2b, p3b])), int(xr_geomedian(xr.Dataset({"red": (("x", "y", "time"), [[[np.float32(p1r), np.float32(p2r), np.float32(p3r)]]]), "green": (("x", "y", "time"), [[[np.float32(p1g), np.float32(p2g), np.float32(p3g)]]]), "blue": (("x", "y", "time"), [[[np.float32(p1b), np.float32(p2b), np.float32(p3b)]]])})).blue.values.ravel()[0])] | ||
labels = [' 1', ' 2', ' 3', ' median', ' geomedian'] | ||
axes6.scatter(x, y, z, c=['black','black','black','r', 'blue'], marker='o') | ||
axes6.set_xlabel('Red') | ||
axes6.set_ylabel('Green') | ||
axes6.set_zlabel('Blue') | ||
axes6.set_xlim3d(0, 255) | ||
axes6.set_ylim3d(0, 255) | ||
axes6.set_zlim3d(0, 255) | ||
for ax, ay, az, label in zip(x, y, z, labels): | ||
axes6.text(ax, ay, az, label) | ||
plt.title('Each band represents a dimension.') | ||
plt.show() | ||
|
||
# Define outputs | ||
outf = widgets.interactive_output(f, {'p1r': p1r, 'p2r': p2r,'p3r': p3r, 'p1g': p1g, 'p2g': p2g,'p3g': p3g, 'p1b': p1b, 'p2b': p2b,'p3b': p3b}) | ||
outg = widgets.interactive_output(g, {'p1r': p1r, 'p2r': p2r,'p3r': p3r, 'p1g': p1g, 'p2g': p2g,'p3g': p3g, 'p1b': p1b, 'p2b': p2b,'p3b': p3b}) | ||
|
||
outh = widgets.interactive_output(h, {'p1r': p1r, 'p1g': p1g, 'p1b': p1b}) | ||
outhh = widgets.interactive_output(hh, {'p2r': p2r, 'p2g': p2g, 'p2b': p2b}) | ||
outhhh = widgets.interactive_output(hhh, {'p3r': p3r, 'p3g': p3g, 'p3b': p3b}) | ||
|
||
outi = widgets.interactive_output(i, {'p1r': p1r, 'p2r': p2r,'p3r': p3r, 'p1g': p1g, 'p2g': p2g,'p3g': p3g, 'p1b': p1b, 'p2b': p2b,'p3b': p3b}) | ||
outii = widgets.interactive_output(ii, {'p1r': p1r, 'p2r': p2r,'p3r': p3r, 'p1g': p1g, 'p2g': p2g,'p3g': p3g, 'p1b': p1b, 'p2b': p2b,'p3b': p3b}) | ||
|
||
outj = widgets.interactive_output(j, {'p1r': p1r, 'p2r': p2r,'p3r': p3r, 'p1g': p1g, 'p2g': p2g,'p3g': p3g, 'p1b': p1b, 'p2b': p2b,'p3b': p3b}) | ||
|
||
app_output = widgets.HBox([widgets.VBox([widgets.HBox([outh, widgets.VBox([ p1r, p1g, p1b])]), widgets.HBox([outhh, widgets.VBox([p2r, p2g, p2b])]), widgets.HBox([outhhh, widgets.VBox([ p3r, p3g, p3b])])]), widgets.VBox([widgets.HBox([widgets.VBox([outf, outi]), widgets.VBox([outg, outii])]), outj])]) | ||
|
||
return app_output |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @JM-GA, everything looks awesome here, great work. One tiny minor comment is that the new data now includes a chunk of nodata here - might be good to add in a call to
datacube.utils.masking import mask_invalid_data
to this example so that users can correctly treat nodata values in their analysis. But not a major issue!There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @robbibt - good idea! I have added in handing of no data pixels into the notebook