Mpld3: Браузер/HTML указывает размер фигуры, а не figsize * dpi

Созданный на 6 февр. 2014  ·  31Комментарии  ·  Источник: mpld3/mpld3

Очень нравится пакет, большое спасибо, что поделились.

Это предлагаемое улучшение, но оно не совсем питоническое. Но опять же, d3js тоже нет :)

Замечательно, что установленный размер фигуры отражается на экране, но я думаю, что было бы «более отзывчиво» иметь возможность установить размер холста в ограничивающий div, а затем позволить этому размеру div определяться шириной браузера / чем угодно иначе хочет разработчик.

Стоит ли мне копаться в _js.py и _object.py, чтобы это заработало?

Самый полезный комментарий

@cliffckerr Я определенно могу добавить это к draw_figure , возможно, в качестве аргумента, который принимает Object и устанавливает все атрибуты, указанные в этом объекте, в svg , чтобы вы могли передать что-то вроде {viewBox: ..., width: '90vw', height: 'auto'} .

Я хотел спросить вас и других в этой теме, считаете ли вы, что это нужно добавить где-нибудь еще, например, для поддержки fig_to_html() . Если это так, возможно, нам следует подумать о решении этой проблемы. В противном случае дайте мне знать, и я сразу же внесу изменения в draw_figure() .

Все 31 Комментарий

Я не совсем понимаю, о чем вы спрашиваете... Мы получаем размер фигуры в дюймах из фигуры matplotlib, а также получаем dpi из фигуры matplotlib. Как вы предлагаете нам это изменить? Спасибо

Вместо того, чтобы использовать абсолютный размер фигуры, установленный в Python, я имею в виду что-то вроде этого:

<div id='parent' class='figsizeinfo'>
//mpld3 generated code
</div>

Где figsizeinfo — это спецификация размера CSS, а mpld3 заполняет div. (по моему опыту, именно так работает flotjs)

Хм... этот вопрос может выдать мою неопытность в веб-вещах, но я думал, что SVG (который использует mpld3) полностью основан на пикселях, и это нельзя легко изменить. Использует ли flotjs SVG или какую-то другую спецификацию?

Графика SVG (масштабируемый векторный формат) основана на векторах, а не на пикселях.

Вот пример изображения SVG, созданного с помощью vanilla matplotlib, которое масштабируется с размером окна:

http://bleepshow.pithy.io/SVG_Example

(явно сфальсифицировано на вашем примере)

Насколько я понимаю, d3js и все рисунки на холсте являются векторными, поэтому они должны уметь это делать.

Хитрость, я думаю, заключается в том, чтобы установить

