gerg_plotting 0.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,214 @@
1
+ Metadata-Version: 2.1
2
+ Name: gerg_plotting
3
+ Version: 0.0.1
4
+ Summary:
5
+ Author: Alec Krueger
6
+ Author-email: alecmkrueger@tamu.edu
7
+ Requires-Python: >=3.12,<4.0
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.12
10
+ Requires-Dist: attrs (>=23.2.0,<24.0.0)
11
+ Requires-Dist: cmocean (>=4.0.3,<5.0.0)
12
+ Requires-Dist: matplotlib (>=3.9.1,<4.0.0)
13
+ Requires-Dist: mayavi (>=4.8.2,<5.0.0)
14
+ Requires-Dist: netcdf4 (>=1.7.1.post1,<2.0.0)
15
+ Requires-Dist: numpy (>=2.0.0,<3.0.0)
16
+ Requires-Dist: pandas (>=2.2.2,<3.0.0)
17
+ Requires-Dist: scipy (>=1.14.0,<2.0.0)
18
+ Requires-Dist: xarray (>=2024.6.0,<2025.0.0)
19
+ Description-Content-Type: text/markdown
20
+
21
+ <a id="readme-top"></a>
22
+
23
+ <!-- PROJECT LOGO -->
24
+ <br />
25
+ <div align="center">
26
+ <a href="https://github.com/alecmkrueger/gerg_plotting">
27
+ <img src="https://raw.githubusercontent.com/alecmkrueger/project_images/9af2f8f58c93e183ac5473a4474619407aee08d3/gerg_logo.svg" alt="Logo" width="500" height="272">
28
+ </a>
29
+
30
+ <h3 align="center">GERG Plotting</h3>
31
+
32
+ <p align="center">
33
+ Data plotting package for GERG
34
+ <br />
35
+ <a href="https://github.com/alecmkrueger/gerg_plotting"><strong>Explore the docs »</strong></a>
36
+ <br />
37
+ <br />
38
+ <a href="https://github.com/alecmkrueger/gerg_plotting/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
39
+ ·
40
+ <a href="https://github.com/alecmkrueger/gerg_plotting/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
41
+ </p>
42
+ </div>
43
+
44
+
45
+
46
+ <!-- TABLE OF CONTENTS -->
47
+ <details>
48
+ <summary>Table of Contents</summary>
49
+ <ol>
50
+ <li>
51
+ <a href="#about-the-project">About The Project</a>
52
+ <ul>
53
+ <li><a href="#built-with">Built With</a></li>
54
+ </ul>
55
+ </li>
56
+ <li>
57
+ <a href="#getting-started">Getting Started</a>
58
+ <ul>
59
+ <li><a href="#dependencies">Dependencies</a></li>
60
+ <li><a href="#installation">Installation</a></li>
61
+ </ul>
62
+ </li>
63
+ <li><a href="#usage">Usage</a></li>
64
+ <li><a href="#contributing">Contributing</a></li>
65
+ <li><a href="#license">License</a></li>
66
+ <li><a href="#contact">Contact</a></li>
67
+ <li><a href="#acknowledgments">Acknowledgments</a></li>
68
+ </ol>
69
+ </details>
70
+
71
+
72
+
73
+ <!-- ABOUT THE PROJECT -->
74
+ ## About The Project
75
+
76
+ This project was created to streamline and standardize the process of generating plots at GERG.
77
+
78
+
79
+
80
+ ### Built With
81
+
82
+ [![Python][Python]][Python-url]
83
+
84
+
85
+
86
+ <!-- GETTING STARTED -->
87
+ ## Getting Started
88
+
89
+ There are three ways to get started
90
+ 1. Create a fresh virtual environment using your favorite method and install the dependencies
91
+ 2. Use an already established virtual environment and install the dependencies
92
+
93
+
94
+
95
+ ### Dependencies
96
+ I have provided some commands to install the dependencies using conda but you can use any package manager
97
+
98
+ List of dependencies:
99
+ * python = 3.12
100
+ * numpy = 2.0.0
101
+ * pandas = 2.2.2
102
+ * matplotlib = 3.9.1
103
+ * xarray = 2024.6.0
104
+ * attrs = 23.2.0
105
+ * netcdf4 = 1.7.1.post1
106
+ * cmocean = 4.0.3
107
+ * scipy = 1.14.0
108
+ * mayavi = 4.8.2
109
+
110
+ 1. #### Creating your own virtual environment then installing dependencies
111
+ You can change "gerg_plotting" to your desired environment name
112
+
113
+ ```sh
114
+ conda create -n gerg_plotting python=3.12
115
+ ```
116
+
117
+ ```sh
118
+ conda activate gerg_plotting
119
+ ```
120
+
121
+ ```sh
122
+ pip install numpy pandas xarray matplotlib attrs notebook
123
+ ```
124
+
125
+ 2. #### Using an already established virtual environment
126
+
127
+ ```sh
128
+ conda activate your_env
129
+ ```
130
+
131
+ ```sh
132
+ pip install numpy pandas xarray gsw attrs
133
+ ```
134
+
135
+ ### Installation
136
+
137
+ 1. Activate your virtual environment
138
+ 1. Verify/Install Dependencies
139
+ 1. Clone the repo
140
+ ```sh
141
+ git clone https://github.com/alecmkrueger/gerg_plotting.git
142
+ ```
143
+
144
+
145
+
146
+
147
+
148
+ <!-- USAGE EXAMPLES -->
149
+ ## Usage
150
+
151
+ Plot data at GERG using Python.
152
+
153
+
154
+
155
+
156
+ <!-- CONTRIBUTING -->
157
+ ## Contributing
158
+
159
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
160
+
161
+ If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
162
+
163
+ 1. Fork the Project
164
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
165
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
166
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
167
+ 5. Open a Pull Request
168
+
169
+
170
+
171
+
172
+
173
+ <!-- LICENSE -->
174
+ ## License
175
+
176
+ Distributed under the MIT License. See `LICENSE` for more information.
177
+
178
+
179
+
180
+ <!-- CONTACT -->
181
+ ## Contact
182
+
183
+ Alec Krueger - alecmkrueger@tamu.edu
184
+
185
+ Project Link: [https://github.com/alecmkrueger/gerg_plotting](https://github.com/alecmkrueger/gerg_plotting)
186
+
187
+
188
+
189
+ <!-- ACKNOWLEDGMENTS -->
190
+ ## Acknowledgments
191
+
192
+ * Alec Krueger, Texas A&M University, Geochemical and Environmental Research Group, alecmkrueger@tamu.edu
193
+
194
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
195
+
196
+
197
+
198
+ <!-- MARKDOWN LINKS & IMAGES -->
199
+ <!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
200
+ [contributors-shield]: https://img.shields.io/github/contributors/alecmkrueger/gerg_plotting.svg?style=for-the-badge
201
+ [contributors-url]: https://github.com/alecmkrueger/gerg_plotting/graphs/contributors
202
+ [forks-shield]: https://img.shields.io/github/forks/alecmkrueger/gerg_plotting.svg?style=for-the-badge
203
+ [forks-url]: https://github.com/alecmkrueger/gerg_plotting/network/members
204
+ [stars-shield]: https://img.shields.io/github/stars/alecmkrueger/gerg_plotting.svg?style=for-the-badge
205
+ [stars-url]: https://github.com/alecmkrueger/gerg_plotting/stargazers
206
+ [issues-shield]: https://img.shields.io/github/issues/alecmkrueger/gerg_plotting.svg?style=for-the-badge
207
+ [issues-url]: https://github.com/alecmkrueger/gerg_plotting/issues
208
+ [license-shield]: https://img.shields.io/github/license/alecmkrueger/gerg_plotting.svg?style=for-the-badge
209
+ [license-url]: https://github.com/alecmkrueger/gerg_plotting/LICENSE
210
+ [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
211
+ [linkedin-url]: https://linkedin.com/in/aleckrueger
212
+ [product-screenshot]: images/screenshot.png
213
+ [Python]: https://img.shields.io/badge/python-000000?&logo=python
214
+ [Python-url]: https://www.python.org/
@@ -0,0 +1,194 @@
1
+ <a id="readme-top"></a>
2
+
3
+ <!-- PROJECT LOGO -->
4
+ <br />
5
+ <div align="center">
6
+ <a href="https://github.com/alecmkrueger/gerg_plotting">
7
+ <img src="https://raw.githubusercontent.com/alecmkrueger/project_images/9af2f8f58c93e183ac5473a4474619407aee08d3/gerg_logo.svg" alt="Logo" width="500" height="272">
8
+ </a>
9
+
10
+ <h3 align="center">GERG Plotting</h3>
11
+
12
+ <p align="center">
13
+ Data plotting package for GERG
14
+ <br />
15
+ <a href="https://github.com/alecmkrueger/gerg_plotting"><strong>Explore the docs »</strong></a>
16
+ <br />
17
+ <br />
18
+ <a href="https://github.com/alecmkrueger/gerg_plotting/issues/new?labels=bug&template=bug-report---.md">Report Bug</a>
19
+ ·
20
+ <a href="https://github.com/alecmkrueger/gerg_plotting/issues/new?labels=enhancement&template=feature-request---.md">Request Feature</a>
21
+ </p>
22
+ </div>
23
+
24
+
25
+
26
+ <!-- TABLE OF CONTENTS -->
27
+ <details>
28
+ <summary>Table of Contents</summary>
29
+ <ol>
30
+ <li>
31
+ <a href="#about-the-project">About The Project</a>
32
+ <ul>
33
+ <li><a href="#built-with">Built With</a></li>
34
+ </ul>
35
+ </li>
36
+ <li>
37
+ <a href="#getting-started">Getting Started</a>
38
+ <ul>
39
+ <li><a href="#dependencies">Dependencies</a></li>
40
+ <li><a href="#installation">Installation</a></li>
41
+ </ul>
42
+ </li>
43
+ <li><a href="#usage">Usage</a></li>
44
+ <li><a href="#contributing">Contributing</a></li>
45
+ <li><a href="#license">License</a></li>
46
+ <li><a href="#contact">Contact</a></li>
47
+ <li><a href="#acknowledgments">Acknowledgments</a></li>
48
+ </ol>
49
+ </details>
50
+
51
+
52
+
53
+ <!-- ABOUT THE PROJECT -->
54
+ ## About The Project
55
+
56
+ This project was created to streamline and standardize the process of generating plots at GERG.
57
+
58
+
59
+
60
+ ### Built With
61
+
62
+ [![Python][Python]][Python-url]
63
+
64
+
65
+
66
+ <!-- GETTING STARTED -->
67
+ ## Getting Started
68
+
69
+ There are three ways to get started
70
+ 1. Create a fresh virtual environment using your favorite method and install the dependencies
71
+ 2. Use an already established virtual environment and install the dependencies
72
+
73
+
74
+
75
+ ### Dependencies
76
+ I have provided some commands to install the dependencies using conda but you can use any package manager
77
+
78
+ List of dependencies:
79
+ * python = 3.12
80
+ * numpy = 2.0.0
81
+ * pandas = 2.2.2
82
+ * matplotlib = 3.9.1
83
+ * xarray = 2024.6.0
84
+ * attrs = 23.2.0
85
+ * netcdf4 = 1.7.1.post1
86
+ * cmocean = 4.0.3
87
+ * scipy = 1.14.0
88
+ * mayavi = 4.8.2
89
+
90
+ 1. #### Creating your own virtual environment then installing dependencies
91
+ You can change "gerg_plotting" to your desired environment name
92
+
93
+ ```sh
94
+ conda create -n gerg_plotting python=3.12
95
+ ```
96
+
97
+ ```sh
98
+ conda activate gerg_plotting
99
+ ```
100
+
101
+ ```sh
102
+ pip install numpy pandas xarray matplotlib attrs notebook
103
+ ```
104
+
105
+ 2. #### Using an already established virtual environment
106
+
107
+ ```sh
108
+ conda activate your_env
109
+ ```
110
+
111
+ ```sh
112
+ pip install numpy pandas xarray gsw attrs
113
+ ```
114
+
115
+ ### Installation
116
+
117
+ 1. Activate your virtual environment
118
+ 1. Verify/Install Dependencies
119
+ 1. Clone the repo
120
+ ```sh
121
+ git clone https://github.com/alecmkrueger/gerg_plotting.git
122
+ ```
123
+
124
+
125
+
126
+
127
+
128
+ <!-- USAGE EXAMPLES -->
129
+ ## Usage
130
+
131
+ Plot data at GERG using Python.
132
+
133
+
134
+
135
+
136
+ <!-- CONTRIBUTING -->
137
+ ## Contributing
138
+
139
+ Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
140
+
141
+ If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement".
142
+
143
+ 1. Fork the Project
144
+ 2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
145
+ 3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
146
+ 4. Push to the Branch (`git push origin feature/AmazingFeature`)
147
+ 5. Open a Pull Request
148
+
149
+
150
+
151
+
152
+
153
+ <!-- LICENSE -->
154
+ ## License
155
+
156
+ Distributed under the MIT License. See `LICENSE` for more information.
157
+
158
+
159
+
160
+ <!-- CONTACT -->
161
+ ## Contact
162
+
163
+ Alec Krueger - alecmkrueger@tamu.edu
164
+
165
+ Project Link: [https://github.com/alecmkrueger/gerg_plotting](https://github.com/alecmkrueger/gerg_plotting)
166
+
167
+
168
+
169
+ <!-- ACKNOWLEDGMENTS -->
170
+ ## Acknowledgments
171
+
172
+ * Alec Krueger, Texas A&M University, Geochemical and Environmental Research Group, alecmkrueger@tamu.edu
173
+
174
+ <p align="right">(<a href="#readme-top">back to top</a>)</p>
175
+
176
+
177
+
178
+ <!-- MARKDOWN LINKS & IMAGES -->
179
+ <!-- https://www.markdownguide.org/basic-syntax/#reference-style-links -->
180
+ [contributors-shield]: https://img.shields.io/github/contributors/alecmkrueger/gerg_plotting.svg?style=for-the-badge
181
+ [contributors-url]: https://github.com/alecmkrueger/gerg_plotting/graphs/contributors
182
+ [forks-shield]: https://img.shields.io/github/forks/alecmkrueger/gerg_plotting.svg?style=for-the-badge
183
+ [forks-url]: https://github.com/alecmkrueger/gerg_plotting/network/members
184
+ [stars-shield]: https://img.shields.io/github/stars/alecmkrueger/gerg_plotting.svg?style=for-the-badge
185
+ [stars-url]: https://github.com/alecmkrueger/gerg_plotting/stargazers
186
+ [issues-shield]: https://img.shields.io/github/issues/alecmkrueger/gerg_plotting.svg?style=for-the-badge
187
+ [issues-url]: https://github.com/alecmkrueger/gerg_plotting/issues
188
+ [license-shield]: https://img.shields.io/github/license/alecmkrueger/gerg_plotting.svg?style=for-the-badge
189
+ [license-url]: https://github.com/alecmkrueger/gerg_plotting/LICENSE
190
+ [linkedin-shield]: https://img.shields.io/badge/-LinkedIn-black.svg?style=for-the-badge&logo=linkedin&colorB=555
191
+ [linkedin-url]: https://linkedin.com/in/aleckrueger
192
+ [product-screenshot]: images/screenshot.png
193
+ [Python]: https://img.shields.io/badge/python-000000?&logo=python
194
+ [Python-url]: https://www.python.org/
@@ -0,0 +1,37 @@
1
+ [tool.poetry]
2
+ name = "gerg_plotting"
3
+ version = "0.0.01"
4
+ description = ""
5
+ authors = ["Alec Krueger <alecmkrueger@tamu.edu>"]
6
+ readme = "README.md"
7
+ packages = [{include = "gerg_plotting", from = "src"}]
8
+ include = ["seafloor_data/gebco_2023_n31.0_s7.0_w-100.0_e-66.5.nc"]
9
+
10
+ [tool.poetry.dependencies]
11
+ python = "^3.12"
12
+ numpy = "^2.0.0"
13
+ pandas = "^2.2.2"
14
+ matplotlib = "^3.9.1"
15
+ xarray = "^2024.6.0"
16
+ attrs = "^23.2.0"
17
+ netcdf4 = "^1.7.1.post1"
18
+ cmocean = "^4.0.3"
19
+ scipy = "^1.14.0"
20
+ mayavi = "^4.8.2"
21
+
22
+
23
+ [tool.poetry.group.dev.dependencies]
24
+ black = "^24.4.2"
25
+ flake8 = "^7.1.0"
26
+ isort = "^5.13.2"
27
+ mypy = "^1.10.1"
28
+ pylint = "^3.2.5"
29
+
30
+
31
+ [tool.poetry.group.test.dependencies]
32
+ pytest = "^8.2.2"
33
+ faker = "^26.0.0"
34
+
35
+ [build-system]
36
+ requires = ["poetry-core"]
37
+ build-backend = "poetry.core.masonry.api"
File without changes
@@ -0,0 +1,136 @@
1
+ import numpy as np
2
+ from attrs import define,field,asdict,validators
3
+ import matplotlib
4
+ from matplotlib.colors import Colormap
5
+ import cmocean
6
+ from pprint import pformat
7
+ import xarray as xr
8
+ from pathlib import Path
9
+
10
+ from gerg_plotting.classes_utils import get_center_of_mass,lat_min_smaller_than_max,lon_min_smaller_than_max
11
+
12
+ @define
13
+ class NonSpatialData:
14
+ def __getitem__(self, key:str):
15
+ return asdict(self)[key]
16
+ def __repr__(self):
17
+ '''Pretty printing'''
18
+ return pformat(asdict(self), indent=1,width=2,compact=True,depth=1)
19
+
20
+ class Lab(NonSpatialData):
21
+ def __init__(self,vars):
22
+ for key,value in vars.items():
23
+ setattr(self,key,value)
24
+ def __getitem__(self, key:str):
25
+ return getattr(self,key)
26
+ def __setitem__(self,key,value):
27
+ return setattr(self,key,value)
28
+ def __repr__(self):
29
+ '''Pretty printing'''
30
+ return pformat(self.__dict__, indent=1,width=2,compact=True,depth=1)
31
+
32
+ @define
33
+ class Bounds(NonSpatialData):
34
+ lat_min:float|int|None = field(default=None,validator=[validators.instance_of(float|int|None),lat_min_smaller_than_max])
35
+ lat_max:float|int = field(default=None)
36
+
37
+ lon_min:float|int|None = field(default=None,validator=[validators.instance_of(float|int|None),lon_min_smaller_than_max])
38
+ lon_max:float|int|None = field(default=None)
39
+
40
+ depth_bottom:float|int|None = field(default=None)
41
+ depth_top:float|int|None = field(default=None)
42
+
43
+
44
+ @define
45
+ class SpatialData:
46
+ # Dims
47
+ lat:np.ndarray = field(default=None)
48
+ lon:np.ndarray = field(default=None)
49
+ depth:np.ndarray = field(default=None)
50
+ time:np.ndarray = field(default=None)
51
+ # Cmaps
52
+ temperature_cmap:Colormap = field(default=cmocean.cm.thermal)
53
+ salinity_cmap:Colormap = field(default=cmocean.cm.haline)
54
+ u_current_cmap:Colormap = field(default=cmocean.cm.delta)
55
+ v_current_cmap:Colormap = field(default=cmocean.cm.delta)
56
+
57
+ def __getitem__(self, key:str):
58
+ return asdict(self)[key]
59
+ def __repr__(self):
60
+ '''Pretty printing'''
61
+ return pformat(asdict(self), indent=1,width=2,compact=True,depth=1)
62
+
63
+ @define
64
+ class Bathy(SpatialData):
65
+ # Vars
66
+ bounds:Bounds = field(default=None)
67
+ resolution_level:float|int|None = field(default=5)
68
+ cmap:Colormap = field(default=matplotlib.cm.get_cmap('Blues'))
69
+ vertical_scaler:int|float = field(default=None)
70
+ vertical_units:str = field(default='')
71
+ center_of_mass:tuple = field(init=False)
72
+
73
+ def __attrs_post_init__(self):
74
+ self.get_bathy()
75
+ if self.vertical_scaler is not None:
76
+ self.depth = self.depth*self.vertical_scaler
77
+ self.center_of_mass = get_center_of_mass(self.lon,self.lat,self.depth)
78
+
79
+ def get_bathy(self):
80
+ '''
81
+ bounds (Bounds): contains attributes of lat_min,lon_min,lat_max,lon_max,depth_max,depth_min
82
+ resolution_level (float|int): how much to coarsen the dataset by in units of degrees
83
+ '''
84
+
85
+ # seafloor_path = Path('seafloor_data/gebco_2023_n31.0_s7.0_w-100.0_e-66.5.nc')
86
+ self_path = Path(__file__)
87
+ seafloor_path = self_path.parent.parent.joinpath('seafloor_data/gebco_2023_n31.0_s7.0_w-100.0_e-66.5.nc')
88
+ ds = xr.open_dataset(seafloor_path) #read in seafloor data
89
+
90
+ if self.resolution_level is not None:
91
+ ds = ds.coarsen(lat=self.resolution_level,boundary='trim').mean().coarsen(lon=self.resolution_level,boundary='trim').mean() #coarsen the seafloor data (speed up figure drawing) #type:ignore
92
+
93
+ ds = ds.sel(lat=slice(self.bounds["lat_min"],self.bounds["lat_max"])).sel(lon=slice(self.bounds["lon_min"],self.bounds["lon_max"])) #slice to the focus area
94
+
95
+ self.depth = ds['elevation'].values*-1 #extract the depth values and flip them
96
+
97
+ if self.bounds["depth_top"] is not None:
98
+ self.depth = np.where(self.depth>self.bounds["depth_top"],self.depth,self.bounds["depth_top"]) #set all depth values less than the depth_top to the same value as depth_top for visuals
99
+ if self.bounds["depth_bottom"] is not None:
100
+ self.depth = np.where(self.depth<self.bounds["depth_bottom"],self.depth,self.bounds["depth_bottom"]) #set all depth values less than the depth_bottom to the same value as depth_bottom for visuals
101
+
102
+ self.lon = ds.coords['lat'].values #extract the latitude values
103
+ self.lat = ds.coords['lon'].values #extract the longitude values
104
+ self.lon, self.lat = np.meshgrid(self.lat, self.lon) #create meshgrid for plotting
105
+
106
+
107
+ @define
108
+ class Glider(SpatialData):
109
+ # Vars
110
+ temperature:np.ndarray = field(default=None)
111
+ salinity:np.ndarray = field(default=None)
112
+
113
+ @define
114
+ class Buoy(SpatialData):
115
+ # Vars
116
+ u_current:np.ndarray = field(default=None)
117
+ v_current:np.ndarray = field(default=None)
118
+
119
+ @define
120
+ class CTD(SpatialData):
121
+ # Dim
122
+ stations:np.ndarray = field(default=None)
123
+ # Vars
124
+ temperature:np.ndarray = field(default=None)
125
+ salinity:np.ndarray = field(default=None)
126
+
127
+ @define
128
+ class WaveGlider(SpatialData):
129
+ # Vars
130
+ temperature:np.ndarray = field(default=None)
131
+ salinity:np.ndarray = field(default=None)
132
+
133
+ @define
134
+ class Radar(SpatialData):
135
+ u_current:np.ndarray = field(default=None)
136
+ v_current:np.ndarray = field(default=None)
@@ -0,0 +1,120 @@
1
+ import matplotlib
2
+ import matplotlib.axes
3
+ import matplotlib.cm
4
+ import matplotlib.figure
5
+ import matplotlib.pyplot
6
+ import matplotlib.dates as mdates
7
+ import numpy as np
8
+ from attrs import define, field, asdict
9
+ from pprint import pformat
10
+ import cmocean
11
+
12
+ from gerg_plotting.classes_data import Bathy,NonSpatialData,SpatialData,Bounds
13
+ from gerg_plotting.utils import calculate_range
14
+
15
+ @define
16
+ class Plotter:
17
+ instrument:SpatialData|NonSpatialData
18
+ bounds:Bounds|None = field(default= None)
19
+
20
+ fig:matplotlib.figure.Figure = field(default=None)
21
+ ax:matplotlib.axes.Axes = field(default=None)
22
+
23
+ def init_figure(self,fig=None,ax=None,three_d=False):
24
+ if fig is None and ax is None:
25
+ self.fig,self.ax = matplotlib.pyplot.subplots(subplot_kw={'projection':('3d' if three_d else None)})
26
+ elif fig is not None and ax is not None:
27
+ self.fig = fig
28
+ self.ax = ax
29
+ if three_d:
30
+ index = [idx for idx,ax in enumerate(self.fig.axes) if ax is self.ax][0]+1
31
+ self.ax.remove()
32
+ gs = self.ax.get_gridspec()
33
+ self.ax = fig.add_subplot(gs.nrows,gs.ncols,index, projection='3d')
34
+
35
+ def __getitem__(self, key:str):
36
+ return asdict(self)[key]
37
+ def __repr__(self):
38
+ '''Pretty printing'''
39
+ return pformat(asdict(self), indent=1,width=2,compact=True,depth=1)
40
+
41
+ @define
42
+ class SurfacePlot(Plotter):
43
+ bathy:Bathy = field(init=False)
44
+
45
+ def init_bathy(self):
46
+ self.bathy = Bathy(bounds=self.bounds,resolution_level=5)
47
+
48
+ def map(self,var:str|None=None,surface_values:bool=False,fig=None,ax=None,seafloor=True):
49
+ self.init_figure(fig,ax)
50
+ if var is None:
51
+ color = 'k'
52
+ cmap = None
53
+ else:
54
+ color_var_values = self.instrument[var].copy()
55
+ if surface_values:
56
+ color_var_values[self.instrument.depth>2] = np.nan
57
+ color = color_var_values
58
+ cmap = self.instrument[f'{var}_cmap']
59
+ if self.bounds is not None:
60
+ self.ax.set_ylim(self.bounds.lat_min,self.bounds.lat_max)
61
+ self.ax.set_xlim(self.bounds.lon_min,self.bounds.lon_max)
62
+ if seafloor:
63
+ self.init_bathy()
64
+ # Remove the white most but of the colormap
65
+ self.bathy.cmap = cmocean.tools.crop_by_percent(self.bathy.cmap,20,'min')
66
+ # Add land color to the colormap
67
+ land_color = [231/255,194/255,139/255,1]
68
+ self.bathy.cmap.set_under(land_color)
69
+ self.ax.contourf(self.bathy.lon,self.bathy.lat,self.bathy.depth,levels=50,cmap=self.bathy.cmap,vmin=0)
70
+
71
+ self.ax.scatter(self.instrument.lon,self.instrument.lat,c=color,cmap=cmap,s=2)
72
+ def quiver(self):
73
+ self.init_figure()
74
+ raise NotImplementedError('Need to add Quiver')
75
+
76
+
77
+ @define
78
+ class DepthPlot(Plotter):
79
+
80
+ def time_series(self,var:str,fig=None,ax=None):
81
+ self.init_figure(fig,ax)
82
+ self.ax.scatter(self.instrument.time,self.instrument.depth,c=self.instrument[var],cmap=self.instrument[f'{var}_cmap'])
83
+ self.ax.invert_yaxis()
84
+ locator = mdates.AutoDateLocator()
85
+ formatter = mdates.AutoDateFormatter(locator)
86
+
87
+ self.ax.xaxis.set_major_locator(locator)
88
+ self.ax.xaxis.set_major_formatter(formatter)
89
+ matplotlib.pyplot.xticks(rotation=60, fontsize='small')
90
+
91
+ def var_var(self,x:str,y:str,color_var:str|None=None,fig=None,ax=None):
92
+ self.init_figure(fig,ax)
93
+ if color_var is not None:
94
+ self.ax.scatter(self.instrument[x],self.instrument[y],c=self.instrument[color_var])
95
+ elif color_var is None:
96
+ self.ax.scatter(self.instrument[x],self.instrument[y])
97
+
98
+ def cross_section(self,longitude,latitude):
99
+ raise NotImplementedError('Need to add method to plot cross sections')
100
+
101
+ @define
102
+ class Histogram(Plotter):
103
+
104
+ def plot(self,var:str,fig=None,ax=None):
105
+ self.init_figure(fig,ax)
106
+ self.ax.hist(self.instrument[var])
107
+
108
+ def plot2d(self,x:str,y:str,fig=None,ax=None,**kwargs):
109
+ self.init_figure(fig,ax)
110
+ range = [calculate_range(self.instrument[x]),calculate_range(self.instrument[y])]
111
+ self.ax.hist2d(self.instrument[x],self.instrument[y],range=range,**kwargs)
112
+
113
+ def plot3d(self,x:str,y:str,fig=None,ax=None,**kwargs):
114
+ from matplotlib import cm
115
+ self.init_figure(fig,ax,three_d=True)
116
+ range = [calculate_range(self.instrument[x]),calculate_range(self.instrument[y])]
117
+ h,xedges,yedges = np.histogram2d(self.instrument[x],self.instrument[y],range=range,**kwargs)
118
+ X,Y = np.meshgrid(xedges[1:],yedges[1:])
119
+ self.ax.plot_surface(X,Y,h, rstride=1, cstride=1, cmap=cm.coolwarm,
120
+ linewidth=0, antialiased=False)
@@ -0,0 +1,8 @@
1
+ from attrs import define
2
+ import numpy as np
3
+ from gerg_plotting.classes_data import SpatialData
4
+
5
+
6
+ @define
7
+ class Plotter3D:
8
+ instrument: SpatialData
@@ -0,0 +1,22 @@
1
+ import numpy as np
2
+
3
+ def lat_min_smaller_than_max(instance, attribute, value):
4
+ if value is not None:
5
+ if value >= instance.lat_max:
6
+ raise ValueError("'lat_min' must to be smaller than 'lat_max'")
7
+
8
+ def lon_min_smaller_than_max(instance, attribute, value):
9
+ if value is not None:
10
+ if value >= instance.lon_max:
11
+ raise ValueError("'lon_min' must to be smaller than 'lon_max'")
12
+
13
+ def validate_array_lengths(instance,attribute,value):
14
+ lengths = {attr.name:len(getattr(instance,attr.name)) for attr in instance.__attrs_attrs__ if isinstance(getattr(instance,attr.name),np.ndarray)}
15
+ if len(set(lengths.values()))>1:
16
+ raise ValueError(f'All Dims and Vars must be the same length, got lengths of {lengths}')
17
+
18
+
19
+ def get_center_of_mass(lon,lat,pressure) -> tuple:
20
+ centroid = tuple([np.nanmean(lon), np.nanmean(lat), np.nanmean(pressure)])
21
+ return centroid
22
+
@@ -0,0 +1,62 @@
1
+ import numpy as np
2
+ import pandas as pd
3
+ import datetime
4
+ import xarray as xr
5
+ import matplotlib.pyplot as plt
6
+ from gerg_plotting.classes_plotter2d import SurfacePlot,DepthPlot,Histogram
7
+ from gerg_plotting.classes_data import Radar,Bounds
8
+ from gerg_plotting.utils import interp_data,filter_var,calculate_range
9
+
10
+ df = pd.read_csv('../../test_data/radar.csv',
11
+ parse_dates=['time'],date_format='%Y-%m-%dT%H:%M:%SZ',skiprows=[1])
12
+
13
+ times = list(set(df.time))
14
+
15
+ df = df.loc[df.time==times[2]]
16
+
17
+ radar = Radar(lat=df['latitude'],
18
+ lon=df['longitude'],
19
+ depth=np.array([0]),
20
+ time=df['time'],
21
+ u_current=df['u'],
22
+ v_current=df['v'])
23
+
24
+ lat_min,lat_max = calculate_range(radar.lat)
25
+ lon_min,lon_max = calculate_range(radar.lon)
26
+
27
+
28
+ bounds = Bounds(lat_min=lat_min,
29
+ lat_max=lat_max,
30
+ lon_max=lon_max,
31
+ lon_min=lon_min,
32
+ depth_bottom=1000,
33
+ depth_top=None)
34
+
35
+
36
+ fig,axes = plt.subplots(nrows=3,figsize = (10,10))
37
+ surfaces = SurfacePlot(instrument=radar,bounds=bounds)
38
+ surfaces.map(fig=fig,ax=axes[0])
39
+ surfaces.map(fig=fig,ax=axes[1],var='u_current',surface_values=False)
40
+ surfaces.map(fig=fig,ax=axes[2],var='v_current',surface_values=False)
41
+ plt.show()
42
+
43
+ # depth_plot = DepthPlot(instrument=radar,bounds=bounds)
44
+
45
+ # depth_plot.time_series(var='u_current')
46
+ # plt.show()
47
+ # depth_plot.time_series(var='v_current')
48
+ # plt.show()
49
+ # depth_plot.var_var(x='v_current',y='u_current',color_var='time')
50
+ # plt.show()
51
+
52
+ fig,axes = plt.subplots(nrows=4,figsize = (5,20))
53
+ hist = Histogram(instrument=radar,bounds=bounds)
54
+ hist.plot(fig=fig,ax=axes[0],var='u_current')
55
+ # plt.show()
56
+ hist.plot(fig=fig,ax=axes[1],var='v_current')
57
+ # plt.show()
58
+ hist.plot2d(fig=fig,ax=axes[2],x='u_current',y='v_current',bins=150,norm='log')
59
+ hist.ax.invert_yaxis()
60
+ # plt.show()
61
+ hist.plot3d(fig=fig,ax=axes[3],x='u_current',y='v_current',bins=150)
62
+ plt.show()
@@ -0,0 +1,31 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pandas as pd
4
+ import xarray as xr
5
+
6
+ def interp_data(ds:xr.Dataset) -> pd.DataFrame:
7
+ new_time_values = ds['time'].values.astype('datetime64[s]').astype('float64')
8
+ new_mtime_values = ds['m_time'].values.astype('datetime64[s]').astype('float64')
9
+
10
+ # Create a mask of non-NaN values in the 'longitude' variable
11
+ valid_longitude = ~np.isnan(ds['longitude'])
12
+ # Now ds_filtered contains the data where NaN values have been dropped based on the longitude variable
13
+
14
+ ds['latitude'] = xr.DataArray(np.interp(new_time_values, new_mtime_values[valid_longitude], ds['latitude'].values[valid_longitude]),[('time',ds.time.values)])
15
+ ds['longitude'] = xr.DataArray(np.interp(new_time_values, new_mtime_values[valid_longitude], ds['longitude'].values[valid_longitude]),[('time',ds.time.values)])
16
+
17
+ df = ds[['latitude','longitude','pressure','salinity','temperature']].to_dataframe().reset_index()
18
+ df['time'] = df['time'].astype('datetime64[s]')
19
+ # df = df.set_index(['time'])
20
+ df = df.dropna()
21
+
22
+ return df
23
+
24
+
25
+ def filter_var(var:pd.Series,min_value,max_value):
26
+ var = var.where(var>min_value)
27
+ var = var.where(var<max_value)
28
+ return var
29
+
30
+ def calculate_range(var:np.ndarray):
31
+ return [np.nanmin(var),np.nanmax(var)]