Skip to content
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

Update code and tests to same as xtgeo.plot #29

Merged
merged 1 commit into from
Dec 7, 2023
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
25 changes: 13 additions & 12 deletions src/xtgeoviz/plot/baseplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def __init__(self):
self._tight = False
self._showok = True
self._fig = None
self._allfigs = []
Copy link

@janbjorge janbjorge Dec 7, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have a weak-feeling that this should maybe be a weakref. My thinking being, if you have a few figures open and close one of them. The closing figures memory should be cleared then and not hang around until all a closed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not so sure about this either. Hopefully we can come back to this code at some point. But for now, it's just copying the current state of xtgeo.plot to here.

I made an issue for it: #30

self._pagesize = "A4"

logger.debug("Ran __init__ for BasePlot")
Expand Down Expand Up @@ -155,13 +156,6 @@ def get_any_colormap_as_table(cmap):
cmaplist = [cmap(i) for i in range(cmap.N)]
return cmaplist

def set_colortable(self, cname, colorlist=None):
"""This is actually deprecated..."""
if colorlist is None:
self.colormap = cname
else:
self.define_colormap(cname, colorlist=colorlist)

def get_colormap_as_table(self):
"""Get the current color map as a list of RGB tuples."""
return self.get_any_colormap_as_table(self._colormap)
Expand Down Expand Up @@ -195,10 +189,10 @@ def canvas(self, title=None, subtitle=None, infotext=None, figscaling=1.0):


"""
# self._fig, (ax1, ax2) = plt.subplots(2, figsize=(11.69, 8.27))
self._fig, self._ax = plt.subplots(
figsize=(11.69 * figscaling, 8.27 * figscaling)
)
self._allfigs.append(self._fig)
if title is not None:
self._fig.suptitle(title, fontsize=18)
if subtitle is not None:
Expand All @@ -223,15 +217,22 @@ def show(self):
logger.warning("Nothing to plot (well outside Z range?)")
return False

def close(self):
"""
Explicitly closes the plot, meaning that memory will be cleared.
After close is called, no more operations can be performed on the plot.
"""
for fig in self._allfigs:
plt.close(fig)

def savefig(self, filename, fformat="png", last=True, **kwargs):
"""Call to matplotlib.pyplot savefig method.

Args:
filename (str): File to plot to
fformat (str): Plot format, e.g. png (default), jpg, svg
last (bool): Default is true, meaning that memory will be cleared;
however if several plot types for the same instance, let last
be False fora all except the last plots.
last (bool): Default is true, calls close on the plot, let last
be False for all except the last plots.
kwargs: Additional keyword arguments that are passed
to matplotlib when saving the figure

Expand All @@ -252,7 +253,7 @@ def savefig(self, filename, fformat="png", last=True, **kwargs):
if self._showok:
plt.savefig(filename, format=fformat, **kwargs)
if last:
plt.close(self._fig)
self.close()
return True

logger.warning("Nothing to plot (well outside Z range?)")
Expand Down
2 changes: 1 addition & 1 deletion src/xtgeoviz/plot/grid3d_slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def _plot_layer(self):
for pos in range(len(ibn)):
nppol = xyc[pos, :, :]
if nppol.mean() > 0.0:
polygon = Polygon(nppol, True)
polygon = Polygon(nppol)
patches.append(polygon)

