Skip to content
Snippets Groups Projects
Commit 48ded44d authored by Loïc Lehnhoff's avatar Loïc Lehnhoff
Browse files

Improved user experience

+Added matplotlib.pyplot shortcuts
parent 89f35aab
No related branches found
No related tags found
No related merge requests found
...@@ -9,7 +9,7 @@ from args import fetch_inputs ...@@ -9,7 +9,7 @@ from args import fetch_inputs
##### MAIN ##### ##### MAIN #####
if __name__ == '__main__': if __name__ == '__main__':
# fetching inputs. # fetching inputs.
dir_explore, max_traj, new_sr, output, modify, initial_basename = fetch_inputs() dir_explore, max_traj, new_sr, output, modify, initial_basename, parameters = fetch_inputs()
if modify: if modify:
with open(os.path.join(output, modify), "r") as f: with open(os.path.join(output, modify), "r") as f:
...@@ -21,10 +21,11 @@ if __name__ == '__main__': ...@@ -21,10 +21,11 @@ if __name__ == '__main__':
new_sr, new_sr,
output, output,
os.path.join(dir_explore, initial_basename), os.path.join(dir_explore, initial_basename),
coords_to_change) coords_to_change,
parameters)
else: else:
# open explorer to select firt file # open explorer to select first file
groot = Tk() groot = Tk()
initial_file = FileExplorer(dir_explore).file initial_file = FileExplorer(dir_explore).file
groot.quit() groot.quit()
...@@ -37,4 +38,5 @@ if __name__ == '__main__': ...@@ -37,4 +38,5 @@ if __name__ == '__main__':
max_traj, max_traj,
new_sr, new_sr,
output, output,
initial_file) initial_file,
overwrite_parameters=parameters)
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
## Features ## Features
- [x] Same tools as matplotlib.pyplot plots.
- [x] Spectrogram contour annotations. - [x] Spectrogram contour annotations.
- [x] Spectrogram automatically computed from waveform. - [x] Spectrogram automatically computed from waveform.
- [x] Choose custom spectrogram resolutions (fft, hop length, clipping dB value and PCEN). - [x] Choose custom spectrogram resolutions (fft, hop length, clipping dB value and PCEN).
...@@ -37,13 +38,15 @@ Run `$python PyAVA.py --help` for details. ...@@ -37,13 +38,15 @@ Run `$python PyAVA.py --help` for details.
The annotations are saved in [JSON](http://www.json.org/) files. Each file contains a dictionnary with the categories annotated. For each category there is a list of points, each point is defined by a list of two elements : [time (in sec), frequency (in Hz)]. The annotations are saved in [JSON](http://www.json.org/) files. Each file contains a dictionnary with the categories annotated. For each category there is a list of points, each point is defined by a list of two elements : [time (in sec), frequency (in Hz)].
### User actions ### User actions
- Use the toolbar to interact with the plot (same as with matplotlib.pyplot). - Use the toolbar to interact with the plot (same as with matplotlib.pyplot)
- Shortcuts "p" and "w" to activate panning, "z" to activate zoom.
- Draw lines : - Draw lines :
- User must not have any toolbar item selected in order to annotate the spectrogram. - User must not have any toolbar item selected in order to annotate the spectrogram.
- Left-click on a name in the listbox to activate annotation with it. - Left-click on a name in the listbox to activate annotation with it.
- Left-click to place a point from the selected category. - Right-click on a name in the listbox to rename it.
- Right-click to remove the nearest point from the selected category. - Left-click on spectrogram to place a point from the selected category.
- Mouse wheel click on a point to move it around. - Right-click on spectrogram to remove the nearest point from the selected category.
- Mouse wheel click on a point on spectrogram to move it around.
- Click on `Open file explorer` Button to change Wavefile used as base (will end the annotation of the current file). - Click on `Open file explorer` Button to change Wavefile used as base (will end the annotation of the current file).
- Change resolution of the spectrogram with `FFT`, `Hop length` and `clipping fields`. - Change resolution of the spectrogram with `FFT`, `Hop length` and `clipping fields`.
- Click on `Update display` button to validate inputs. - Click on `Update display` button to validate inputs.
......
...@@ -56,13 +56,11 @@ def fetch_inputs(): ...@@ -56,13 +56,11 @@ def fetch_inputs():
parser.add_argument( parser.add_argument(
'-max', '--max_contours', '-max', '--max_contours',
type=int, type=int,
default=15, default=1,
nargs='?', nargs='?',
required=False, required=False,
help=("Number of contours that can be annotated at the same time." help=("Default number of contours available at launcg."
"\nDue to restrictions with the module used," "\nDue to restrictions with the module used, max number of contours is 99 per file.\n\n")
"\nonly a fixed number of contours can be annotated at once."
"\nValue cannot exceed 50. Default value is '15'.\n\n")
) )
parser.add_argument( parser.add_argument(
...@@ -92,11 +90,21 @@ def fetch_inputs(): ...@@ -92,11 +90,21 @@ def fetch_inputs():
type=str, type=str,
nargs=2, nargs=2,
required=False, required=False,
help=("Name of a file generated by a previous annitation," help=("Name of a file generated by a previous annotation,"
"\nand name of the associated wavefile." "\nand name of the associated wavefile."
"\nThis will open the interface with the contours from this file" "\nThis will open the interface with the contours from this file"
"\nand enable modification of these contours.")) "\nand enable modification of these contours."))
parser.add_argument(
'-p', '--parameters',
type=str,
nargs="?",
required=False,
default=None,
help=("Path to a file with spectrogram parameters."
"\nMust come from a previous usage of PyAVA."
"\nParameters loaded from this file will overwrite default parameters."))
# fetching arguments # fetching arguments
args = parser.parse_args() args = parser.parse_args()
outputs = args.output outputs = args.output
...@@ -113,6 +121,9 @@ def fetch_inputs(): ...@@ -113,6 +121,9 @@ def fetch_inputs():
try: try:
assert (os.path.exists(outputs)), ( assert (os.path.exists(outputs)), (
f"\nInputError: Could not find dir '{outputs}'.") f"\nInputError: Could not find dir '{outputs}'.")
if isinstance(args.parameters, str):
assert (os.path.exists(args.parameters)), (
f"\nInputError: Could not find dir '{args.parameters}'.")
assert (os.path.exists(explore)), ( assert (os.path.exists(explore)), (
f"\nInputError: Could not find dir '{explore}'.") f"\nInputError: Could not find dir '{explore}'.")
if modify_file: if modify_file:
...@@ -126,7 +137,7 @@ def fetch_inputs(): ...@@ -126,7 +137,7 @@ def fetch_inputs():
print(e) print(e)
sys.exit(1) sys.exit(1)
return (explore, contour, resampl, outputs, modify_file, from_wav) return (explore, contour, resampl, outputs, modify_file, from_wav, args.parameters)
# if running `$python ARGS.py -h` for help. # if running `$python ARGS.py -h` for help.
if __name__ == '__main__': if __name__ == '__main__':
......
##### IMPORTATIONS ##### ##### IMPORTATIONS #####
import os import os
import json
import numpy as np import numpy as np
from tkinter import * from tkinter import *
from tkinter import simpledialog as sd
from tkinter import filedialog as fd from tkinter import filedialog as fd
from tkinter import ttk from tkinter import ttk
from matplotlib.backends.backend_tkagg import (NavigationToolbar2Tk, from matplotlib.backends.backend_tkagg import (NavigationToolbar2Tk,
...@@ -153,6 +155,8 @@ class App(object): ...@@ -153,6 +155,8 @@ class App(object):
coords_to_modify : dict coords_to_modify : dict
Coordinates of points (from a previous annotation) that can be used Coordinates of points (from a previous annotation) that can be used
as input to add modifications. as input to add modifications.
overwrite_parameters : str
Path to a file containing parameters to overwrite before launch
Attributes Attributes
---------- ----------
...@@ -236,8 +240,10 @@ class App(object): ...@@ -236,8 +240,10 @@ class App(object):
Loads default variables to local variables. Loads default variables to local variables.
submit(): submit():
Loads user inputs to local variables. Loads user inputs to local variables.
switch(self) switch()
Updates spectrogram displayed to PCEN (and conversely). Updates spectrogram displayed to PCEN (and conversely).
_rename_label(event):
A function to manually rename an item in listbox
_frame_listbox_scroll(): _frame_listbox_scroll():
Just a callable part of layout() Just a callable part of layout()
_quit(): _quit():
...@@ -255,7 +261,8 @@ class App(object): ...@@ -255,7 +261,8 @@ class App(object):
NEW_SR, NEW_SR,
DIR_OUT, DIR_OUT,
WAVEFILE, WAVEFILE,
coords_to_modify={}): coords_to_modify={},
overwrite_parameters=None):
# init variables # init variables
self.DIR = DIR self.DIR = DIR
...@@ -265,12 +272,27 @@ class App(object): ...@@ -265,12 +272,27 @@ class App(object):
self.WAVEFILE = WAVEFILE self.WAVEFILE = WAVEFILE
self.NAME0 = 0 self.NAME0 = 0
self.NAME1 = MAX_C self.NAME1 = MAX_C
self.setup() self._default_pcen = False
# load audio data # check if parameters should be overwritten
self.load_audio() if isinstance(overwrite_parameters, str):
with open(os.path.join(self.DIR_OUT, "..","last-parameters-used.json"), "r") as f:
parameter_dict = json.load(f)
self._default_hop_length = parameter_dict["HOP_LENGTH"]
self._default_nfft = parameter_dict["NFFT"]
self._default_clipping = parameter_dict["CLIPPING"]
self.NEW_SR = parameter_dict["SR"]
self._default_pcen = parameter_dict["PCEN"]
if self._default_pcen:
self.initial_text_pcen = "Switch to PCEN"
else:
self.initial_text_pcen = "Switch to Spectrogram"
# init interface # init interface
self.setup()
self.load_audio()
self.root = Tk() self.root = Tk()
self.root.style = ttk.Style() self.root.style = ttk.Style()
self.root.style.theme_use('clam') self.root.style.theme_use('clam')
...@@ -288,8 +310,7 @@ class App(object): ...@@ -288,8 +310,7 @@ class App(object):
self.layout() self.layout()
self.axis.set_position(self._default_bounds) self.axis.set_position(self._default_bounds)
# To avoid probles, disconnect matplotlib keypress # To avoid problems, disconnect matplotlib keypress
# and replace it with tkinter keypress.
self.figure.canvas.mpl_disconnect(self.klicker.key_press) self.figure.canvas.mpl_disconnect(self.klicker.key_press)
self.root.bind('<Key>', self.get_key_pressed) self.root.bind('<Key>', self.get_key_pressed)
...@@ -390,15 +411,17 @@ class App(object): ...@@ -390,15 +411,17 @@ class App(object):
""" """
class EmptyObject(object): class EmptyObject(object):
""" """
Empty class that is just a hacky of creating an object that Empty class that is just a hacky way of creating an object
can be used in matplotlib. that can be used in matplotlib.
""" """
pass pass
# create key attribute and use it # create key attribute and use it
dummy_event = EmptyObject() dummy_event = EmptyObject()
dummy_event.key = event.char dummy_event.key = event.char
self.klicker.get_key_event(dummy_event, show=False)
if dummy_event.key=="A":
self.klicker.add_category(False)
# if a category is added. Update listbox and canvas. # if a category is added. Update listbox and canvas.
if len(self.klicker.legend_labels) > self.listbox.size(): if len(self.klicker.legend_labels) > self.listbox.size():
...@@ -423,6 +446,12 @@ class App(object): ...@@ -423,6 +446,12 @@ class App(object):
self.axis.set_position(self._default_bounds) self.axis.set_position(self._default_bounds)
self.figure.canvas.draw() self.figure.canvas.draw()
elif dummy_event.key=="p" or dummy_event.key=="w":
self.toolbar.pan()
elif dummy_event.key=="z":
self.toolbar.zoom()
def layout(self): def layout(self):
""" """
This *long* function lays the structure of the tkinter interface This *long* function lays the structure of the tkinter interface
...@@ -450,7 +479,7 @@ class App(object): ...@@ -450,7 +479,7 @@ class App(object):
self.list_label = Label( self.list_label = Label(
self.root, self.root,
width=self._default_left_panel_width, width=self._default_left_panel_width,
text='Pick a line to draw.\n(Shift+a adds a new line)', text='Pick a line to draw.\n(Shift+a adds a new line\nRight-click to rename item)',
font=('calibre',10,'bold')) font=('calibre',10,'bold'))
self.list_label.grid(row=2, column=0) self.list_label.grid(row=2, column=0)
...@@ -522,7 +551,7 @@ class App(object): ...@@ -522,7 +551,7 @@ class App(object):
self.switch_view_button = Button( self.switch_view_button = Button(
self.root, self.root,
text="Switch to PCEN", text=self.initial_text_pcen,
width=self._default_left_panel_width, width=self._default_left_panel_width,
command=self.switch) command=self.switch)
self.switch_view_button.grid(row=13, column=0) self.switch_view_button.grid(row=13, column=0)
...@@ -559,8 +588,6 @@ class App(object): ...@@ -559,8 +588,6 @@ class App(object):
Changes the focus to be on a new category, corresponding to Changes the focus to be on a new category, corresponding to
the selected item in listbox widget. the selected item in listbox widget.
...
Parameters Parameters
---------- ----------
event : tkinter object event : tkinter object
...@@ -720,6 +747,85 @@ class App(object): ...@@ -720,6 +747,85 @@ class App(object):
vmax=np.nanmax(self.spectrogram)) vmax=np.nanmax(self.spectrogram))
self.canvas.draw() self.canvas.draw()
def _rename_label(self, event):
"""
A function that allows the user to rename a category
Parameters
----------
event : tkinter object
event containing the item clicked in listbox widget.
Returns
-------
None : Shows a popup that ask for the name to give to the contour.
"""
self.listbox.selection_clear(0,END)
index_item = self.listbox.nearest(event.y)
save_config = self.listbox.itemconfig(index_item)
save_config = {
'bg':save_config['background'][-1],
'selectbackground':save_config['selectbackground'][-1],
'selectforeground':save_config['selectforeground'][-1],
}
# update selection
self.klicker.current_line = index_item
self.listbox.select_clear(0, END)
self.listbox.select_set(index_item)
self.listbox.see(index_item)
self.listbox.activate(index_item)
self.listbox.selection_anchor(index_item)
# get new name from user
new_name = sd.askstring(
"Rename window",
f"Insert new name for '{self.klicker.legend_labels[index_item]}':"
)
if isinstance(new_name, str):
if new_name in self.klicker.legend_labels:
count=0
for label in self.klicker.legend_labels:
if (label==new_name) or ("_".join(label.split("_")[:-1])==new_name):
count+=1
new_name = new_name + f"_{count}"
# replace spaces
new_name = new_name.replace(" ", "_")
# destroy item
self.listbox.delete(
index_item)
old_name = self.klicker.legend_labels.pop(index_item)
# handle klicker
self.klicker.legend_labels.insert(index_item, new_name)
self.klicker.set_legend()
self.klicker.current_line = index_item
if old_name in self.klicker.coords.keys():
self.klicker.coords[new_name] = self.klicker.coords.pop(old_name)
self.klicker.update_lines()
# insert item at the same index in listbox, with new name
self.listbox.insert(
index_item,
new_name)
self.listbox.itemconfig(
index_item,
save_config
)
# update selection
self.listbox.select_clear(0, END)
self.listbox.select_set(index_item)
self.listbox.see(index_item)
self.listbox.activate(index_item)
self.listbox.selection_anchor(index_item)
self.axis.set_position(self._default_bounds)
self.figure.canvas.draw()
def _frame_listbox_scroll(self): def _frame_listbox_scroll(self):
""" """
Just a callable part of "layout" Just a callable part of "layout"
...@@ -746,6 +852,7 @@ class App(object): ...@@ -746,6 +852,7 @@ class App(object):
'selectforeground': 'white'}) 'selectforeground': 'white'})
self.listbox.pack(side="left", fill="y") self.listbox.pack(side="left", fill="y")
self.listbox.bind("<<ListboxSelect>>", self.link_select) self.listbox.bind("<<ListboxSelect>>", self.link_select)
self.listbox.bind("<Button-3>", self._rename_label)
self.listbox.select_set(0) self.listbox.select_set(0)
self.scrollbar = Scrollbar(self.frame_list, orient="vertical") self.scrollbar = Scrollbar(self.frame_list, orient="vertical")
...@@ -756,6 +863,7 @@ class App(object): ...@@ -756,6 +863,7 @@ class App(object):
def _quit(self): def _quit(self):
""" """
A function that saves coordinates of lines before closing app. A function that saves coordinates of lines before closing app.
Also saves the last parameters in memory (for further use).
... ...
...@@ -778,8 +886,8 @@ class App(object): ...@@ -778,8 +886,8 @@ class App(object):
"HOP_LENGTH":self.HOP_LENGTH, "HOP_LENGTH":self.HOP_LENGTH,
"CLIPPING":self.CLIPPING "CLIPPING":self.CLIPPING
}, },
os.path.join(self.DIR_OUT, "parameters"), os.path.join(self.DIR_OUT, ".."),
os.path.basename(self.WAVEFILE)[:-4]+"-params.json" "last-parameters-used.json"
) )
# quit window # quit window
......
{
"PCEN": false,
"SR": 96000,
"NFFT": 2048,
"HOP_LENGTH": 512,
"CLIPPING": -80
}
\ No newline at end of file
No preview for this file type
{ {
"Line1": [ "invert_N": [
[ [
0.2556607438674337, 0.25875445892991433,
16569.1151082533 16543.49446379686
], ],
[ [
0.2804261968710533, 0.38842553301349875,
16278.071710573218 11307.172337705057
], ],
[ [
0.28339805123148765, 0.4532610700552909,
15210.912585746242 9280.8561126657
], ],
[ [
0.3081635042351073, 0.501630438959485,
14677.333023332758 9160.480891376234
], ],
[ [
0.34877884716104346, 0.5633785694754776,
12712.790088992195 9461.4189445999
], ],
[ [
0.39335666256755875, 0.6457094101634677,
11160.558634698416 11046.359358244545
], ],
[ [
0.43100015113306056, 0.6971661855934617,
9656.83441335132 12129.736349849745
], ],
[ [
0.4825122933805894, 0.7743513487384523,
9074.74761799115 12912.17528823128
], ],
[ [
0.5478930893101452, 0.8268372596770459,
9341.537399197896 13694.614226612812
], ],
[ [
0.6142645033598458, 0.9060806938392365,
10287.428441658165 13574.239005323345
], ],
[ [
0.682617153649836, 0.9863532635100267,
11936.674361845304 12771.737530060234
], ],
[ [
0.7252137328160617, 1.0645675621636173,
12373.239458365431 11868.923370389233
], ],
[ [
0.7846508200247487, 1.1777724681096038,
13003.833486672276 9361.106260192011
], ],
[ [
0.825266162950685, 1.2899482385469903,
13610.173898505785 8357.979416113123
], ],
[ [
0.856965942795318, 1.3342010654167848,
13610.173898505785 7936.66614159999
], ],
[ [
0.8995625219615438, 1.390803518389778,
13464.652199665743 5830.099769034323
],
[
0.926309211205453,
13294.876884352361
],
[
0.9570183729299413,
12931.072637252259
],
[
0.9649433178910996,
12882.565404305577
],
[
0.9926806252551535,
12688.536472518856
],
[
1.0115023695379044,
12470.253924258792
],
[
1.0303241138206554,
12276.22499247207
],
[
1.0521177124638406,
11960.927978318647
],
[
1.1541513788387534,
9923.624194558062
],
[
1.1729731231215044,
9632.580796877977
],
[
1.1794070626717919,
9479.66604006841
],
[
1.2234946472488883,
9001.986768571129
],
[
1.267081844535259,
8565.421672051005
],
[
1.3205752230230774,
8104.60295905754
],
[
1.3483125303871313,
7571.023396644054
],
[
1.3631718021893031,
6988.936601283886
],
[
1.3810029283519092,
6188.567257663657
],
[
1.3988340545145153,
5752.002161143532
] ]
], ],
"Line2": [ "invert_N_1": [
[
1.2314195922100466,
14095.246227972591
],
[
1.2413257734114946,
13173.608801985662
],
[
1.262128753934535,
11863.913512425286
],
[
1.2789692619769963,
10893.768853491674
],
[
1.3116596599417742,
10772.500771124971
],
[ [
1.336425112945394, 0.37263093871064235,
10772.500771124971 23846.21083835054
], ],
[ [
1.3483125303871313, 0.44654468833897776,
10311.682058131508 18624.0282993784
], ],
[ [
1.3601999478288687, 0.49556911411287374,
10287.428441658165 18211.20754530945
], ],
[ [
1.3740686015108956, 0.6366086159546975,
11160.558634698416 21493.13254015756
], ],
[ [
1.390909109553357, 0.6878957075335426,
12421.74669131211 23928.774989164325
], ],
[ [
1.4027965269950944, 0.7271152481526594,
13513.159432612425 24795.69857270911
], ],
[ [
1.4166651806771213, 0.8138507706757061,
14192.260693865952 26797.879229943486
], ],
[ [
1.432515070599438, 0.8425112042050606,
15162.405352799564 27375.82828564001
], ],
[ [
1.4413724760470132, 0.8689089719294661,
16287.542250441644 27293.26413482622
], ],
[ [
1.4490057835548567, 0.9375431680129205,
19078.485781877196 26446.981588984883
], ],
[ [
1.4515679818356721, 1.0008978105514938,
19196.707818930037 25208.519326778056
], ],
[ [
1.4733184911158894, 1.0914044427494556,
18661.618655692724 22463.261312219576
], ],
[ [
1.4937878542675378, 1.154759085288029,
17396.273242381794 19924.41367469557
], ],
[ [
1.507527807781656, 1.1856821846223324,
16956.60405592277 18665.31037478529
], ],
[ [
1.5294099559708072, 1.2324439445912794,
16899.255901167242 17715.82264042672
] ]
], ],
"Line3": [ "invert_N_2": [
[ [
0.37038441199132144, 0.5011509232640762,
23845.111348935927 27344.786753383632
], ],
[ [
0.4050533169552495, 0.5487797158111636,
21890.595023197493 27832.33775911113
], ],
[ [
0.4152003135300576, 0.6271367616144365,
20611.713970553825 31523.795373905064
], ],
[ [
0.43211197448807126, 0.6755337604929286,
19139.794268454512 34901.827342159886
], ],
[ [
0.4811557912663108, 0.6916660934524259,
18174.60102117627 36120.70485647864
], ],
[ [
0.5589494316731736, 0.7139440770631604,
18681.327475997346 36886.85643690757
], ],
[ [
0.5961550857808036, 0.8138109001457632,
19694.780385639497 40230.06333332471
], ],
[ [
0.6316695737926322, 0.8460755660647579,
21287.34924364859 41031.03998559132
], ],
[ [
0.6680296448523616, 0.8960089776060592,
23072.956751113335 40439.013764350784
], ],
[ [
0.6891692210498787, 0.9735978170779275,
23965.760504845708 38384.33452592775
], ],
[ [
0.7111543802952963, 1.0373589425845124,
24496.61679084874 36643.08093404381
], ],
[ [
0.7365218717323168, 1.0872923541258137,
24930.953752123947 34205.32590540632
], ],
[ [
0.7593526140256353, 1.12647087702745,
25510.06970049089 31523.795373905064
], ],
[ [
0.8320727561450939, 1.2117417798133647,
27295.677207955632 27101.01125051988
],
[
0.8811165729233335,
27102.638558499988
],
[
0.8980282338813471,
26885.47007786238
],
[
0.9267780575099703,
26692.431428406733
],
[
0.9614469624738983,
25847.88733703827
],
[
1.0054172809647337,
25075.73273921568
],
[
1.0510787655513707,
23869.241180117882
],
[
1.1035049145212128,
22011.24417910727
],
[
1.1339459042456375,
20828.882451191428
],
[
1.1474752330120483,
19936.07869745906
],
[
1.2108939616045995,
18053.951865266492
],
[
1.2464084496164283,
17450.70608571759
] ]
], ],
"Line4": [ "n": [
[
1.220195375131507,
26813.08058431651
],
[
1.1821441379759765,
27898.92298750453
],
[
1.177916222736473,
28550.42842941734
],
[
1.079828589179994,
34462.23706899656
],
[
1.024020108018549,
37044.129005465846
],
[
0.9606013794259978,
38853.866344112546
],
[
0.9242413083662684,
40036.22807202839
],
[
0.9115575626477581,
40374.04570857577
],
[
0.8946459016897446,
40277.52638384795
],
[
0.8608225797737172,
40904.9019945788
],
[
0.8160066782349811,
40398.17553975773
],
[ [
0.7771098580315496, 0.8091567176081755,
38853.866344112546 46866.257456874
], ],
[ [
0.7500512004987279, 0.8199952219812153,
37840.41343447039 47257.77728018231
], ],
[ [
0.720455793822204, 0.8430558695834277,
37019.99917428389 47845.05701514477
], ],
[ [
0.6917059701935808, 0.8624268135692862,
35861.76727755 47859.03986597721
], ],
[ [
0.6739487261876664, 0.8822589705071888,
34703.535380816116 47481.50289350134
],
[
0.6638017296128582,
33714.212302355925
],
[
0.6426621534153412,
32242.29260025661
],
[
0.6265960755052282,
31325.359015342277
],
[
0.5995374179724065,
29829.30948206101
],
[
0.5682508452000812,
28453.90910468952
],
[
0.5361186893798553,
27585.235182139102
],
[
0.49553070308062247,
27199.157883227806
],
[
0.45325155068558837,
27826.53349395866
],
[
0.41520031353005765,
30722.113235793382
] ]
], ],
"Line5": [ "n_1": [
[
1.4205985574839692,
28502.16876705343
],
[
1.4036868965259557,
27609.36501332106
],
[ [
1.3960766490948493, 0.7981661995571241,
26716.56125958869 33032.82951685946
], ],
[ [
1.3952310660469487, 0.8237910808460172,
25775.497843492405 33858.07615751977
], ],
[ [
1.386775235567942, 0.8464874042733224,
24906.82392094199 34184.90651025652
], ],
[ [
1.3800105711847364, 0.8750408434238032,
23603.813037116368 34029.66209270656
], ],
[ [
1.3757826559452329, 0.8874872143355512,
22590.360127474218 33866.24691633818
],
[
1.3707091576578287,
21359.73873719446
],
[
1.3664812424183255,
20828.882451191428
],
[
1.348723998412411,
20273.89633400644
],
[
1.3444960831729078,
20949.53160710121
],
[
1.3343490865980996,
21190.82991892077
],
[
1.3089815951610793,
21407.99839955837
],
[
1.2785406054366546,
21673.426542559886
],
[
1.2658568597181443,
22807.528608111817
],
[
1.256555446191237,
24737.9151026683
],
[
1.24809961571223,
26089.185648857834
] ]
], ],
"Line6": [ "n_2": [
[
2.0661243541857277,
13285.951796092879
],
[
2.039050804089352,
13986.16628625902
],
[
2.028385466172598,
14382.954497353168
],
[
1.9766995978067898,
14756.402225441776
],
[
1.960291385627168,
15153.190436535922
],
[
1.8150787078375163,
15573.319130635608
]
],
"Line7": [
[
2.234323175389529,
7952.965023630615
],
[
2.2500756801682016,
8003.241178682962
],
[
2.2694633783573366,
8832.797737046665
],
[
2.2912745388201143,
9913.735070672095
],
[
2.3385320531561318,
11824.228962661231
],
[
2.3979068788603586,
13759.860932176538
],
[
2.426988426144062,
14212.346327647649
],
[
2.480304596164184,
13910.689397333574
],
[
2.517868261405634,
13332.513614231599
],
[
2.544526346415695,
12628.647443498761
],
[
2.5869369362044288,
12301.852435658513
],
[
2.6257123325826996,
11723.676652556538
],
[
2.6669111912346124,
10994.672404297527
],
[
2.7262860169388397,
10215.39200098617
],
[
2.7844491115062455,
9762.90660551506
],
[
2.8280714324318,
9536.663907779503
],
[
2.9383389658825076,
9184.730822413085
],
[
3.1188869052688313,
8606.55503931111
],
[
3.2024963537094777,
8254.62195394469
],
[
3.2255192453090755,
7927.826946104442
],
[
3.3127638871601848,
7450.20347310716
],
[
3.3345750476229625,
6846.889612479012
],
[
3.370926981727591,
6092.747286693827
],
[
3.398796797874473,
5841.366511432098
],
[
3.403643722421757,
6168.161519272346
],
[
3.41939622720043,
6243.5757518508635
],
[
3.421819689474072,
5841.366511432098
],
[
3.4618068169891636,
6092.747286693827
],
[
3.5042174067778973,
6520.094604638764
],
[
3.5236051049670323,
7450.20347310716
],
[
3.5587453079348403,
7776.998480947406
],
[
3.602367628860395,
8053.517333735306
],
[
3.627813982733635,
8204.345798892344
],
[
3.639931294101845,
8355.174264049381
],
[
3.6738597659328316,
8405.450419101726
],
[
3.7077882377638183,
8480.864651680246
],
[
3.7368697850475217,
8455.726574154072
],
[
3.752622289826194,
9410.97352014864
],
[
3.7635278700575827,
8480.864651680246
]
],
"Line8": [
[
2.236746637663171,
15745.76905674419
],
[
2.257346066989127,
16072.564064584436
],
[
2.2743103029046208,
17932.781801521225
],
[
2.294909732230577,
19843.27569351036
],
[
2.3191443549669963,
21904.598050656532
],
[
2.3458024399770574,
24368.129648221468
],
[
2.385789567492149,
27208.732408678996
],
[
2.4112359213653893,
28214.25550972591
],
[
2.460916897975049,
28214.25550972591
],
[
2.4996922943533195,
27284.146641257514
],
[
2.5360442284579485,
25675.309679582453
],
[
2.6257123325826996,
23387.74462470073
],
[
2.686298889423748,
21552.66496529011
],
[
2.742038521717512,
20119.79454629826
],
[
2.8208010456108745,
19038.857212672832
],
[
2.892293182683311,
18536.095662149375
],
[
2.979537824534421,
17983.05795657357
],
[
3.065570735248709,
17480.296406050114
],
[
3.162509226194386,
16826.70639036962
],
[
3.2109784716672243,
16248.530607267647
],
[
3.2303661698563597,
15796.045211796536
],
[
3.3127638871601848,
14840.798265801968
],
[
3.3491158212648138,
13106.270916496043
],
[
3.3927381421903684,
11849.367040187402
],
[
3.404855453558578,
12301.852435658513
],
[
3.41939622720043,
12301.852435658513
],
[
3.4230314206108927,
11572.8481873995
],
[
3.458171623578701,
11899.643195239749
],
[
3.498158751093792,
12804.61398618197
],
[
3.5163347181461067,
13910.689397333574
],
[
3.5332989540616,
15142.455196116043
],
[
3.5732860815766916,
15745.76905674419
],
[
3.625390520459993,
16173.116374689129
],
[
3.6241787893231723,
16525.049460055547
],
[
3.6993061198060717,
17002.672933052832
],
[
3.7368697850475217,
16851.844467895797
]
],
"Line9": [
[
2.3116012235318193,
31764.84090906388
],
[
2.3559597629309463,
37557.48611007064
],
[
2.3959906399496704,
41342.01430806173
],
[
2.4154651206614823,
42346.07280956957
],
[
2.4630694068459116,
42075.74936685592
],
[
2.5031002838646357,
40762.74978796105
],
[
2.5160832710058436,
39449.75020906619
],
[
2.5864077846873865,
36823.75105127645
],
[
2.5928992782579905,
36051.39835780888
],
[
2.6123737589698024,
35549.36910705496
],
[
2.651322720393426,
33541.25210403929
],
[
2.6913535974121503,
31842.076178410636
],
[
2.774661098234901,
29370.547559314415
],
[
2.897999476076376,
27632.753999012384
],
[
3.087334705218991,
26010.813342730493
],
[
3.180379446397648,
24929.5195718759
],
[
3.2258199013918754,
23848.2258010213
],
[
3.316700811380331,
21994.579336699135
],
[
3.3556497728039547,
19291.34490956265
],
[
3.395680649822679,
17630.786618607373
],
[
3.401090227798182,
18248.66877338143
],
[
3.417318961724692,
18325.904042728187
],
[
3.423810455295296,
17514.93371458724
],
[
3.4692509102895235,
17978.34533066778
],
[
3.503872209332745,
19716.13889096981
],
[
3.535247761590664,
22728.314395493326
],
[
3.585015878965294,
23693.755262327788
],
[ [
3.6218010091987165, 0.8072955488925098,
24118.549243734953 20071.56535619266
], ],
[ [
3.6250467559840187, 0.8279188810699657,
24659.19612916225 20403.612203459543
], ],
[ [
3.6845521137145547, 0.849016312837708,
25470.166457303196 20551.188580022605
], ],
[ [
3.739729809064688, 0.876751138869459,
25199.843014589547 20403.612203459543
] ]
] ]
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment