Mahmudm commited on
Commit
3a12729
·
verified ·
1 Parent(s): 63d4222

Upload 191 files

Browse files
Files changed (48) hide show
  1. .gitattributes +15 -39
  2. LICENSE +674 -0
  3. README.md +2 -11
  4. app.py +3 -4
  5. app.zip +3 -0
  6. ash_animator/__init__.py +1 -1
  7. ash_animator/__pycache__/animation_single.cpython-312.pyc +0 -0
  8. ash_animator/__pycache__/animation_vertical.cpython-312.pyc +0 -0
  9. ash_animator/__pycache__/basemaps.cpython-312.pyc +0 -0
  10. ash_animator/__pycache__/converter.cpython-312.pyc +0 -0
  11. ash_animator/__pycache__/export.cpython-312.pyc +0 -0
  12. ash_animator/__pycache__/interpolation.cpython-312.pyc +0 -0
  13. ash_animator/__pycache__/plot_3dfield_data.cpython-312.pyc +0 -0
  14. ash_animator/__pycache__/plot_horizontal_data.cpython-312.pyc +0 -0
  15. ash_animator/__pycache__/utils.cpython-312.pyc +0 -0
  16. ash_animator/basemaps.py +25 -11
  17. ash_animator/converter.py +12 -147
  18. ash_animator/plot_3dfield_data.py +9 -2
  19. ash_animator/plot_horizontal_data.py +10 -286
  20. ash_output/3D/T1.nc +3 -0
  21. ash_output/3D/T10.nc +3 -0
  22. ash_output/3D/T2.nc +3 -0
  23. ash_output/3D/T3.nc +3 -0
  24. ash_output/3D/T4.nc +3 -0
  25. ash_output/3D/T5.nc +3 -0
  26. ash_output/3D/T6.nc +3 -0
  27. ash_output/3D/T7.nc +3 -0
  28. ash_output/3D/T8.nc +3 -0
  29. ash_output/3D/T9.nc +3 -0
  30. ash_output/horizontal/AQOutput_HorizontalField_C1_T10_202001121400.nc +3 -0
  31. ash_output/horizontal/AQOutput_HorizontalField_C1_T1_202001120500.nc +3 -0
  32. ash_output/horizontal/AQOutput_HorizontalField_C1_T2_202001120600.nc +3 -0
  33. ash_output/horizontal/AQOutput_HorizontalField_C1_T3_202001120700.nc +3 -0
  34. ash_output/horizontal/AQOutput_HorizontalField_C1_T4_202001120800.nc +3 -0
  35. ash_output/horizontal/AQOutput_HorizontalField_C1_T5_202001120900.nc +3 -0
  36. ash_output/horizontal/AQOutput_HorizontalField_C1_T6_202001121000.nc +3 -0
  37. ash_output/horizontal/AQOutput_HorizontalField_C1_T7_202001121100.nc +3 -0
  38. ash_output/horizontal/AQOutput_HorizontalField_C1_T8_202001121200.nc +3 -0
  39. ash_output/horizontal/AQOutput_HorizontalField_C1_T9_202001121300.nc +3 -0
  40. media/2D/2d_fields/wet_deposition_rate/wet_deposition_rate.gif +3 -0
  41. media/2D/frames/wet_deposition_rate/frame_0001.jpg +3 -0
  42. media/2D/frames/wet_deposition_rate/frame_0005.jpg +3 -0
  43. media/2D/frames/wet_deposition_rate/frame_0006.jpg +3 -0
  44. media/2D/frames/wet_deposition_rate/frame_0007.jpg +3 -0
  45. media/2D/frames/wet_deposition_rate/frame_0008.jpg +3 -0
  46. media/2D/frames/wet_deposition_rate/frame_0009.jpg +3 -0
  47. media/2D/frames/wet_deposition_rate/frame_0010.jpg +3 -0
  48. requirements.txt +1 -10
.gitattributes CHANGED
@@ -1,37 +1,6 @@
1
- *.7z filter=lfs diff=lfs merge=lfs -text
2
- *.arrow filter=lfs diff=lfs merge=lfs -text
3
- *.bin filter=lfs diff=lfs merge=lfs -text
4
- *.bz2 filter=lfs diff=lfs merge=lfs -text
5
- *.ckpt filter=lfs diff=lfs merge=lfs -text
6
- *.ftz filter=lfs diff=lfs merge=lfs -text
7
- *.gz filter=lfs diff=lfs merge=lfs -text
8
- *.h5 filter=lfs diff=lfs merge=lfs -text
9
- *.joblib filter=lfs diff=lfs merge=lfs -text
10
- *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
- *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
- *.model filter=lfs diff=lfs merge=lfs -text
13
- *.msgpack filter=lfs diff=lfs merge=lfs -text
14
- *.npy filter=lfs diff=lfs merge=lfs -text
15
- *.npz filter=lfs diff=lfs merge=lfs -text
16
- *.onnx filter=lfs diff=lfs merge=lfs -text
17
- *.ot filter=lfs diff=lfs merge=lfs -text
18
- *.parquet filter=lfs diff=lfs merge=lfs -text
19
- *.pb filter=lfs diff=lfs merge=lfs -text
20
- *.pickle filter=lfs diff=lfs merge=lfs -text
21
- *.pkl filter=lfs diff=lfs merge=lfs -text
22
- *.pt filter=lfs diff=lfs merge=lfs -text
23
- *.pth filter=lfs diff=lfs merge=lfs -text
24
- *.rar filter=lfs diff=lfs merge=lfs -text
25
- *.safetensors filter=lfs diff=lfs merge=lfs -text
26
- saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
- *.tar.* filter=lfs diff=lfs merge=lfs -text
28
- *.tflite filter=lfs diff=lfs merge=lfs -text
29
- *.tgz filter=lfs diff=lfs merge=lfs -text
30
- *.wasm filter=lfs diff=lfs merge=lfs -text
31
- *.xz filter=lfs diff=lfs merge=lfs -text
32
- *.zip filter=lfs diff=lfs merge=lfs -text
33
- *.zst filter=lfs diff=lfs merge=lfs -text
34
- *tfevents* filter=lfs diff=lfs merge=lfs -text
35
  ash_output/3D/T1.nc filter=lfs diff=lfs merge=lfs -text
36
  ash_output/3D/T10.nc filter=lfs diff=lfs merge=lfs -text
37
  ash_output/3D/T2.nc filter=lfs diff=lfs merge=lfs -text
@@ -52,8 +21,15 @@ ash_output/horizontal/AQOutput_HorizontalField_C1_T6_202001121000.nc filter=lfs
52
  ash_output/horizontal/AQOutput_HorizontalField_C1_T7_202001121100.nc filter=lfs diff=lfs merge=lfs -text
53
  ash_output/horizontal/AQOutput_HorizontalField_C1_T8_202001121200.nc filter=lfs diff=lfs merge=lfs -text
54
  ash_output/horizontal/AQOutput_HorizontalField_C1_T9_202001121300.nc filter=lfs diff=lfs merge=lfs -text
55
- media/2D/2d_fields/air_concentration/air_concentration.gif filter=lfs diff=lfs merge=lfs -text
56
- media/2D/frames/air_concentration/frame_0001.jpg filter=lfs diff=lfs merge=lfs -text
57
- media/2D/frames/air_concentration/frame_0008.jpg filter=lfs diff=lfs merge=lfs -text
58
- media/2D/frames/air_concentration/frame_0009.jpg filter=lfs diff=lfs merge=lfs -text
59
- media/2D/frames/air_concentration/frame_0010.jpg filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
3
+ app.zip filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  ash_output/3D/T1.nc filter=lfs diff=lfs merge=lfs -text
5
  ash_output/3D/T10.nc filter=lfs diff=lfs merge=lfs -text
6
  ash_output/3D/T2.nc filter=lfs diff=lfs merge=lfs -text
 
21
  ash_output/horizontal/AQOutput_HorizontalField_C1_T7_202001121100.nc filter=lfs diff=lfs merge=lfs -text
22
  ash_output/horizontal/AQOutput_HorizontalField_C1_T8_202001121200.nc filter=lfs diff=lfs merge=lfs -text
23
  ash_output/horizontal/AQOutput_HorizontalField_C1_T9_202001121300.nc filter=lfs diff=lfs merge=lfs -text
