15 июн. 2013 г.

Результаты голосования Думы по "анти-пиратскому закону" - первое чтение

Вы, возможно, слышали о новой громкой инициативе народных избранников - так называемый "анти-пиратский закон". Официальное название - "О внесении изменений в законодательные акты Российской Федерации по вопросам защиты интеллектуальных прав в информационно-телекоммуникационных сетях".
Сейчас этот законопроект просто с космической скоростью движется в Государственной Думе. 6 июня три депутата ГД  - оперная певица Максакова-Игенбергс М.П. (ЕР), режиссер Бортко В.В. (КПРФ), актриса Драпеко Е.Г. (СР) - официально представили законопроект. И уже 14 июня, то есть через 8 дней, законопроект прошел первое чтение. Я не буду касаться сути законопроекта, она отлично изложена в последней заметке Ъ.
Посмотрим на результаты голосования по партиям:
О внесении изменений в законодательные акты Российской Федерации по вопросам защиты интеллектуальных прав в информационно-телекоммуникационных сетях"
Добавьте подпись
Ниже можно посмотреть пофамильные результаты и найти своего любимого депутата.


Как видно, законопроект был принят 257 голосами "за" (237 от ЕР, 1 голос от КПРФ и 19 голосов от СР). Причем довольного много депутатов(189 человек всего) не голосовало. Я, честно говоря, до сих пор не очень понимаю эту логику. Кворум составляет 226 депутатов. Поэтому если ЕР голосует дисциплинированно (а так происходит почти всегда), то "не голосовать" смысла нет, кворум будет все равно. "Утопить" законопроект не-голосованием при текущем количественном соотношении депутатов невозможно.

Довольно странным мне показалось, что единственный голос в поддержку законопроекта от КПРФ принадлежит не режиссеру Бортко, который выступил инициатором (как можно было бы ожидать), а некоему депутату Ющенко А.А. Режиссер Бортко почему-то не стал голосовать за свой же законопроект (!). Депутат Драпеко вместе с еще 18 избранниками от СР  проголосовала "за". Три решительных голоса "против" - это депутаты Иванов С.В. (ЛДПР), Пономарев И.В. (СР) и Гудков Д.Г. (СР). Вообще с партийной дисциплиной у эсеров явно не складывается.

Судя по взятым темпам, принято решение принять законопроект до летних каникул. Сейчас наступает наиболее важный этап - второе чтение, на котором возможно, удастся будет придать  ему хоть более или менее разумное представление. Досудебное блокирование целых доменов - это явно что-то из области маразма. И напоследок следующая цитата из пояснительной записки к законопроекту: "Важнейшей новеллой ГПК РФ является введение института предварительных обеспечительных мер защиты интеллектуальных прав в информационно-телекоммуникационных сетях, в том числе в сети «Интернет» (Статья 144'ГПК РФ)." Новеллой!

13 июн. 2013 г.

