Время прочтения: 5 мин.

Каждый аудитор рано или поздно сталкивается с вопросом как лучше представить результаты проведенной проверки. Сегодня мы поделимся своим опытом.

По мере завершения анализа аналогов для арендуемых нами объектов на сайтах объявлений, перед нами стал вопрос как лучше представить полученные результаты. Отчёт в документе или таблица в excel, выглядят довольно «сухо», так как не могут в полной мере отразить полученный результат и сформировать окончательное мнение аудитора.

В результате было принято решение, о представлении полученных данных в виде интерактивной карты, на которой будут отображены объекты-аналоги для максимально удобного использования коллегами.

Для реализации такой интерактивности, было принято решение об использовании популярной javascript-библиотеки для работы с геоданными – leaflet.js.

Данные об арендуемых объектах и их аналогах среди объявлений в сети интернет необходимо обработать средствами python. Для предварительной обработки на вход подаётся excel-файл со следующими столбцами:

Далее, на основании полученного файла, средствами python будет формироваться json-объект, хранящий необходимые для работы библиотеки leaflet данные. Предварительно соберём информацию обо всех объектах, используя метод searchObjects:

def searchObjects(num_address,num_lat,num_lon,num_square,num_price,num_link=30,num_dist=31):
    wb = openpyxl.load_workbook(file_path)
    sheet = wb['Result']
    addresses_list = []
    json = {}
    for count in range(2,sheet.max_row+1):
        address = str((sheet.cell(row=count, column=num_address)).value)
        if address not in addresses_list:
            addresses_list.append(address)
            json[address] = {}
            json[address][“latitude”]=float((sheet.cell(row=count,column=num_lat)).value)
            json[address][“longtitude”] =float((sheet.cell(row=count,column=num_lon)).value)
            json[address][“square”] =float((sheet.cell(row=count,column=num_square)).value)
            json[address][“price”] =float((sheet.cell(row=count,column=num_price)).value)
            json[address][“neighbors”] =[]
            json[address][“link”] =float((sheet.cell(row=count,column=num_link)).value)
            json[address][“distance”] =float((sheet.cell(row=count,column=num_dist)).value)
        else:
            continue
    return json

Теперь, когда информация о необходимых объектах заполнена, необходимо произвести поиск объектов-аналогов для каждого из арендуемых объектов. Для этого предназначен метод searchNeighbors:

def searchNeighbors(self,addressesJson):
        wb = openpyxl.load_workbook(self.file_path)
        sheet = wb['Result']
        for count in range(2,sheet.max_row+1):
            cell = sheet.cell(row=count, column=1)
            address = cell.value
            cell = sheet.cell(row=count,column=6)
            neighbor_address = cell.value
            addressesJson[address]["neighbors"].append(neighbor_address)
        return addressesJson

Метод, который объединяет в себе поиск информации об объектах и их аналогах и формирует файл, который в дальнейшем будет использован для визуализации:

    def createJson(self):
        file = open("map.js","w",encoding="utf-8")
        json1 = self.searchObjects(1,2,3,5,4)
        json2 = self.searchObjects(6,7,8,10,9,11,12)
        json1.update(json2)
        resultJson = self.searchNeighbors(json1)
        file.write("objects="+str(resultJson))
        file.close()

В результате данных манипуляций, получим js-файл, в котором будет находится json-объект данного формата:

Теперь можно приступить к дальнейшей разработке. Переходим на страницу библиотеки leaflet на вкладку Download и скачиваем актуальную версию библиотеки:

После этого создаём html страницу нашего итогового приложения и подключаем в нем эту библиотеку и js-файл с json – объектом, хранящим наши объекты в head – разделе:

<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" href="leaflet/leaflet.css" />
  <script src="leaflet/leaflet.js"></script>
  <script src="map.js"></script>
</head>

После этого в теле нашего html-файла создадим объект, в котором будет отображаться наша итоговая карта:

<div id="map"></div>

Для этого объекта указываем css – свойства: высоту и ширину окна:

    #map {
      width: 55%;
      height: 99%;
    }

