Как стать автором
Обновить

Построение графиков на Android: sl4a, python и flot

Время на прочтение4 мин
Количество просмотров14K
Доброго времени суток, %username%!

Введение


Графики — наглядный способ представления информации. Картинка стоит тысячи слов, а график в некоторых случаях часто полностью описывает результаты эксперимента, физического или вычислительного. В конце концов, мне нравятся графики.

Однажды я оказался в ситуации, что данные для построения графика уже есть, а компьютера под рукой нет. Но ведь с такой задачей может справиться и смартфон! Так я смог заставить себя начать применять знания, полученные из наполовину пройденного курса по Python от Google, и использовать sl4a, уже успевший покрыться виртуальной пылью. Итак, для работы понадобятся sl4a (кто еще не слышал такую аббревиатуру, прочитайте это, это и это) + flot (подойдет любая библиотека для построения графиков на js).

Вдоль оси абсцисс будем отсчитывать номер наблюдаемой величины, вдоль оси ординат — её значение. Значения вычисляются следующим образом: есть 30 логов, содержащих строчки вида «value = 0.1 0.2 0.15 0.12 ...», где «0.1 0.2 ...» — значения, «value» — название величины. Значение «1» есть среднее по всем первым числам из соответствующих строк логов («0.1» в примере строки), «2» — по всем вторым и т.д. В итоге получается двумерная матрица размера M*N, где M — количество строк в логе, N — количество чисел в строке. Предполагается, что логи содержат одинаковое количество строк и одинаковое количество чисел в каждой строке.

Реализация


Отображение графика с помощью flot

За построение графика отвечает плагин flot к jquery. Из полного комплекта с сайта разработчиков для нашей задачи понадобятся только файлы jquery.flot.js и jquery.js. Сам код log_manager.html:

<html>

  <head>
    <title>Plot</title>
    <link href="layout.css" rel="stylesheet" type="text/css">
    <script src="jquery.js"></script>
    <script src="jquery.flot.js"></script>
  </head>

  <body>
    <div id="placeholder" style="width:535px;height:270px;"></div>
    <script>
        var plotData = function(d) {$.plot($("#placeholder"), [ {label: "flux", data: eval(d.data), color: "rgb(255, 100, 100)" }] );};
        var droid = new Android();
        droid.registerCallback("plotData", plotData);
    </script> 
  </body>

</html>


Строка 13 — построение графика с помощью flot. Например, можно написать

$.plot($("#placeholder"), [ {label: "flux", data: [[0,0],[1,1],[2,4],[3,9],[4,16]], color: "rgb(255, 100, 100)" }] );


и на графике отобразится кусок параболы. Таким образом, данные для построения должны иметь вид [[x0,y0],[x1,y1],[x2,y2],[x3,y3], ...]. Самый простой способ, пришедший мне в голову — подготовить их в python-скрипте в строку точно такого же вида и обернуть в javascript в eval(), которая выполнит переданную строку как если бы это был кусок js-кода. Далее я использую именно этот способ.

Модификация существующих и добавление новых свойств отображения кривых на графике реализуется просто. Например, чтобы отключить тень под кривой, достаточно добавить «shadowSize: 0»:

$.plot($("#placeholder"), [ {label: "flux", data: [[0,0],[1,1],[2,4],[3,9],[4,16]], shadowSize: 0, color: "rgb(255, 100, 100)" }] );


Две кривых на одном графике:

$.plot($("#placeholder"), [ {label: "flux", data: [[0,0],[1,1],[2,4],[3,9],[4,16],[5,25]], shadowSize: 0, color: "rgb(255, 100, 100)" }, {label: "flux", data: [[0,0],[5,25]], shadowSize: 0, color: "rgb(255, 100, 100)" }] );


В строке 14 создается объект для взаимодействия с Android API (его возвращает встроеная в sl4a функция «Android()»).

В 15 строке описывается, как обрабатывать полученный event с именем «plotData». Как только получен event с таким именем, вызывается функция «plotData». Переданные с ним данные (строка-массив) будут находиться в <имя_входной_переменной_в_функции>.data.

Осталось только написать скрипт, который файлы прочитает, строку подготовит и пошлет её. Об этом следующая часть.

Подготовка данных с помощью Python

Код log_manager.py:

#!/usr/python

## Import libraries
#  android for access to Android API
#  time for sleep(sec) 
import android, time

#  Filename is "<FileCounter>-of-<NumberOfFiles>.log"
filename = "/sdcard/864x864x30-0-of-30.log"

#  Get number of files
N = int(filename.split("/")[-1].split("-")[-1].split(".")[0])

# Read first file
file = open(filename,"r")

value = []
for line in file.readlines():

    if "value =" in line:
        value.append([])
        for val in line.split(" "):
            try:
                value[-1].append(float(val))
           
            except:
                continue 

# Read other files
for f in range(1, N):
    file = open(filename.replace("-0-","-"+str(f)+"-"))
    i = 0
    for line in file.readlines():
        if "value =" in line:
            j = 0
            for val in line.split(" "):
                try:
                    value[i][j] += float(val)
                    j += 1
                except:
                    continue
    i += 1

# Prepare string for flot
toBePlotted = "["
for i in range(0, len(value[-1])):
    toBePlotted += "[" + str(i) + "," + str(value[-1][i]) + "],"
toBePlotted += "]"

# Get droid object to use Android API
droid = android.Android()

# Set web view
droid.webViewShow('file:///sdcard/sl4a/scripts/log_manager.html')

# Wait 3 seconds while web view starts
time.sleep(3)

# Post event 'plotData' to web view
droid.eventPost('plotData', toBePlotted)


Данный код плох, так писать не стоит. Но свою задачу он выполняет: получает матрицу, состоящую из соответствующих средних по логам.

В строках 1-43 происходит считывание данных из файлов в двумерный массив value. В 44-48 подготавливается строка для вывода графика в flot. В 50-60 создается webView на основе странички log_manager.html (54), ждем 3 секунды, скрипт ждет, пока страничка загрузится (плохой подход!) (57), и посылает событие с данными для построения графика (60).

Результаты


Чтобы протестировать написанный скрипт, необходимо положить log_manager.py, log_manager.html, jquery.flot.js и jquery.js в папку /sdcard/sl4a/scripts. В корне карты памяти должны лежать файлы с именами «864x864x30-0-of-30.log»...«864x864x30-29-of-30.log». В каждом логе должно быть записано записано одинаковое число строк вида «value = 0.2 0.34 0.343 ...» с одинаковым количеством чисел в каждой строке. Скрипт построит график на основе средних значений последних строк логов и имеющий вид:



Архив с файлами, упомянутыми в статье. Также в архиве присутствуют jquery.js и jquery.flot.js из комплекта с сайта flot.
Теги:
Хабы:
+12
Комментарии7

Публикации

Изменить настройки темы

Истории

Работа

Ближайшие события

PG Bootcamp 2024
Дата16 апреля
Время09:30 – 21:00
Место
МинскОнлайн
EvaConf 2024
Дата16 апреля
Время11:00 – 16:00
Место
МоскваОнлайн
Weekend Offer в AliExpress
Дата20 – 21 апреля
Время10:00 – 20:00
Место
Онлайн