patchcoll = PatchCollection(
Expand Down
17 changes: 9 additions & 8 deletions src/xtgeoviz/plot/xsection.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import logging
import math
import warnings
from collections import OrderedDict
from typing import Optional, Union

import matplotlib.pyplot as plt
Expand All @@ -16,7 +15,7 @@
from matplotlib.colors import LinearSegmentedColormap, ListedColormap
from matplotlib.lines import Line2D

from ._libwrapper import scipy_gaussianfilter
from ._libwrapper import matplotlib_colormap, scipy_gaussianfilter
from .baseplot import BasePlot

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -84,6 +83,7 @@ def __init__(
self._ax1 = None
self._ax2 = None
self._ax3 = None
self._allfigs = []

self._colormap_cube = None
self._colorlegend_cube = False
Expand All @@ -92,7 +92,7 @@ def __init__(
self._colorlegend_grid = False

if colormap is None:
self._colormap = plt.cm.get_cmap("viridis")
self._colormap = matplotlib_colormap("viridis")
else:
self.define_colormap(colormap)

Expand Down Expand Up @@ -257,9 +257,11 @@ def canvas(self, title=None, subtitle=None, infotext=None, figscaling=1.0):
plt.rcParams["ytick.color"] = (0, 0, 0, 0)

self._fig = plt.figure(figsize=(11.69 * figscaling, 8.27 * figscaling))
ax1 = OrderedDict()
self._allfigs.append(self._fig)

ax1["main"] = plt.subplot2grid((20, 28), (0, 0), rowspan=20, colspan=23)
ax1 = {
"main": plt.subplot2grid((20, 28), (0, 0), rowspan=20, colspan=23),
}

ax2 = plt.subplot2grid(
(20, 28), (10, 23), rowspan=5, colspan=5, frame_on=self._has_legend
Expand Down Expand Up @@ -548,7 +550,6 @@ def _plot_well_zlog(self, df, ax, bba, zonelogname, logwidth=4, legend=False):

ax.add_collection(lc)

legend = False
if legend:
zrecord = self._well.get_logrecord(zonelogname)
zrecord = {val: zname for val, zname in zrecord.items() if val >= 0}
Expand Down Expand Up @@ -597,7 +598,7 @@ def _plot_well_faclog(self, df, ax, bba, facieslogname, logwidth=9, legend=True)
frecord = self._well.get_logrecord(facieslogname)
frecord = {val: fname for val, fname in frecord.items() if val >= 0}

fcolors = dict()
fcolors = {}
for facies in frecord:
if isinstance(idx[facies], str):
color = idx[facies]
Expand Down Expand Up @@ -643,7 +644,7 @@ def _plot_well_perflog(self, df, ax, bba, perflogname, logwidth=12, legend=True)
precord = self._well.get_logrecord(perflogname)
precord = {val: pname for val, pname in precord.items() if val >= 0}

pcolors = dict()
pcolors = {}
for perf in precord:
if isinstance(idx[perf], str):
color = idx[perf]
Expand Down
36 changes: 36 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,42 @@
import pytest


def pytest_addoption(parser):
parser.addoption(
"--testdatapath",
help="path to xtgeo-testdata, defaults to ../xtgeo-testdata"
"and is overriden by the XTG_TESTPATH environment variable."
"Experimental feature, not all tests obey this option.",
action="store",
default="../xtgeo-testdata",
)
parser.addoption(
"--generate-plots",
help="whether to generate plot files. The files are written to the"
"pytest tmpfolder. In order to inspect whether plots are correctly"
"generated, the files must be manually inspected.",
action="store_true",
default=False,
)


@pytest.fixture(name="generate_plot")
def fixture_generate_plot(request):
if "ROXENV" in os.environ:
pytest.skip("Skip plotting tests in roxar environment")
return request.config.getoption("--generate-plots")


@pytest.fixture(name="show_plot")
def fixture_xtgshow():
"""For eventual plotting, to be uses in an if sence inside a test."""
if "ROXENV" in os.environ:
pytest.skip("Skip plotting tests in roxar environment")
if any(word in os.environ for word in ["XTGSHOW", "XTG_SHOW"]):
return True
return False


@pytest.fixture(name="testdir")
def fixure_testdir():
"""Relative path to xtgeo-testdata, defaulted to ../xtgeo-testdata."""
Expand Down
18 changes: 18 additions & 0 deletions tests/test_plot/test_colortables.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import pathlib

import xtgeoviz.plot._colortables as ct

TPATH = pathlib.Path("../xtgeo-testdata")


def test_readfromfile():
"""Read color table from RMS file."""
cfile = TPATH / "etc/colortables/colfacies.txt"
ctable = ct.colorsfromfile(cfile)
assert ctable[5] == (0.49019608, 0.38431373, 0.05882353)


def test_xtgeo_colors():
"""Read the XTGeo color table."""
ctable = ct.xtgeocolors()
assert ctable[5] == (0.000, 1.000, 1.000)
41 changes: 41 additions & 0 deletions tests/test_plot/test_grid3dsliceplot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import os
import pathlib

import pytest
import xtgeo

from xtgeoviz.plot import Grid3DSlice

TPATH = pathlib.Path("../xtgeo-testdata")

USEFILE1 = TPATH / "3dgrids/reek/reek_sim_grid.roff"
USEFILE2 = TPATH / "3dgrids/reek/reek_sim_poro.roff"
USEFILE3 = TPATH / "etc/colortables/rainbow_reverse.rmscolor"


def test_slice_simple_layer(tmpdir, show_plot, generate_plot):
"""Trigger XSection class, and do some simple things basically."""
layslice = Grid3DSlice()

mygrid = xtgeo.grid_from_file(USEFILE1)
myprop = xtgeo.gridproperty_from_file(USEFILE2, grid=mygrid, name="PORO")

assert myprop.values.mean() == pytest.approx(0.1677, abs=0.001)

wd = None # [457000, 464000, 1650, 1800]
for lay in range(1, mygrid.nlay + 1):
layslice.canvas(title=f"My Grid Layer plot for layer {lay}")
layslice.plot_gridslice(
mygrid,
prop=myprop,
mode="layer",
index=lay,
window=wd,
linecolor="black",
)

if show_plot:
layslice.show()
if generate_plot:
layslice.savefig(os.path.join(tmpdir, "layerslice_" + str(lay) + ".png"))
layslice.close()
92 changes: 92 additions & 0 deletions tests/test_plot/test_map.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import pathlib
from os.path import join

import xtgeo

from xtgeoviz.plot import Map

TPATH = pathlib.Path("../xtgeo-testdata")

SFILE1 = TPATH / "surfaces/reek/1/topreek_rota.gri"
PFILE1 = TPATH / "polygons/reek/1/top_upper_reek_faultpoly.pol"
SFILE2 = TPATH / "surfaces/reek/1/reek_perm_lay1.gri"


def test_simple_plot(tmpdir, generate_plot):
"""Test as simple map plot only making an instance++ and plot."""

mysurf = xtgeo.surface_from_file(SFILE1)

# just make the instance, with a lot of defaults behind the scene
myplot = Map()
myplot.canvas(title="My o my")
myplot.colormap = "gist_ncar"
myplot.plot_surface(mysurf)

if generate_plot:
myplot.savefig(join(tmpdir, "map_simple.png"), last=True)
else:
myplot.close()


def test_map_plot_with_points(tmpdir, generate_plot):
"""Test as simple map plot with underlying points."""

mysurf = xtgeo.surface_from_file(SFILE1)

mypoints = xtgeo.points_from_surface(mysurf)

df = mypoints.dataframe.copy()
df = df[::20]
mypoints.dataframe = df

# just make the instance, with a lot of defaults behind the scene
myplot = Map()
myplot.canvas(title="My o my")
myplot.colormap = "gist_ncar"
myplot.plot_surface(mysurf)
myplot.plot_points(mypoints)

if generate_plot:
myplot.savefig(join(tmpdir, "map_with_points.png"), last=True)
else:
myplot.close()


def test_more_features_plot(tmpdir, generate_plot):
"""Map with some more features added, such as label rotation."""

mysurf = xtgeo.surface_from_file(SFILE1)

myfaults = xtgeo.polygons_from_file(PFILE1)

# just make the instance, with a lot of defaults behind the scene
myplot = Map()
myplot.canvas(title="Label rotation")
myplot.colormap = "rainbow"
myplot.plot_surface(mysurf, minvalue=1250, maxvalue=2200, xlabelrotation=45)

myplot.plot_faults(myfaults)

if generate_plot:
myplot.savefig(join(tmpdir, "map_more1.png"), last=True)
else:
myplot.close()


def test_perm_logarithmic_map(tmpdir, generate_plot):
"""Map with PERM, log scale."""

mysurf = xtgeo.surface_from_file(SFILE2)

myplot = Map()
myplot.canvas(title="PERMX normal scale")
myplot.colormap = "rainbow"
myplot.plot_surface(
mysurf, minvalue=0, maxvalue=6000, xlabelrotation=45, logarithmic=True
)

if generate_plot:
myplot.savefig(join(tmpdir, "permx_normal.png"), last=True)
else:
myplot.close()
Loading