birdnet-analyzer 2.0.0__py3-none-any.whl
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.
- birdnet_analyzer/__init__.py +8 -0
- birdnet_analyzer/analyze/__init__.py +5 -0
- birdnet_analyzer/analyze/__main__.py +4 -0
- birdnet_analyzer/analyze/cli.py +25 -0
- birdnet_analyzer/analyze/core.py +245 -0
- birdnet_analyzer/analyze/utils.py +701 -0
- birdnet_analyzer/audio.py +372 -0
- birdnet_analyzer/cli.py +707 -0
- birdnet_analyzer/config.py +242 -0
- birdnet_analyzer/eBird_taxonomy_codes_2021E.json +25280 -0
- birdnet_analyzer/embeddings/__init__.py +4 -0
- birdnet_analyzer/embeddings/__main__.py +3 -0
- birdnet_analyzer/embeddings/cli.py +13 -0
- birdnet_analyzer/embeddings/core.py +70 -0
- birdnet_analyzer/embeddings/utils.py +193 -0
- birdnet_analyzer/evaluation/__init__.py +195 -0
- birdnet_analyzer/evaluation/__main__.py +3 -0
- birdnet_analyzer/gui/__init__.py +23 -0
- birdnet_analyzer/gui/__main__.py +3 -0
- birdnet_analyzer/gui/analysis.py +174 -0
- birdnet_analyzer/gui/assets/arrow_down.svg +4 -0
- birdnet_analyzer/gui/assets/arrow_left.svg +4 -0
- birdnet_analyzer/gui/assets/arrow_right.svg +4 -0
- birdnet_analyzer/gui/assets/arrow_up.svg +4 -0
- birdnet_analyzer/gui/assets/gui.css +29 -0
- birdnet_analyzer/gui/assets/gui.js +94 -0
- birdnet_analyzer/gui/assets/img/birdnet-icon.ico +0 -0
- birdnet_analyzer/gui/assets/img/birdnet_logo.png +0 -0
- birdnet_analyzer/gui/assets/img/birdnet_logo_no_transparent.png +0 -0
- birdnet_analyzer/gui/assets/img/clo-logo-bird.svg +1 -0
- birdnet_analyzer/gui/embeddings.py +620 -0
- birdnet_analyzer/gui/evaluation.py +813 -0
- birdnet_analyzer/gui/localization.py +68 -0
- birdnet_analyzer/gui/multi_file.py +246 -0
- birdnet_analyzer/gui/review.py +527 -0
- birdnet_analyzer/gui/segments.py +191 -0
- birdnet_analyzer/gui/settings.py +129 -0
- birdnet_analyzer/gui/single_file.py +269 -0
- birdnet_analyzer/gui/species.py +95 -0
- birdnet_analyzer/gui/train.py +698 -0
- birdnet_analyzer/gui/utils.py +808 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_af.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ar.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_bg.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ca.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_cs.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_da.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_de.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_el.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_en_uk.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_es.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_fi.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_fr.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_he.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_hr.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_hu.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_in.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_is.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_it.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ja.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ko.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_lt.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ml.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_nl.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_no.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pl.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pt_BR.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_pt_PT.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ro.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_ru.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sk.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sl.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sr.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_sv.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_th.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_tr.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_uk.txt +6522 -0
- birdnet_analyzer/labels/V2.4/BirdNET_GLOBAL_6K_V2.4_Labels_zh.txt +6522 -0
- birdnet_analyzer/lang/de.json +335 -0
- birdnet_analyzer/lang/en.json +335 -0
- birdnet_analyzer/lang/fi.json +335 -0
- birdnet_analyzer/lang/fr.json +335 -0
- birdnet_analyzer/lang/id.json +335 -0
- birdnet_analyzer/lang/pt-br.json +335 -0
- birdnet_analyzer/lang/ru.json +335 -0
- birdnet_analyzer/lang/se.json +335 -0
- birdnet_analyzer/lang/tlh.json +335 -0
- birdnet_analyzer/lang/zh_TW.json +335 -0
- birdnet_analyzer/model.py +1243 -0
- birdnet_analyzer/search/__init__.py +3 -0
- birdnet_analyzer/search/__main__.py +3 -0
- birdnet_analyzer/search/cli.py +12 -0
- birdnet_analyzer/search/core.py +78 -0
- birdnet_analyzer/search/utils.py +111 -0
- birdnet_analyzer/segments/__init__.py +3 -0
- birdnet_analyzer/segments/__main__.py +3 -0
- birdnet_analyzer/segments/cli.py +14 -0
- birdnet_analyzer/segments/core.py +78 -0
- birdnet_analyzer/segments/utils.py +394 -0
- birdnet_analyzer/species/__init__.py +3 -0
- birdnet_analyzer/species/__main__.py +3 -0
- birdnet_analyzer/species/cli.py +14 -0
- birdnet_analyzer/species/core.py +35 -0
- birdnet_analyzer/species/utils.py +75 -0
- birdnet_analyzer/train/__init__.py +3 -0
- birdnet_analyzer/train/__main__.py +3 -0
- birdnet_analyzer/train/cli.py +14 -0
- birdnet_analyzer/train/core.py +113 -0
- birdnet_analyzer/train/utils.py +847 -0
- birdnet_analyzer/translate.py +104 -0
- birdnet_analyzer/utils.py +419 -0
- birdnet_analyzer-2.0.0.dist-info/METADATA +129 -0
- birdnet_analyzer-2.0.0.dist-info/RECORD +117 -0
- birdnet_analyzer-2.0.0.dist-info/WHEEL +5 -0
- birdnet_analyzer-2.0.0.dist-info/entry_points.txt +11 -0
- birdnet_analyzer-2.0.0.dist-info/licenses/LICENSE +19 -0
- birdnet_analyzer-2.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
import json
|
2
|
+
import os
|
3
|
+
|
4
|
+
import birdnet_analyzer.gui.settings as settings
|
5
|
+
|
6
|
+
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
|
7
|
+
LANGUAGE_DIR = os.path.join(os.path.dirname(SCRIPT_DIR), "lang")
|
8
|
+
LANGUAGE_LOOKUP = {}
|
9
|
+
TARGET_LANGUAGE = settings.FALLBACK_LANGUAGE
|
10
|
+
|
11
|
+
|
12
|
+
def load_local_state():
|
13
|
+
"""
|
14
|
+
Loads the local language settings and populates the LANGUAGE_LOOKUP dictionary with the appropriate translations.
|
15
|
+
This function performs the following steps:
|
16
|
+
"""
|
17
|
+
global LANGUAGE_LOOKUP
|
18
|
+
global TARGET_LANGUAGE
|
19
|
+
|
20
|
+
settings.ensure_settings_file()
|
21
|
+
|
22
|
+
try:
|
23
|
+
TARGET_LANGUAGE = json.load(open(settings.GUI_SETTINGS_PATH, encoding="utf-8"))["language-id"]
|
24
|
+
except FileNotFoundError:
|
25
|
+
print(f"gui-settings.json not found. Using fallback language {settings.FALLBACK_LANGUAGE}.")
|
26
|
+
|
27
|
+
try:
|
28
|
+
with open(f"{LANGUAGE_DIR}/{TARGET_LANGUAGE}.json", "r", encoding="utf-8") as f:
|
29
|
+
LANGUAGE_LOOKUP = json.load(f)
|
30
|
+
except FileNotFoundError:
|
31
|
+
print(
|
32
|
+
f"Language file for {TARGET_LANGUAGE} not found in {LANGUAGE_DIR}. Using fallback language {settings.FALLBACK_LANGUAGE}."
|
33
|
+
)
|
34
|
+
|
35
|
+
if TARGET_LANGUAGE != settings.FALLBACK_LANGUAGE:
|
36
|
+
with open(f"{LANGUAGE_DIR}/{settings.FALLBACK_LANGUAGE}.json", "r") as f:
|
37
|
+
fallback: dict = json.load(f)
|
38
|
+
|
39
|
+
for key, value in fallback.items():
|
40
|
+
if key not in LANGUAGE_LOOKUP:
|
41
|
+
LANGUAGE_LOOKUP[key] = value
|
42
|
+
|
43
|
+
|
44
|
+
def localize(key: str) -> str:
|
45
|
+
"""
|
46
|
+
Translates a given key into its corresponding localized string.
|
47
|
+
|
48
|
+
Args:
|
49
|
+
key (str): The key to be localized.
|
50
|
+
|
51
|
+
Returns:
|
52
|
+
str: The localized string corresponding to the given key. If the key is not found in the localization lookup, the original key is returned.
|
53
|
+
"""
|
54
|
+
return LANGUAGE_LOOKUP.get(key, key)
|
55
|
+
|
56
|
+
|
57
|
+
def set_language(language: str):
|
58
|
+
"""
|
59
|
+
Sets the language for the application by updating the GUI settings file.
|
60
|
+
This function ensures that the settings file exists, reads the current settings,
|
61
|
+
updates the "language-id" field with the provided language, and writes the updated
|
62
|
+
settings back to the file.
|
63
|
+
|
64
|
+
Args:
|
65
|
+
language (str): The language identifier to set in the settings file.
|
66
|
+
"""
|
67
|
+
if language:
|
68
|
+
settings.set_setting("language-id", language)
|
@@ -0,0 +1,246 @@
|
|
1
|
+
import gradio as gr
|
2
|
+
|
3
|
+
import birdnet_analyzer.config as cfg
|
4
|
+
import birdnet_analyzer.gui.utils as gu
|
5
|
+
import birdnet_analyzer.gui.localization as loc
|
6
|
+
|
7
|
+
OUTPUT_TYPE_MAP = {
|
8
|
+
"Raven selection table": "table",
|
9
|
+
"Audacity": "audacity",
|
10
|
+
"CSV": "csv",
|
11
|
+
"Kaleidoscope": "kaleidoscope",
|
12
|
+
}
|
13
|
+
|
14
|
+
|
15
|
+
@gu.gui_runtime_error_handler
|
16
|
+
def run_batch_analysis(
|
17
|
+
output_path,
|
18
|
+
use_top_n,
|
19
|
+
top_n,
|
20
|
+
confidence,
|
21
|
+
sensitivity,
|
22
|
+
overlap,
|
23
|
+
merge_consecutive,
|
24
|
+
audio_speed,
|
25
|
+
fmin,
|
26
|
+
fmax,
|
27
|
+
species_list_choice,
|
28
|
+
species_list_file,
|
29
|
+
lat,
|
30
|
+
lon,
|
31
|
+
week,
|
32
|
+
use_yearlong,
|
33
|
+
sf_thresh,
|
34
|
+
custom_classifier_file,
|
35
|
+
output_type,
|
36
|
+
combine_tables,
|
37
|
+
locale,
|
38
|
+
batch_size,
|
39
|
+
threads,
|
40
|
+
input_dir,
|
41
|
+
skip_existing,
|
42
|
+
progress=gr.Progress(),
|
43
|
+
):
|
44
|
+
from birdnet_analyzer.gui.analysis import run_analysis
|
45
|
+
|
46
|
+
gu.validate(input_dir, loc.localize("validation-no-directory-selected"))
|
47
|
+
batch_size = int(batch_size)
|
48
|
+
threads = int(threads)
|
49
|
+
|
50
|
+
if species_list_choice == gu._CUSTOM_SPECIES:
|
51
|
+
gu.validate(species_list_file, loc.localize("validation-no-species-list-selected"))
|
52
|
+
|
53
|
+
if fmin is None or fmax is None or fmin < cfg.SIG_FMIN or fmax > cfg.SIG_FMAX or fmin > fmax:
|
54
|
+
raise gr.Error(f"{loc.localize('validation-no-valid-frequency')} [{cfg.SIG_FMIN}, {cfg.SIG_FMAX}]")
|
55
|
+
|
56
|
+
return run_analysis(
|
57
|
+
None,
|
58
|
+
output_path,
|
59
|
+
use_top_n,
|
60
|
+
top_n,
|
61
|
+
confidence,
|
62
|
+
sensitivity,
|
63
|
+
overlap,
|
64
|
+
merge_consecutive,
|
65
|
+
audio_speed,
|
66
|
+
fmin,
|
67
|
+
fmax,
|
68
|
+
species_list_choice,
|
69
|
+
species_list_file,
|
70
|
+
lat,
|
71
|
+
lon,
|
72
|
+
week,
|
73
|
+
use_yearlong,
|
74
|
+
sf_thresh,
|
75
|
+
custom_classifier_file,
|
76
|
+
output_type,
|
77
|
+
combine_tables,
|
78
|
+
"en" if not locale else locale,
|
79
|
+
batch_size if batch_size and batch_size > 0 else 1,
|
80
|
+
threads if threads and threads > 0 else 4,
|
81
|
+
input_dir,
|
82
|
+
skip_existing,
|
83
|
+
True,
|
84
|
+
progress,
|
85
|
+
)
|
86
|
+
|
87
|
+
|
88
|
+
def build_multi_analysis_tab():
|
89
|
+
with gr.Tab(loc.localize("multi-tab-title")):
|
90
|
+
input_directory_state = gr.State()
|
91
|
+
output_directory_predict_state = gr.State()
|
92
|
+
|
93
|
+
with gr.Row():
|
94
|
+
with gr.Column():
|
95
|
+
select_directory_btn = gr.Button(loc.localize("multi-tab-input-selection-button-label"))
|
96
|
+
directory_input = gr.Matrix(
|
97
|
+
interactive=False,
|
98
|
+
headers=[
|
99
|
+
loc.localize("multi-tab-samples-dataframe-column-subpath-header"),
|
100
|
+
loc.localize("multi-tab-samples-dataframe-column-duration-header"),
|
101
|
+
],
|
102
|
+
)
|
103
|
+
|
104
|
+
def select_directory_on_empty(): # Nishant - Function modified for For Folder selection
|
105
|
+
folder = gu.select_folder(state_key="batch-analysis-data-dir")
|
106
|
+
|
107
|
+
if folder:
|
108
|
+
files_and_durations = gu.get_audio_files_and_durations(folder)
|
109
|
+
if len(files_and_durations) > 100:
|
110
|
+
return [folder, files_and_durations[:100] + [["..."]]] # hopefully fixes issue#272
|
111
|
+
return [folder, files_and_durations]
|
112
|
+
|
113
|
+
return ["", [[loc.localize("multi-tab-samples-dataframe-no-files-found")]]]
|
114
|
+
|
115
|
+
select_directory_btn.click(
|
116
|
+
select_directory_on_empty, outputs=[input_directory_state, directory_input], show_progress=True
|
117
|
+
)
|
118
|
+
|
119
|
+
with gr.Column():
|
120
|
+
select_out_directory_btn = gr.Button(loc.localize("multi-tab-output-selection-button-label"))
|
121
|
+
selected_out_textbox = gr.Textbox(
|
122
|
+
label=loc.localize("multi-tab-output-textbox-label"),
|
123
|
+
interactive=False,
|
124
|
+
placeholder=loc.localize("multi-tab-output-textbox-placeholder"),
|
125
|
+
)
|
126
|
+
|
127
|
+
def select_directory_wrapper(): # Nishant - Function modified for For Folder selection
|
128
|
+
folder = gu.select_folder(state_key="batch-analysis-output-dir")
|
129
|
+
return (folder, folder) if folder else ("", "")
|
130
|
+
|
131
|
+
select_out_directory_btn.click(
|
132
|
+
select_directory_wrapper,
|
133
|
+
outputs=[output_directory_predict_state, selected_out_textbox],
|
134
|
+
show_progress=False,
|
135
|
+
)
|
136
|
+
|
137
|
+
(
|
138
|
+
use_top_n,
|
139
|
+
top_n_input,
|
140
|
+
confidence_slider,
|
141
|
+
sensitivity_slider,
|
142
|
+
overlap_slider,
|
143
|
+
merge_consecutive_slider,
|
144
|
+
audio_speed_slider,
|
145
|
+
fmin_number,
|
146
|
+
fmax_number,
|
147
|
+
) = gu.sample_sliders()
|
148
|
+
|
149
|
+
(
|
150
|
+
species_list_radio,
|
151
|
+
species_file_input,
|
152
|
+
lat_number,
|
153
|
+
lon_number,
|
154
|
+
week_number,
|
155
|
+
sf_thresh_number,
|
156
|
+
yearlong_checkbox,
|
157
|
+
selected_classifier_state,
|
158
|
+
map_plot,
|
159
|
+
) = gu.species_lists()
|
160
|
+
|
161
|
+
with gr.Accordion(loc.localize("multi-tab-output-accordion-label"), open=True):
|
162
|
+
with gr.Group():
|
163
|
+
output_type_radio = gr.CheckboxGroup(
|
164
|
+
list(OUTPUT_TYPE_MAP.items()),
|
165
|
+
value="table",
|
166
|
+
label=loc.localize("multi-tab-output-radio-label"),
|
167
|
+
info=loc.localize("multi-tab-output-radio-info"),
|
168
|
+
)
|
169
|
+
|
170
|
+
with gr.Row():
|
171
|
+
with gr.Column():
|
172
|
+
combine_tables_checkbox = gr.Checkbox(
|
173
|
+
False,
|
174
|
+
label=loc.localize("multi-tab-output-combine-tables-checkbox-label"),
|
175
|
+
info=loc.localize("multi-tab-output-combine-tables-checkbox-info"),
|
176
|
+
)
|
177
|
+
|
178
|
+
with gr.Row():
|
179
|
+
skip_existing_checkbox = gr.Checkbox(
|
180
|
+
False,
|
181
|
+
label=loc.localize("multi-tab-skip-existing-checkbox-label"),
|
182
|
+
info=loc.localize("multi-tab-skip-existing-checkbox-info"),
|
183
|
+
)
|
184
|
+
|
185
|
+
with gr.Row():
|
186
|
+
batch_size_number = gr.Number(
|
187
|
+
precision=1,
|
188
|
+
label=loc.localize("multi-tab-batchsize-number-label"),
|
189
|
+
value=1,
|
190
|
+
info=loc.localize("multi-tab-batchsize-number-info"),
|
191
|
+
minimum=1,
|
192
|
+
)
|
193
|
+
threads_number = gr.Number(
|
194
|
+
precision=1,
|
195
|
+
label=loc.localize("multi-tab-threads-number-label"),
|
196
|
+
value=4,
|
197
|
+
info=loc.localize("multi-tab-threads-number-info"),
|
198
|
+
minimum=1,
|
199
|
+
)
|
200
|
+
|
201
|
+
locale_radio = gu.locale()
|
202
|
+
|
203
|
+
start_batch_analysis_btn = gr.Button(loc.localize("analyze-start-button-label"), variant="huggingface")
|
204
|
+
|
205
|
+
result_grid = gr.Matrix(
|
206
|
+
headers=[
|
207
|
+
loc.localize("multi-tab-result-dataframe-column-file-header"),
|
208
|
+
loc.localize("multi-tab-result-dataframe-column-execution-header"),
|
209
|
+
],
|
210
|
+
)
|
211
|
+
|
212
|
+
inputs = [
|
213
|
+
output_directory_predict_state,
|
214
|
+
use_top_n,
|
215
|
+
top_n_input,
|
216
|
+
confidence_slider,
|
217
|
+
sensitivity_slider,
|
218
|
+
overlap_slider,
|
219
|
+
merge_consecutive_slider,
|
220
|
+
audio_speed_slider,
|
221
|
+
fmin_number,
|
222
|
+
fmax_number,
|
223
|
+
species_list_radio,
|
224
|
+
species_file_input,
|
225
|
+
lat_number,
|
226
|
+
lon_number,
|
227
|
+
week_number,
|
228
|
+
yearlong_checkbox,
|
229
|
+
sf_thresh_number,
|
230
|
+
selected_classifier_state,
|
231
|
+
output_type_radio,
|
232
|
+
combine_tables_checkbox,
|
233
|
+
locale_radio,
|
234
|
+
batch_size_number,
|
235
|
+
threads_number,
|
236
|
+
input_directory_state,
|
237
|
+
skip_existing_checkbox,
|
238
|
+
]
|
239
|
+
|
240
|
+
start_batch_analysis_btn.click(run_batch_analysis, inputs=inputs, outputs=result_grid)
|
241
|
+
|
242
|
+
return lat_number, lon_number, map_plot
|
243
|
+
|
244
|
+
|
245
|
+
if __name__ == "__main__":
|
246
|
+
gu.open_window(build_multi_analysis_tab)
|