Далее в коде, после нашего объекта, хранящего карту, разместим блок, в котором будем писать код на javascript для взаимодействия с картой:

<script type='text/javascript'>
//код писать будем здесь
</script>

Теперь в данном блоке напишем код, который будет отображать нашу карту:

var map = L.map('map').setView([47.222078, 39.720349], 13);
L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; <a rel="nofollow" href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);

Метод setView в качестве параметров принимает в себя значение долготы и широты места, на котором будет центрироваться наша карта, а также величину зума, а с помощью L.tileLayer мы добавляем на нашу карту слой OpenStreetMap. Уже теперь можно посмотреть на первые результаты! Для этого запустим наш html-файл в браузере:

Теперь необходимо задать иконки, с помощью которых на нашей карте будут отображаться исследуемые объекты и создать слой, на котором будут отображаться объекты-аналоги:

  var LeafIcon = L.Icon.extend({
options: {iconSize:[20, 25], iconAnchor:[10,25], popupAnchor:[0, 0]}
}); // задаём иконку, с помощью которой будем отображать арендуемые объекты
var neighborIcon = new LeafIcon({iconUrl: 'leaflet/neigh_baloon.png'}); // иконка объектов-аналогов
var objectsN = L.layerGroup(); // задаём слой для отображения объектов-аналогов

Можно приступить к размещению на карте арендуемых объектов. Для этого из созданного и подключенного к нашему html файлу json-объекта будем собирать необходимую информацию с помощью следующего кода:

for (let key of Object.keys(objects)) {
    if (objects[key]["neighbors"].length!=0){
      latitude = objects[key]["latitude"];
      longtitude = objects[key]["longtitude"];
      square = String(objects[key]["square"]);
      price = String(objects[key]["price"])
      description="<strong>"+key+"</strong><p>"+square+" м<sup>2</sup></p><p>Цена: "+price+"</p>";//описание для popup маркера
      var marker = L.marker([latitude, longtitude],{icon: neighborIcon});
      marker.on("click", object_popup_click);
      marker.properties = {object_address: key, object_square:square, object_price:price};
      marker.addTo(map).bindPopup(description);}}

Строка marker.on(“click”,object_popup_click) является обработчиком события и при нажатии на размещенный маркер будет запускать метод object_popup_click, который будет отображать объекты-аналоги, для этого добавим код этого метода в наш html-файл:

function object_popup_click(e){
try{objectsN.eachLayer(function(layer){map.removeLayer(layer);});}
catch(err){console.log("Ошибка очистки значения");}//при ошибке выводим сообщение в консоль
var object_latitude = e.latlng.lat;
var object_longtitude = e.latlng.lng;
var circle = L.circle([object_latitude,object_longtitude],{//создаём окружность для отрисоки
color:'#00008B',fillColor:'#6495ED',
fillOpacity: 0.5,radius: 1000});
objectsN.addLayer(circle).addTo(map);//добавляем окружность для рисования
object_address = e.sourceTarget.properties["object_address"];
object_square = e.sourceTarget.properties["object_square"];
object_price = e.sourceTarget.properties["object_price"]
neighbors = objects[object_address]["neighbors"];
neighbors_number = neighbors.length;
for (var i=0; i<neighbors_number; i++){
data = objects[neighbors[i]];
link = "<a href=\""+data["link"]+"\"target=\"_blank\">Ссылка</a>"
neighbor_description = "<strong>"+neighbors[i]+"</strong><p>"+data["square"]+" м<sup>2</sup></p><p>Цена:"+data["price"]+"</p>"+link+"<p>Расстояние:"+data["distance"]+"</p>";
neighbor_marker = L.marker([data["latitude"],data["longtitude"]]).bindPopup(neighbor_description);
objectsN.addLayer(neighbor_marker).addTo(map);}}

Запускаем итоговое приложение и выбираем один из интересующих объектов:

Пробуем нажать на один из появившихся маркеров:

В итоге мы получили практические навыки по обработке данных на языке python и их дальнейшее отображение на карте с помощью javascript-библиотеки leaflet.js.