Расписание подмосковных электричек на диаграмме Маре (Marey's Trains) c помощью d3.js

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




Как читать эту диаграмму (если не очень понятно): 
  • по оси X - время (в данном случае - с 4.30 утра до 12.00). по оси Y - идут станции Ленинградского направления (от Москвы Ленинградской до Твери). Расстояние между названиями по оси соответствует реальному расстоянию между станциями в километрах. Поэтому некоторые станции почти "налезают" друг на друга  расстояние между ними совсем небольшое (по крайней мере, по тем данным, которые у меня есть). 
  • каждая линия представляет собой поезд, каждая точка на линии - станцию. 
  • по умолчанию выбраны оба направления, но можно выбрать отдельно - "в Москву"/"в область". 
  • при наведении мышкой на станцию появляется маленькое окошко, которое показывает название станции и время прибытия. 
  • чем круче линия, тем быстрее идет данный поезд. 
  • Цветом обозначены типы электричек: черный - ежедневно, рыжий - по выходным, фиолетовый - выходные /кроме субботы/кроме воскресенья, красный - электричка отменилась. 
  • Информация по расписанию взята с tutu.ru и соответствует 13 июня 2013 года, со всеми изменениями в расписании. 

Немного об истории вопроса 

Такое представление расписания поездов первым представил в своей книге 1885 года (128 лет назад!) La méthode graphique французский ученый Этьен-Жюль Маре. Таким образом в книге было изображено расписание  поездов между Парижем и Лионом. 
Тем, кто занимается графической визуализацией, это представление во многом известно благодаря культовой книге Эдварда Тафте (Edward Tafte) - "The Visual Display of Quantiative Information". Именно диаграмма Маре вынесена на обложку книги, и Тафте по ходу несколько раз возвращается к этой диаграмме. Такое представление соответствует "принципам графического совершенства" (principles of graphical excellence) от Тафте - хорошая визуальная презентация данных является сочетанием сути вопроса, статистики и дизайна. Сложные идеи представлены ясно, точно и эффективно. Читатель получает максимальное количество идей в минимальный период времени и с минимальным количеством "чернила" на единицу пространства.  
Разумеется, с помощью современных технологий подобной репрезентации можно придать интерактивность и дополнительное удобство представления. 
 К примеру, вот пример расписания пригородных поездов Сан-Франциско в стиле Маре, созданный дизайнером Nicholas Rougeux. Недавно я увидел аналогичный пример, созданный в d3 автором этой удивительной библиотеки (Mike Bostock) и решил сделать аналогичную визуализацию для наших данных в качестве урока по изучению d3, создания визуализации в стиле Тафте, а также потому, что мне кажется, что используемые представления расписания электричек как на самих станциях, так и в Интернете, можно значительно улучшить. 

Исходные данные
Разумеется, сначала необходимо получить исходные данные - расписание движения пригородных поездов в удобном для машинной обработки виде. Как ни удивительно, но официальный перевозчик - ОАО «Центральная пригородная пассажирская компания» - не предоставляет общественности подобной информацииии. Раздел "Он-лайн табло" на официальном сайте находится в "стадии наполнения". 
Почему-то компания, имеющая почти $1 млрд ежегодной выручки и более $100 млн чистой прибыли, не нашла возможности сообщать пассажирам о расписании движения. Правительство г. Москвы также не имеет подобной информации.  Широко разрекламированный "Портал открытых данных" содержит информацию о стоимости проезда, но не расписании движения пригородных поездов. 
Разумеется, все кто ездил на электричках, знают альтернативные источники информации :) Это конечно, Яндекс и tutu.ru. Обращает кстати внимание, что оба сервиса используют довольно скудное текстовое представление расписания. 
Я написал небольшой скрипт в R, который собирает данные с tutu.tu, хотя концептуально это не очень правильно - перевозчик, либо местные власти должны предоставлять подобную информацию в удобном виде.   
В нашем случае для Ленинградского направления, но разумеется, можно собрать информацию по и другим направлениям/вокзалам. Причем информацию по расстояниями между станциями пришлось "парсить" тоже с tutu.ru, так как я не смог найти какой-либо официальной информации по этому поводу. 
Итоговый файл представляет собой матрицу, в котором по столбцам идут остановки, а по строкам - отдельные поезда. В названии столбцам закодированы расстояния между станциями и зоны оплаты. Выглядит это вот так: 





Соответственно мы видим, что на Ленинградском направлении в день проходит 165 поездов (по обоим направлениям), которые останавливаются на 45 различных станциях. Матрица состоит из почти трех тысяч значений, поэтому необходимо специальные средства представления этой информации в графическом виде. 

Построение диаграммы в стиле Маре
Как уже говорилось, я использовал графическую библиотеку Data-Driven Documents (или d3), которая представляет собой нечто среднее между библиотеками готовых графиков и самостоятельным рисованием диаграмм в графическом редакторе вроде Inkscape. 
Это мой второй опыт самостоятельного рисования в d3 (первый - карты хороплет для РФ). Поэтому я основывался на готовом примере Майка, но несколько видоизменил его для своих данных и дополнил дополнительными интерактивными элементами. 
Вариант с этими "плюшечками" занимает около 300 строк кода, но вполне возможно, потому что я использовал не самые оптимальные конструкции. 