figwidth = $(“#parent”).width //(jquery based, but you get the point )

скорее, чем

figwidth = figsize[0] * dpi;

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

Нет, это довольно легко.

Вот хак, который я применил к вашему коду fig_to_d3:

print mpld3.fig_to_d3(fig).replace("\n","\r").replace("var figwidth = 8.0 * 80","var figwidth = $(window).width()*.9;").replace("var figheight = 6.0 * 80","var figheight = $(window).height()*.9;")

что появляется как:

http://bleepshow.pithy.io/mpld3_window_scale_test

Теперь метки находятся не в том месте, но опять же, это «просто» вопрос ссылки на их положение в div, а не совсем на фигуру. Но рендеринг фигуры работает хорошо, насколько я могу судить.

(обратите внимание, что это не изменяет размер, если вы не обновляете, но с небольшим количеством клея, который также прямолинеен)

В настоящее время я разрабатываю для себя решение, основанное на этом, и я рад попытаться отшлифовать его во что-то приличное для запроса на включение.

Адаптивный размер фигуры mpld3 будет очень полезен. Если вы добавите это с помощью кнопки (на панели инструментов), чтобы иметь возможность открывать текущую фигуру в новом окне, и вся фигура будет легко изменять размер.

+1

@hadim Я бы хотел, чтобы это было «питоновским», так что что-то вроде

mpld3.fig_to_d3(fig,size="adaptive")

будет хорошим триггером

Я согласен !

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

Философия этого mpld3 заключается в создании простых выходных данных, максимально точно отражающих то, что изображено на рисунках matplotlib. Если вы хотите изменить размер выходной фигуры, предпочтительным методом будет настройка размера фигуры matplotlib. Что-то еще кажется, что это быстро станет серьезной головной болью для внедрения, тестирования и обслуживания.

Что насчет плагина?

plugins.connect(fig, plugins.ResponsiveSize())

Плагин, вероятно, был бы хорошим способом сделать это. Но опять же, как вы справляетесь с адаптацией размера шрифта, ширины линий, размеров маркеров, расположения легенды и расположения текста на осях? Из-за всех этих проблем, без какой-либо обширной инфраструктуры для поддержки изменения размера, я думаю, что такой плагин будет иметь очень ограниченный диапазон полезности.

@jakevdp Я не согласен: единственное, что пострадало в моем трехсекундном взломе выше, - это расположение меток, и опять же, это вопрос написания лучшего javascript. DOM допускает абсолютное и относительное позиционирование без особых усилий.

То, как код реализован сейчас, все жестко закодировано в фигуре. Немного поработав, ширину/высоту, толщину линий и размер шрифта можно линейно масштабировать относительно размера div. Самой сложной частью будет соотношение сторон, и его можно заблокировать. Как только соотношение сторон заблокировано, линейное масштабирование становится довольно простым.

@hadim , это хорошая идея.

Я не знаю d3.js, поэтому понятия не имею. Но поскольку мы работаем над файлом svg, я действительно не думаю, что мы не можем легко это сделать...

Несколько ссылок, чтобы начать думать о том, как лучше всего это сделать:

+1 для @dansteingart. Почему бы не установить всю внутреннюю длину и положение SVG в относительных координатах, а затем перед выводом использовать viewBox для изменения размера всей фигуры и, таким образом, соответствовать параметру figsize matplotlib (или реагировать в другом случае).

@dansteingart - я согласен, что с достаточным количеством хаков JS вы можете заставить это работать. Но, тем не менее, я не поддерживаю фундаментальное изменение этого пакета для включения этой функции.

Почему? Ну, во-первых, это противоречит вышеупомянутой философии пакета, которая заключается в том, что элементы графика, размеры фигур и т. д. должны быть определены через интерфейс matplotlib.

Во-вторых, это не «обязательная» функция, и значительное усложнение кодовой базы для такой необязательной функции повредит пакету в долгосрочной перспективе. Чтобы узнать, почему это может быть, см. прошлогодний доклад @ellisonbg на SciPy.

Если вы хотите поработать над плагином для добавления такого поведения, добро пожаловать. Если он работает хорошо, возможно, его даже стоит включить в модуль plugins . Но я категорически против серьезных модификаций базового макета фигурки ради новых функций, которые идут вразрез с философией упаковки, какими бы крутыми они ни были.

Я просто увлекся этим, и мне кажется, что какой-то плагин может выполнять какое-то интересное отзывчивое поведение при изменении размера фигуры. @dansteingart начал эту тему с идеи для функции и вопроса о том, стоит ли начинать реализовывать эту функцию определенным образом. В ответ на вопрос я бы посоветовал вам начать с плагина и посмотреть, как далеко он может зайти без изменения _objects.py или _js.py. Но если вы готовы, я хотел бы сделать шаг назад и рассказать о том, какую проблему мы пытаемся решить:

Замечательно, что установленный размер фигуры отражается на экране, но я думаю, что было бы «более отзывчиво» иметь возможность установить размер холста в ограничивающий div, а затем позволить этому размеру div определяться шириной браузера / чем угодно иначе хочет разработчик.

Я хотел бы получить некоторые разъяснения относительно варианта использования, в котором это произойдет. В моем обычном рабочем процессе я использую ipython с сервером ноутбука, работающим в облаке, с развернутым веб-браузером. Так что это может случиться, если я переключусь с рабочего дисплея на дисплей ноутбука и у меня будет меньшая ширина экрана. Но я уверен, что есть и другие настройки, о которых думают другие. Что еще?

@jakevdp Достаточно честно, и я согласен с тем, что _вообще_ ничего не должно меняться на стороне python. Тем не менее, я думаю, что все это честная игра на стороне JS, и если смысл эксперимента состоит в том, чтобы объединить лучшие аспекты matplotlib и d3js, я думаю, что стоит продолжать.

Как я это вижу, как только вы вызываете fig_to_d3, вы выходите из страны Python и делаете фигуру отзывчивой = пишете лучший JS.

Что касается полезности адаптивных страниц, только для вывода iPython, я согласен с вами, но python — это больше, чем блокнот iPython, и я думаю, что в конечном итоге использование mpl3d для создания адаптивных веб-страниц будет более полезным, чем вы предполагаете здесь.

По вашей логике, если я хочу увеличить детали в соответствии с matplotlib, я должен просто изменить xlim/ylim.

Еще раз спасибо за отличный пакет, я посмотрю, что я не могу сделать с плагином, и вернусь к вам.

@aflaxman

Я хотел бы получить некоторые разъяснения относительно варианта использования, в котором это произойдет. В моем обычном рабочем процессе я использую ipython с сервером ноутбука, работающим в облаке, с развернутым веб-браузером. Так что это может случиться, если я переключусь с рабочего дисплея на дисплей ноутбука и у меня будет меньшая ширина экрана. Но я уверен, что есть и другие настройки, о которых думают другие. Что еще?

см. http://pithy.io

Я написал содержательно, чтобы позволить мне/моей группе/моим классам писать сценарии, которые затем превращаются в веб-приложения. Если фигурка подходит к окну, жизнь становится намного приятнее. MPL3d дает мне гораздо более удобные инструменты для создания интерактивных графиков (я взламывал флот), и если интерактивные графики реагируют на размер, все в порядке.

Спасибо @dansteingart. Имейте в виду, что даже если JS скрыт от пользователя Python, это все еще код, и его все равно нужно поддерживать. Мой многолетний опыт разработки с открытым исходным кодом показывает, что часто приходят люди, которые взволнованы внедрением новых функций, и как только эти функции объединены, их обслуживание и поддержка ложатся на плечи тех немногих разработчиков, которые инвестировали в пакет в длительный срок. Я уже настолько перегружен, что вынужден игнорировать отчеты об ошибках в часто используемых пакетах, которые я создал всего несколько лет назад. Я действительно не хочу, чтобы mpld3 дошел до этого.

Спасибо за понимание, и я с нетерпением жду возможности увидеть, что вы можете собрать вместе в плагине.

@jakevdp этот момент хорошо понят, и я думаю, что архитектура плагина хорошо подходит для этой цели. Если он сломается, это будет моя вина, а не ваша (то есть, если вы не измените fig_to_d3 :-p )

Переписанная версия вышла, и ее может быть _немного_ проще реализовать в виде плагина, по крайней мере, для особых ситуаций. Однако я писал это не с учетом такой динамической ситуации, поэтому могут быть некоторые подводные камни. Дайте мне знать, если вы добьетесь прогресса в этом.

Привет, спасибо за отличный проект. Есть ли прогресс в этом вопросе? Был ли разработан плагин/функция? В частности, я имею в виду «возможность установить размер холста для ограничивающего div». Спасибо.

Я думаю, что это достойная функция, но для справки после построения графика вы можете использовать d3, чтобы сделать фигуру автомасштабируемой (здесь с высотой окна)

fetch("d3/" + figure + ".json")
    .then((response) => response.json())
    .then((data) => mpld3.draw_figure(figure, data))
    .then(() => {
        d3.select("#" + figure)
            .selectAll(".mpld3-figure")
            .attr("width", "100%")
            .attr("height", "70vh")
            .attr("viewBox", "0 0 1200 800")
            .attr("preserveAspectRatio", "xMinYMin meet");
    });

Здесь я предложу @hadim и @carlinmack использовать viewBox . На самом деле это может быть очень просто. Например, если у вас в настоящее время есть <svg width="1200" height="800"> , попробуйте вместо этого <svg viewBox="0 0 1200 800"> . Вот и все. viewBox определяет систему координат внутри svg, а параметры width и height становятся необязательными и определяют внешние размеры, как и любой другой элемент. Вы также можете иметь width=100% или установить значение напрямую через css (ширина и высота, поскольку css имеют приоритет над атрибутами).

Я успешно использовал это с последней версией Chrome. Для получения подробностей следует изучить зависимость от разных браузеров, но я думаю, что суть ясна.

PS: на https://css-tricks.com/scale-svg есть справочная статья, но я нахожу это запутанным, когда описанный выше метод просто работает (по крайней мере, в современных браузерах) и концептуально прост: viewBox = "0 0 ${width} ${height}" для внутреннего кода, width=... и height=... в качестве атрибута svg или параметра css для повторного масштабирования, если это необходимо.

Да, это именно то, что предложил @carlinmack . Меня смутило «использовать d3 для автоматического масштабирования фигуры», так как это чистый HTML/CSS, но ладно, манипулирование DOM — это то, что делает d3. Я считаю, что «preserveAspectRatio», как указано @carlinmack , является значением по умолчанию (по крайней мере, это объясняется в ссылке css-tricks.com). Зачем указывать height="70vh" , если соотношение сторон все равно сохраняется? Это какая-то верхняя граница для очень узких и высоких фигур?

правильно, я не хотел, чтобы портретные фигуры были выше окна просмотра :)