24
+ default_model.zip filter=lfs diff=lfs merge=lfs -text
25
+ media/2D/2d_fields/wet_deposition_rate/wet_deposition_rate.gif filter=lfs diff=lfs merge=lfs -text
26
+ media/2D/frames/wet_deposition_rate/frame_0001.jpg filter=lfs diff=lfs merge=lfs -text
27
+ media/2D/frames/wet_deposition_rate/frame_0005.jpg filter=lfs diff=lfs merge=lfs -text
28
+ media/2D/frames/wet_deposition_rate/frame_0006.jpg filter=lfs diff=lfs merge=lfs -text
29
+ media/2D/frames/wet_deposition_rate/frame_0007.jpg filter=lfs diff=lfs merge=lfs -text
30
+ media/2D/frames/wet_deposition_rate/frame_0008.jpg filter=lfs diff=lfs merge=lfs -text
31
+ media/2D/frames/wet_deposition_rate/frame_0009.jpg filter=lfs diff=lfs merge=lfs -text
32
+ media/2D/frames/wet_deposition_rate/frame_0010.jpg filter=lfs diff=lfs merge=lfs -text
33
+ media/default_model.zip filter=lfs diff=lfs merge=lfs -text
34
+ media/Taal_273070_20200112_scenario_yizhou.zip filter=lfs diff=lfs merge=lfs -text
35
+ Taal_273070_20200112_scenario_yizhou.zip filter=lfs diff=lfs merge=lfs -text
LICENSE ADDED
@@ -0,0 +1,674 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+ Preamble
9
+
10
+ The GNU General Public License is a free, copyleft license for
11
+ software and other kinds of works.
12
+
13
+ The licenses for most software and other practical works are designed
14
+ to take away your freedom to share and change the works. By contrast,
15
+ the GNU General Public License is intended to guarantee your freedom to
16
+ share and change all versions of a program--to make sure it remains free
17
+ software for all its users. We, the Free Software Foundation, use the
18
+ GNU General Public License for most of our software; it applies also to
19
+ any other work released this way by its authors. You can apply it to
20
+ your programs, too.
21
+
22
+ When we speak of free software, we are referring to freedom, not
23
+ price. Our General Public Licenses are designed to make sure that you
24
+ have the freedom to distribute copies of free software (and charge for
25
+ them if you wish), that you receive source code or can get it if you
26
+ want it, that you can change the software or use pieces of it in new
27
+ free programs, and that you know you can do these things.
28
+
29
+ To protect your rights, we need to prevent others from denying you
30
+ these rights or asking you to surrender the rights. Therefore, you have
31
+ certain responsibilities if you distribute copies of the software, or if
32
+ you modify it: responsibilities to respect the freedom of others.
33
+
34
+ For example, if you distribute copies of such a program, whether
35
+ gratis or for a fee, you must pass on to the recipients the same
36
+ freedoms that you received. You must make sure that they, too, receive
37
+ or can get the source code. And you must show them these terms so they
38
+ know their rights.
39
+
40
+ Developers that use the GNU GPL protect your rights with two steps:
41
+ (1) assert copyright on the software, and (2) offer you this License
42
+ giving you legal permission to copy, distribute and/or modify it.
43
+
44
+ For the developers' and authors' protection, the GPL clearly explains
45
+ that there is no warranty for this free software. For both users' and
46
+ authors' sake, the GPL requires that modified versions be marked as
47
+ changed, so that their problems will not be attributed erroneously to
48
+ authors of previous versions.
49
+
50
+ Some devices are designed to deny users access to install or run
51
+ modified versions of the software inside them, although the manufacturer
52
+ can do so. This is fundamentally incompatible with the aim of
53
+ protecting users' freedom to change the software. The systematic
54
+ pattern of such abuse occurs in the area of products for individuals to
55
+ use, which is precisely where it is most unacceptable. Therefore, we
56
+ have designed this version of the GPL to prohibit the practice for those
57
+ products. If such problems arise substantially in other domains, we
58
+ stand ready to extend this provision to those domains in future versions
59
+ of the GPL, as needed to protect the freedom of users.
60
+
61
+ Finally, every program is threatened constantly by software patents.
62
+ States should not allow patents to restrict development and use of
63
+ software on general-purpose computers, but in those that do, we wish to
64
+ avoid the special danger that patents applied to a free program could
65
+ make it effectively proprietary. To prevent this, the GPL assures that
66
+ patents cannot be used to render the program non-free.
67
+
68
+ The precise terms and conditions for copying, distribution and
69
+ modification follow.
70
+
71
+ TERMS AND CONDITIONS
72
+
73
+ 0. Definitions.
74
+
75
+ "This License" refers to version 3 of the GNU General Public License.
76
+
77
+ "Copyright" also means copyright-like laws that apply to other kinds of
78
+ works, such as semiconductor masks.
79
+
80
+ "The Program" refers to any copyrightable work licensed under this
81
+ License. Each licensee is addressed as "you". "Licensees" and
82
+ "recipients" may be individuals or organizations.
83
+
84
+ To "modify" a work means to copy from or adapt all or part of the work
85
+ in a fashion requiring copyright permission, other than the making of an
86
+ exact copy. The resulting work is called a "modified version" of the
87
+ earlier work or a work "based on" the earlier work.
88
+
89
+ A "covered work" means either the unmodified Program or a work based
90
+ on the Program.
91
+
92
+ To "propagate" a work means to do anything with it that, without
93
+ permission, would make you directly or secondarily liable for
94
+ infringement under applicable copyright law, except executing it on a
95
+ computer or modifying a private copy. Propagation includes copying,
96
+ distribution (with or without modification), making available to the
97
+ public, and in some countries other activities as well.
98
+
99
+ To "convey" a work means any kind of propagation that enables other
100
+ parties to make or receive copies. Mere interaction with a user through
101
+ a computer network, with no transfer of a copy, is not conveying.
102
+
103
+ An interactive user interface displays "Appropriate Legal Notices"
104
+ to the extent that it includes a convenient and prominently visible
105
+ feature that (1) displays an appropriate copyright notice, and (2)
106
+ tells the user that there is no warranty for the work (except to the
107
+ extent that warranties are provided), that licensees may convey the
108
+ work under this License, and how to view a copy of this License. If
109
+ the interface presents a list of user commands or options, such as a
110
+ menu, a prominent item in the list meets this criterion.
111
+
112
+ 1. Source Code.
113
+
114
+ The "source code" for a work means the preferred form of the work
115
+ for making modifications to it. "Object code" means any non-source
116
+ form of a work.
117
+
118
+ A "Standard Interface" means an interface that either is an official
119
+ standard defined by a recognized standards body, or, in the case of
120
+ interfaces specified for a particular programming language, one that
121
+ is widely used among developers working in that language.
122
+
123
+ The "System Libraries" of an executable work include anything, other
124
+ than the work as a whole, that (a) is included in the normal form of
125
+ packaging a Major Component, but which is not part of that Major
126
+ Component, and (b) serves only to enable use of the work with that
127
+ Major Component, or to implement a Standard Interface for which an
128
+ implementation is available to the public in source code form. A
129
+ "Major Component", in this context, means a major essential component
130
+ (kernel, window system, and so on) of the specific operating system
131
+ (if any) on which the executable work runs, or a compiler used to
132
+ produce the work, or an object code interpreter used to run it.
133
+
134
+ The "Corresponding Source" for a work in object code form means all
135
+ the source code needed to generate, install, and (for an executable
136
+ work) run the object code and to modify the work, including scripts to
137
+ control those activities. However, it does not include the work's
138
+ System Libraries, or general-purpose tools or generally available free
139
+ programs which are used unmodified in performing those activities but
140
+ which are not part of the work. For example, Corresponding Source
141
+ includes interface definition files associated with source files for
142
+ the work, and the source code for shared libraries and dynamically
143
+ linked subprograms that the work is specifically designed to require,
144
+ such as by intimate data communication or control flow between those
145
+ subprograms and other parts of the work.
146
+
147
+ The Corresponding Source need not include anything that users
148
+ can regenerate automatically from other parts of the Corresponding
149
+ Source.
150
+
151
+ The Corresponding Source for a work in source code form is that
152
+ same work.
153
+
154
+ 2. Basic Permissions.
155
+
156
+ All rights granted under this License are granted for the term of
157
+ copyright on the Program, and are irrevocable provided the stated
158
+ conditions are met. This License explicitly affirms your unlimited
159
+ permission to run the unmodified Program. The output from running a
160
+ covered work is covered by this License only if the output, given its
161
+ content, constitutes a covered work. This License acknowledges your
162
+ rights of fair use or other equivalent, as provided by copyright law.
163
+
164
+ You may make, run and propagate covered works that you do not
165
+ convey, without conditions so long as your license otherwise remains
166
+ in force. You may convey covered works to others for the sole purpose
167
+ of having them make modifications exclusively for you, or provide you
168
+ with facilities for running those works, provided that you comply with
169
+ the terms of this License in conveying all material for which you do
170
+ not control copyright. Those thus making or running the covered works
171
+ for you must do so exclusively on your behalf, under your direction
172
+ and control, on terms that prohibit them from making any copies of
173
+ your copyrighted material outside their relationship with you.
174
+
175
+ Conveying under any other circumstances is permitted solely under
176
+ the conditions stated below. Sublicensing is not allowed; section 10
177
+ makes it unnecessary.
178
+
179
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180
+
181
+ No covered work shall be deemed part of an effective technological
182
+ measure under any applicable law fulfilling obligations under article
183
+ 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184
+ similar laws prohibiting or restricting circumvention of such
185
+ measures.
186
+
187
+ When you convey a covered work, you waive any legal power to forbid
188
+ circumvention of technological measures to the extent such circumvention
189
+ is effected by exercising rights under this License with respect to
190
+ the covered work, and you disclaim any intention to limit operation or
191
+ modification of the work as a means of enforcing, against the work's
192
+ users, your or third parties' legal rights to forbid circumvention of
193
+ technological measures.
194
+
195
+ 4. Conveying Verbatim Copies.
196
+
197
+ You may convey verbatim copies of the Program's source code as you
198
+ receive it, in any medium, provided that you conspicuously and
199
+ appropriately publish on each copy an appropriate copyright notice;
200
+ keep intact all notices stating that this License and any
201
+ non-permissive terms added in accord with section 7 apply to the code;
202
+ keep intact all notices of the absence of any warranty; and give all
203
+ recipients a copy of this License along with the Program.
204
+
205
+ You may charge any price or no price for each copy that you convey,
206
+ and you may offer support or warranty protection for a fee.
207
+
208
+ 5. Conveying Modified Source Versions.
209
+
210
+ You may convey a work based on the Program, or the modifications to
211
+ produce it from the Program, in the form of source code under the
212
+ terms of section 4, provided that you also meet all of these conditions:
213
+
214
+ a) The work must carry prominent notices stating that you modified
215
+ it, and giving a relevant date.
216
+
217
+ b) The work must carry prominent notices stating that it is
218
+ released under this License and any conditions added under section
219
+ 7. This requirement modifies the requirement in section 4 to
220
+ "keep intact all notices".
221
+
222
+ c) You must license the entire work, as a whole, under this
223
+ License to anyone who comes into possession of a copy. This
224
+ License will therefore apply, along with any applicable section 7
225
+ additional terms, to the whole of the work, and all its parts,
226
+ regardless of how they are packaged. This License gives no
227
+ permission to license the work in any other way, but it does not
228
+ invalidate such permission if you have separately received it.
229
+
230
+ d) If the work has interactive user interfaces, each must display
231
+ Appropriate Legal Notices; however, if the Program has interactive
232
+ interfaces that do not display Appropriate Legal Notices, your
233
+ work need not make them do so.
234
+
235
+ A compilation of a covered work with other separate and independent
236
+ works, which are not by their nature extensions of the covered work,
237
+ and which are not combined with it such as to form a larger program,
238
+ in or on a volume of a storage or distribution medium, is called an
239
+ "aggregate" if the compilation and its resulting copyright are not
240
+ used to limit the access or legal rights of the compilation's users
241
+ beyond what the individual works permit. Inclusion of a covered work
242
+ in an aggregate does not cause this License to apply to the other
243
+ parts of the aggregate.
244
+
245
+ 6. Conveying Non-Source Forms.
246
+
247
+ You may convey a covered work in object code form under the terms
248
+ of sections 4 and 5, provided that you also convey the
249
+ machine-readable Corresponding Source under the terms of this License,
250
+ in one of these ways:
251
+
252
+ a) Convey the object code in, or embodied in, a physical product
253
+ (including a physical distribution medium), accompanied by the
254
+ Corresponding Source fixed on a durable physical medium
255
+ customarily used for software interchange.
256
+
257
+ b) Convey the object code in, or embodied in, a physical product
258
+ (including a physical distribution medium), accompanied by a
259
+ written offer, valid for at least three years and valid for as
260
+ long as you offer spare parts or customer support for that product
261
+ model, to give anyone who possesses the object code either (1) a
262
+ copy of the Corresponding Source for all the software in the
263
+ product that is covered by this License, on a durable physical
264
+ medium customarily used for software interchange, for a price no
265
+ more than your reasonable cost of physically performing this
266
+ conveying of source, or (2) access to copy the
267
+ Corresponding Source from a network server at no charge.
268
+
269
+ c) Convey individual copies of the object code with a copy of the
270
+ written offer to provide the Corresponding Source. This
271
+ alternative is allowed only occasionally and noncommercially, and
272
+ only if you received the object code with such an offer, in accord
273
+ with subsection 6b.
274
+
275
+ d) Convey the object code by offering access from a designated
276
+ place (gratis or for a charge), and offer equivalent access to the
277
+ Corresponding Source in the same way through the same place at no
278
+ further charge. You need not require recipients to copy the
279
+ Corresponding Source along with the object code. If the place to
280
+ copy the object code is a network server, the Corresponding Source
281
+ may be on a different server (operated by you or a third party)
282
+ that supports equivalent copying facilities, provided you maintain
283
+ clear directions next to the object code saying where to find the
284
+ Corresponding Source. Regardless of what server hosts the
285
+ Corresponding Source, you remain obligated to ensure that it is
286
+ available for as long as needed to satisfy these requirements.
287
+
288
+ e) Convey the object code using peer-to-peer transmission, provided
289
+ you inform other peers where the object code and Corresponding
290
+ Source of the work are being offered to the general public at no
291
+ charge under subsection 6d.
292
+
293
+ A separable portion of the object code, whose source code is excluded
294
+ from the Corresponding Source as a System Library, need not be
295
+ included in conveying the object code work.
296
+
297
+ A "User Product" is either (1) a "consumer product", which means any
298
+ tangible personal property which is normally used for personal, family,
299
+ or household purposes, or (2) anything designed or sold for incorporation
300
+ into a dwelling. In determining whether a product is a consumer product,
301
+ doubtful cases shall be resolved in favor of coverage. For a particular
302
+ product received by a particular user, "normally used" refers to a
303
+ typical or common use of that class of product, regardless of the status
304
+ of the particular user or of the way in which the particular user
305
+ actually uses, or expects or is expected to use, the product. A product
306
+ is a consumer product regardless of whether the product has substantial
307
+ commercial, industrial or non-consumer uses, unless such uses represent
308
+ the only significant mode of use of the product.
309
+
310
+ "Installation Information" for a User Product means any methods,
311
+ procedures, authorization keys, or other information required to install
312
+ and execute modified versions of a covered work in that User Product from
313
+ a modified version of its Corresponding Source. The information must
314
+ suffice to ensure that the continued functioning of the modified object
315
+ code is in no case prevented or interfered with solely because
316
+ modification has been made.
317
+
318
+ If you convey an object code work under this section in, or with, or
319
+ specifically for use in, a User Product, and the conveying occurs as
320
+ part of a transaction in which the right of possession and use of the
321
+ User Product is transferred to the recipient in perpetuity or for a
322
+ fixed term (regardless of how the transaction is characterized), the
323
+ Corresponding Source conveyed under this section must be accompanied
324
+ by the Installation Information. But this requirement does not apply
325
+ if neither you nor any third party retains the ability to install
326
+ modified object code on the User Product (for example, the work has
327
+ been installed in ROM).
328
+
329
+ The requirement to provide Installation Information does not include a
330
+ requirement to continue to provide support service, warranty, or updates
331
+ for a work that has been modified or installed by the recipient, or for
332
+ the User Product in which it has been modified or installed. Access to a
333
+ network may be denied when the modification itself materially and
334
+ adversely affects the operation of the network or violates the rules and
335
+ protocols for communication across the network.
336
+
337
+ Corresponding Source conveyed, and Installation Information provided,
338
+ in accord with this section must be in a format that is publicly
339
+ documented (and with an implementation available to the public in
340
+ source code form), and must require no special password or key for
341
+ unpacking, reading or copying.
342
+
343
+ 7. Additional Terms.
344
+
345
+ "Additional permissions" are terms that supplement the terms of this
346
+ License by making exceptions from one or more of its conditions.
347
+ Additional permissions that are applicable to the entire Program shall
348
+ be treated as though they were included in this License, to the extent
349
+ that they are valid under applicable law. If additional permissions
350
+ apply only to part of the Program, that part may be used separately
351
+ under those permissions, but the entire Program remains governed by
352
+ this License without regard to the additional permissions.
353
+
354
+ When you convey a copy of a covered work, you may at your option
355
+ remove any additional permissions from that copy, or from any part of
356
+ it. (Additional permissions may be written to require their own
357
+ removal in certain cases when you modify the work.) You may place
358
+ additional permissions on material, added by you to a covered work,
359
+ for which you have or can give appropriate copyright permission.
360
+
361
+ Notwithstanding any other provision of this License, for material you
362
+ add to a covered work, you may (if authorized by the copyright holders of
363
+ that material) supplement the terms of this License with terms:
364
+
365
+ a) Disclaiming warranty or limiting liability differently from the
366
+ terms of sections 15 and 16 of this License; or
367
+
368
+ b) Requiring preservation of specified reasonable legal notices or
369
+ author attributions in that material or in the Appropriate Legal
370
+ Notices displayed by works containing it; or
371
+
372
+ c) Prohibiting misrepresentation of the origin of that material, or
373
+ requiring that modified versions of such material be marked in
374
+ reasonable ways as different from the original version; or
375
+
376
+ d) Limiting the use for publicity purposes of names of licensors or
377
+ authors of the material; or
378
+
379
+ e) Declining to grant rights under trademark law for use of some
380
+ trade names, trademarks, or service marks; or
381
+
382
+ f) Requiring indemnification of licensors and authors of that
383
+ material by anyone who conveys the material (or modified versions of
384
+ it) with contractual assumptions of liability to the recipient, for
385
+ any liability that these contractual assumptions directly impose on
386
+ those licensors and authors.
387
+
388
+ All other non-permissive additional terms are considered "further
389
+ restrictions" within the meaning of section 10. If the Program as you
390
+ received it, or any part of it, contains a notice stating that it is
391
+ governed by this License along with a term that is a further
392
+ restriction, you may remove that term. If a license document contains
393
+ a further restriction but permits relicensing or conveying under this
394
+ License, you may add to a covered work material governed by the terms
395
+ of that license document, provided that the further restriction does
396
+ not survive such relicensing or conveying.
397
+
398
+ If you add terms to a covered work in accord with this section, you
399
+ must place, in the relevant source files, a statement of the
400
+ additional terms that apply to those files, or a notice indicating
401
+ where to find the applicable terms.
402
+
403
+ Additional terms, permissive or non-permissive, may be stated in the
404
+ form of a separately written license, or stated as exceptions;
405
+ the above requirements apply either way.
406
+
407
+ 8. Termination.
408
+
409
+ You may not propagate or modify a covered work except as expressly
410
+ provided under this License. Any attempt otherwise to propagate or
411
+ modify it is void, and will automatically terminate your rights under
412
+ this License (including any patent licenses granted under the third
413
+ paragraph of section 11).
414
+
415
+ However, if you cease all violation of this License, then your
416
+ license from a particular copyright holder is reinstated (a)
417
+ provisionally, unless and until the copyright holder explicitly and
418
+ finally terminates your license, and (b) permanently, if the copyright
419
+ holder fails to notify you of the violation by some reasonable means
420
+ prior to 60 days after the cessation.
421
+
422
+ Moreover, your license from a particular copyright holder is
423
+ reinstated permanently if the copyright holder notifies you of the
424
+ violation by some reasonable means, this is the first time you have
425
+ received notice of violation of this License (for any work) from that
426
+ copyright holder, and you cure the violation prior to 30 days after
427
+ your receipt of the notice.
428
+
429
+ Termination of your rights under this section does not terminate the
430
+ licenses of parties who have received copies or rights from you under
431
+ this License. If your rights have been terminated and not permanently
432
+ reinstated, you do not qualify to receive new licenses for the same
433
+ material under section 10.
434
+
435
+ 9. Acceptance Not Required for Having Copies.
436
+
437
+ You are not required to accept this License in order to receive or
438
+ run a copy of the Program. Ancillary propagation of a covered work
439
+ occurring solely as a consequence of using peer-to-peer transmission
440
+ to receive a copy likewise does not require acceptance. However,
441
+ nothing other than this License grants you permission to propagate or
442
+ modify any covered work. These actions infringe copyright if you do
443
+ not accept this License. Therefore, by modifying or propagating a
444
+ covered work, you indicate your acceptance of this License to do so.
445
+
446
+ 10. Automatic Licensing of Downstream Recipients.
447
+
448
+ Each time you convey a covered work, the recipient automatically
449
+ receives a license from the original licensors, to run, modify and
450
+ propagate that work, subject to this License. You are not responsible
451
+ for enforcing compliance by third parties with this License.
452
+
453
+ An "entity transaction" is a transaction transferring control of an
454
+ organization, or substantially all assets of one, or subdividing an
455
+ organization, or merging organizations. If propagation of a covered
456
+ work results from an entity transaction, each party to that
457
+ transaction who receives a copy of the work also receives whatever
458
+ licenses to the work the party's predecessor in interest had or could
459
+ give under the previous paragraph, plus a right to possession of the
460
+ Corresponding Source of the work from the predecessor in interest, if
461
+ the predecessor has it or can get it with reasonable efforts.
462
+
463
+ You may not impose any further restrictions on the exercise of the
464
+ rights granted or affirmed under this License. For example, you may
465
+ not impose a license fee, royalty, or other charge for exercise of
466
+ rights granted under this License, and you may not initiate litigation
467
+ (including a cross-claim or counterclaim in a lawsuit) alleging that
468
+ any patent claim is infringed by making, using, selling, offering for
469
+ sale, or importing the Program or any portion of it.
470
+
471
+ 11. Patents.
472
+
473
+ A "contributor" is a copyright holder who authorizes use under this
474
+ License of the Program or a work on which the Program is based. The
475
+ work thus licensed is called the contributor's "contributor version".
476
+
477
+ A contributor's "essential patent claims" are all patent claims
478
+ owned or controlled by the contributor, whether already acquired or
479
+ hereafter acquired, that would be infringed by some manner, permitted
480
+ by this License, of making, using, or selling its contributor version,
481
+ but do not include claims that would be infringed only as a
482
+ consequence of further modification of the contributor version. For
483
+ purposes of this definition, "control" includes the right to grant
484
+ patent sublicenses in a manner consistent with the requirements of
485
+ this License.
486
+
487
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
488
+ patent license under the contributor's essential patent claims, to
489
+ make, use, sell, offer for sale, import and otherwise run, modify and
490
+ propagate the contents of its contributor version.
491
+
492
+ In the following three paragraphs, a "patent license" is any express
493
+ agreement or commitment, however denominated, not to enforce a patent
494
+ (such as an express permission to practice a patent or covenant not to
495
+ sue for patent infringement). To "grant" such a patent license to a
496
+ party means to make such an agreement or commitment not to enforce a
497
+ patent against the party.
498
+
499
+ If you convey a covered work, knowingly relying on a patent license,
500
+ and the Corresponding Source of the work is not available for anyone
501
+ to copy, free of charge and under the terms of this License, through a
502
+ publicly available network server or other readily accessible means,
503
+ then you must either (1) cause the Corresponding Source to be so
504
+ available, or (2) arrange to deprive yourself of the benefit of the
505
+ patent license for this particular work, or (3) arrange, in a manner
506
+ consistent with the requirements of this License, to extend the patent
507
+ license to downstream recipients. "Knowingly relying" means you have
508
+ actual knowledge that, but for the patent license, your conveying the
509
+ covered work in a country, or your recipient's use of the covered work
510
+ in a country, would infringe one or more identifiable patents in that
511
+ country that you have reason to believe are valid.
512
+
513
+ If, pursuant to or in connection with a single transaction or
514
+ arrangement, you convey, or propagate by procuring conveyance of, a
515
+ covered work, and grant a patent license to some of the parties
516
+ receiving the covered work authorizing them to use, propagate, modify
517
+ or convey a specific copy of the covered work, then the patent license
518
+ you grant is automatically extended to all recipients of the covered
519
+ work and works based on it.
520
+
521
+ A patent license is "discriminatory" if it does not include within
522
+ the scope of its coverage, prohibits the exercise of, or is
523
+ conditioned on the non-exercise of one or more of the rights that are
524
+ specifically granted under this License. You may not convey a covered
525
+ work if you are a party to an arrangement with a third party that is
526
+ in the business of distributing software, under which you make payment
527
+ to the third party based on the extent of your activity of conveying
528
+ the work, and under which the third party grants, to any of the
529
+ parties who would receive the covered work from you, a discriminatory
530
+ patent license (a) in connection with copies of the covered work
531
+ conveyed by you (or copies made from those copies), or (b) primarily
532
+ for and in connection with specific products or compilations that
533
+ contain the covered work, unless you entered into that arrangement,
534
+ or that patent license was granted, prior to 28 March 2007.
535
+
536
+ Nothing in this License shall be construed as excluding or limiting
537
+ any implied license or other defenses to infringement that may
538
+ otherwise be available to you under applicable patent law.
539
+
540
+ 12. No Surrender of Others' Freedom.
541
+
542
+ If conditions are imposed on you (whether by court order, agreement or
543
+ otherwise) that contradict the conditions of this License, they do not
544
+ excuse you from the conditions of this License. If you cannot convey a
545
+ covered work so as to satisfy simultaneously your obligations under this
546
+ License and any other pertinent obligations, then as a consequence you may
547
+ not convey it at all. For example, if you agree to terms that obligate you
548
+ to collect a royalty for further conveying from those to whom you convey
549
+ the Program, the only way you could satisfy both those terms and this
550
+ License would be to refrain entirely from conveying the Program.
551
+
552
+ 13. Use with the GNU Affero General Public License.
553
+
554
+ Notwithstanding any other provision of this License, you have
555
+ permission to link or combine any covered work with a work licensed
556
+ under version 3 of the GNU Affero General Public License into a single
557
+ combined work, and to convey the resulting work. The terms of this
558
+ License will continue to apply to the part which is the covered work,
559
+ but the special requirements of the GNU Affero General Public License,
560
+ section 13, concerning interaction through a network will apply to the
561
+ combination as such.
562
+
563
+ 14. Revised Versions of this License.
564
+
565
+ The Free Software Foundation may publish revised and/or new versions of
566
+ the GNU General Public License from time to time. Such new versions will
567
+ be similar in spirit to the present version, but may differ in detail to
568
+ address new problems or concerns.
569
+
570
+ Each version is given a distinguishing version number. If the
571
+ Program specifies that a certain numbered version of the GNU General
572
+ Public License "or any later version" applies to it, you have the
573
+ option of following the terms and conditions either of that numbered
574
+ version or of any later version published by the Free Software
575
+ Foundation. If the Program does not specify a version number of the
576
+ GNU General Public License, you may choose any version ever published
577
+ by the Free Software Foundation.
578
+
579
+ If the Program specifies that a proxy can decide which future
580
+ versions of the GNU General Public License can be used, that proxy's
581
+ public statement of acceptance of a version permanently authorizes you
582
+ to choose that version for the Program.
583
+
584
+ Later license versions may give you additional or different
585
+ permissions. However, no additional obligations are imposed on any
586
+ author or copyright holder as a result of your choosing to follow a
587
+ later version.
588
+
589
+ 15. Disclaimer of Warranty.
590
+
591
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592
+ APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593
+ HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594
+ OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596
+ PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597
+ IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598
+ ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599
+
600
+ 16. Limitation of Liability.
601
+
602
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603
+ WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604
+ THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605
+ GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606
+ USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607
+ DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608
+ PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609
+ EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610
+ SUCH DAMAGES.
611
+
612
+ 17. Interpretation of Sections 15 and 16.
613
+
614
+ If the disclaimer of warranty and limitation of liability provided
615
+ above cannot be given local legal effect according to their terms,
616
+ reviewing courts shall apply local law that most closely approximates
617
+ an absolute waiver of all civil liability in connection with the
618
+ Program, unless a warranty or assumption of liability accompanies a
619
+ copy of the Program in return for a fee.
620
+
621
+ END OF TERMS AND CONDITIONS
622
+
623
+ How to Apply These Terms to Your New Programs
624
+
625
+ If you develop a new program, and you want it to be of the greatest
626
+ possible use to the public, the best way to achieve this is to make it
627
+ free software which everyone can redistribute and change under these terms.
628
+
629
+ To do so, attach the following notices to the program. It is safest
630
+ to attach them to the start of each source file to most effectively
631
+ state the exclusion of warranty; and each file should have at least
632
+ the "copyright" line and a pointer to where the full notice is found.
633
+
634
+ <one line to give the program's name and a brief idea of what it does.>
635
+ Copyright (C) <year> <name of author>
636
+
637
+ This program is free software: you can redistribute it and/or modify
638
+ it under the terms of the GNU General Public License as published by
639
+ the Free Software Foundation, either version 3 of the License, or
640
+ (at your option) any later version.
641
+
642
+ This program is distributed in the hope that it will be useful,
643
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
644
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645
+ GNU General Public License for more details.
646
+
647
+ You should have received a copy of the GNU General Public License
648
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
649
+
650
+ Also add information on how to contact you by electronic and paper mail.
651
+
652
+ If the program does terminal interaction, make it output a short
653
+ notice like this when it starts in an interactive mode:
654
+
655
+ <program> Copyright (C) <year> <name of author>
656
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657
+ This is free software, and you are welcome to redistribute it
658
+ under certain conditions; type `show c' for details.
659
+
660
+ The hypothetical commands `show w' and `show c' should show the appropriate
661
+ parts of the General Public License. Of course, your program's commands
662
+ might be different; for a GUI interface, you would use an "about box".
663
+
664
+ You should also get your employer (if you work as a programmer) or school,
665
+ if any, to sign a "copyright disclaimer" for the program, if necessary.
666
+ For more information on this, and how to apply and follow the GNU GPL, see
667
+ <https://www.gnu.org/licenses/>.
668
+
669
+ The GNU General Public License does not permit incorporating your program
670
+ into proprietary programs. If your program is a subroutine library, you
671
+ may consider it more useful to permit linking proprietary applications with
672
+ the library. If this is what you want to do, use the GNU Lesser General
673
+ Public License instead of this License. But first, please read
674
+ <https://www.gnu.org/licenses/why-not-lgpl.html>.
README.md CHANGED
@@ -1,11 +1,2 @@
1
- ---
2
- title: Build Dashboard
3
- emoji: 📈
4
- colorFrom: gray
5
- colorTo: green
6
- sdk: docker
7
- pinned: false
8
- license: mit
9
- ---
10
-
11
- For info check out [Panel](https://panel.holoviz.org).
 
1
+ # Ash_Dispersion_Visualizer
2
+
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -306,7 +306,7 @@ def generate_output_gallery(base_folder):
306
 
307
  def make_preview(file_path):
308
  ext = os.path.splitext(file_path)[1].lower()
309
- title = pn.pane.Markdown(f"### {os.path.basename(file_path)}", width=640)
310
  download_button = pn.widgets.FileDownload(file=file_path, filename=os.path.basename(file_path),
311
  label="⬇ Download", button_type="success", width=150)
312
 
@@ -441,7 +441,7 @@ This dashboard allows users to upload and visualize outputs from the NAME ash di
441
  - Reset the app with 🔄 if needed.
442
  - View logs if an error occurs.
443
  - Outputs are temporary per session.
444
- """, sizing_mode="stretch_width", width=800))
445
 
446
  tabs = pn.Tabs(
447
  ("🧱 3D Field", tab3d),
@@ -457,8 +457,7 @@ sidebar = pn.Column(
457
  pn.Card(pn.Column(download_button, log_link, sizing_mode="stretch_width"),
458
  title="📁 Downloads & Logs", collapsible=True, sizing_mode="stretch_width"),
459
  pn.Card(status, title="📢 Status", collapsible=True, sizing_mode="stretch_width"),
460
- sizing_mode="stretch_width", width=300
461
- )
462
 
463
  restore_previous_session()
464
 
 
306
 
307
  def make_preview(file_path):
308
  ext = os.path.splitext(file_path)[1].lower()
309
+ title = pn.pane.Markdown(f"### {os.path.basename(file_path)}")
310
  download_button = pn.widgets.FileDownload(file=file_path, filename=os.path.basename(file_path),
311
  label="⬇ Download", button_type="success", width=150)
312
 
 
441
  - Reset the app with 🔄 if needed.
442
  - View logs if an error occurs.
443
  - Outputs are temporary per session.
444
+ """, sizing_mode="stretch_width"))
445
 
