Очень нравится пакет, большое спасибо, что поделились.
Это предлагаемое улучшение, но оно не совсем питоническое. Но опять же, d3js тоже нет :)
Замечательно, что установленный размер фигуры отражается на экране, но я думаю, что было бы «более отзывчиво» иметь возможность установить размер холста в ограничивающий div, а затем позволить этому размеру div определяться шириной браузера / чем угодно иначе хочет разработчик.
Стоит ли мне копаться в _js.py и _object.py, чтобы это заработало?
Я не совсем понимаю, о чем вы спрашиваете... Мы получаем размер фигуры в дюймах из фигуры 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()
.
Самый полезный комментарий
@cliffckerr Я определенно могу добавить это к
draw_figure
, возможно, в качестве аргумента, который принимаетObject
и устанавливает все атрибуты, указанные в этом объекте, вsvg
, чтобы вы могли передать что-то вроде{viewBox: ..., width: '90vw', height: 'auto'}
.Я хотел спросить вас и других в этой теме, считаете ли вы, что это нужно добавить где-нибудь еще, например, для поддержки
fig_to_html()
. Если это так, возможно, нам следует подумать о решении этой проблемы. В противном случае дайте мне знать, и я сразу же внесу изменения вdraw_figure()
.