За исключением того, что это делает фигуру больше, чем необходимо, не подходит, когда требуется плотное прилегание к окружающему содержимому. Использование max-height вместо этого работает для меня.

Вот как я заканчиваю загрузку рисунков mpld3 в браузере:

      let figureID = "id_12345" ; 
      let dataURL = figureID + ".json" ; 

      d3.json(dataURL).then( function(data) {
        mpld3.draw_figure(figureID, data);
        return data;
      }).then( function(data) {
        d3.select("#" + figureID)
          .selectAll(".mpld3-figure")
          .attr("width", null)   // remove "width" and "height" attributes as set by mpld3
          .attr("height", null)  
          .attr("viewBox", `0 0 ${data.width} ${data.height}`)
      });

Спасибо за обсуждение @carlinmack @perrette ! По совпадению, мы тоже только что столкнулись с этим, решение @dkong-idm было:

    const resizeChart = (viewBoxSettings) => {
        let svg = document.getElementsByClassName("mpld3-figure");

        if (svg && svg.length > 0) {
            svg[0].setAttribute("viewBox",viewBoxSettings );
            svg[0].setAttribute("width", "90vw");
            svg[0].setAttribute("height", "auto");
        }
    }

@vladh , было бы много работы, чтобы добавить эту функцию автоматического масштабирования в mpld3 либо в качестве необязательного аргумента в draw_figure , либо в качестве отдельной функции?

@cliffckerr Я определенно могу добавить это к draw_figure , возможно, в качестве аргумента, который принимает Object и устанавливает все атрибуты, указанные в этом объекте, в svg , чтобы вы могли передать что-то вроде {viewBox: ..., width: '90vw', height: 'auto'} .

Я хотел спросить вас и других в этой теме, считаете ли вы, что это нужно добавить где-нибудь еще, например, для поддержки fig_to_html() . Если это так, возможно, нам следует подумать о решении этой проблемы. В противном случае дайте мне знать, и я сразу же внесу изменения в draw_figure() .

@vladh Да, это также было бы очень полезно в fig_to_html() .

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

pranet picture pranet  ·  6Комментарии

edvakf picture edvakf  ·  29Комментарии

ajasja picture ajasja  ·  17Комментарии

andreatramacere picture andreatramacere  ·  8Комментарии

jakevdp picture jakevdp  ·  4Комментарии