• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mbakker7 / ttim / 12312733157

13 Dec 2024 09:08AM UTC coverage: 77.784% (+2.4%) from 75.342%
12312733157

Pull #81

github

web-flow
Merge fcd788ee4 into f9283bd02
Pull Request #81: Add cross-section models

503 of 632 new or added lines in 12 files covered. (79.59%)

42 existing lines in 3 files now uncovered.

3011 of 3871 relevant lines covered (77.78%)

2.33 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.68
/ttim/plots.py
1
from typing import Optional
3✔
2

3
import matplotlib.pyplot as plt
3✔
4
import numpy as np
3✔
5

6

7
class PlotTtim:
3✔
8
    def __init__(self, ml):
3✔
9
        self._ml = ml
3✔
10

11
    def topview(self, win=None, ax=None, figsize=None, layers=None):
3✔
12
        """Plot top-view.
13

14
        Parameters
15
        ----------
16
        win : list or tuple
17
            [x1, x2, y1, y2]
18
        """
19
        if ax is None:
3✔
20
            _, ax = plt.subplots(figsize=figsize)
×
21
            ax.set_aspect("equal", adjustable="box")
×
22
        if layers is not None and isinstance(layers, int):
3✔
23
            layers = [layers]
×
24
        for e in self._ml.elementlist:
3✔
25
            if layers is None or np.isin(e.layers, layers):
3✔
26
                e.plot(ax=ax)
3✔
27
        if win is not None:
3✔
28
            ax.axis(win)
3✔
29
        return ax
3✔
30

31
    def xsection(
3✔
32
        self,
33
        xy: Optional[list[tuple[float]]] = None,
34
        labels=True,
35
        params=False,
36
        ax=None,
37
    ):
38
        if ax is None:
3✔
39
            _, ax = plt.subplots(1, 1, figsize=(8, 4))
3✔
40

41
        if xy is not None:
3✔
42
            (x0, y0), (x1, y1) = xy
3✔
43
            r = np.sqrt((x1 - x0) ** 2 + (y1 - y0) ** 2)
3✔
44
            if y0 == 0 and y1 == 0:
3✔
45
                r0 = x0
3✔
46
                ax.set_xlim(x0, x1)
3✔
NEW
47
            elif x0 == 0 and x1 == 0:
×
NEW
48
                ax.set_ylim(y0, y1)
×
NEW
49
                r0 = y0
×
50
            else:
NEW
51
                ax.set_xlim(0, r)
×
NEW
52
                r0 = 0.0
×
53
        else:
NEW
54
            r0 = 0.0
×
UNCOV
55
            r = 1.0
×
56

57
        if labels:
3✔
58
            lli = 1 if self._ml.aq.topboundary == "con" else 0
3✔
59
            aqi = 0
3✔
60
        else:
61
            lli = None
×
62
            aqi = None
×
63

64
        for i in range(self._ml.aq.nlayers):
3✔
65
            if self._ml.aq.ltype[i] == "l":
3✔
66
                ax.axhspan(
3✔
67
                    ymin=self._ml.aq.z[i + 1],
68
                    ymax=self._ml.aq.z[i],
69
                    color=[0.8, 0.8, 0.8],
70
                )
71
                if labels:
3✔
72
                    ax.text(
3✔
73
                        r0 + 0.5 * r if not params else r0 + 0.25 * r,
74
                        np.mean(self._ml.aq.z[i : i + 2]),
75
                        f"leaky layer {lli}",
76
                        ha="center",
77
                        va="center",
78
                    )
79
                if params:
3✔
80
                    ax.text(
3✔
81
                        r0 + 0.75 * r if labels else r0 + 0.5 * r,
82
                        np.mean(self._ml.aq.z[i : i + 2]),
83
                        (
84
                            f"$c$ = {self._ml.aq.c[lli]}, "
85
                            f"$S_s$ = {self._ml.aq.Sll[lli]:.2e}"
86
                        ),
87
                        ha="center",
88
                        va="center",
89
                    )
90
                if labels or params:
3✔
91
                    lli += 1
3✔
92

93
            if labels and self._ml.aq.ltype[i] == "a":
3✔
94
                ax.text(
3✔
95
                    r0 + 0.5 * r if not params else r0 + 0.25 * r,
96
                    np.mean(self._ml.aq.z[i : i + 2]),
97
                    f"aquifer {aqi}",
98
                    ha="center",
99
                    va="center",
100
                )
101
            if params and self._ml.aq.ltype[i] == "a":
3✔
102
                if aqi == 0 and self._ml.aq.phreatictop:
3✔
103
                    paramtxt = (
3✔
104
                        f"$k_h$ = {self._ml.aq.kaq[aqi]}, "
105
                        f"$S$ = {self._ml.aq.Saq[aqi]}"
106
                    )
107
                else:
108
                    paramtxt = (
3✔
109
                        f"$k_h$ = {self._ml.aq.kaq[aqi]}, "
110
                        f"$S_s$ = {self._ml.aq.Saq[aqi]:.2e}"
111
                    )
112
                ax.text(
3✔
113
                    r0 + 0.75 * r if labels else r0 + 0.5 * r,
114
                    np.mean(self._ml.aq.z[i : i + 2]),
115
                    paramtxt,
116
                    ha="center",
117
                    va="center",
118
                )
119
            if (labels or params) and self._ml.aq.ltype[i] == "a":
3✔
120
                aqi += 1
3✔
121

122
        for i in range(1, self._ml.aq.nlayers):
3✔
123
            if self._ml.aq.ltype[i] == "a" and self._ml.aq.ltype[i - 1] == "a":