446
  tabs = pn.Tabs(
447
  ("🧱 3D Field", tab3d),
 
457
  pn.Card(pn.Column(download_button, log_link, sizing_mode="stretch_width"),
458
  title="📁 Downloads & Logs", collapsible=True, sizing_mode="stretch_width"),
459
  pn.Card(status, title="📢 Status", collapsible=True, sizing_mode="stretch_width"),
460
+ sizing_mode="stretch_width")
 
461
 
462
  restore_previous_session()
463
 
app.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b8fb449b683f01259e6dae2a50663cc2ec85fcd085ce6f09780cfb667b10fbb2
3
+ size 6200682
ash_animator/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
 
2
  # Auto-generated __init__.py to import all modules
3
- from .basemaps import draw_etopo_basemap
4
  from .converter import *
5
  from .interpolation import *
6
  from .plot_3dfield_data import *
 
1
 
2
  # Auto-generated __init__.py to import all modules
3
+ from .basemaps import *
4
  from .converter import *
5
  from .interpolation import *
6
  from .plot_3dfield_data import *
ash_animator/__pycache__/animation_single.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/animation_single.cpython-312.pyc and b/ash_animator/__pycache__/animation_single.cpython-312.pyc differ
 
ash_animator/__pycache__/animation_vertical.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/animation_vertical.cpython-312.pyc and b/ash_animator/__pycache__/animation_vertical.cpython-312.pyc differ
 