Основная "рабочая" функция преобразует матрицу поезда-станции и преобразует ее в JS-объект. На основе этого объекта собственно и строится вся графическая составляющая. 
function type(d, i) {

  // Extract the stations from the "stop|*" columns.
  if (!i) for (var k in d) {
    if (/^stop\|/.test(k)) {
      var p = k.split("|");
      stations.push({
        key: k,
        name: p[1],
        distance: +p[2],
        zone: +p[3]
      });
    }
  }

  return {
    number: d.number,
    type: d.type,
    direction: d.direction,
    stops: stations
        .map(function(s) { return {station: s, time: parseTime(d[s.key])}; })
        .filter(function(s) { return s.time != null; })
  };

Информационное окно

В дополнении примеру Майка я добавил еще всплывающее окошко, которое появляется при наведении мышкой на любую круг - станцию. Делается это с помощью простого event-listener, реагирующего на mouseover.

train.selectAll("circle")
      .data(function(d) { return d.stops; })
    .enter().append("circle")
      .attr("transform", function(d) { return "translate(" + x(d.time) + "," + y(d.station.distance) + ")"; })
      .attr("r", 3)
       .on("mouseover", function(d) { 
                  var xPosition = x(d.time)+margin.left + margin.right;
                  var yPosition = y(d.station.distance);

      d3.select("#tooltip")
            .style("left", xPosition + "px")
            .style("top", yPosition + "px")           
            .select("#stations")
            .text(d.station.name);
      d3.select("#tooltip")
            .select("#time")
            .text(formatTime(d.time));
      d3.select("#tooltip").classed("hidden", false);
      
            })
       
                .on("mouseout",  function() {
                    d3.select("#tooltip").classed("hidden", true);
                          });



Соответственно объект tooltip то появляется и наполняется информационным содержанием (название станции и время прибытия поезда на эту станцию), то исчезает. 


Выбор направления

В исходном примере Майка отображается только одно направление, я же хотел, чтобы была возможность посмотреть оба направления одновременно, а также по отдельности. Это делается с помощью отдельной формы и функции, которая реагирует на изменение этой формы. 
d3.selectAll("input[name=f_direction]")
  .on("change", function(){
    cur_direction = this.id;
      if (this.id == 'moscow'){
        d3.selectAll(".moscow").classed("hidden", false);
        d3.selectAll(".oblast").classed("hidden", true);
           }
      if (this.id == 'oblast'){
        d3.selectAll(".moscow").classed("hidden", true);
        d3.selectAll(".oblast").classed("hidden", false);
           }
  })


Соответственно все объекта класса "oblast" или "moscow" показываются, либо скрываются от зрителя. Переменная cur_direction нужна для того, чтобы правильно реагировать на выбор для недели, когда направление уже выбрано. 


Выбор дня недели

Исходные данные имеют для каждого поезда его тип: ежедневно, по выходным, по рабочим, кроме суббот, кроме воскресений, отменен. Но пользователя на самом деле интересует какие поезда идут в конкретный день, поэтому я решил целесообразнее предоставить выбор для недели и в зависимости от этого рисовать нужные поезда. Соответственно, поезд, который ходит в режим "кроме воскресений" не будет отображаться в при выборе воскресенья. При выборе субботы или воскресенья также не будут показываться электрички, которые ходят по рабочим дням. 
Реализация этой логики сделана топорным if :) Отмененные электрички (красным цветом) должны отображаться при любом раскладе
d3.selectAll("input[name=type_train]")
  .on("change", function(){

      if (this.id == 'working'){
        d3.selectAll(".daily"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".working"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".weekend"+"."+cur_direction).classed("hidden", true);
        d3.selectAll(".ex_saturday"+"."+cur_direction).classed("hidden", true);
        d3.selectAll(".ex_sunday"+"."+cur_direction).classed("hidden", true);
      }
      if (this.id == 'saturday'){
        d3.selectAll(".daily"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".working"+"."+cur_direction).classed("hidden", true);
        d3.selectAll(".weekend"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".ex_saturday"+"."+cur_direction).classed("hidden", true);
        d3.selectAll(".ex_sunday"+"."+cur_direction).classed("hidden", false);
      }  

      if (this.id == 'sunday'){
        d3.selectAll(".daily"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".working"+"."+cur_direction).classed("hidden", true);
        d3.selectAll(".weekend"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".ex_saturday"+"."+cur_direction).classed("hidden", false);
        d3.selectAll(".ex_sunday"+"."+cur_direction).classed("hidden", true);
      }      
  })



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

12 июн. 2013 г.

Закон об оскорблении чувств верующих - результаты голосований по чтениям

Если вы не в курсе, Государственная Дума вчера окончательно приняла закон об оскорблении чувств верующих. Мы уже рассматривали результаты голосования в первом чтении, которое состоялось 9 апреля 2013 года. Теперь можно посмотреть на результаты всех чтений сразу:


Обращает внимание, что вторых чтений было два - 21 мая 2013 и вчера - 10 июня 2013 года. Вчера было принято решение вернуть законопроект во второе чтение - видимо для того, чтобы принять новые поправки. Процедура работы ГД не позволяет осуществлять содержательную правку законопроекта на этапе третьего чтения, поэтому технически его надо вернуть во второе чтение, внести правки и снова проголосовать. Вообще второе чтение - как правило, наиболее важный этап в судьбе любого законопроекта. Насколько я понял, основное нововведение - дополнить часть с наказанием по ст 148 УК РФ следующим пунктом: "после слов «лишением свободы на тот же срок» дополнить словами «с лишением права занимать определенные должности или заниматься определенной деятельностью на срок до двух лет».


Что значит конкретно - "определенные должности" и "определенная деятельность" - я не понял.

Теперь о результатах. Как видно, результаты практически не изменились от чтения к чтению. ЕР и ЛДПР поддерживают законопроект. КПРФ и большая часть СР не голосуют, что можно трактовать как оппозицию закону.

В третьем итоговом чтении только два депутата голосовали "против". Вот имена этих героев - Гудков Д.Г. (СР) и Журавлев С.В. (ЛДПР). Среди депутатов Единой России не голосовало четыре человека (Ткачев А. Н., Долгих В.И., Кривоносов С.В., Кузин С.П) - то ли их не было, то ли выражали таким образом свое несогласие.