Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 18 additions & 27 deletions discretize/mixins/mpl_mod.py
Original file line number Diff line number Diff line change
Expand Up @@ -792,9 +792,6 @@ def plot_3d_slicer(
# Connect figure to scrolling
fig.canvas.mpl_connect("scroll_event", tracker.onscroll)

# Show figure
plt.show()

# TensorMesh plotting
def __plot_grid_tensor(
self,
Expand Down Expand Up @@ -2458,6 +2455,7 @@ def __init__(
"""Initialize interactive figure."""
_, plt = load_matplotlib()
from matplotlib.widgets import Slider # Lazy loaded
from matplotlib.colors import Normalize

# 0. Some checks, not very extensive
if "pcolorOpts" in kwargs:
Expand Down Expand Up @@ -2512,7 +2510,7 @@ def __init__(

# Store data in self as (nx, ny, nz)
self.v = mesh.reshape(v.reshape((mesh.nC, -1), order="F"), "CC", "CC", "M")
self.v = np.ma.masked_where(np.isnan(self.v), self.v)
self.v = np.ma.masked_array(self.v, np.isnan(self.v))

# Store relevant information from mesh in self
self.x = mesh.nodes_x # x-node locations
Expand Down Expand Up @@ -2552,30 +2550,22 @@ def __init__(
else:
aspect3 = 1.0 / aspect2

# set color limits if clim is None (and norm doesn't have vmin, vmax).
if clim is None:
if "norm" in self.pc_props:
vmin = self.pc_props["norm"].vmin
vmax = self.pc_props["norm"].vmax
else:
vmin = vmax = None
clim = [
np.nanmin(self.v) if vmin is None else vmin,
np.nanmax(self.v) if vmax is None else vmax,
]
# In the case of a homogeneous fullspace provide a small range to
# avoid problems with colorbar and the three subplots.
if clim[0] == clim[1]:
clim[0] *= 0.99
clim[1] *= 1.01

# ensure vmin/vmax of the norm is consistent with clim
if "norm" in self.pc_props:
self.pc_props["norm"].vmin = clim[0]
self.pc_props["norm"].vmax = clim[1]
# Ensure a consistent color normalization for the three plots.
if (norm := self.pc_props.get("norm", None)) is None:
# Create a default normalizer
norm = Normalize()
if clim is not None:
norm.vmin, norm.vmax = clim
self.pc_props["norm"] = norm
else:
self.pc_props["vmin"] = clim[0]
self.pc_props["vmax"] = clim[1]
if clim is not None:
raise ValueError(
"Passing a Normalize instance simultaneously with clim is not supported. "
"Please pass vmin/vmax directly to the norm when creating it."
)

# Auto scales None values for norm.vmin and norm.vmax.
norm.autoscale_None(self.v[~self.v.mask].reshape(-1, order="A"))

# 2. Start populating figure

Expand Down Expand Up @@ -2668,6 +2658,7 @@ def __init__(

# Remove transparent value
if isinstance(transparent, str) and transparent.lower() == "slider":
clim = (norm.vmin, norm.vmax)
# Sliders
self.ax_smin = plt.axes([0.7, 0.11, 0.15, 0.03])
self.ax_smax = plt.axes([0.7, 0.15, 0.15, 0.03])
Expand Down
12 changes: 11 additions & 1 deletion examples/plot_slicer_demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
Using the inversion result from the example notebook
`plot_laguna_del_maule_inversion.ipynb <http://docs.simpeg.xyz/content/examples/20-published/plot_laguna_del_maule_inversion.html>`_

In the notebook, you have to use :code:`%matplotlib notebook`.
You have to use :code:`%matplotlib notebook` in Jupyter Notebook, and
:code:`%matplotlib widget` in Jupyter Lab (latter requires the package
``ipympl``).
"""

# %matplotlib notebook
# %matplotlib widget
import discretize
import numpy as np
import matplotlib.pyplot as plt
Expand Down Expand Up @@ -47,6 +50,7 @@
# ^^^^^^^^^^^^^^^^^^^

mesh.plot_3d_slicer(Lpout)
plt.show()

###############################################################################
# 1.2 Create a function to improve plots, labeling after creation
Expand Down Expand Up @@ -101,6 +105,7 @@ def beautify(title, fig=None):
#
mesh.plot_3d_slicer(Lpout)
beautify("mesh.plot_3d_slicer(Lpout)")
plt.show()

###############################################################################
# 1.3 Set `xslice`, `yslice`, and `zslice`; transparent region
Expand All @@ -115,6 +120,7 @@ def beautify(title, fig=None):
"mesh.plot_3d_slicer("
"\nLpout, 370000, 6002500, -2500, transparent=[[-0.02, 0.1]])"
)
plt.show()

###############################################################################
# 1.4 Set `clim`, use `pcolor_opts` to show grid lines
Expand All @@ -127,6 +133,7 @@ def beautify(title, fig=None):
"mesh.plot_3d_slicer(\nLpout, clim=[-0.4, 0.2], "
"pcolor_opts={'edgecolor': 'k', 'linewidth': 0.1})"
)
plt.show()

###############################################################################
# 1.5 Use `pcolor_opts` to set `SymLogNorm`, and another `cmap`
Expand All @@ -139,6 +146,7 @@ def beautify(title, fig=None):
"mesh.plot_3d_slicer(Lpout,"
"\npcolor_opts={'norm': SymLogNorm(linthresh=0.01),'cmap': 'RdBu_r'})`"
)
plt.show()

###############################################################################
# 1.6 Use :code:`aspect` and :code:`grid`
Expand All @@ -156,6 +164,7 @@ def beautify(title, fig=None):

mesh.plot_3d_slicer(Lpout, aspect=["equal", 1.5], grid=[4, 4, 3])
beautify("mesh.plot_3d_slicer(Lpout, aspect=['equal', 1.5], grid=[4, 4, 3])")
plt.show()

###############################################################################
# 1.7 Transparency-slider
Expand All @@ -166,6 +175,7 @@ def beautify(title, fig=None):

mesh.plot_3d_slicer(Lpout, transparent="slider")
beautify("mesh.plot_3d_slicer(Lpout, transparent='slider')")
plt.show()


###############################################################################
Expand Down
56 changes: 56 additions & 0 deletions tests/base/test_slicer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import numpy as np
import pytest
from matplotlib.colors import Normalize
import discretize
from discretize.mixins.mpl_mod import Slicer


@pytest.fixture()
def mesh():
return discretize.TensorMesh([9, 10, 11])


def test_slicer_errors(mesh):
model = np.ones(mesh.shape_cells)
with pytest.raises(
ValueError,
match="(Passing a Normalize instance simultaneously with clim is not supported).*",
):
Slicer(mesh, model, clim=[0, 1], pcolor_opts={"norm": Normalize()})


def test_slicer_default_clim(mesh):
model = np.ones(mesh.shape_cells)
model[0, 0, 0] = 0.5
slc = Slicer(mesh, model)
norm = slc.pc_props["norm"]
assert (norm.vmin, norm.vmax) == (0.5, 1.0)


def test_slicer_set_clim(mesh):
model = np.ones(mesh.shape_cells)
slc = Slicer(mesh, model, clim=(0.5, 1.5))
norm = slc.pc_props["norm"]
assert (norm.vmin, norm.vmax) == (0.5, 1.5)


def test_slicer_set_norm(mesh):
model = np.ones(mesh.shape_cells)
norm = Normalize(0.5, 1.5)
slc = Slicer(mesh, model, pcolor_opts={"norm": norm})
norm = slc.pc_props["norm"]
assert (norm.vmin, norm.vmax) == (0.5, 1.5)


def test_slicer_ones_clim(mesh):
model = np.ones(mesh.shape_cells)
slc = Slicer(mesh, model)
norm = slc.pc_props["norm"]
assert (norm.vmin, norm.vmax) == (0.9, 1.1)


def test_slicer_zeros_clim(mesh):
model = np.zeros(mesh.shape_cells)
slc = Slicer(mesh, model)
norm = slc.pc_props["norm"]
assert (norm.vmin, norm.vmax) == (-0.1, 0.1)