ash_animator/__pycache__/basemaps.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/basemaps.cpython-312.pyc and b/ash_animator/__pycache__/basemaps.cpython-312.pyc differ
 
ash_animator/__pycache__/converter.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/converter.cpython-312.pyc and b/ash_animator/__pycache__/converter.cpython-312.pyc differ
 
ash_animator/__pycache__/export.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/export.cpython-312.pyc and b/ash_animator/__pycache__/export.cpython-312.pyc differ
 
ash_animator/__pycache__/interpolation.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/interpolation.cpython-312.pyc and b/ash_animator/__pycache__/interpolation.cpython-312.pyc differ
 
ash_animator/__pycache__/plot_3dfield_data.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/plot_3dfield_data.cpython-312.pyc and b/ash_animator/__pycache__/plot_3dfield_data.cpython-312.pyc differ
 
ash_animator/__pycache__/plot_horizontal_data.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/plot_horizontal_data.cpython-312.pyc and b/ash_animator/__pycache__/plot_horizontal_data.cpython-312.pyc differ
 
ash_animator/__pycache__/utils.cpython-312.pyc CHANGED
Binary files a/ash_animator/__pycache__/utils.cpython-312.pyc and b/ash_animator/__pycache__/utils.cpython-312.pyc differ
 
ash_animator/basemaps.py CHANGED
@@ -1,24 +1,33 @@
1
  import os