3✔
124
                ax.axhspan(
×
125
                    ymin=self._ml.aq.z[i], ymax=self._ml.aq.z[i], color=[0.8, 0.8, 0.8]
126
                )
127

128
        ax.axhline(self._ml.aq.z[0], color="k", lw=0.75)
3✔
129
        ax.axhline(self._ml.aq.z[-1], color="k", lw=3.0)
3✔
130
        ax.set_ylabel("elevation")
3✔
131
        return ax
3✔
132

133
    def head_along_line(
3✔
134
        self,
135
        x1=0,
136
        x2=1,
137
        y1=0,
138
        y2=0,
139
        npoints=100,
140
        t=1.0,
141
        layers=0,
142
        sstart=0,
143
        color=None,
144
        lw=1,
145
        figsize=None,
146
        ax=None,
147
        legend=True,
148
        grid=True,
149
    ):
150
        layers = np.atleast_1d(layers)
3✔
151
        t = np.atleast_1d(t)
3✔
152
        if ax is None:
3✔
153
            _, ax = plt.subplots(figsize=figsize)
3✔
154
        x = np.linspace(x1, x2, npoints)
3✔
155
        y = np.linspace(y1, y2, npoints)
3✔
156
        s = np.sqrt((x - x[0]) ** 2 + (y - y[0]) ** 2) + sstart
3✔
157
        h = self._ml.headalongline(x, y, t, layers)
3✔
158
        nlayers, ntime, npoints = h.shape
3✔
159
        for i in range(nlayers):
3✔
160
            for j in range(ntime):
3✔
161
                lbl = f"head (t={t[j]}, layer={layers[i]})"
3✔
162
                if color is None:
3✔
163
                    ax.plot(s, h[i, j, :], lw=lw, label=lbl)
3✔
164
                else:
165
                    ax.plot(s, h[i, j, :], color, lw=lw, label=lbl)
×
166
        if legend:
3✔
167
            ax.legend(loc=(0, 1), ncol=3, frameon=False)
3✔
168
        if grid:
3✔
169
            ax.grid(True)
3✔
170
        return ax
3✔
171

172
    def contour(
3✔
173
        self,
174
        win,
175
        ngr=20,
176
        t=1,
177
        layers=0,
178
        levels=20,
179
        layout=True,
180
        labels=True,
181
        decimals=1,
182
        color=None,
183
        ax=None,
184
        figsize=None,
185
        legend=True,
186
    ):
187
        """Contour plot.
188

189
        Parameters
190
        ----------
191
        win : list or tuple
192
            [x1, x2, y1, y2]
193
        ngr : scalar, tuple or list
194
            if scalar: number of grid points in x and y direction
195
            if tuple or list: nx, ny, number of grid points in x and y direction
196
        t : scalar
197
            time
198
        layers : integer, list or array
199
            layers for which grid is returned
200
        levels : integer or array (default 20)
201
            levels that are contoured
202
        layout : boolean (default True_)
203
            plot layout of elements
204
        labels : boolean (default True)
205
            print labels along contours
206
        decimals : integer (default 1)
207
            number of decimals of labels along contours
208
        color : str or list of strings
209
            color of contour lines
210
        ax : matplotlib.Axes
211
            axes to plot on, default is None which creates a new figure
212
        figsize : tuple of 2 values (default is mpl default)
213
            size of figure
214
        legend : list or boolean (default True)
215
            add legend to figure
216
            if list of strings: use strings as names in legend
217
        """
218
        x1, x2, y1, y2 = win
3✔
219
        if np.isscalar(ngr):
3✔
220
            nx = ny = ngr
3✔
221
        else:
222
            nx, ny = ngr
3✔
223
        layers = np.atleast_1d(layers)
3✔
224
        xg = np.linspace(x1, x2, nx)
3✔
225
        yg = np.linspace(y1, y2, ny)
3✔
226
        h = self._ml.headgrid(xg, yg, t, layers)
3✔
227
        if ax is None:
3✔
228
            _, ax = plt.subplots(figsize=figsize)
3✔
229
            ax.set_aspect("equal", adjustable="box")
3✔
230
        # color
231
        if color is None:
3✔
232
            c = plt.rcParams["axes.prop_cycle"].by_key()["color"]
3✔
233
        elif isinstance(color, str):
3✔
234
            c = len(layers) * [color]
3✔
235
        elif isinstance(color, list):
×
236
            c = color
×
237
        if len(c) < len(layers):
3✔
238
            n = np.ceil(self._ml.aq.naq / len(c))
×
239
            c = n * c
×
240

241
        # contour
242
        cslist = []
3✔
243
        cshandlelist = []
3✔
244
        for i in range(len(layers)):
3✔
245
            cs = ax.contour(
3✔
246
                xg, yg, h[i, 0], levels, colors=c[i], negative_linestyles="solid"
247
            )
248
            cslist.append(cs)
3✔
249
            handles, _ = cs.legend_elements()
3✔
250
            cshandlelist.append(handles[0])
3✔
251
            if labels:
3✔
252
                fmt = f"%1.{decimals}f"
3✔
253
                ax.clabel(cs, fmt=fmt)
3✔
254
        if isinstance(legend, list):
3✔
255
            ax.legend(cshandlelist, legend, loc=(0, 1), ncol=3, frameon=False)
×
256
        elif legend:
3✔
257
            legendlist = ["layer " + str(i) for i in layers]
3✔
258
            ax.legend(cshandlelist, legendlist, loc=(0, 1), ncol=3, frameon=False)
3✔
259

260
        if layout:
3✔
261
            self.topview(win=[x1, x2, y1, y2], ax=ax)
3✔
262
        return ax
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc