Ejemplo n.º 1
0
    def test_get_image_feature_by_key(self):
        map = Mapillary(API_KEY)

        key = "LwrHXqFRN_pszCopTKHF_Q"

        raw_json = map.get_image_feature_by_key(key=key)

        properties_ca_angle = raw_json['properties']['ca']

        self.assertEqual(323.0319999999999, properties_ca_angle)
Ejemplo n.º 2
0
    def test_search_sequences(self):
        map = Mapillary(API_KEY)

        userkeys = "AGfe-07BEJX0-kxpu9J3rA"
        per_page = 1

        raw_json = map.search_sequences(userkeys=userkeys, per_page=per_page)
        type_json = raw_json['type']

        self.assertEqual("FeatureCollection", type_json)
Ejemplo n.º 3
0
    def test_get_changeset_by_key(self):
        map = Mapillary(API_KEY)

        key = "obWjkY7TGbstLRNy1qYRD7"

        raw_json = map.get_changeset_by_key(key=key)

        type_json = raw_json['type']

        self.assertEqual("location", type_json)
Ejemplo n.º 4
0
    def test_get_sequence_by_key(self):
        map = Mapillary(API_KEY)

        key = "cHBf9e8n0pG8O0ZVQHGFBQ"

        raw_json = map.get_sequence_by_key(key=key)

        properties_captured_at_json = raw_json['properties']['captured_at']

        self.assertEqual("2016-03-14T13:44:37.206Z",
                         properties_captured_at_json)
Ejemplo n.º 5
0
    def test_get_user_by_key(self):

        map = Mapillary(API_KEY)

        key = "2BJl04nvnfW1y2GNaj7x5w"

        raw_json = map.get_user_by_key(key=key)

        username_json = raw_json['username']

        self.assertEqual("gyllen", username_json)
Ejemplo n.º 6
0
    def test_get_user_stats_by_key(self):

        map = Mapillary(API_KEY)

        key = "2BJl04nvnfW1y2GNaj7x5w"

        raw_json = map.get_user_stats_by_key(key=key)

        user_key_json = raw_json['user_key']

        self.assertEqual("2BJl04nvnfW1y2GNaj7x5w", user_key_json)
Ejemplo n.º 7
0
    def test_search_changesets(self):
        map = Mapillary(API_KEY)

        types = "location"
        per_page = 1  # default is 200

        raw_json = map.search_changesets(types=types, per_page=per_page)

        for i in raw_json:
            type_json = i['type']

        self.assertEqual("location", type_json)
Ejemplo n.º 8
0
    def test_get_pagnation_resources(self):
        map = Mapillary(API_KEY)

        page_num = 1
        per_page = 1

        raw_json = map.get_pagnation_resources(page_num=page_num,
                                               per_page=per_page)

        # Since the page can change, I just check if a request just went through
        features_json = raw_json['features']
        self.assertEqual(type([]), type(features_json))
Ejemplo n.º 9
0
    def test_search_users(self):
        map = Mapillary(API_KEY)

        userkeys = "HvOINSQU9fhnCQTpm0nN7Q"
        per_page = 1  # default is 200

        raw_json = map.search_users(userkeys=userkeys, per_page=per_page)

        for i in raw_json:
            username_json = i['username']

        self.assertEqual("maning", username_json)
Ejemplo n.º 10
0
    def test_filter_image_upload_lboards(self):

        map = Mapillary(API_KEY)

        iso_countries = "SE"  # given as ISO 3166 country codes.
        per_page = 1

        raw_json = map.filter_image_upload_lboards(iso_countries=iso_countries,
                                                   per_page=per_page)

        for i in raw_json:
            username_json = i['username']

        self.assertEqual("roadroid", username_json)
Ejemplo n.º 11
0
    def test_search_images(self):
        map = Mapillary(API_KEY)

        bbox = "16.430300,7.241686,16.438757,7.253186"
        per_page = 1

        raw_json = map.search_images(bbox=bbox, per_page=per_page)
        features_json = raw_json['features']

        # The json's is in a list
        for features in features_json:
            coordinate = features['geometry']['coordinates']

        self.assertEqual([16.432976, 7.249027], coordinate)
Ejemplo n.º 12
0
class MapillaryLocationDownloader:
    def __init__(self):
        self.location_saver = LocationSaver(SAVE_PATH)
        self.map_api = Mapillary(
            "dThHWFVHb0dNdnIyb0xDbm11NHVadzo1MjgxMWMyZDNjOTM0YjAy")

    def download_location(self, location_data):
        image_key = location_data["properties"]["key"]
        lon, lat = location_data["geometry"]["coordinates"]
        direction = location_data["properties"]["ca"]

        image_file_path = self.location_saver.save_new_location(
            lat, lon, direction)
        if os.path.exists(image_file_path):
            os.remove(image_file_path)
        download_image_by_key(image_key, IMAGE_WIDTH, image_file_path)
        format_image(image_file_path)

    def download_randomly_in_bounding_box(self, boundingbox, num):
        if num == 0:
            return 0

        lat1, lon1, lat2, lon2 = boundingbox

        bbox = ",".join(map(lambda x: "%.6f" % x, [lon1, lat1, lon2, lat2]))

        try:
            res = self.map_api.search_images(
                bbox=bbox, per_page=MAX_PER_REQUEST)
        except:
            print(bbox)
            raise "Error while searching images in Mapillary"
        if "features" not in res:
            print(res)
        res_locations = res["features"]

        if len(res_locations) == MAX_PER_REQUEST and num > 1:
            # Too many locations, splitting up query to spread out images
            mid_lat = (lat1+lat2)/2
            mid_lon = (lon1+lon2)/2

            new_bounding_boxes = []
            new_bounding_boxes.append([lat1, lon1, mid_lat, mid_lon])
            new_bounding_boxes.append([mid_lat, lon1, lat2, mid_lon])
            new_bounding_boxes.append([lat1, mid_lon, mid_lat, lon2])
            new_bounding_boxes.append([mid_lat, mid_lon, lat2, lon2])
            random.shuffle(new_bounding_boxes)

            has_downloaded = 0
            for i in range(4):
                has_downloaded += self.download_randomly_in_bounding_box(
                    new_bounding_boxes[i], (num-has_downloaded)//(4-i))
            return has_downloaded

        num = min(len(res_locations), num)

        for location_data in random.choices(res_locations, k=num):
            self.download_location(location_data)

        return num
Ejemplo n.º 13
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code

from pymapillary import Mapillary
from pymapillary.utils import *

# Every parameter example that can be passed in to this search function
# Plug and play as you please
bbox = "16.430300,7.241686,16.438757,7.253186"  # minx,miny,maxx,maxy
per_page = 1  # default is 200
states = "pending, approved"
types = "location"
userkeys = "HvOINSQU9fhnCQTpm0nN7Q"

map = Mapillary("insert client id here")
raw_json = map.search_changesets(types=types, per_page=per_page)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json,
                 "../sample_json_output/search_changesets_example.json")
Ejemplo n.º 14
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code get map features detections. I can't really test it because
# I don't have access to it.

from pymapillary import Mapillary
from pymapillary.utils import *

layers = "trafficsigns"

map = Mapillary("insert client id here")
raw_json = map.search_map_features(layers=layers)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json, "../sample_json_output/search_map_features_example.json")
Ejemplo n.º 15
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code

from pymapillary import Mapillary
from pymapillary.utils import *

key = "cHBf9e8n0pG8O0ZVQHGFBQ"

map = Mapillary("insert client id here")
raw_json = map.get_sequence_by_key(key=key)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json,
                 "../sample_json_output/get_sequence_by_key_example.json")
Ejemplo n.º 16
0
 def __init__(self):
     self.location_saver = LocationSaver(SAVE_PATH)
     self.map_api = Mapillary(
         "dThHWFVHb0dNdnIyb0xDbm11NHVadzo1MjgxMWMyZDNjOTM0YjAy")
Ejemplo n.º 17
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code

from pymapillary import Mapillary
from pymapillary.utils import *

key = "2BJl04nvnfW1y2GNaj7x5w"

map = Mapillary("insert client id here")
raw_json = map.get_user_stats_by_key(key=key)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json,
                 "../sample_json_output/get_user_stats_by_key_example.json")
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code

from pymapillary import Mapillary
from pymapillary.utils import *

# Every parameter that can be passed in to this search function
# Plug and play as you please
bbox = "16.430300,7.241686,16.438757,7.253186"  # minx,miny,maxx,maxy
end_time = "2016-03-14T13:44:37.206Z"  #must be a valid ISO 8601 date
iso_countries = "SE"  # given as ISO 3166 country codes.
per_page = 1  # default is 200
start_time = "2016-03-14T13:44:37.206Z"  #start_time" must be a valid ISO 8601 date
userkeys = "AGfe-07BEJX0-kxpu9J3rA"
usernames = "maning"  #example user name

map = Mapillary("insert client id here")
raw_json = map.filter_image_upload_lboards(iso_countries=iso_countries,
                                           per_page=per_page)
print(raw_json)

# Download the beautified json for debugging
return_json_file(
    raw_json, "../sample_json_output/filter_image_upload_lboards_example.json")
Ejemplo n.º 19
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code gets a number of resources requested.

from pymapillary import Mapillary
from pymapillary.utils import *

page_num = 1  # What page you want
per_page = 1  # Results per page

map = Mapillary("insert client id here")
raw_json = map.get_pagnation_resources(1, 1)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json,
                 "../sample_json_output/get_pagnation_resources_example.json")
    #"SG":{"area_gh":"u0qt","suffix":["v3","v7","tx","ub","vu","su"]},
    #"SZ":{"area_gh":"u0q5", "suffix":["kz", "s3", "mn","7g","ds"]},

    #"TG":{"area_gh":"u0qq", "suffix":["d3", "df", "9f","em","3v"]},
    #"AG":{"area_gh":"u0m" ,"suffix":["tx5","tx1","txf","vd4", "vdj","v9e"]},
    #"RU":{"area_gh":"", "suffix":["u0mufst", "u0mu27","u0qw9m","u0qn66","u0qhnr","u0myj4","u0qkfy","u0qssc","u0qwt7", "u0qwq9","u0qv90","u0qjq7"]}
}

#We get images from 2015 onwards
start_date = datetime.datetime(2015, 1, 1)

# Create a Mapillary Object
load_dotenv()
key = os.getenv("MAPILLARY_KEY")

map = Mapillary(key)

#Used to name images
i = 3261
image_resolution = 1024

for key_canton in gh_cantons.keys():
    area_canton = 0
    while area_canton < len(gh_cantons[key_canton]["suffix"]):
        gh_urban = gh_cantons[key_canton]["area_gh"] + gh_cantons[key_canton][
            "suffix"][area_canton]
        #gh_urban = geohash_compl[area_canton]
        print(gh_urban)
        gh_box_map = convetBBoxtoMapillary(gh_urban)
        #we query sequences because we don't want many similar images in one area
        raw_json = map.search_sequences(bbox=gh_box_map, start_time=start_date)
Ejemplo n.º 21
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code searchs for sequences by the specified variables below.

from pymapillary import Mapillary
from pymapillary.utils import *

# Every parameter that can be passed in to this search function
# Plug and play as you please
bbox = "16.430300,7.241686,16.438757,7.253186"  # minx,miny,maxx,maxy
end_time = "2016-03-14T13:44:37.206Z"  #must be a valid ISO 8601 date
per_page = 1  # default is 200
starred = "true"  # or "false" it has to be lower cased
start_time = "2016-03-14T13:44:37.206Z"  #start_time" must be a valid ISO 8601 date
userkeys = "AGfe-07BEJX0-kxpu9J3rA"
usernames = "maning"  #example user name

map = Mapillary("insert client id here")
raw_json = map.search_sequences(userkeys=userkeys, per_page=per_page)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json,
                 "../sample_json_output/search_sequences_example.json")
Ejemplo n.º 22
0
# This example uses the function search_images to do a query based
# on the variables that are declared below.

from pymapillary import Mapillary
from pymapillary.utils import *

# Every parameter that can be passed in to this search function
# Plug and play as you please
bbox = "16.430300,7.241686,16.438757,7.253186"  # minx,miny,maxx,maxy
closeto = "13.0006076843,55.6089295863"  #longitude, latitude
end_time = "2016-03-14T13:44:37.206Z"  #must be a valid ISO 8601 date
image_keys = "LwrHXqFRN_pszCopTKHF_Q, Aufjv2hdCKwg9LySWWVSwg"
lookat = "12.9981086701,55.6075236275"  #longitude, latitude
pano = "true"  # or "false" it has to be lower cased
per_page = 1  # default is 200
project_keys = "HvOINSQU9fhnCQTpm0nN7Q"  #json is userkey this worked too? PSaXX2JB7snjFyHJF-Rb1A for sequence key? JnLaPNIam8LFNZL1Zh9bPQ all keys work?
radius = 100  # In meters
sequence_keys = "PSaXX2JB7snjFyHJF-Rb1A, LMlIPUNhaj24h_q9v4ArNw"
start_time = "2016-03-14T13:44:37.206Z"  #start_time" must be a valid ISO 8601 date
userkeys = "HvOINSQU9fhnCQTpm0nN7Q"
usernames = "maning"  #example user name

# Create a Mapillary Object
map = Mapillary("insert client id here")
raw_json = map.search_images(bbox=bbox, per_page=per_page)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json, "../sample_json_output/search_images_example.json")
Ejemplo n.º 23
0
    def download_mapillary(self, mapillary_key, start=0, end=-1):
        """
        Downloads Mapillary images of points from a ArcGis layer

        :param mapillary_key: Mapillary API key
        :type mapillary_key: str
        :param start: index of the feature of the layer from where download starts
        :type start: int
        :param end: index of the feature of the layer where download ends
        :type end: int
        """
        # Initialization of variables
        self.nb_mapillary_jpg = 0
        self.nb_mapillary_panos = 0
        cmp_err = 0
        err_list = []

        # Creation of directory
        self.mapillary_dir = safe_folder_creation(self.mapillary_dir)
        self.mapillary_dir_pano = safe_folder_creation(self.mapillary_dir_pano)

        # Convert layer file
        ds = ogr.Open(self.layer_path)
        layer = ds.GetLayer()

        # Determine the number of locations to download
        loc_max = len(layer)
        if start < end < len(layer):
            stop = end
        else:
            stop = loc_max
        n_loc = stop - start

        # Create a Mapillary Object
        mapillary = Mapillary(mapillary_key)

        # Display advancement of downloading
        pbar = progressbar.ProgressBar()
        for i in pbar(range(start, stop)):
            # Get location
            feature = layer[i]
            lon = feature.GetGeometryRef().GetX()
            lat = feature.GetGeometryRef().GetY()
            close_to = "{},{}".format(lon, lat)

            # Catch metadata search errors
            try:
                raw_json = mapillary.search_images(closeto=close_to,
                                                   per_page=1,
                                                   radius=10)
                raw_json_pano = mapillary.search_images(closeto=close_to,
                                                        per_page=1,
                                                        radius=10,
                                                        pano="true")
            except Exception as err:
                print(err)
                print("Error during metadata search on feature {}, lat = {}, lon = {} ".format(i, lat, lon))
                cmp_err += 1
                err_list.append(i)
                continue

            # Check if there is a image at this location and download it
            try:
                if len(raw_json['features']):
                    image_key = raw_json['features'][0]['properties']['key']
                    image_date = raw_json['features'][0]['properties']['captured_at'][:-5]
                    image_date = image_date.replace(":", "-")
                    image_lon = raw_json['features'][0]['geometry']['coordinates'][0]
                    image_lat = raw_json['features'][0]['geometry']['coordinates'][1]
                    image_lon = "{0:.6f}".format(image_lon)
                    image_lat = "{0:.6f}".format(image_lat)

                    image_filename = '{}_{}_{}_000_{}.jpg'.format(image_lon, image_lat, image_key, image_date)
                    image_path = os.path.join(self.mapillary_dir, image_filename)
                    download_image_by_key(image_key, 640, image_path)
                    self.nb_mapillary_jpg += 1
            except Exception as err:
                print(err)
                print("Error when downloading image on feature {}, lat = {}, lon = {} ".format(i, lat, lon))
                cmp_err += 1
                err_list.append(i)
                continue

            # Check if there is a pano at this location and download it
            try:
                if len(raw_json_pano['features']):
                    pano_key = raw_json_pano['features'][0]['properties']['key']
                    pano_date = raw_json_pano['features'][0]['properties']['captured_at'][:-5]
                    pano_date = pano_date.replace(":", "-")
                    pano_lon = raw_json_pano['features'][0]['geometry']['coordinates'][0]
                    pano_lat = raw_json_pano['features'][0]['geometry']['coordinates'][1]
                    pano_lon = "{0:.6f}".format(pano_lon)
                    pano_lat = "{0:.6f}".format(pano_lat)

                    pano_filename = '{}_{}_{}_999_{}.jpg'.format(pano_lon, pano_lat, pano_key, pano_date)
                    pano_path = os.path.join(self.mapillary_dir_pano, pano_filename)
                    download_image_by_key(pano_key, 2048, pano_path)
                    self.nb_mapillary_panos += 1
            except Exception as err:
                print(err)
                print("Error when downloading panorama on feature {}, lat = {}, lon = {} ".format(i, lat, lon))
                cmp_err += 1
                err_list.append(i)
                continue

        # Display information
        print("Number of locations            : {}".format(n_loc))
        print("Number of images downloaded    : {}".format(self.nb_mapillary_jpg))
        print("Number of panoramas downloaded : {}".format(self.nb_mapillary_panos))
        print("Number of errors caught : {}".format(cmp_err))
        print("List of features index with errors : {}".format(err_list))
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from pymapillary import Mapillary
from pymapillary.utils import *
#import cv2
import os
import cv2
import glob

# Create a mappilary object
map = Mapillary("insert client id here")

# Get a sequence. This key was found by going to the site and getting a random
# sequence that seemed short. This sequence has 293 frames
raw_json = map.get_sequence_by_key("nntwXcD2QLuJ_w3dTcXi0Q")

# Download the beautified json for debugging
#return_json_file(raw_json, "result.json")

# Get the image keys value which is a list type
image_keys_json = raw_json['properties']['coordinateProperties']['image_keys']

# Create a images directory
directory = "images"
if not os.path.exists(directory):
    os.makedirs(directory)

# Make shift downloader
count = 0
for image_key in image_keys_json:
Ejemplo n.º 25
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code uses a changeset key to get a changeset

from pymapillary import Mapillary
from pymapillary.utils import *

key = "obWjkY7TGbstLRNy1qYRD7"

map = Mapillary("insert client id here")
raw_json = map.get_changeset_by_key(key=key)
print(raw_json)

# Download the beautified json for debugging
return_json_file(raw_json,
                 "../sample_json_output/get_changeset_by_key_example.json")
Ejemplo n.º 26
0
#!/usr/bin/env python
# -*- coding: utf-8 -*-

# This sample code uses a image key to get the image feature.

from pymapillary import Mapillary
from pymapillary.utils import *

key = "LwrHXqFRN_pszCopTKHF_Q"

map = Mapillary("insert client id here")
raw_json = map.get_image_feature_by_key(key=key)
print(raw_json)

# Download the beautified json for debugging
return_json_file(
    raw_json, "../sample_json_output/get_image_feature_by_key_example.json")
def query_only_id_bboxes(city, enlarge=True):

    # get coordinates of city, request ot open-street-map
    if enlarge:
        top, right, bot, left = getCityLimitsBoundingBox(city, 0.3)
    else:
        top, right, bot, left = getCityLimitsBoundingBox(city)

    left_most = float(left[0])
    right_most = float(right[0])
    top_most = float(top[1])
    bot_most = float(bot[1])

    # Get the maximum direction and center
    center_lon = (left_most + right_most) / 2
    center_lat = (top_most + bot_most) / 2

    d = latlongdist(left_most, top_most, right_most, bot_most) * 1000

    os.makedirs(cfg.mapillary["data_dir"], exist_ok=True)
    city_dir_path = os.path.join(cfg.mapillary["data_dir"], city)
    os.makedirs(city_dir_path, exist_ok=True)
    seq_city_dir_path = os.path.join(city_dir_path, "seq")
    os.makedirs(seq_city_dir_path, exist_ok=True)
    img_city_dir_path = os.path.join(city_dir_path, "img")
    os.makedirs(img_city_dir_path, exist_ok=True)
    imgdata_city_dir_path = os.path.join(city_dir_path, "img_data")
    os.makedirs(imgdata_city_dir_path, exist_ok=True)

    # Create a Mapillary Object
    map = Mapillary(cfg.mapillary["api_key"])
    bbox = str(left_most) + "," + str(bot_most) + "," + str(
        right_most) + "," + str(top_most)
    if not path.exists(os.path.join(city_dir_path, city + "_result.json")):
        data, next_img = map.search_images(bbox=bbox,
                                           per_page=cfg.mapillary["per_page"])
        data = aggregate(data, next_img, cfg.mapillary["per_page"], map)
        # Download the beautified json for debugging
        return_json_file(data,
                         os.path.join(city_dir_path, city + "_result.json"))
    else:
        data = json.load(
            open(os.path.join(city_dir_path, city + "_result.json")))

    nodes = []

    for idx, f in enumerate(data["features"]):
        if not 'sequence_key' in f["properties"]:
            print('Skip ', str(idx), '/', len(data["features"]))
            continue
        print('Processing ', str(idx), '/', len(data["features"]), ' - ',
              f["properties"]["sequence_key"])

        seq_raw_path = os.path.join(seq_city_dir_path,
                                    f["properties"]["sequence_key"] + ".json")
        if not path.exists(seq_raw_path):
            try:
                print('Pulling ', str(idx), '/', len(data["features"]), ' - ',
                      f["properties"]["sequence_key"])
                seq_raw_json = map.get_sequence_by_key(
                    key=f["properties"]["sequence_key"])
            except:
                print('Failed to acuire, skipping')
                continue
            return_json_file(seq_raw_json, seq_raw_path)
        else:
            print('Loading ', str(idx), '/', len(data["features"]), ' - ',
                  f["properties"]["sequence_key"])
            seq_raw_json = json.load(open(seq_raw_path))

        for i, img_id in enumerate(seq_raw_json["properties"]
                                   ["coordinateProperties"]["image_keys"]):

            # Check is in target area
            lon, lat = seq_raw_json["geometry"]["coordinates"][i]

            img_path = os.path.join(img_city_dir_path, img_id + ".jpg")
            img_data_path = os.path.join(imgdata_city_dir_path,
                                         img_id + ".json")
            if not path.exists(img_path):
                print(' Pulling', img_id)
                download_image_by_key(img_id, 2048, img_path)
            if not path.exists(img_data_path):
                # Organise a custom Json to massively redundant but abstracts sequences
                img_data = {}
                img_data["coordinate_location"] = seq_raw_json["geometry"][
                    "coordinates"][i]
                img_data["file_path"] = img_path
                img_data["image_key"] = img_id
                img_data["camera_make"] = seq_raw_json["properties"][
                    "camera_make"]
                img_data["captured_at"] = seq_raw_json["properties"][
                    "captured_at"]
                img_data["created_at"] = seq_raw_json["properties"][
                    "created_at"]
                img_data["pano"] = seq_raw_json["properties"]["pano"]
                img_data["user_key"] = seq_raw_json["properties"]["user_key"]
                img_data["username"] = seq_raw_json["properties"]["username"]
                img_data["cas"] = seq_raw_json["properties"][
                    "coordinateProperties"]["cas"][i]

                with open(img_data_path, "w") as write_file:
                    json.dump(img_data, write_file, indent=2)
            else:
                img_data = json.load(open(img_data_path))
            # Add to Knowledge Graph
            keys = []
            values = []
            for k, v in img_data.items():
                keys.append(k)
                values.append(v)
            nodes.append([keys, values])

    return nodes