2
- import tempfile
3
  import hashlib
4
- #import contextily as ctx
 
5
  from mpl_toolkits.basemap import Basemap
6
  import cartopy.crs as ccrs
7
  import cartopy.feature as cfeature
8
  from PIL import Image
9
  import matplotlib.pyplot as plt
10
 
11
- # Use writable temporary directory for tile caching
12
- CTX_TILE_CACHE_DIR = os.path.join(tempfile.gettempdir(), "contextily_cache")
13
- BASEMAP_TILE_CACHE_DIR = os.path.join(tempfile.gettempdir(), "contextily_cache")
 
 
 
 
 
 
 
 
 
14
 
15
- # Ensure directories exist
16
- os.makedirs(CTX_TILE_CACHE_DIR, exist_ok=True)
17
- os.makedirs(BASEMAP_TILE_CACHE_DIR, exist_ok=True)
18
 
19
- # Optionally set environment variable for contextily
20
  os.environ["XDG_CACHE_HOME"] = CTX_TILE_CACHE_DIR
21
-
 
22
 
23
  def draw_etopo_basemap(ax, mode="basemap", zoom=11):
24
  """
@@ -38,6 +47,12 @@ def draw_etopo_basemap(ax, mode="basemap", zoom=11):
38
 
39
  zoom : int, optional
40
  Tile zoom level (only for "contextily"). Higher = more detail. Default is 7.
 
 
 
 
 
 
41
  """
42
  try:
43
  if mode == "stock":
@@ -71,7 +86,6 @@ def draw_etopo_basemap(ax, mode="basemap", zoom=11):
71
  llcrnrlon=extent[0], urcrnrlon=extent[1],
72
  llcrnrlat=extent[2], urcrnrlat=extent[3],
73
  resolution='f', ax=temp_ax)
74
-
75
  m.shadedrelief()
76
 
77
  temp_fig.savefig(cache_file, dpi=300, bbox_inches='tight', pad_inches=0)
 
1
  import os
 
2
  import hashlib
3
+ import tempfile
4
+ import contextily as ctx
5
  from mpl_toolkits.basemap import Basemap
6
  import cartopy.crs as ccrs
7
  import cartopy.feature as cfeature
8
  from PIL import Image
9
  import matplotlib.pyplot as plt
10
 
11
+ # Determine platform and fallback cache path
12
+ def get_cache_dir(app_name):
13
+ if os.name == 'nt':
14
+ return os.path.join(os.getenv('LOCALAPPDATA', tempfile.gettempdir()), f"{app_name}_cache")
15
+ elif os.name == 'posix':
16
+ home_dir = os.path.expanduser("~")
17
+ if os.path.isdir(home_dir) and os.access(home_dir, os.W_OK):
18
+ return os.path.join(home_dir, f".{app_name}_cache")
19
+ else:
20
+ return os.path.join(tempfile.gettempdir(), f"{app_name}_cache")
21
+ else:
22
+ return os.path.join(tempfile.gettempdir(), f"{app_name}_cache")
23
 
24
+ # Define cache directories
25
+ CTX_TILE_CACHE_DIR = get_cache_dir("contextily")
26
+ BASEMAP_TILE_CACHE_DIR = get_cache_dir("basemap")
27
 
 
28
  os.environ["XDG_CACHE_HOME"] = CTX_TILE_CACHE_DIR
29
+ os.makedirs(CTX_TILE_CACHE_DIR, exist_ok=True)
30
+ os.makedirs(BASEMAP_TILE_CACHE_DIR, exist_ok=True)
31
 
32
  def draw_etopo_basemap(ax, mode="basemap", zoom=11):
33
  """
 
47
 
48
  zoom : int, optional
49
  Tile zoom level (only for "contextily"). Higher = more detail. Default is 7.
50
+
51
+ Notes
52
+ -----
53
+ - Uses high resolution for Basemap (resolution='h') and saves figure at 300 DPI.
54
+ - Cached images are reused using extent-based hashing to avoid re-rendering.
55
+ - Basemap is deprecated; Cartopy with web tiles is recommended for new projects.
56
  """
57
  try:
58
  if mode == "stock":
 
86
  llcrnrlon=extent[0], urcrnrlon=extent[1],
87
  llcrnrlat=extent[2], urcrnrlat=extent[3],
88
  resolution='f', ax=temp_ax)
 
89
  m.shadedrelief()
90
 
91
  temp_fig.savefig(cache_file, dpi=300, bbox_inches='tight', pad_inches=0)
ash_animator/converter.py CHANGED
@@ -1,148 +1,4 @@
1
- # # Full updated and corrected version of NAMEDataConverter with sanitized metadata keys
2
-
3
- # import os
4
- # import re
5
- # import zipfile
6
- # import shutil
7
- # import numpy as np
8
- # import xarray as xr
9
- # import matplotlib.pyplot as plt
10
- # import matplotlib.animation as animation
11
- # from typing import List, Tuple
12
-
13
- # class NAMEDataConverter:
14
- # def __init__(self, output_dir: str):
15
- # self.output_dir = output_dir
16
- # os.makedirs(self.output_dir, exist_ok=True)
17
-
18
- # def _sanitize_key(self, key: str) -> str:
19
- # # Replace non-alphanumeric characters with underscores, and ensure it starts with a letter
20
- # key = re.sub(r'\W+', '_', key)
21
- # if not key[0].isalpha():
22
- # key = f"attr_{key}"
23
- # return key
24
-
25
- # def _parse_metadata(self, lines: List[str]) -> dict:
26
- # metadata = {}
27
- # for line in lines:
28
- # if ":" in line:
29
- # key, value = line.split(":", 1)
30
- # clean_key = self._sanitize_key(key.strip().lower())
31
- # metadata[clean_key] = value.strip()
32
-
33
- # try:
34
- # metadata.update({
35
- # "x_origin": float(metadata["x_grid_origin"]),
36
- # "y_origin": float(metadata["y_grid_origin"]),
37
- # "x_size": int(metadata["x_grid_size"]),
38
- # "y_size": int(metadata["y_grid_size"]),
39
- # "x_res": float(metadata["x_grid_resolution"]),
40
- # "y_res": float(metadata["y_grid_resolution"]),
41
- # "prelim_cols": int(metadata["number_of_preliminary_cols"]),
42
- # "n_fields": int(metadata["number_of_field_cols"]),
43
- # })
44
- # except KeyError as e:
45
- # raise ValueError(f"Missing required metadata field: {e}")
46
- # except ValueError as e:
47
- # raise ValueError(f"Invalid value in metadata: {e}")
48
-
49
- # if metadata["x_res"] == 0 or metadata["y_res"] == 0:
50
- # raise ZeroDivisionError("Grid resolution cannot be zero.")
51
-
52
- # return metadata
53
-
54
- # def _get_data_lines(self, lines: List[str]) -> List[str]:
55
- # idx = next(i for i, l in enumerate(lines) if l.strip() == "Fields:")
56
- # return lines[idx + 1:]
57
-
58
- # def convert_3d_group(self, group: List[Tuple[int, str]], output_filename: str) -> str:
59
- # first_file_path = group[0][1]
60
- # with open(first_file_path, 'r') as f:
61
- # lines = f.readlines()
62
- # meta = self._parse_metadata(lines)
63
-
64
- # lons = np.round(np.arange(meta["x_origin"], meta["x_origin"] + meta["x_size"] * meta["x_res"], meta["x_res"]), 6)
65
- # lats = np.round(np.arange(meta["y_origin"], meta["y_origin"] + meta["y_size"] * meta["y_res"], meta["y_res"]), 6)
66
-
67
- # z_levels = []
68
- # z_coords = []
69
-
70
- # for z_idx, filepath in group:
71
- # with open(filepath, 'r') as f:
72
- # lines = f.readlines()
73
- # data_lines = self._get_data_lines(lines)
74
- # grid = np.zeros((meta["y_size"], meta["x_size"]), dtype=np.float32)
75
-
76
- # for line in data_lines:
77
- # parts = [p.strip().strip(',') for p in line.strip().split(',') if p.strip()]
78
- # if len(parts) >= 5 and parts[0].isdigit() and parts[1].isdigit():
79
- # try:
80
- # x = int(parts[0]) - 1
81
- # y = int(parts[1]) - 1
82
- # val = float(parts[4])
83
- # if 0 <= x < meta["x_size"] and 0 <= y < meta["y_size"]:
84
- # grid[y, x] = val
85
- # except Exception:
86
- # continue
87
- # z_levels.append(grid)
88
- # z_coords.append(z_idx)
89
-
90
- # z_cube = np.stack(z_levels, axis=0)
91
- # ds = xr.Dataset(
92
- # {
93
- # "ash_concentration": (['altitude', 'latitude', 'longitude'], z_cube)
94
- # },
95
- # coords={
96
- # "altitude": np.array(z_coords, dtype=np.float32),
97
- # "latitude": lats,
98
- # "longitude": lons
99
- # },
100
- # attrs={
101
- # "title": "Volcanic Ash Concentration",
102
- # "source": "NAME model output processed to NetCDF",
103
- # **{k: str(v) for k, v in meta.items()} # Ensure all attrs are strings
104
- # }
105
- # )
106
- # ds["ash_concentration"].attrs.update({
107
- # "units": "g/m^3",
108
- # "long_name": "Volcanic ash concentration"
109
- # })
110
- # ds["altitude"].attrs["units"] = "kilometers above sea level"
111
- # ds["latitude"].attrs["units"] = "degrees_north"
112
- # ds["longitude"].attrs["units"] = "degrees_east"
113
-
114
- # out_path = os.path.join(self.output_dir, output_filename)
115
- # ds.to_netcdf(out_path)
116
- # return out_path
117
-
118
- # def batch_process_zip(self, zip_path: str) -> List[str]:
119
- # extract_dir = os.path.join(self.output_dir, "unzipped")
120
- # os.makedirs(extract_dir, exist_ok=True)
121
-
122
- # with zipfile.ZipFile(zip_path, 'r') as zip_ref:
123
- # zip_ref.extractall(extract_dir)
124
-
125
- # txt_files = []
126
- # for root, _, files in os.walk(extract_dir):
127
- # for file in files:
128
- # if file.endswith(".txt"):
129
- # txt_files.append(os.path.join(root, file))
130
-
131
- # pattern = re.compile(r"_T(\d+)_.*_Z(\d+)\.txt$")
132
- # grouped = {}
133
- # for f in txt_files:
134
- # match = pattern.search(f)
135
- # if match:
136
- # t = int(match.group(1))
137
- # z = int(match.group(2))
138
- # grouped.setdefault(t, []).append((z, f))
139
-
140
- # nc_files = []
141
- # for t_key in sorted(grouped):
142
- # group = sorted(grouped[t_key])
143
- # out_nc = self.convert_3d_group(group, f"T{t_key}.nc")
144
- # nc_files.append(out_nc)
145
- # return nc_files
146
 
147
  # Re-defining the integrated class first
148
  import os
@@ -154,8 +10,17 @@ from typing import List, Tuple
154
  import shutil
155
 
156
 
 
 
157
  class NAMEDataProcessor:
158
- def __init__(self, output_root: str):
 
 
 
 
 
 
 
159
  self.output_root = output_root
160
  self.output_3d = os.path.join(self.output_root, "3D")
161
  self.output_horizontal = os.path.join(self.output_root, "horizontal")
@@ -332,7 +197,7 @@ class NAMEDataProcessor:
332
 
333
 
334
  def batch_process_zip(self, zip_path: str) -> List[str]:
335
- extract_dir = os.path.abspath("unzipped")
336
 
337
  os.makedirs(extract_dir, exist_ok=True)
338
 
 
1
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  # Re-defining the integrated class first
4
  import os
 
10
  import shutil
11
 
12
 
13
+ import tempfile # Added for safe temp directory usage
14
+
15
  class NAMEDataProcessor:
16
+ def __init__(self, output_root: str = None):
17
+ if output_root is None:
18
+ output_root = os.path.join(tempfile.gettempdir(), "name_outputs")
19
+ self.output_root = output_root
20
+ self.output_3d = os.path.join(self.output_root, "3D")
21
+ self.output_horizontal = os.path.join(self.output_root, "horizontal")
22
+ os.makedirs(self.output_3d, exist_ok=True)
23
+ os.makedirs(self.output_horizontal, exist_ok=True)
24
  self.output_root = output_root
25
  self.output_3d = os.path.join(self.output_root, "3D")
26
  self.output_horizontal = os.path.join(self.output_root, "horizontal")
 
197
 
198
 
199
  def batch_process_zip(self, zip_path: str) -> List[str]:
200
+ extract_dir = os.path.join(tempfile.gettempdir(), "unzipped_name_extract")
201
 
202
  os.makedirs(extract_dir, exist_ok=True)
203
 
ash_animator/plot_3dfield_data.py CHANGED
@@ -11,6 +11,7 @@ from .interpolation import interpolate_grid
11
  from .basemaps import draw_etopo_basemap
12
  import imageio.v2 as imageio
13
  import shutil
 
14
 
15
  class Plot_3DField_Data:
16
 
@@ -70,7 +71,13 @@ class Plot_3DField_Data:
70
  include_metadata=True, threshold=0.1,
71
  zoom_width_deg=6.0, zoom_height_deg=6.0, zoom_level=7, basemap_type="basemap"):
72
  self.animator = animator
73
- self.output_dir = os.path.abspath(os.path.join(os.getcwd(), output_dir))
 
 
 
 
 
 
74
  os.makedirs(self.output_dir, exist_ok=True)
75
  self.cmap = cmap
76
  self.fps = fps
@@ -460,6 +467,6 @@ class Plot_3DField_Data:
460
  formatter = mticker.FuncFormatter(lambda x, _: f'{x:.2g}')
461
  cbar.ax.yaxis.set_major_formatter(formatter)
462
  frame_path = os.path.join(z_dir, f"frame_{t+1:04d}.jpg")
463
- plt.savefig(frame_path, dpi=150, bbox_inches='tight')
464
  plt.close(fig)
465
  print(f"📸 Saved {frame_path}")
 
11
  from .basemaps import draw_etopo_basemap
12
  import imageio.v2 as imageio
13
  import shutil
14
+ import tempfile
15
 
16
  class Plot_3DField_Data:
17
 
 
71
  include_metadata=True, threshold=0.1,
72
  zoom_width_deg=6.0, zoom_height_deg=6.0, zoom_level=7, basemap_type="basemap"):
73
  self.animator = animator
74
+
75
+ self.output_dir = os.path.abspath(
76
+ os.path.join(
77
+ os.environ.get("NAME_OUTPUT_DIR", tempfile.gettempdir()),
78
+ output_dir
79
+ )
80
+ )
81
  os.makedirs(self.output_dir, exist_ok=True)
82
  self.cmap = cmap
83
  self.fps = fps
 
467
  formatter = mticker.FuncFormatter(lambda x, _: f'{x:.2g}')
468
  cbar.ax.yaxis.set_major_formatter(formatter)
469
  frame_path = os.path.join(z_dir, f"frame_{t+1:04d}.jpg")
470
+ plt.savefig(frame_path, bbox_inches='tight')
471
  plt.close(fig)
472
  print(f"📸 Saved {frame_path}")
ash_animator/plot_horizontal_data.py CHANGED
@@ -1,286 +1,3 @@
1
- ''' import os
2
- import numpy as np
3
- import matplotlib.pyplot as plt
4
- import matplotlib.animation as animation
5
- import matplotlib.ticker as mticker
6
- import cartopy.crs as ccrs
7
- import cartopy.feature as cfeature
8
- import cartopy.io.shapereader as shpreader
9
- from adjustText import adjust_text
10
- from ash_animator.interpolation import interpolate_grid
11
- from ash_animator.basemaps import draw_etopo_basemap
12
-
13
- class Plot_Horizontal_Data:
14
- def __init__(self, animator, output_dir="plots", cmap="rainbow", fps=2,
15
- include_metadata=True, threshold=0.1,
16
- zoom_width_deg=6.0, zoom_height_deg=6.0, zoom_level=7, static_frame_export=False):
17
- self.animator = animator
18
- self.output_dir = os.path.abspath(os.path.join(os.getcwd(), output_dir))
19
- os.makedirs(self.output_dir, exist_ok=True)
20
- self.cmap = cmap
21
- self.fps = fps
22
- self.include_metadata = include_metadata
23
- self.threshold = threshold
24
- self.zoom_width = zoom_width_deg
25
- self.zoom_height = zoom_height_deg
26
- shp = shpreader.natural_earth(resolution='110m', category='cultural', name='admin_0_countries')
27
- self.country_geoms = list(shpreader.Reader(shp).records())
28
- self.interpolate_grid= interpolate_grid
29
- self._draw_etopo_basemap=draw_etopo_basemap
30
- self.zoom_level=zoom_level
31
- self.static_frame_export=static_frame_export
32
-
33
- def _make_dirs(self, path):
34
- os.makedirs(os.path.abspath(os.path.join(os.getcwd(), os.path.dirname(path))), exist_ok=True)
35
-
36
- def _get_max_concentration_location(self, field):
37
- max_val = -np.inf
38
- lat = lon = None
39
- for ds in self.animator.datasets:
40
- data = ds[field].values
41
- if np.max(data) > max_val:
42
- max_val = np.max(data)
43
- idx = np.unravel_index(np.argmax(data), data.shape)
44
- lat = self.animator.lat_grid[idx]
45
- lon = self.animator.lon_grid[idx]
46
- return lat, lon
47
-
48
- def _get_zoom_indices(self, center_lat, center_lon):
49
- lon_min = center_lon - self.zoom_width / 2
50
- lon_max = center_lon + self.zoom_width / 2
51
- lat_min = center_lat - self.zoom_height / 2
52
- lat_max = center_lat + self.zoom_height / 2
53
- lat_idx = np.where((self.animator.lats >= lat_min) & (self.animator.lats <= lat_max))[0]
54
- lon_idx = np.where((self.animator.lons >= lon_min) & (self.animator.lons <= lon_max))[0]
55
- return lat_idx, lon_idx, lon_min, lon_max, lat_min, lat_max
56
-
57
- def _add_country_labels(self, ax, extent):
58
- proj = ccrs.PlateCarree()
59
- texts = []
60
- for country in self.country_geoms:
61
- name = country.attributes['NAME_LONG']
62
- geom = country.geometry
63
- try:
64
- lon, lat = geom.centroid.x, geom.centroid.y
65
- if extent[0] <= lon <= extent[1] and extent[2] <= lat <= extent[3]:
66
- text = ax.text(lon, lat, name, fontsize=6, transform=proj,
67
- ha='center', va='center', color='white',
68
- bbox=dict(facecolor='black', alpha=0.5, linewidth=0))
69
- texts.append(text)
70
- except:
71
- continue
72
- adjust_text(texts, ax=ax, only_move={'points': 'y', 'text': 'y'},
73
- arrowprops=dict(arrowstyle="->", color='white', lw=0.5))
74
-
75
- def _draw_metadata_sidebar(self, fig, meta_dict):
76
- lines = [
77
- f"Run name: {meta_dict.get('run_name', 'N/A')}",
78
- f"Run time: {meta_dict.get('run_time', 'N/A')}",
79
- f"Met data: {meta_dict.get('met_data', 'N/A')}",
80
- f"Start release: {meta_dict.get('start_of_release', 'N/A')}",
81
- f"End release: {meta_dict.get('end_of_release', 'N/A')}",
82
- f"Source strength: {meta_dict.get('source_strength', 'N/A')} g/s",
83
- f"Release loc: {meta_dict.get('release_location', 'N/A')}",
84
- f"Release height: {meta_dict.get('release_height', 'N/A')} m asl",
85
- f"Run duration: {meta_dict.get('run_duration', 'N/A')}"
86
- ]
87
-
88
- # Split into two columns
89
- mid = len(lines) // 2 + len(lines) % 2
90
- left_lines = lines[:mid]
91
- right_lines = lines[mid:]
92
-
93
- left_text = "\n".join(left_lines)
94
- right_text = "\n".join(right_lines)
95
-
96
- # right column
97
- fig.text(0.05, 0.05, left_text, va='bottom', ha='left',
98
- fontsize=9, family='monospace', color='black',
99
- bbox=dict(facecolor='white', alpha=0.8, edgecolor='gray'))
100
-
101
- # left column
102
- fig.text(0.3, 0.05, right_text, va='bottom', ha='left',
103
- fontsize=9, family='monospace', color='black',
104
- bbox=dict(facecolor='white', alpha=0.8, edgecolor='gray'))
105
-
106
-
107
-
108
-
109
-
110
- def _plot_frame(self, ax, data, lons, lats, title, levels, scale_label, proj):
111
- self._draw_etopo_basemap(ax, mode='basemap', zoom=self.zoom_level)
112
- c = ax.contourf(lons, lats, data, levels=levels, cmap=self.cmap, alpha=0.6, transform=proj)
113
- ax.set_title(title)
114
- ax.set_extent([lons.min(), lons.max(), lats.min(), lats.max()])
115
- ax.coastlines()
116
- ax.add_feature(cfeature.BORDERS, linestyle=':')
117
- ax.add_feature(cfeature.LAND)
118
- ax.add_feature(cfeature.OCEAN)
119
- return c
120
-
121
- def get_available_2d_fields(self):
122
- ds = self.animator.datasets[0]
123
- return [v for v in ds.data_vars if ds[v].ndim == 2]
124
-
125
- def plot_single_field_over_time(self, field, filename="field.gif"):
126
- output_path = os.path.join(self.output_dir, "2d_fields", field, filename)
127
- meta = self.animator.datasets[0].attrs
128
- center_lat, center_lon = self._get_max_concentration_location(field)
129
- lat_idx, lon_idx, lon_min, lon_max, lat_min, lat_max = self._get_zoom_indices(center_lat, center_lon)
130
- lat_zoom = self.animator.lats[lat_idx]
131
- lon_zoom = self.animator.lons[lon_idx]
132
-
133
- valid_frames = []
134
- for t in range(len(self.animator.datasets)):
135
- data = self.animator.datasets[t][field].values
136
- interp = self.interpolate_grid(data, self.animator.lon_grid, self.animator.lat_grid)
137
- if np.isfinite(interp).sum() > 0:
138
- valid_frames.append(t)
139
-
140
- if not valid_frames:
141
- print(f"No valid frames to plot for field '{field}'.")
142
- return
143
-
144
- fig = plt.figure(figsize=(16, 8))
145
- proj = ccrs.PlateCarree()
146
- ax1 = fig.add_subplot(1, 2, 1, projection=proj)
147
- ax2 = fig.add_subplot(1, 2, 2, projection=proj)
148
-
149
- def update(t):
150
- ax1.clear()
151
- ax2.clear()
152
- data = self.animator.datasets[t][field].values
153
- interp = self.interpolate_grid(data, self.animator.lon_grid, self.animator.lat_grid)
154
- zoom = interp[np.ix_(lat_idx, lon_idx)]
155
- valid = interp[np.isfinite(interp)]
156
- if valid.size == 0:
157
- return []
158
-
159
- min_val, max_val = np.nanmin(valid), np.nanmax(valid)
160
- log_cutoff = 1e-3
161
- use_log = min_val > log_cutoff and (max_val / (min_val + 1e-6)) > 100
162
- levels = np.logspace(np.log10(log_cutoff), np.log10(max_val), 20) if use_log else np.linspace(0, max_val, 20)
163
- plot_data = np.where(interp > log_cutoff, interp, np.nan) if use_log else interp
164
- scale_label = "Log" if use_log else "Linear"
165
-
166
- c = self._plot_frame(ax1, plot_data, self.animator.lons, self.animator.lats,
167
- f"T{t+1} | {field} (Full - {scale_label})", levels, scale_label, proj)
168
- self._plot_frame(ax2, zoom, lon_zoom, lat_zoom,
169
- f"T{t+1} | {field} (Zoom - {scale_label})", levels, scale_label, proj)
170
-
171
- self._add_country_labels(ax1, [self.animator.lons.min(), self.animator.lons.max(),
172
- self.animator.lats.min(), self.animator.lats.max()])
173
- self._add_country_labels(ax2, [lon_min, lon_max, lat_min, lat_max])
174
-
175
- # Inside update() function:
176
- if not hasattr(update, "colorbar"):
177
- unit_label = f"{field}:({self.animator.datasets[0][field].attrs.get("units", field)})" #self.animator.datasets[0][field].attrs.get("units", field)
178
- update.colorbar = fig.colorbar(c, ax=[ax1, ax2], orientation='vertical', label=unit_label)
179
- formatter = mticker.FuncFormatter(lambda x, _: f'{x:.2g}')
180
- update.colorbar.ax.yaxis.set_major_formatter(formatter)
181
-
182
-
183
- if np.nanmax(valid) > self.threshold:
184
- ax1.contour(self.animator.lons, self.animator.lats, interp, levels=[self.threshold],
185
- colors='red', linewidths=2, transform=proj)
186
- ax2.contour(lon_zoom, lat_zoom, zoom, levels=[self.threshold],
187
- colors='red', linewidths=2, transform=proj)
188
- ax2.text(0.99, 0.01, f"⚠ Max Thresold Exceed: {np.nanmax(valid):.2f} > {self.threshold}",
189
- transform=ax2.transAxes, ha='right', va='bottom',
190
- fontsize=9, color='red',
191
- bbox=dict(facecolor='white', alpha=0.8, edgecolor='red'))
192
-
193
- if self.static_frame_export:
194
- frame_folder = os.path.join(self.output_dir, "frames", field)
195
- os.makedirs(frame_folder, exist_ok=True)
196
- frame_path = os.path.join(frame_folder, f"frame_{t+1:04d}.jpg")
197
- plt.savefig(frame_path, dpi=300, bbox_inches='tight')
198
- print(f"🖼️ Saved static frame: {frame_path}")
199
-
200
- return []
201
-
202
- if self.include_metadata:
203
- self._draw_metadata_sidebar(fig, meta)
204
-
205
- self._make_dirs(output_path)
206
- fig.tight_layout()
207
- ani = animation.FuncAnimation(fig, update, frames=valid_frames, blit=False, cache_frame_data =False)
208
- ani.save(output_path, writer='pillow', fps=self.fps)
209
- plt.close()
210
- print(f"✅ Saved enhanced 2D animation for {field} to {output_path}")
211
-
212
- # def export_frames_as_jpgs(self, fields=None, include_metadata=True):
213
- # all_fields = self.get_available_2d_fields()
214
- # if fields:
215
- # fields = [f for f in fields if f in all_fields]
216
- # else:
217
- # fields = all_fields
218
-
219
- # meta = self.animator.datasets[0].attrs
220
-
221
- # for field in fields:
222
- # print(f"📤 Exporting frames for field: {field}")
223
- # output_folder = os.path.join(self.output_dir, "frames", field)
224
- # os.makedirs(output_folder, exist_ok=True)
225
-
226
- # center_lat, center_lon = self._get_max_concentration_location(field)
227
- # lat_idx, lon_idx, lon_min, lon_max, lat_min, lat_max = self._get_zoom_indices(center_lat, center_lon)
228
- # lat_zoom = self.animator.lats[lat_idx]
229
- # lon_zoom = self.animator.lons[lon_idx]
230
-
231
- # for t, ds in enumerate(self.animator.datasets):
232
- # data = ds[field].values
233
- # interp = self.interpolate_grid(data, self.animator.lon_grid, self.animator.lat_grid)
234
- # if not np.isfinite(interp).any():
235
- # continue
236
-
237
- # fig = plt.figure(figsize=(16, 8))
238
- # proj = ccrs.PlateCarree()
239
- # ax1 = fig.add_subplot(1, 2, 1, projection=proj)
240
- # ax2 = fig.add_subplot(1, 2, 2, projection=proj)
241
- # zoom = interp[np.ix_(lat_idx, lon_idx)]
242
- # valid = interp[np.isfinite(interp)]
243
- # min_val, max_val = np.nanmin(valid), np.nanmax(valid)
244
- # log_cutoff = 1e-3
245
- # use_log = min_val > log_cutoff and (max_val / (min_val + 1e-6)) > 100
246
- # levels = np.logspace(np.log10(log_cutoff), np.log10(max_val), 20) if use_log else np.linspace(0, max_val, 20)
247
- # plot_data = np.where(interp > log_cutoff, interp, np.nan) if use_log else interp
248
- # scale_label = "Log" if use_log else "Linear"
249
-
250
- # c = self._plot_frame(ax1, plot_data, self.animator.lons, self.animator.lats,
251
- # f"T{t+1} | {field} (Full - {scale_label})", levels, scale_label, proj)
252
- # self._plot_frame(ax2, zoom, lon_zoom, lat_zoom,
253
- # f"T{t+1} | {field} (Zoom - {scale_label})", levels, scale_label, proj)
254
-
255
- # self._add_country_labels(ax1, [self.animator.lons.min(), self.animator.lons.max(),
256
- # self.animator.lats.min(), self.animator.lats.max()])
257
- # self._add_country_labels(ax2, [lon_min, lon_max, lat_min, lat_max])
258
-
259
- # if include_metadata:
260
- # self._draw_metadata_sidebar(fig, meta)
261
-
262
- # cbar = fig.colorbar(c, ax=[ax1, ax2], orientation='vertical', shrink=0.75, pad=0.03)
263
- # unit_label = f"{field}:({self.animator.datasets[0][field].attrs.get('units', field)})"
264
- # cbar.set_label(unit_label)
265
- # formatter = mticker.FuncFormatter(lambda x, _: f'{x:.2g}')
266
- # cbar.ax.yaxis.set_major_formatter(formatter)
267
-
268
- # if np.nanmax(valid) > self.threshold:
269
- # ax1.contour(self.animator.lons, self.animator.lats, interp, levels=[self.threshold],
270
- # colors='red', linewidths=2, transform=proj)
271
- # ax2.contour(lon_zoom, lat_zoom, zoom, levels=[self.threshold],
272
- # colors='red', linewidths=2, transform=proj)
273
- # ax2.text(0.99, 0.01, f"⚠ Max: {np.nanmax(valid):.2f} > {self.threshold}",
274
- # transform=ax2.transAxes, ha='right', va='bottom',
275
- # fontsize=9, color='red',
276
- # bbox=dict(facecolor='white', alpha=0.8, edgecolor='red'))
277
-
278
- # frame_path = os.path.join(output_folder, f"frame_{t+1:04d}.jpg")
279
- # plt.savefig(frame_path, dpi=150, bbox_inches='tight')
280
- # plt.close(fig)
281
- # print(f"📸 Saved {frame_path}")
282
- '''
283
-
284
  import os
285
  import numpy as np
286
  import matplotlib.pyplot as plt
@@ -292,13 +9,20 @@ import cartopy.io.shapereader as shpreader
292
  from adjustText import adjust_text
293
  from ash_animator.interpolation import interpolate_grid
294
  from ash_animator.basemaps import draw_etopo_basemap
 
295
 
296
  class Plot_Horizontal_Data:
297
  def __init__(self, animator, output_dir="plots", cmap="rainbow", fps=2,
298
  include_metadata=True, threshold=0.1,
299
  zoom_width_deg=6.0, zoom_height_deg=6.0, zoom_level=7, static_frame_export=False):
300
  self.animator = animator
301
- self.output_dir = os.path.abspath(os.path.join(os.getcwd(), output_dir))
 
 
 
 
 
 
302
  os.makedirs(self.output_dir, exist_ok=True)
303
  self.cmap = cmap
304
  self.fps = fps
@@ -457,7 +181,7 @@ class Plot_Horizontal_Data:
457
 
458
  # Inside update() function:
459
  if not hasattr(update, "colorbar"):
460
- unit_label = f"{field}:({self.animator.datasets[0][field].attrs.get('units', field)})" #self.animator.datasets[0][field].attrs.get("units", field)
461
  update.colorbar = fig.colorbar(c, ax=[ax1, ax2], orientation='vertical', label=unit_label)
462
  formatter = mticker.FuncFormatter(lambda x, _: f'{x:.2g}')
463
  update.colorbar.ax.yaxis.set_major_formatter(formatter)
@@ -477,7 +201,7 @@ class Plot_Horizontal_Data:
477
  frame_folder = os.path.join(self.output_dir, "frames", field)
478
  os.makedirs(frame_folder, exist_ok=True)
479
  frame_path = os.path.join(frame_folder, f"frame_{t+1:04d}.jpg")
480
- plt.savefig(frame_path, dpi=300, bbox_inches='tight')
481
  print(f"🖼️ Saved static frame: {frame_path}")
482
 
483
  return []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import os
2
  import numpy as np
3
  import matplotlib.pyplot as plt
 
9
  from adjustText import adjust_text
10
  from ash_animator.interpolation import interpolate_grid
11
  from ash_animator.basemaps import draw_etopo_basemap
12
+ import tempfile
13
 
14
  class Plot_Horizontal_Data:
15
  def __init__(self, animator, output_dir="plots", cmap="rainbow", fps=2,
16
  include_metadata=True, threshold=0.1,
17
  zoom_width_deg=6.0, zoom_height_deg=6.0, zoom_level=7, static_frame_export=False):
18
  self.animator = animator
19
+
20
+ self.output_dir = os.path.abspath(
21
+ os.path.join(
22
+ os.environ.get("NAME_OUTPUT_DIR", tempfile.gettempdir()),
23
+ output_dir
24
+ )
25
+ )
26
  os.makedirs(self.output_dir, exist_ok=True)
27
  self.cmap = cmap
28
  self.fps = fps
 
181
 
182
  # Inside update() function:
183
  if not hasattr(update, "colorbar"):
184
+ unit_label = f"{field}:({self.animator.datasets[0][field].attrs.get('units', field)})" #self.animator.datasets[0][field].attrs.get('units', field)
185
  update.colorbar = fig.colorbar(c, ax=[ax1, ax2], orientation='vertical', label=unit_label)
186
  formatter = mticker.FuncFormatter(lambda x, _: f'{x:.2g}')
187
  update.colorbar.ax.yaxis.set_major_formatter(formatter)
 
201
  frame_folder = os.path.join(self.output_dir, "frames", field)
202
  os.makedirs(frame_folder, exist_ok=True)
203
  frame_path = os.path.join(frame_folder, f"frame_{t+1:04d}.jpg")
204
+ plt.savefig(frame_path, bbox_inches='tight')
205
  print(f"🖼️ Saved static frame: {frame_path}")
206
 
207
  return []
ash_output/3D/T1.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7f04bb4ebcd78d22d304f989a1db3798ba8973c3605d409cf5d8c214e10640ae
3
+ size 2995772
ash_output/3D/T10.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:fe2756a79311d5a93cef00a673e3f7bdc13a569527177a3a1d8bb98a2e2aec4b
3
+ size 2995772
ash_output/3D/T2.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:417fd7f9876bc5cd90aa9b337d4643a2f60c4c16bcb02d387cac0d4e14865bdb
3
+ size 2995772
ash_output/3D/T3.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2ec9f03b1d56ef60f53c7d896b314391ef43aad5d8a483429f1225019a3cd9ba
3
+ size 2995772
ash_output/3D/T4.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1f5588d08a7e435beff468d8395104cc9e6e74e096669e2ffd626a6bcd4ce029
3
+ size 2995772
ash_output/3D/T5.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6ab72f23b1002e1282a249ca69a1b86edb931434d4061da53623a35259099e70
3
+ size 2995772
ash_output/3D/T6.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:59e5b28106a70437df8acbe5f3a09bae1cb02452c64c81829ca024e45748ae01
3
+ size 2995772
ash_output/3D/T7.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ff112cf7b8c3fe57eebbb137d347689161cc294f08c5594f03f511531513e6ae
3
+ size 2995772
ash_output/3D/T8.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1b3147e15ec2c41fc248cd547633ecdb19282e5b4f99c72cbe3fe0685defd7d4
3
+ size 2995772
ash_output/3D/T9.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:779e66b51cced7ff2fcdb898497bd9239cc63dd1f98c3ea1e47ea227e033a469
3
+ size 2995772
ash_output/horizontal/AQOutput_HorizontalField_C1_T10_202001121400.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:30423a57456aac09b692d4626113cfad7354c10ebfe2a6b8dc2bfc67660a087f
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T1_202001120500.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e8d702759a96a17a9ee42f048e495634071edf3134d3e44498b1a4400c3e09fc
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T2_202001120600.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3ecee00afe0a4d182d1ef81fb693e55a1b692e2be6e3652e935de486c7bb7512
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T3_202001120700.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:be479227b11adf3b7dc893379eb237ccb977dec090b8fd61d4d124bbbedf9818
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T4_202001120800.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:4486fd0527002f561c922a5a6281f3398a3813d857a5095cb20bb6ffd8646c97
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T5_202001120900.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:7677dd47e53ff9d1f6529c64c3447b3a17dc49edc740bedbc275798169eabf8f
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T6_202001121000.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:2c098cbd98dc31e6401fe90491324c068c9b9eb35e2d6893f74d18ca9c4161c4
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T7_202001121100.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f50cadb7ab79147d443212d94778666a97c844aa2ac775a7053b978878135937
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T8_202001121200.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:b21e0a229a6831c8a1a394f3dc6650a0e045058cac23fe4d908024db387e2874
3
+ size 760991
ash_output/horizontal/AQOutput_HorizontalField_C1_T9_202001121300.nc ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:d55b4912c21a4b2b43d7fabc608c0095c72afa337fe7dead76cd100921e6bf7f
3
+ size 760991
media/2D/2d_fields/wet_deposition_rate/wet_deposition_rate.gif ADDED

Git LFS Details

  • SHA256: d51a54d114d7fcc08d53e215099eb5fd20f552d906c62c1611958ad04f03b5d6
  • Pointer size: 131 Bytes
  • Size of remote file: 920 kB
media/2D/frames/wet_deposition_rate/frame_0001.jpg ADDED

Git LFS Details

  • SHA256: fadafab42242db5f26901c8ae379991e2334fb6074ed43de07b17c3379eabb59
  • Pointer size: 131 Bytes
  • Size of remote file: 780 kB
media/2D/frames/wet_deposition_rate/frame_0005.jpg ADDED

Git LFS Details

  • SHA256: 0322d267034dc2ded02877dca73a1108ad8ba1f5357743a370fcb17c298d133b
  • Pointer size: 131 Bytes
  • Size of remote file: 763 kB
media/2D/frames/wet_deposition_rate/frame_0006.jpg ADDED

Git LFS Details

  • SHA256: 147c5d374aa3ea84aad52c4ae48515a18325c94b787c6f857098df143d2f8615
  • Pointer size: 131 Bytes
  • Size of remote file: 764 kB
media/2D/frames/wet_deposition_rate/frame_0007.jpg ADDED

Git LFS Details

  • SHA256: 6cd4cedd8381586657088283d079d9e8ab84f239aaf5a4b7d30ccb29274b96e0
  • Pointer size: 131 Bytes
  • Size of remote file: 761 kB
media/2D/frames/wet_deposition_rate/frame_0008.jpg ADDED

Git LFS Details

  • SHA256: 959809771d5944da0227bcbc6ae5b7cb96a1f44580790a4de1d943b9d0153ca3
  • Pointer size: 131 Bytes
  • Size of remote file: 763 kB
media/2D/frames/wet_deposition_rate/frame_0009.jpg ADDED

Git LFS Details

  • SHA256: a4b3fdb6cf39e5b89276fbe00bc2cf321e40e39beaa42f342dd5e30a46a455d0
  • Pointer size: 131 Bytes
  • Size of remote file: 764 kB
media/2D/frames/wet_deposition_rate/frame_0010.jpg ADDED

Git LFS Details

  • SHA256: 9e3f15b996ef5cc8e49b54d1b2a28d39cece86f1d5ad6f061cddb32ac8c910bf
  • Pointer size: 131 Bytes
  • Size of remote file: 779 kB
requirements.txt CHANGED
@@ -11,13 +11,4 @@ geopy
11
  adjustText
12
  basemap
13
  imageio
14
- panel
15
- matplotlib
16
- pillow
17
- numpy
18
- pandas
19
- rasterio
20
- contextily
21
- cartopy
22
- basemap
23
- scipy
 
11
  adjustText
12
  basemap
13
  imageio
14
+ basemap-data-hires