',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:0,container:!1,fallbackPlacement:"flip",boundary:"scrollParent",sanitize:!0,sanitizeFn:null,whiteList:Ee},je="show",He="out",Re={HIDE:"hide"+De,HIDDEN:"hidden"+De,SHOW:"show"+De,SHOWN:"shown"+De,INSERTED:"inserted"+De,CLICK:"click"+De,FOCUSIN:"focusin"+De,FOCUSOUT:"focusout"+De,MOUSEENTER:"mouseenter"+De,MOUSELEAVE:"mouseleave"+De},xe="fade",Fe="show",Ue=".tooltip-inner",We=".arrow",qe="hover",Me="focus",Ke="click",Qe="manual",Be=function(){function i(t,e){if("undefined"==typeof u)throw new TypeError("Bootstrap's tooltips require Popper.js (https://popper.js.org/)");this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this.element=t,this.config=this._getConfig(e),this.tip=null,this._setListeners()}var t=i.prototype;return t.enable=function(){this._isEnabled=!0},t.disable=function(){this._isEnabled=!1},t.toggleEnabled=function(){this._isEnabled=!this._isEnabled},t.toggle=function(t){if(this._isEnabled)if(t){var e=this.constructor.DATA_KEY,n=g(t.currentTarget).data(e);n||(n=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(e,n)),n._activeTrigger.click=!n._activeTrigger.click,n._isWithActiveTrigger()?n._enter(null,n):n._leave(null,n)}else{if(g(this.getTipElement()).hasClass(Fe))return void this._leave(null,this);this._enter(null,this)}},t.dispose=function(){clearTimeout(this._timeout),g.removeData(this.element,this.constructor.DATA_KEY),g(this.element).off(this.constructor.EVENT_KEY),g(this.element).closest(".modal").off("hide.bs.modal"),this.tip&&g(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,(this._activeTrigger=null)!==this._popper&&this._popper.destroy(),this._popper=null,this.element=null,this.config=null,this.tip=null},t.show=function(){var e=this;if("none"===g(this.element).css("display"))throw new Error("Please use show on visible elements");var t=g.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){g(this.element).trigger(t);var n=_.findShadowRoot(this.element),i=g.contains(null!==n?n:this.element.ownerDocument.documentElement,this.element);if(t.isDefaultPrevented()||!i)return;var o=this.getTipElement(),r=_.getUID(this.constructor.NAME);o.setAttribute("id",r),this.element.setAttribute("aria-describedby",r),this.setContent(),this.config.animation&&g(o).addClass(xe);var s="function"==typeof this.config.placement?this.config.placement.call(this,o,this.element):this.config.placement,a=this._getAttachment(s);this.addAttachmentClass(a);var l=this._getContainer();g(o).data(this.constructor.DATA_KEY,this),g.contains(this.element.ownerDocument.documentElement,this.tip)||g(o).appendTo(l),g(this.element).trigger(this.constructor.Event.INSERTED),this._popper=new u(this.element,o,{placement:a,modifiers:{offset:this._getOffset(),flip:{behavior:this.config.fallbackPlacement},arrow:{element:We},preventOverflow:{boundariesElement:this.config.boundary}},onCreate:function(t){t.originalPlacement!==t.placement&&e._handlePopperPlacementChange(t)},onUpdate:function(t){return e._handlePopperPlacementChange(t)}}),g(o).addClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().on("mouseover",null,g.noop);var c=function(){e.config.animation&&e._fixTransition();var t=e._hoverState;e._hoverState=null,g(e.element).trigger(e.constructor.Event.SHOWN),t===He&&e._leave(null,e)};if(g(this.tip).hasClass(xe)){var h=_.getTransitionDurationFromElement(this.tip);g(this.tip).one(_.TRANSITION_END,c).emulateTransitionEnd(h)}else c()}},t.hide=function(t){var e=this,n=this.getTipElement(),i=g.Event(this.constructor.Event.HIDE),o=function(){e._hoverState!==je&&n.parentNode&&n.parentNode.removeChild(n),e._cleanTipClass(),e.element.removeAttribute("aria-describedby"),g(e.element).trigger(e.constructor.Event.HIDDEN),null!==e._popper&&e._popper.destroy(),t&&t()};if(g(this.element).trigger(i),!i.isDefaultPrevented()){if(g(n).removeClass(Fe),"ontouchstart"in document.documentElement&&g(document.body).children().off("mouseover",null,g.noop),this._activeTrigger[Ke]=!1,this._activeTrigger[Me]=!1,this._activeTrigger[qe]=!1,g(this.tip).hasClass(xe)){var r=_.getTransitionDurationFromElement(n);g(n).one(_.TRANSITION_END,o).emulateTransitionEnd(r)}else o();this._hoverState=""}},t.update=function(){null!==this._popper&&this._popper.scheduleUpdate()},t.isWithContent=function(){return Boolean(this.getTitle())},t.addAttachmentClass=function(t){g(this.getTipElement()).addClass(Ae+"-"+t)},t.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},t.setContent=function(){var t=this.getTipElement();this.setElementContent(g(t.querySelectorAll(Ue)),this.getTitle()),g(t).removeClass(xe+" "+Fe)},t.setElementContent=function(t,e){"object"!=typeof e||!e.nodeType&&!e.jquery?this.config.html?(this.config.sanitize&&(e=Se(e,this.config.whiteList,this.config.sanitizeFn)),t.html(e)):t.text(e):this.config.html?g(e).parent().is(t)||t.empty().append(e):t.text(g(e).text())},t.getTitle=function(){var t=this.element.getAttribute("data-original-title");return t||(t="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),t},t._getOffset=function(){var e=this,t={};return"function"==typeof this.config.offset?t.fn=function(t){return t.offsets=l({},t.offsets,e.config.offset(t.offsets,e.element)||{}),t}:t.offset=this.config.offset,t},t._getContainer=function(){return!1===this.config.container?document.body:_.isElement(this.config.container)?g(this.config.container):g(document).find(this.config.container)},t._getAttachment=function(t){return Pe[t.toUpperCase()]},t._setListeners=function(){var i=this;this.config.trigger.split(" ").forEach(function(t){if("click"===t)g(i.element).on(i.constructor.Event.CLICK,i.config.selector,function(t){return i.toggle(t)});else if(t!==Qe){var e=t===qe?i.constructor.Event.MOUSEENTER:i.constructor.Event.FOCUSIN,n=t===qe?i.constructor.Event.MOUSELEAVE:i.constructor.Event.FOCUSOUT;g(i.element).on(e,i.config.selector,function(t){return i._enter(t)}).on(n,i.config.selector,function(t){return i._leave(t)})}}),g(this.element).closest(".modal").on("hide.bs.modal",function(){i.element&&i.hide()}),this.config.selector?this.config=l({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},t._fixTitle=function(){var t=typeof this.element.getAttribute("data-original-title");(this.element.getAttribute("title")||"string"!==t)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},t._enter=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusin"===t.type?Me:qe]=!0),g(e.getTipElement()).hasClass(Fe)||e._hoverState===je?e._hoverState=je:(clearTimeout(e._timeout),e._hoverState=je,e.config.delay&&e.config.delay.show?e._timeout=setTimeout(function(){e._hoverState===je&&e.show()},e.config.delay.show):e.show())},t._leave=function(t,e){var n=this.constructor.DATA_KEY;(e=e||g(t.currentTarget).data(n))||(e=new this.constructor(t.currentTarget,this._getDelegateConfig()),g(t.currentTarget).data(n,e)),t&&(e._activeTrigger["focusout"===t.type?Me:qe]=!1),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=He,e.config.delay&&e.config.delay.hide?e._timeout=setTimeout(function(){e._hoverState===He&&e.hide()},e.config.delay.hide):e.hide())},t._isWithActiveTrigger=function(){for(var t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1},t._getConfig=function(t){var e=g(this.element).data();return Object.keys(e).forEach(function(t){-1!==Oe.indexOf(t)&&delete e[t]}),"number"==typeof(t=l({},this.constructor.Default,e,"object"==typeof t&&t?t:{})).delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),_.typeCheckConfig(be,t,this.constructor.DefaultType),t.sanitize&&(t.template=Se(t.template,t.whiteList,t.sanitizeFn)),t},t._getDelegateConfig=function(){var t={};if(this.config)for(var e in this.config)this.constructor.Default[e]!==this.config[e]&&(t[e]=this.config[e]);return t},t._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ne);null!==e&&e.length&&t.removeClass(e.join(""))},t._handlePopperPlacementChange=function(t){var e=t.instance;this.tip=e.popper,this._cleanTipClass(),this.addAttachmentClass(this._getAttachment(t.placement))},t._fixTransition=function(){var t=this.getTipElement(),e=this.config.animation;null===t.getAttribute("x-placement")&&(g(t).removeClass(xe),this.config.animation=!1,this.hide(),this.show(),this.config.animation=e)},i._jQueryInterface=function(n){return this.each(function(){var t=g(this).data(Ie),e="object"==typeof n&&n;if((t||!/dispose|hide/.test(n))&&(t||(t=new i(this,e),g(this).data(Ie,t)),"string"==typeof n)){if("undefined"==typeof t[n])throw new TypeError('No method named "'+n+'"');t[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"Default",get:function(){return Le}},{key:"NAME",get:function(){return be}},{key:"DATA_KEY",get:function(){return Ie}},{key:"Event",get:function(){return Re}},{key:"EVENT_KEY",get:function(){return De}},{key:"DefaultType",get:function(){return ke}}]),i}();g.fn[be]=Be._jQueryInterface,g.fn[be].Constructor=Be,g.fn[be].noConflict=function(){return g.fn[be]=we,Be._jQueryInterface};var Ve="popover",Ye="bs.popover",ze="."+Ye,Xe=g.fn[Ve],$e="bs-popover",Ge=new RegExp("(^|\\s)"+$e+"\\S+","g"),Je=l({},Be.Default,{placement:"right",trigger:"click",content:"",template:'
'}),Ze=l({},Be.DefaultType,{content:"(string|element|function)"}),tn="fade",en="show",nn=".popover-header",on=".popover-body",rn={HIDE:"hide"+ze,HIDDEN:"hidden"+ze,SHOW:"show"+ze,SHOWN:"shown"+ze,INSERTED:"inserted"+ze,CLICK:"click"+ze,FOCUSIN:"focusin"+ze,FOCUSOUT:"focusout"+ze,MOUSEENTER:"mouseenter"+ze,MOUSELEAVE:"mouseleave"+ze},sn=function(t){var e,n;function i(){return t.apply(this,arguments)||this}n=t,(e=i).prototype=Object.create(n.prototype),(e.prototype.constructor=e).__proto__=n;var o=i.prototype;return o.isWithContent=function(){return this.getTitle()||this._getContent()},o.addAttachmentClass=function(t){g(this.getTipElement()).addClass($e+"-"+t)},o.getTipElement=function(){return this.tip=this.tip||g(this.config.template)[0],this.tip},o.setContent=function(){var t=g(this.getTipElement());this.setElementContent(t.find(nn),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(on),e),t.removeClass(tn+" "+en)},o._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},o._cleanTipClass=function(){var t=g(this.getTipElement()),e=t.attr("class").match(Ge);null!==e&&0
=this._offsets[o]&&("undefined"==typeof this._offsets[o+1]||t li > .active",Wn='[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]',qn=".dropdown-toggle",Mn="> .dropdown-menu .active",Kn=function(){function i(t){this._element=t}var t=i.prototype;return t.show=function(){var n=this;if(!(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&g(this._element).hasClass(Pn)||g(this._element).hasClass(Ln))){var t,i,e=g(this._element).closest(xn)[0],o=_.getSelectorFromElement(this._element);if(e){var r="UL"===e.nodeName||"OL"===e.nodeName?Un:Fn;i=(i=g.makeArray(g(e).find(r)))[i.length-1]}var s=g.Event(On.HIDE,{relatedTarget:this._element}),a=g.Event(On.SHOW,{relatedTarget:i});if(i&&g(i).trigger(s),g(this._element).trigger(a),!a.isDefaultPrevented()&&!s.isDefaultPrevented()){o&&(t=document.querySelector(o)),this._activate(this._element,e);var l=function(){var t=g.Event(On.HIDDEN,{relatedTarget:n._element}),e=g.Event(On.SHOWN,{relatedTarget:i});g(i).trigger(t),g(n._element).trigger(e)};t?this._activate(t,t.parentNode,l):l()}}},t.dispose=function(){g.removeData(this._element,wn),this._element=null},t._activate=function(t,e,n){var i=this,o=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?g(e).children(Fn):g(e).find(Un))[0],r=n&&o&&g(o).hasClass(jn),s=function(){return i._transitionComplete(t,o,n)};if(o&&r){var a=_.getTransitionDurationFromElement(o);g(o).removeClass(Hn).one(_.TRANSITION_END,s).emulateTransitionEnd(a)}else s()},t._transitionComplete=function(t,e,n){if(e){g(e).removeClass(Pn);var i=g(e.parentNode).find(Mn)[0];i&&g(i).removeClass(Pn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}if(g(t).addClass(Pn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),_.reflow(t),t.classList.contains(jn)&&t.classList.add(Hn),t.parentNode&&g(t.parentNode).hasClass(kn)){var o=g(t).closest(Rn)[0];if(o){var r=[].slice.call(o.querySelectorAll(qn));g(r).addClass(Pn)}t.setAttribute("aria-expanded",!0)}n&&n()},i._jQueryInterface=function(n){return this.each(function(){var t=g(this),e=t.data(wn);if(e||(e=new i(this),t.data(wn,e)),"string"==typeof n){if("undefined"==typeof e[n])throw new TypeError('No method named "'+n+'"');e[n]()}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}}]),i}();g(document).on(On.CLICK_DATA_API,Wn,function(t){t.preventDefault(),Kn._jQueryInterface.call(g(this),"show")}),g.fn.tab=Kn._jQueryInterface,g.fn.tab.Constructor=Kn,g.fn.tab.noConflict=function(){return g.fn.tab=Nn,Kn._jQueryInterface};var Qn="toast",Bn="bs.toast",Vn="."+Bn,Yn=g.fn[Qn],zn={CLICK_DISMISS:"click.dismiss"+Vn,HIDE:"hide"+Vn,HIDDEN:"hidden"+Vn,SHOW:"show"+Vn,SHOWN:"shown"+Vn},Xn="fade",$n="hide",Gn="show",Jn="showing",Zn={animation:"boolean",autohide:"boolean",delay:"number"},ti={animation:!0,autohide:!0,delay:500},ei='[data-dismiss="toast"]',ni=function(){function i(t,e){this._element=t,this._config=this._getConfig(e),this._timeout=null,this._setListeners()}var t=i.prototype;return t.show=function(){var t=this;g(this._element).trigger(zn.SHOW),this._config.animation&&this._element.classList.add(Xn);var e=function(){t._element.classList.remove(Jn),t._element.classList.add(Gn),g(t._element).trigger(zn.SHOWN),t._config.autohide&&t.hide()};if(this._element.classList.remove($n),this._element.classList.add(Jn),this._config.animation){var n=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},t.hide=function(t){var e=this;this._element.classList.contains(Gn)&&(g(this._element).trigger(zn.HIDE),t?this._close():this._timeout=setTimeout(function(){e._close()},this._config.delay))},t.dispose=function(){clearTimeout(this._timeout),this._timeout=null,this._element.classList.contains(Gn)&&this._element.classList.remove(Gn),g(this._element).off(zn.CLICK_DISMISS),g.removeData(this._element,Bn),this._element=null,this._config=null},t._getConfig=function(t){return t=l({},ti,g(this._element).data(),"object"==typeof t&&t?t:{}),_.typeCheckConfig(Qn,t,this.constructor.DefaultType),t},t._setListeners=function(){var t=this;g(this._element).on(zn.CLICK_DISMISS,ei,function(){return t.hide(!0)})},t._close=function(){var t=this,e=function(){t._element.classList.add($n),g(t._element).trigger(zn.HIDDEN)};if(this._element.classList.remove(Gn),this._config.animation){var n=_.getTransitionDurationFromElement(this._element);g(this._element).one(_.TRANSITION_END,e).emulateTransitionEnd(n)}else e()},i._jQueryInterface=function(n){return this.each(function(){var t=g(this),e=t.data(Bn);if(e||(e=new i(this,"object"==typeof n&&n),t.data(Bn,e)),"string"==typeof n){if("undefined"==typeof e[n])throw new TypeError('No method named "'+n+'"');e[n](this)}})},s(i,null,[{key:"VERSION",get:function(){return"4.3.1"}},{key:"DefaultType",get:function(){return Zn}},{key:"Default",get:function(){return ti}}]),i}();g.fn[Qn]=ni._jQueryInterface,g.fn[Qn].Constructor=ni,g.fn[Qn].noConflict=function(){return g.fn[Qn]=Yn,ni._jQueryInterface},function(){if("undefined"==typeof g)throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");var t=g.fn.jquery.split(" ")[0].split(".");if(t[0]<2&&t[1]<9||1===t[0]&&9===t[1]&&t[2]<1||4<=t[0])throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(),t.Util=_,t.Alert=p,t.Button=P,t.Carousel=lt,t.Collapse=bt,t.Dropdown=Jt,t.Modal=ve,t.Popover=sn,t.Scrollspy=Dn,t.Tab=Kn,t.Toast=ni,t.Tooltip=Be,Object.defineProperty(t,"__esModule",{value:!0})});
-//# sourceMappingURL=bootstrap.min.js.map
diff --git a/js/html5shiv.min.js b/js/html5shiv.min.js
new file mode 100644
index 0000000..1a01c94
--- /dev/null
+++ b/js/html5shiv.min.js
@@ -0,0 +1,4 @@
+/**
+* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+*/
+!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);
diff --git a/js/theme.js b/js/theme.js
new file mode 100644
index 0000000..9299d96
--- /dev/null
+++ b/js/theme.js
@@ -0,0 +1,2 @@
+/* sphinx_rtd_theme version 1.0.0 | MIT license */
+!function(n){var e={};function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:i})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var i=Object.create(null);if(t.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var o in n)t.d(i,o,function(e){return n[e]}.bind(null,o));return i},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=0)}([function(n,e,t){t(1),n.exports=t(3)},function(n,e,t){(function(){var e="undefined"!=typeof window?window.jQuery:t(2);n.exports.ThemeNav={navBar:null,win:null,winScroll:!1,winResize:!1,linkScroll:!1,winPosition:0,winHeight:null,docHeight:null,isRunning:!1,enable:function(n){var t=this;void 0===n&&(n=!0),t.isRunning||(t.isRunning=!0,e((function(e){t.init(e),t.reset(),t.win.on("hashchange",t.reset),n&&t.win.on("scroll",(function(){t.linkScroll||t.winScroll||(t.winScroll=!0,requestAnimationFrame((function(){t.onScroll()})))})),t.win.on("resize",(function(){t.winResize||(t.winResize=!0,requestAnimationFrame((function(){t.onResize()})))})),t.onResize()})))},enableSticky:function(){this.enable(!0)},init:function(n){n(document);var e=this;this.navBar=n("div.wy-side-scroll:first"),this.win=n(window),n(document).on("click","[data-toggle='wy-nav-top']",(function(){n("[data-toggle='wy-nav-shift']").toggleClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift")})).on("click",".wy-menu-vertical .current ul li a",(function(){var t=n(this);n("[data-toggle='wy-nav-shift']").removeClass("shift"),n("[data-toggle='rst-versions']").toggleClass("shift"),e.toggleCurrent(t),e.hashChange()})).on("click","[data-toggle='rst-current-version']",(function(){n("[data-toggle='rst-versions']").toggleClass("shift-up")})),n("table.docutils:not(.field-list,.footnote,.citation)").wrap(""),n("table.docutils.footnote").wrap(""),n("table.docutils.citation").wrap(""),n(".wy-menu-vertical ul").not(".simple").siblings("a").each((function(){var t=n(this);expand=n(''),expand.on("click",(function(n){return e.toggleCurrent(t),n.stopPropagation(),!1})),t.prepend(expand)}))},reset:function(){var n=encodeURI(window.location.hash)||"#";try{var e=$(".wy-menu-vertical"),t=e.find('[href="'+n+'"]');if(0===t.length){var i=$('.document [id="'+n.substring(1)+'"]').closest("div.section");0===(t=e.find('[href="#'+i.attr("id")+'"]')).length&&(t=e.find('[href="#"]'))}if(t.length>0){$(".wy-menu-vertical .current").removeClass("current").attr("aria-expanded","false"),t.addClass("current").attr("aria-expanded","true"),t.closest("li.toctree-l1").parent().addClass("current").attr("aria-expanded","true");for(let n=1;n<=10;n++)t.closest("li.toctree-l"+n).addClass("current").attr("aria-expanded","true");t[0].scrollIntoView()}}catch(n){console.log("Error expanding nav for anchor",n)}},onScroll:function(){this.winScroll=!1;var n=this.win.scrollTop(),e=n+this.winHeight,t=this.navBar.scrollTop()+(n-this.winPosition);n<0||e>this.docHeight||(this.navBar.scrollTop(t),this.winPosition=n)},onResize:function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},hashChange:function(){this.linkScroll=!0,this.win.one("hashchange",(function(){this.linkScroll=!1}))},toggleCurrent:function(n){var e=n.closest("li");e.siblings("li.current").removeClass("current").attr("aria-expanded","false"),e.siblings().find("li.current").removeClass("current").attr("aria-expanded","false");var t=e.find("> ul li");t.length&&(t.removeClass("current").attr("aria-expanded","false"),e.toggleClass("current").attr("aria-expanded",(function(n,e){return"true"==e?"false":"true"})))}},"undefined"!=typeof window&&(window.SphinxRtdTheme={Navigation:n.exports.ThemeNav,StickyNav:n.exports.ThemeNav}),function(){for(var n=0,e=["ms","moz","webkit","o"],t=0;t
+
+
+
+
+
+
+ Drawpyo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Search Results
+
+
+
+
+ Searching...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/search/search_index.json b/search/search_index.json
index b6d9385..3eac920 100644
--- a/search/search_index.json
+++ b/search/search_index.json
@@ -1 +1 @@
-{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Welcome to drawpyo Drawpyo is a Python library for programmatically generating Diagrams.net/Draw.io charts. It enables creating a diagram object, placing and styling objects, then writing the object to a file.","title":"Home"},{"location":"#welcome-to-drawpyo","text":"Drawpyo is a Python library for programmatically generating Diagrams.net/Draw.io charts. It enables creating a diagram object, placing and styling objects, then writing the object to a file.","title":"Welcome to drawpyo"},{"location":"about/","text":"History/Justification I love Draw.io! Compared to expensive and heavy commercial options like Visio and Miro, Draw.io's free and lightweight app allows wider and more universal distribution of diagrams. Because the files are stored in plaintext they can be versioned alongside code in a repository as documentation. The XML-based file format makes these diagrams semi-portable, and could easily be ported to other applications if Draw.io ever failed you. For these reason, I think it's one of the best options for documentation diagrams. When I had a need to generate heirarchical tree diagrams of requirement structures I was surprised to find there wasn't even a single existing Python library for working with these files. I took the project home and spent a weekend building the initial functionality. I've been adding functionality, robustness, and documentation intermittently since.","title":"About"},{"location":"about/#historyjustification","text":"I love Draw.io! Compared to expensive and heavy commercial options like Visio and Miro, Draw.io's free and lightweight app allows wider and more universal distribution of diagrams. Because the files are stored in plaintext they can be versioned alongside code in a repository as documentation. The XML-based file format makes these diagrams semi-portable, and could easily be ported to other applications if Draw.io ever failed you. For these reason, I think it's one of the best options for documentation diagrams. When I had a need to generate heirarchical tree diagrams of requirement structures I was surprised to find there wasn't even a single existing Python library for working with these files. I took the project home and spent a weekend building the initial functionality. I've been adding functionality, robustness, and documentation intermittently since.","title":"History/Justification"}]}
\ No newline at end of file
+{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Welcome to drawpyo Drawpyo is a Python library for programmatically generating Draw.io charts. It enables creating a diagram object, placing and styling objects, then writing the object to a file. History/Justification I love Draw.io! Compared to expensive and heavy commercial options like Visio and Miro, Draw.io's free and lightweight app allows wider and more universal distribution of diagrams. Because the files are stored in plaintext they can be versioned alongside code in a repository as documentation. Draw.io also maintains back compatibility and any diagram created in the app since it was launched can still be opened. The XML-based file format makes these diagrams semi-portable, and could easily be ported to other applications if Draw.io ever disappeared. For these reason, I think it's one of the best options for documentation diagrams. So wen I had a need to generate heirarchical tree diagrams of requirement structures I looked to Draw.io but I was surprised to find there wasn't even a single existing Python library for working with these files. I took the project home and spent a weekend building the initial functionality. I've been adding functionality, robustness, and documentation intermittently since. The Future of Drawpyo I will continue to tinker away with this tool, creating new functionality as I need it or find it interesting. But it's unfortunately a rather low priority so if anyone wants to contribute I would be grateful for the help! Reach out to me at xander@merriman.industries if you want to contribute.","title":"Home"},{"location":"#welcome-to-drawpyo","text":"Drawpyo is a Python library for programmatically generating Draw.io charts. It enables creating a diagram object, placing and styling objects, then writing the object to a file.","title":"Welcome to drawpyo"},{"location":"#historyjustification","text":"I love Draw.io! Compared to expensive and heavy commercial options like Visio and Miro, Draw.io's free and lightweight app allows wider and more universal distribution of diagrams. Because the files are stored in plaintext they can be versioned alongside code in a repository as documentation. Draw.io also maintains back compatibility and any diagram created in the app since it was launched can still be opened. The XML-based file format makes these diagrams semi-portable, and could easily be ported to other applications if Draw.io ever disappeared. For these reason, I think it's one of the best options for documentation diagrams. So wen I had a need to generate heirarchical tree diagrams of requirement structures I looked to Draw.io but I was surprised to find there wasn't even a single existing Python library for working with these files. I took the project home and spent a weekend building the initial functionality. I've been adding functionality, robustness, and documentation intermittently since.","title":"History/Justification"},{"location":"#the-future-of-drawpyo","text":"I will continue to tinker away with this tool, creating new functionality as I need it or find it interesting. But it's unfortunately a rather low priority so if anyone wants to contribute I would be grateful for the help! Reach out to me at xander@merriman.industries if you want to contribute.","title":"The Future of Drawpyo"},{"location":"about/","text":"Conventions and Naming This library contains quite a lot of camel case (capitalizeEachWord) attributes. While the Python convention is snake case (underscores_between_lowercase) the Draw.io style strings and attributes are camel case. Wherever possible, drawpyo uses the terminology and variable names from Draw.io to make it more intuitive to work between the two apps. However, any attribute that does not have an analogy in the Draw.io app is snake case. While this is a bit confusing I hope it helps to clarify when there's a direct analog between drawpyo and Draw.io and when the variable is a drawpyo abstraction. If this is confusing please share that feedback on the GitHub page or email and it may be changed in future versions! Basic Diagrams Drawpyo's basic functionality provides the same features as using the Draw.io app. You can create files with one or more pages, add objects to them, and position those objects. You can style objects from built-in shape libraries, manually, or from style strings. Those objects can be shapes, containers, or edges to connect them. Finally you can save your diagrams where they can be opened with the Draw.io app. See the full documentation for these functions in Basic Diagrams - Usage . Extended Functionality Drawpyo extends the basic functionality of the Draw.io app with custom diagram types. These custom diagrams have automated styling and layouting to make common or complex diagrams easier to generate. TreeDiagram This diagram makes creating directed tree graphs easy. Define trees, nodes, and the apply an auto layout. Documentation","title":"About"},{"location":"about/#conventions-and-naming","text":"This library contains quite a lot of camel case (capitalizeEachWord) attributes. While the Python convention is snake case (underscores_between_lowercase) the Draw.io style strings and attributes are camel case. Wherever possible, drawpyo uses the terminology and variable names from Draw.io to make it more intuitive to work between the two apps. However, any attribute that does not have an analogy in the Draw.io app is snake case. While this is a bit confusing I hope it helps to clarify when there's a direct analog between drawpyo and Draw.io and when the variable is a drawpyo abstraction. If this is confusing please share that feedback on the GitHub page or email and it may be changed in future versions!","title":"Conventions and Naming"},{"location":"about/#basic-diagrams","text":"Drawpyo's basic functionality provides the same features as using the Draw.io app. You can create files with one or more pages, add objects to them, and position those objects. You can style objects from built-in shape libraries, manually, or from style strings. Those objects can be shapes, containers, or edges to connect them. Finally you can save your diagrams where they can be opened with the Draw.io app. See the full documentation for these functions in Basic Diagrams - Usage .","title":"Basic Diagrams"},{"location":"about/#extended-functionality","text":"Drawpyo extends the basic functionality of the Draw.io app with custom diagram types. These custom diagrams have automated styling and layouting to make common or complex diagrams easier to generate.","title":"Extended Functionality"},{"location":"about/#treediagram","text":"This diagram makes creating directed tree graphs easy. Define trees, nodes, and the apply an auto layout. Documentation","title":"TreeDiagram"},{"location":"diagram_types/tree_diagrams/","text":"Tree Diagrams These very useful diagram types are why drawpyo was written initially! The TreeDiagram module allows the easy creation of heirarchical directed trees, managing the parent and children relationships, then providing a convenient auto layout function. Create a Tree The two main objects to work with in drawpyo's trees are TreeDiagrams and LeafObjects. To start, create a TreeDiagram: import drawpyo.diagram_types import TreeDiagram tree = TreeDiagram( file_path = 'path/to/tree', file_name = 'Tree Name.drawio', ) There are a number of configuration parameters available to fine tune the layout of the TreeDiagram. They can be passed in during initialization or later. Parameter Effect Default direction direction that the tree grows from the root ('up', 'down', 'left', 'right') 'down' link_style Connection style of the edges ('orthogonal', 'straight', 'curved') 'orthogonal' level_spacing Spacing in pixels between levels 60 item_spacing Spacing in pixels between groups within a level 15 padding Spacing in pixels between objects within a group 10 Add Nodes The custom object type that defines the nodes on the tree are called LeafObjects. Create some LeafObjects: from drawpyo.diagram_types import LeafObject # Top object grinders = LeafObject(tree=tree, value=\"Appliances for Grinding Coffee\", base_style=\"rounded rectangle\") # Main categories blade_grinders = LeafObject(tree=tree, value=\"Blade Grinders\", trunk=grinders) burr_grinders = LeafObject(tree=tree, value=\"Burr Grinders\", trunk=grinders) blunt_objects = LeafObject(tree=tree, value=\"Blunt Objects\", trunk=grinders) Note that the base_style was manually declared for the first object. But LeafObjects will default to \"rounded rectangle\" so it's not necessary for every one. Any LeafObject can be a parent, so you can keep adding objects down the tree: # Other elec_blade = LeafObject(tree=tree, value=\"Electric Blade Grinder\", trunk=blade_grinders) mnp = LeafObject(tree=tree, value=\"Mortar and Pestle\", trunk=blunt_objects) # Conical Burrs conical = LeafObject(tree=tree, value=\"Conical Burrs\", trunk=burr_grinders) elec_conical = LeafObject(tree=tree, value=\"Electric\", trunk=conical) manual_conical = LeafObject(tree=tree, value=\"Manual\", trunk=conical) Important Note: TreeDiagrams do not currently support LeafObjects with multiple parents! It may not ever as this seriously complicates the auto layout process. However, you can add links between any two objects in the tree and render them in the diagram. They just may look ugly until you manually rearrange the diagram. Finally, before writing the diagram you'll want to run the magic penultimate step: auto layout. tree.auto_layout() tree.write()","title":"Tree Diagrams"},{"location":"diagram_types/tree_diagrams/#tree-diagrams","text":"These very useful diagram types are why drawpyo was written initially! The TreeDiagram module allows the easy creation of heirarchical directed trees, managing the parent and children relationships, then providing a convenient auto layout function.","title":"Tree Diagrams"},{"location":"diagram_types/tree_diagrams/#create-a-tree","text":"The two main objects to work with in drawpyo's trees are TreeDiagrams and LeafObjects. To start, create a TreeDiagram: import drawpyo.diagram_types import TreeDiagram tree = TreeDiagram( file_path = 'path/to/tree', file_name = 'Tree Name.drawio', ) There are a number of configuration parameters available to fine tune the layout of the TreeDiagram. They can be passed in during initialization or later. Parameter Effect Default direction direction that the tree grows from the root ('up', 'down', 'left', 'right') 'down' link_style Connection style of the edges ('orthogonal', 'straight', 'curved') 'orthogonal' level_spacing Spacing in pixels between levels 60 item_spacing Spacing in pixels between groups within a level 15 padding Spacing in pixels between objects within a group 10","title":"Create a Tree"},{"location":"diagram_types/tree_diagrams/#add-nodes","text":"The custom object type that defines the nodes on the tree are called LeafObjects. Create some LeafObjects: from drawpyo.diagram_types import LeafObject # Top object grinders = LeafObject(tree=tree, value=\"Appliances for Grinding Coffee\", base_style=\"rounded rectangle\") # Main categories blade_grinders = LeafObject(tree=tree, value=\"Blade Grinders\", trunk=grinders) burr_grinders = LeafObject(tree=tree, value=\"Burr Grinders\", trunk=grinders) blunt_objects = LeafObject(tree=tree, value=\"Blunt Objects\", trunk=grinders) Note that the base_style was manually declared for the first object. But LeafObjects will default to \"rounded rectangle\" so it's not necessary for every one. Any LeafObject can be a parent, so you can keep adding objects down the tree: # Other elec_blade = LeafObject(tree=tree, value=\"Electric Blade Grinder\", trunk=blade_grinders) mnp = LeafObject(tree=tree, value=\"Mortar and Pestle\", trunk=blunt_objects) # Conical Burrs conical = LeafObject(tree=tree, value=\"Conical Burrs\", trunk=burr_grinders) elec_conical = LeafObject(tree=tree, value=\"Electric\", trunk=conical) manual_conical = LeafObject(tree=tree, value=\"Manual\", trunk=conical) Important Note: TreeDiagrams do not currently support LeafObjects with multiple parents! It may not ever as this seriously complicates the auto layout process. However, you can add links between any two objects in the tree and render them in the diagram. They just may look ugly until you manually rearrange the diagram. Finally, before writing the diagram you'll want to run the magic penultimate step: auto layout. tree.auto_layout() tree.write()","title":"Add Nodes"},{"location":"usage/basic_usage/","text":"Basic Functionality Drawpyo's basic functionality provides the same features as using the Draw.io app. You can create files with one or more pages, add objects to them, and position those objects. You can style objects from built-in shape libraries, manually, or from style strings. Those objects can be shapes, containers, or edges to connect them. Finally you can save your diagrams where they can be opened with the Draw.io app. Files Make a new file A File object represents a Draw.io file. If no file_path is set the default path will be 'user/Drawpyo Charts' where 'user' will be an OS-specific user home folder. diagram = drawpyo.File() file.file_path = r\"C:\\drawpyo\" file.file_name = \"Test Generated Edges.drawio\" Write a file Files can be written simply with the write() function. This function takes a few parameters to make it more flexible: | Parameter | Setting | | - | - | | file_path | This will overwrite the previously set file_path. | | file_name | This will overwrite the previously set file_name. Like file_path, useful in creating multiple copies of a diagram with slight variations | | overwrite | This boolean parameter controls whether an existing diagram should be overwritten or not. | Pages Add a page The Page object represents the different diagram pages that you can create in Draw.io. A Page can be created without linking it to a File but it won't be writable without a File object. # Add a page page = drawpy.Page(file=file) Page Parameters There are a number of customizable parameter for pages: argument description width Width of the document in pixels height Height of the document in pixels grid Enable grid (0 or 1) grid_size Side of grid squares in pixels guides Enable guides (0 or 1) tooltips Enable tooltips (0 or 1) scale Scale of the drawing","title":"Usage"},{"location":"usage/basic_usage/#basic-functionality","text":"Drawpyo's basic functionality provides the same features as using the Draw.io app. You can create files with one or more pages, add objects to them, and position those objects. You can style objects from built-in shape libraries, manually, or from style strings. Those objects can be shapes, containers, or edges to connect them. Finally you can save your diagrams where they can be opened with the Draw.io app.","title":"Basic Functionality"},{"location":"usage/basic_usage/#files","text":"","title":"Files"},{"location":"usage/basic_usage/#make-a-new-file","text":"A File object represents a Draw.io file. If no file_path is set the default path will be 'user/Drawpyo Charts' where 'user' will be an OS-specific user home folder. diagram = drawpyo.File() file.file_path = r\"C:\\drawpyo\" file.file_name = \"Test Generated Edges.drawio\"","title":"Make a new file"},{"location":"usage/basic_usage/#write-a-file","text":"Files can be written simply with the write() function. This function takes a few parameters to make it more flexible: | Parameter | Setting | | - | - | | file_path | This will overwrite the previously set file_path. | | file_name | This will overwrite the previously set file_name. Like file_path, useful in creating multiple copies of a diagram with slight variations | | overwrite | This boolean parameter controls whether an existing diagram should be overwritten or not. |","title":"Write a file"},{"location":"usage/basic_usage/#pages","text":"","title":"Pages"},{"location":"usage/basic_usage/#add-a-page","text":"The Page object represents the different diagram pages that you can create in Draw.io. A Page can be created without linking it to a File but it won't be writable without a File object. # Add a page page = drawpy.Page(file=file)","title":"Add a page"},{"location":"usage/basic_usage/#page-parameters","text":"There are a number of customizable parameter for pages: argument description width Width of the document in pixels height Height of the document in pixels grid Enable grid (0 or 1) grid_size Side of grid squares in pixels guides Enable guides (0 or 1) tooltips Enable tooltips (0 or 1) scale Scale of the drawing","title":"Page Parameters"},{"location":"usage/edges/","text":"Edges Edges are the lines and arrows that connect objects in Draw.io. There's quite a bit of variabiability in how they're created and styled so there's a bit more complexity than with objects. Creating a basic edge Like objects, there's a BasicEdge object that can be easily created: link = drawpyo.diagram.BasicEdge( page=page, source=item_1, target=item_2, ) Edge Geometry Besides the source and target, the edge geometry can be very finely tuned. There are eight parameters that control where and how the edge meets the source and target objects: Parameter Definition entryX From where along the X axis on the source object the edge originates (0-1) entryY From where along the Y axis on the source object the edge originates (0-1) entryDx Applies an offset in pixels to the X axis entry point entryDy Applies an offset in pixels to the Y axis entry point exitX From where along the X axis on the target object the edge originates (0-1) exitY From where along the Y axis on the target object the edge originates (0-1) exitDx Applies an offset in pixels to the X axis exit point exitDy Applies an offset in pixels to the Y axis exit point If these parameters are set to None then the Draw.io rendering engine will place the origination and direction of the edge wherever makes the most sense based on the layout of the objects. This is the same as the behavior in the app when an edge is dragged to the center of a shape (highlighting the whole object green) instead of to a specific node on the border (and seeing just that node highlighted in green). Other attributes for controlling the general shape of the object are: Parameter Definition rounded Sets whether the corners of a line are set to sharp or rounded off (0-1) jettySize Defines the length of the straight line coming out of or into an object before the edge makes its first turn Styling edges Just about every edge styling option from the Draw.io app is implemented in Drawpyo. It's easiest to just play with all of the different line styling options in Draw.io to understand how they render but the major options are listed here. Waypoints The waypoint parameter controls how the line is routed from the source to the target. For example, a straight line is just point to point. A curved line tries to maintain gentle curves and perpendicularity to the source and target objects. Options are: Parameter Rendered straight orthogonal vertical horizontal isometric isometric_vertical curved entity_relation Connections The connection parameter is abstractly named but it controls what type of edge this is. Most edges are lines but other types are available. Parameter Rendered line link arrow simple_arrow Patterns The pattern parameter controls how the line stroke is rendered. Options are: Parameter Rendered solid dashed_small dashed_medium dashed_large dotted_small dotted_medium dotted_large Line Ends The line_end_target and line_end_source parameter sets whatever is rendered where the edge meets the objects. There are secondary boolean parameters for the fill of the ends ( endFill_target and endFill_source ) but not all ends can be filled. Parameter Rendered Unfilled Rendered Filled classic classicThin open na openThin na openAsync na block blockThin async oval diamond diamondThin dash na halfCircle na cross na circlePlus na circle na baseDash na ERone na ERmandOne na ERmany na ERoneToMany na ERzeroToOne na ERzeroToMany na doubleBlock","title":"Edges"},{"location":"usage/edges/#edges","text":"Edges are the lines and arrows that connect objects in Draw.io. There's quite a bit of variabiability in how they're created and styled so there's a bit more complexity than with objects.","title":"Edges"},{"location":"usage/edges/#creating-a-basic-edge","text":"Like objects, there's a BasicEdge object that can be easily created: link = drawpyo.diagram.BasicEdge( page=page, source=item_1, target=item_2, )","title":"Creating a basic edge"},{"location":"usage/edges/#edge-geometry","text":"Besides the source and target, the edge geometry can be very finely tuned. There are eight parameters that control where and how the edge meets the source and target objects: Parameter Definition entryX From where along the X axis on the source object the edge originates (0-1) entryY From where along the Y axis on the source object the edge originates (0-1) entryDx Applies an offset in pixels to the X axis entry point entryDy Applies an offset in pixels to the Y axis entry point exitX From where along the X axis on the target object the edge originates (0-1) exitY From where along the Y axis on the target object the edge originates (0-1) exitDx Applies an offset in pixels to the X axis exit point exitDy Applies an offset in pixels to the Y axis exit point If these parameters are set to None then the Draw.io rendering engine will place the origination and direction of the edge wherever makes the most sense based on the layout of the objects. This is the same as the behavior in the app when an edge is dragged to the center of a shape (highlighting the whole object green) instead of to a specific node on the border (and seeing just that node highlighted in green). Other attributes for controlling the general shape of the object are: Parameter Definition rounded Sets whether the corners of a line are set to sharp or rounded off (0-1) jettySize Defines the length of the straight line coming out of or into an object before the edge makes its first turn","title":"Edge Geometry"},{"location":"usage/edges/#styling-edges","text":"Just about every edge styling option from the Draw.io app is implemented in Drawpyo. It's easiest to just play with all of the different line styling options in Draw.io to understand how they render but the major options are listed here.","title":"Styling edges"},{"location":"usage/edges/#waypoints","text":"The waypoint parameter controls how the line is routed from the source to the target. For example, a straight line is just point to point. A curved line tries to maintain gentle curves and perpendicularity to the source and target objects. Options are: Parameter Rendered straight orthogonal vertical horizontal isometric isometric_vertical curved entity_relation","title":"Waypoints"},{"location":"usage/edges/#connections","text":"The connection parameter is abstractly named but it controls what type of edge this is. Most edges are lines but other types are available. Parameter Rendered line link arrow simple_arrow","title":"Connections"},{"location":"usage/edges/#patterns","text":"The pattern parameter controls how the line stroke is rendered. Options are: Parameter Rendered solid dashed_small dashed_medium dashed_large dotted_small dotted_medium dotted_large","title":"Patterns"},{"location":"usage/edges/#line-ends","text":"The line_end_target and line_end_source parameter sets whatever is rendered where the edge meets the objects. There are secondary boolean parameters for the fill of the ends ( endFill_target and endFill_source ) but not all ends can be filled. Parameter Rendered Unfilled Rendered Filled classic classicThin open na openThin na openAsync na block blockThin async oval diamond diamondThin dash na halfCircle na cross na circlePlus na circle na baseDash na ERone na ERmandOne na ERmany na ERoneToMany na ERzeroToOne na ERzeroToMany na doubleBlock","title":"Line Ends"},{"location":"usage/objects/","text":"Objects Though some diagram types have their own object subclasses, the main class for creating objects is the BasicObject class. Creating a basic object base_obj = drawpyo.diagram.BasicObject(page=page) The default object type is a rounded corner rectangle with white background and a black border just like in the Draw.io app. The value attribute holds the text to display in the object. base_obj.value = \"This Object's Name is Fred\" Creating an object from a shape library Just like the built-in shape libraries in the Draw.io app, Drawpyo supports generating shapes from libraries. Currently the 'general' library from the Draw.io app is defined but more will be added in the future. These libraries are defined in TOML files and drawpyo supports importing custom shape libraries! See [Shape Libraries][/usage/shape_libs.md] for more information. To generate an object from a library: object = drawpyo.diagram.object_from_library( library=\"general\", obj_name=\"process\", page=page, ) This function returns a normal BasicObject but prestyled by the library. It can then be further styled or modified. Object Geometry All objects contain a structure called ObjectGeometry that provides a layer of abstraction. Interacting directly with the geometry class is optional. Object Sizing The three parameters that affect object placement are size and aspect. Size can be set with a tuple containing the width then height. BasicObject.size = (120, 80) BasicObject.aspect = 'fixed' The size attribute is an abstraction of the ObjectGeometry object, so the width and height can also be accessed directly. BasicObject.geometry.height = 80 BasicObject.geometry.width = 120 Object Geometry and Placement Repositioning objects is simple but there are a few convenience features to know about. There are two attributes available for setting the position by either the top left corner or the center: BasicObject.position = (0, 0) BasicObject.center_position = (0, 0) As with the size, the X and Y positions can be accessed directly in the geometry object. BasicObject.geometry.x = 0 BasicObject.geometry.y = 0 Styling Objects There are infinite permutations of object formatting and styling available. There are some higher order attributes that set the template for the object. What lower order styling attributes may or may not apply in combination. Then there are attributes like size and text formatting that apply in all cases. These interactions are difficult to predict in drawpyo alone so a good way to get familiar with all of the possible options and types of customizations is just to play with the Draw.io app directly to design formatting to your taste. Almost all styling attributes are optional (and drawpyo adds the non-optional ones automatically). If an attribute is unset or set to None then it won't be included in the file output. This will set that specific styling behavior to a default mode. BaseStyle and Shape The highest order styling attribute in Draw.io for objects is shape . This sets how the object behaves and is rendered. Different values include: parallelogram shape process hexagon document cylinder3 internalStorage cube step tape trapezoid note card callout dataStorage and many more. Confusingly there is another attribute called baseStyle that is sometimes used in combination with shape and sometimes without. BaseStyles include: text ellipse rhombus triangle swimlane It can be hard to predict how these two attributes will interact. To utilize them it's recommended to start in the Draw.io app, use their shape libraries or templates to get the desired style, then look at the style string to see what shape and baseStyle were used. When creating an object from a shape library these two attributes are handled automatically. Basic Styling Attributes These attributes mostly apply to most shape/baseStyle combinations and can be set on almost any object. rounded fillColor strokeColor opacity whiteSpace glass shadow comic linePattern Further Styling Attributes As mentioned above, not all of these attributes will apply to all object shapes and types. But some commonly called include: darkOpacity darkOpacity2 backgroundOutline perimeter Text Styling Attributes The text set in the value attribute of the BasicObject class can also be styled with the expected text formatting tools. fontColor fontFamily fontSize align verticalAlign labelPosition labelBackgroundColor labelBorderColor textOpacity Due to complexities with the actual combination of styling strings used by Draw.io, there are some more that are abstracted by drawpyo to make them easy to work with: text_direction bold_font italic_font underline_font Attribute Data Type fontColor str (Hex Code: '#ffffff') fontFamily str (see Draw.io for available fonts) fontSize int (size in pts) align str ('left', 'center', or 'right') verticalAlign str ('top', 'middle', 'bottom') labelPosition str ('left', 'center', or 'right') verticalLabelPosition str ('top', 'middle', 'bottom') labelBackgroundColor str (Hex Code: '#ffffff') labelBorderColor str (Hex Code: '#ffffff') textOpacity int (0-100) text_direction bold_font bool italic_font bool underline_font bool","title":"Objects"},{"location":"usage/objects/#objects","text":"Though some diagram types have their own object subclasses, the main class for creating objects is the BasicObject class.","title":"Objects"},{"location":"usage/objects/#creating-a-basic-object","text":"base_obj = drawpyo.diagram.BasicObject(page=page) The default object type is a rounded corner rectangle with white background and a black border just like in the Draw.io app. The value attribute holds the text to display in the object. base_obj.value = \"This Object's Name is Fred\"","title":"Creating a basic object"},{"location":"usage/objects/#creating-an-object-from-a-shape-library","text":"Just like the built-in shape libraries in the Draw.io app, Drawpyo supports generating shapes from libraries. Currently the 'general' library from the Draw.io app is defined but more will be added in the future. These libraries are defined in TOML files and drawpyo supports importing custom shape libraries! See [Shape Libraries][/usage/shape_libs.md] for more information. To generate an object from a library: object = drawpyo.diagram.object_from_library( library=\"general\", obj_name=\"process\", page=page, ) This function returns a normal BasicObject but prestyled by the library. It can then be further styled or modified.","title":"Creating an object from a shape library"},{"location":"usage/objects/#object-geometry","text":"All objects contain a structure called ObjectGeometry that provides a layer of abstraction. Interacting directly with the geometry class is optional.","title":"Object Geometry"},{"location":"usage/objects/#object-sizing","text":"The three parameters that affect object placement are size and aspect. Size can be set with a tuple containing the width then height. BasicObject.size = (120, 80) BasicObject.aspect = 'fixed' The size attribute is an abstraction of the ObjectGeometry object, so the width and height can also be accessed directly. BasicObject.geometry.height = 80 BasicObject.geometry.width = 120","title":"Object Sizing"},{"location":"usage/objects/#object-geometry-and-placement","text":"Repositioning objects is simple but there are a few convenience features to know about. There are two attributes available for setting the position by either the top left corner or the center: BasicObject.position = (0, 0) BasicObject.center_position = (0, 0) As with the size, the X and Y positions can be accessed directly in the geometry object. BasicObject.geometry.x = 0 BasicObject.geometry.y = 0","title":"Object Geometry and Placement"},{"location":"usage/objects/#styling-objects","text":"There are infinite permutations of object formatting and styling available. There are some higher order attributes that set the template for the object. What lower order styling attributes may or may not apply in combination. Then there are attributes like size and text formatting that apply in all cases. These interactions are difficult to predict in drawpyo alone so a good way to get familiar with all of the possible options and types of customizations is just to play with the Draw.io app directly to design formatting to your taste. Almost all styling attributes are optional (and drawpyo adds the non-optional ones automatically). If an attribute is unset or set to None then it won't be included in the file output. This will set that specific styling behavior to a default mode.","title":"Styling Objects"},{"location":"usage/objects/#basestyle-and-shape","text":"The highest order styling attribute in Draw.io for objects is shape . This sets how the object behaves and is rendered. Different values include: parallelogram shape process hexagon document cylinder3 internalStorage cube step tape trapezoid note card callout dataStorage and many more. Confusingly there is another attribute called baseStyle that is sometimes used in combination with shape and sometimes without. BaseStyles include: text ellipse rhombus triangle swimlane It can be hard to predict how these two attributes will interact. To utilize them it's recommended to start in the Draw.io app, use their shape libraries or templates to get the desired style, then look at the style string to see what shape and baseStyle were used. When creating an object from a shape library these two attributes are handled automatically.","title":"BaseStyle and Shape"},{"location":"usage/objects/#basic-styling-attributes","text":"These attributes mostly apply to most shape/baseStyle combinations and can be set on almost any object. rounded fillColor strokeColor opacity whiteSpace glass shadow comic linePattern","title":"Basic Styling Attributes"},{"location":"usage/objects/#further-styling-attributes","text":"As mentioned above, not all of these attributes will apply to all object shapes and types. But some commonly called include: darkOpacity darkOpacity2 backgroundOutline perimeter","title":"Further Styling Attributes"},{"location":"usage/objects/#text-styling-attributes","text":"The text set in the value attribute of the BasicObject class can also be styled with the expected text formatting tools. fontColor fontFamily fontSize align verticalAlign labelPosition labelBackgroundColor labelBorderColor textOpacity Due to complexities with the actual combination of styling strings used by Draw.io, there are some more that are abstracted by drawpyo to make them easy to work with: text_direction bold_font italic_font underline_font Attribute Data Type fontColor str (Hex Code: '#ffffff') fontFamily str (see Draw.io for available fonts) fontSize int (size in pts) align str ('left', 'center', or 'right') verticalAlign str ('top', 'middle', 'bottom') labelPosition str ('left', 'center', or 'right') verticalLabelPosition str ('top', 'middle', 'bottom') labelBackgroundColor str (Hex Code: '#ffffff') labelBorderColor str (Hex Code: '#ffffff') textOpacity int (0-100) text_direction bold_font bool italic_font bool underline_font bool","title":"Text Styling Attributes"},{"location":"usage/shape_libs/","text":"Shape Libraries The Draw.io app has a lot of built-in shape libraries available. The basic library contains shapes and building blocks but there are increasingly more specific libraries such as flowcharts, wiring diagrams, and org charts. You can also export and import shape libraries into Draw.io. To replicate this feature for drawpyo, I created a library format based on TOML. Draw.io's libraries are XML which isn't as human readable or writable and is more specification than necessary. Supporting Draw.io's XML based library is a planned feature. Built-In Shape Libaries Drawpyo uses these TOML shape libraries to store the default libaries. Currently the only library that ships with drawpyo is the general library but more will come. The default libraries are in /drawpyo/shape_libraries. There is also a set of TOML databases for other formats, like all of the various combinations of edge styles and the line styles. These are stored in /drawpyo/formatting_database. Custom Shape Libaries This functionality is available to the user so you can define your own custom libraries! TOML was selected because it's a very simple and human-readable config file format. the TOML project website has a very nice high level overview. But drawpyo is hardly scratching the surface of what TOML is capable of so little expertise is needed. Creating a Shape Library To define a shape library create a .toml file. Current convention is to start with a title tag for clarity. title = \"Custom drawpyo shapes\" You can then define a custom object by naming the object in square brackets and adding whichever attributes you want: [square] size = [80, 80] aspect = \"fixed\" You can also have any shape inherit another and then either modify or extend its style: [perfect_circle] inherit = \"square\" baseStyle = \"ellipse\" This perfect_circle will now inherit the fixed aspect and size attributes from square but with the ellipse baseStyle. Style Attribute Types The attributes in the TOML file can come from three sets: Drawpyo attributes (snake_case) These are the attributes that drawpyo uses to abstract some complicated style strings, such as size instead of the Draw.io parameters of width and height . Predefined style attributes Such as any of the attributes listed in the Styling section of Objects . These will simply be overwritten with the values in the TOML file. Any new style attributes If you want to add a rare style attribute that drawpyo hasn't defined or worked with yet, no worries! When you import the TOML library if there are new style attributes defined then they'll get added to the BasicObject and exported into the Draw.io file. Using a Custom Library To use a custom shape library it just needs to be imported then passed to the object definition function: custom_library = drawpyo.diagram.import_shape_database( file_name=r\"path/to/toml_lib\" ) new_obj = drawpyo.diagram.object_from_library( library = custom_library, obj_name = 'object_name_from_lib', page=page, )","title":"Shape Libraries"},{"location":"usage/shape_libs/#shape-libraries","text":"The Draw.io app has a lot of built-in shape libraries available. The basic library contains shapes and building blocks but there are increasingly more specific libraries such as flowcharts, wiring diagrams, and org charts. You can also export and import shape libraries into Draw.io. To replicate this feature for drawpyo, I created a library format based on TOML. Draw.io's libraries are XML which isn't as human readable or writable and is more specification than necessary. Supporting Draw.io's XML based library is a planned feature.","title":"Shape Libraries"},{"location":"usage/shape_libs/#built-in-shape-libaries","text":"Drawpyo uses these TOML shape libraries to store the default libaries. Currently the only library that ships with drawpyo is the general library but more will come. The default libraries are in /drawpyo/shape_libraries. There is also a set of TOML databases for other formats, like all of the various combinations of edge styles and the line styles. These are stored in /drawpyo/formatting_database.","title":"Built-In Shape Libaries"},{"location":"usage/shape_libs/#custom-shape-libaries","text":"This functionality is available to the user so you can define your own custom libraries! TOML was selected because it's a very simple and human-readable config file format. the TOML project website has a very nice high level overview. But drawpyo is hardly scratching the surface of what TOML is capable of so little expertise is needed.","title":"Custom Shape Libaries"},{"location":"usage/shape_libs/#creating-a-shape-library","text":"To define a shape library create a .toml file. Current convention is to start with a title tag for clarity. title = \"Custom drawpyo shapes\" You can then define a custom object by naming the object in square brackets and adding whichever attributes you want: [square] size = [80, 80] aspect = \"fixed\" You can also have any shape inherit another and then either modify or extend its style: [perfect_circle] inherit = \"square\" baseStyle = \"ellipse\" This perfect_circle will now inherit the fixed aspect and size attributes from square but with the ellipse baseStyle.","title":"Creating a Shape Library"},{"location":"usage/shape_libs/#style-attribute-types","text":"The attributes in the TOML file can come from three sets:","title":"Style Attribute Types"},{"location":"usage/shape_libs/#drawpyo-attributes-snake_case","text":"These are the attributes that drawpyo uses to abstract some complicated style strings, such as size instead of the Draw.io parameters of width and height .","title":"Drawpyo attributes (snake_case)"},{"location":"usage/shape_libs/#predefined-style-attributes","text":"Such as any of the attributes listed in the Styling section of Objects . These will simply be overwritten with the values in the TOML file.","title":"Predefined style attributes"},{"location":"usage/shape_libs/#any-new-style-attributes","text":"If you want to add a rare style attribute that drawpyo hasn't defined or worked with yet, no worries! When you import the TOML library if there are new style attributes defined then they'll get added to the BasicObject and exported into the Draw.io file.","title":"Any new style attributes"},{"location":"usage/shape_libs/#using-a-custom-library","text":"To use a custom shape library it just needs to be imported then passed to the object definition function: custom_library = drawpyo.diagram.import_shape_database( file_name=r\"path/to/toml_lib\" ) new_obj = drawpyo.diagram.object_from_library( library = custom_library, obj_name = 'object_name_from_lib', page=page, )","title":"Using a Custom Library"}]}
\ No newline at end of file
diff --git a/sitemap.xml b/sitemap.xml
index 0f8724e..a48e2ef 100644
--- a/sitemap.xml
+++ b/sitemap.xml
@@ -1,3 +1,38 @@
+
+ https://merrimanind.github.io/drawpyo/
+ 2024-03-17
+ daily
+
+
+ https://merrimanind.github.io/drawpyo/about/
+ 2024-03-17
+ daily
+
+
+ https://merrimanind.github.io/drawpyo/diagram_types/tree_diagrams/
+ 2024-03-17
+ daily
+
+
+ https://merrimanind.github.io/drawpyo/usage/basic_usage/
+ 2024-03-17
+ daily
+
+
+ https://merrimanind.github.io/drawpyo/usage/edges/
+ 2024-03-17
+ daily
+
+
+ https://merrimanind.github.io/drawpyo/usage/objects/
+ 2024-03-17
+ daily
+
+
+ https://merrimanind.github.io/drawpyo/usage/shape_libs/
+ 2024-03-17
+ daily
+
\ No newline at end of file
diff --git a/sitemap.xml.gz b/sitemap.xml.gz
index 39d21dc..a071e0a 100644
Binary files a/sitemap.xml.gz and b/sitemap.xml.gz differ
diff --git a/usage/basic_usage/index.html b/usage/basic_usage/index.html
new file mode 100644
index 0000000..696ff3b
--- /dev/null
+++ b/usage/basic_usage/index.html
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+ Usage - Drawpyo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Basic Functionality
+
Drawpyo's basic functionality provides the same features as using the Draw.io app. You can create files with one or more pages, add objects to them, and position those objects. You can style objects from built-in shape libraries, manually, or from style strings. Those objects can be shapes, containers, or edges to connect them. Finally you can save your diagrams where they can be opened with the Draw.io app.
+
Files
+
Make a new file
+
A File object represents a Draw.io file. If no file_path is set the default path will be 'user/Drawpyo Charts' where 'user' will be an OS-specific user home folder.
+
diagram = drawpyo.File()
+file.file_path = r"C:\drawpyo"
+file.file_name = "Test Generated Edges.drawio"
+
+
Write a file
+
Files can be written simply with the write() function. This function takes a few parameters to make it more flexible:
+| Parameter | Setting |
+| - | - |
+| file_path
| This will overwrite the previously set file_path. |
+| file_name
| This will overwrite the previously set file_name. Like file_path, useful in creating multiple copies of a diagram with slight variations |
+| overwrite
| This boolean parameter controls whether an existing diagram should be overwritten or not. |
+
Pages
+
Add a page
+
The Page object represents the different diagram pages that you can create in Draw.io. A Page can be created without linking it to a File but it won't be writable without a File object.
+
# Add a page
+page = drawpy.Page(file=file)
+
+
Page Parameters
+
There are a number of customizable parameter for pages:
+
+
+
+argument |
+description |
+
+
+
+
+width |
+Width of the document in pixels |
+
+
+height |
+Height of the document in pixels |
+
+
+grid |
+Enable grid (0 or 1) |
+
+
+grid_size |
+Side of grid squares in pixels |
+
+
+guides |
+Enable guides (0 or 1) |
+
+
+tooltips |
+Enable tooltips (0 or 1) |
+
+
+scale |
+Scale of the drawing |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usage/edges/index.html b/usage/edges/index.html
new file mode 100644
index 0000000..9274d66
--- /dev/null
+++ b/usage/edges/index.html
@@ -0,0 +1,478 @@
+
+
+
+
+
+
+
+ Edges - Drawpyo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Edges
+
Edges are the lines and arrows that connect objects in Draw.io. There's quite a bit of variabiability in how they're created and styled so there's a bit more complexity than with objects.
+
Creating a basic edge
+
Like objects, there's a BasicEdge object that can be easily created:
+
link = drawpyo.diagram.BasicEdge(
+ page=page,
+ source=item_1,
+ target=item_2,
+ )
+
+
Edge Geometry
+
Besides the source and target, the edge geometry can be very finely tuned. There are eight parameters that control where and how the edge meets the source and target objects:
+
+
+
+Parameter |
+Definition |
+
+
+
+
+entryX |
+From where along the X axis on the source object the edge originates (0-1) |
+
+
+entryY |
+From where along the Y axis on the source object the edge originates (0-1) |
+
+
+entryDx |
+Applies an offset in pixels to the X axis entry point |
+
+
+entryDy |
+Applies an offset in pixels to the Y axis entry point |
+
+
+exitX |
+From where along the X axis on the target object the edge originates (0-1) |
+
+
+exitY |
+From where along the Y axis on the target object the edge originates (0-1) |
+
+
+exitDx |
+Applies an offset in pixels to the X axis exit point |
+
+
+exitDy |
+Applies an offset in pixels to the Y axis exit point |
+
+
+
+
If these parameters are set to None
then the Draw.io rendering engine will place the origination and direction of the edge wherever makes the most sense based on the layout of the objects. This is the same as the behavior in the app when an edge is dragged to the center of a shape (highlighting the whole object green) instead of to a specific node on the border (and seeing just that node highlighted in green).
+
Other attributes for controlling the general shape of the object are:
+
+
+
+Parameter |
+Definition |
+
+
+
+
+rounded |
+Sets whether the corners of a line are set to sharp or rounded off (0-1) |
+
+
+jettySize |
+Defines the length of the straight line coming out of or into an object before the edge makes its first turn |
+
+
+
+
Styling edges
+
Just about every edge styling option from the Draw.io app is implemented in Drawpyo. It's easiest to just play with all of the different line styling options in Draw.io to understand how they render but the major options are listed here.
+
Waypoints
+
The waypoint
parameter controls how the line is routed from the source to the target. For example, a straight line is just point to point. A curved line tries to maintain gentle curves and perpendicularity to the source and target objects. Options are:
+
+
+
+Parameter |
+Rendered |
+
+
+
+
+straight |
+ |
+
+
+orthogonal |
+ |
+
+
+vertical |
+ |
+
+
+horizontal |
+ |
+
+
+isometric |
+ |
+
+
+isometric_vertical |
+ |
+
+
+curved |
+ |
+
+
+entity_relation |
+ |
+
+
+
+
Connections
+
The connection
parameter is abstractly named but it controls what type of edge this is. Most edges are lines but other types are available.
+
+
+
+Parameter |
+Rendered |
+
+
+
+
+line |
+ |
+
+
+link |
+ |
+
+
+arrow |
+ |
+
+
+simple_arrow |
+ |
+
+
+
+
Patterns
+
The pattern
parameter controls how the line stroke is rendered. Options are:
+
+
+
+Parameter |
+Rendered |
+
+
+
+
+solid |
+ |
+
+
+dashed_small |
+ |
+
+
+dashed_medium |
+ |
+
+
+dashed_large |
+ |
+
+
+dotted_small |
+ |
+
+
+dotted_medium |
+ |
+
+
+dotted_large |
+ |
+
+
+
+
Line Ends
+
The line_end_target
and line_end_source
parameter sets whatever is rendered where the edge meets the objects. There are secondary boolean parameters for the fill of the ends (endFill_target
and endFill_source
) but not all ends can be filled.
+
+
+
+Parameter |
+Rendered Unfilled |
+Rendered Filled |
+
+
+
+
+classic |
+ |
+ |
+
+
+classicThin |
+ |
+ |
+
+
+open |
+ |
+na |
+
+
+openThin |
+ |
+na |
+
+
+openAsync |
+ |
+na |
+
+
+block |
+ |
+ |
+
+
+blockThin |
+ |
+ |
+
+
+async |
+ |
+ |
+
+
+oval |
+ |
+ |
+
+
+diamond |
+ |
+ |
+
+
+diamondThin |
+ |
+ |
+
+
+dash |
+ |
+na |
+
+
+halfCircle |
+ |
+na |
+
+
+cross |
+ |
+na |
+
+
+circlePlus |
+ |
+na |
+
+
+circle |
+ |
+na |
+
+
+baseDash |
+ |
+na |
+
+
+ERone |
+ |
+na |
+
+
+ERmandOne |
+ |
+na |
+
+
+ERmany |
+ |
+na |
+
+
+ERoneToMany |
+ |
+na |
+
+
+ERzeroToOne |
+ |
+na |
+
+
+ERzeroToMany |
+ |
+na |
+
+
+doubleBlock |
+ |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usage/objects/index.html b/usage/objects/index.html
new file mode 100644
index 0000000..617e88d
--- /dev/null
+++ b/usage/objects/index.html
@@ -0,0 +1,349 @@
+
+
+
+
+
+
+
+ Objects - Drawpyo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Objects
+
Though some diagram types have their own object subclasses, the main class for creating objects is the BasicObject class.
+
Creating a basic object
+
base_obj = drawpyo.diagram.BasicObject(page=page)
+
+
The default object type is a rounded corner rectangle with white background and a black border just like in the Draw.io app.
+
The value attribute holds the text to display in the object.
+
base_obj.value = "This Object's Name is Fred"
+
+
Creating an object from a shape library
+
Just like the built-in shape libraries in the Draw.io app, Drawpyo supports generating shapes from libraries. Currently the 'general' library from the Draw.io app is defined but more will be added in the future.
+
+These libraries are defined in TOML files and drawpyo supports importing custom shape libraries! See [Shape Libraries][/usage/shape_libs.md] for more information.
+
+
To generate an object from a library:
+
object = drawpyo.diagram.object_from_library(
+ library="general",
+ obj_name="process",
+ page=page,
+ )
+
+
This function returns a normal BasicObject but prestyled by the library. It can then be further styled or modified.
+
Object Geometry
+
All objects contain a structure called ObjectGeometry that provides a layer of abstraction. Interacting directly with the geometry class is optional.
+
Object Sizing
+
The three parameters that affect object placement are size and aspect. Size can be set with a tuple containing the width then height.
+
BasicObject.size = (120, 80)
+BasicObject.aspect = 'fixed'
+
+
The size
attribute is an abstraction of the ObjectGeometry object, so the width and height can also be accessed directly.
+
BasicObject.geometry.height = 80
+BasicObject.geometry.width = 120
+
+
Object Geometry and Placement
+
Repositioning objects is simple but there are a few convenience features to know about. There are two attributes available for setting the position by either the top left corner or the center:
+
BasicObject.position = (0, 0)
+BasicObject.center_position = (0, 0)
+
+
As with the size, the X and Y positions can be accessed directly in the geometry object.
+
BasicObject.geometry.x = 0
+BasicObject.geometry.y = 0
+
+
Styling Objects
+
There are infinite permutations of object formatting and styling available. There are some higher order attributes that set the template for the object. What lower order styling attributes may or may not apply in combination. Then there are attributes like size and text formatting that apply in all cases. These interactions are difficult to predict in drawpyo alone so a good way to get familiar with all of the possible options and types of customizations is just to play with the Draw.io app directly to design formatting to your taste.
+
Almost all styling attributes are optional (and drawpyo adds the non-optional ones automatically). If an attribute is unset or set to None then it won't be included in the file output. This will set that specific styling behavior to a default mode.
+
BaseStyle and Shape
+
The highest order styling attribute in Draw.io for objects is shape
. This sets how the object behaves and is rendered. Different values include:
+
+- parallelogram
+- shape
+- process
+- hexagon
+- document
+- cylinder3
+- internalStorage
+- cube
+- step
+- tape
+- trapezoid
+- note
+- card
+- callout
+- dataStorage
+
+
and many more.
+
Confusingly there is another attribute called baseStyle
that is sometimes used in combination with shape
and sometimes without.
+
BaseStyles include:
+
+- text
+- ellipse
+- rhombus
+- triangle
+- swimlane
+
+
It can be hard to predict how these two attributes will interact. To utilize them it's recommended to start in the Draw.io app, use their shape libraries or templates to get the desired style, then look at the style string to see what shape
and baseStyle
were used. When creating an object from a shape library these two attributes are handled automatically.
+
Basic Styling Attributes
+
These attributes mostly apply to most shape/baseStyle combinations and can be set on almost any object.
+
+- rounded
+- fillColor
+- strokeColor
+- opacity
+- whiteSpace
+- glass
+- shadow
+- comic
+- linePattern
+
+
Further Styling Attributes
+
As mentioned above, not all of these attributes will apply to all object shapes and types. But some commonly called include:
+
+- darkOpacity
+- darkOpacity2
+- backgroundOutline
+- perimeter
+
+
Text Styling Attributes
+
The text set in the value
attribute of the BasicObject class can also be styled with the expected text formatting tools.
+
+- fontColor
+- fontFamily
+- fontSize
+- align
+- verticalAlign
+- labelPosition
+- labelBackgroundColor
+- labelBorderColor
+- textOpacity
+
+
Due to complexities with the actual combination of styling strings used by Draw.io, there are some more that are abstracted by drawpyo to make them easy to work with:
+
+- text_direction
+- bold_font
+- italic_font
+- underline_font
+
+
+
+
+Attribute |
+Data Type |
+
+
+
+
+fontColor |
+str (Hex Code: '#ffffff') |
+
+
+fontFamily |
+str (see Draw.io for available fonts) |
+
+
+fontSize |
+int (size in pts) |
+
+
+align |
+str ('left', 'center', or 'right') |
+
+
+verticalAlign |
+str ('top', 'middle', 'bottom') |
+
+
+labelPosition |
+str ('left', 'center', or 'right') |
+
+
+verticalLabelPosition |
+str ('top', 'middle', 'bottom') |
+
+
+labelBackgroundColor |
+str (Hex Code: '#ffffff') |
+
+
+labelBorderColor |
+str (Hex Code: '#ffffff') |
+
+
+textOpacity |
+int (0-100) |
+
+
+text_direction |
+ |
+
+
+bold_font |
+bool |
+
+
+italic_font |
+bool |
+
+
+underline_font |
+bool |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usage/shape_libs/index.html b/usage/shape_libs/index.html
new file mode 100644
index 0000000..e70d850
--- /dev/null
+++ b/usage/shape_libs/index.html
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+ Shape Libraries - Drawpyo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Shape Libraries
+
The Draw.io app has a lot of built-in shape libraries available. The basic library contains shapes and building blocks but there are increasingly more specific libraries such as flowcharts, wiring diagrams, and org charts. You can also export and import shape libraries into Draw.io.
+
To replicate this feature for drawpyo, I created a library format based on TOML. Draw.io's libraries are XML which isn't as human readable or writable and is more specification than necessary.
+
+Supporting Draw.io's XML based library is a planned feature.
+
+
Built-In Shape Libaries
+
Drawpyo uses these TOML shape libraries to store the default libaries. Currently the only library that ships with drawpyo is the general library but more will come. The default libraries are in /drawpyo/shape_libraries.
+
There is also a set of TOML databases for other formats, like all of the various combinations of edge styles and the line styles. These are stored in /drawpyo/formatting_database.
+
Custom Shape Libaries
+
This functionality is available to the user so you can define your own custom libraries! TOML was selected because it's a very simple and human-readable config file format. the TOML project website has a very nice high level overview. But drawpyo is hardly scratching the surface of what TOML is capable of so little expertise is needed.
+
Creating a Shape Library
+
To define a shape library create a .toml file. Current convention is to start with a title tag for clarity.
+
title = "Custom drawpyo shapes"
+
+
You can then define a custom object by naming the object in square brackets and adding whichever attributes you want:
+
[square]
+size = [80, 80]
+aspect = "fixed"
+
+
You can also have any shape inherit another and then either modify or extend its style:
+
[perfect_circle]
+inherit = "square"
+baseStyle = "ellipse"
+
+
This perfect_circle
will now inherit the fixed aspect and size attributes from square
but with the ellipse baseStyle.
+
Style Attribute Types
+
The attributes in the TOML file can come from three sets:
+
Drawpyo attributes (snake_case)
+
These are the attributes that drawpyo uses to abstract some complicated style strings, such as size
instead of the Draw.io parameters of width
and height
.
+
Predefined style attributes
+
Such as any of the attributes listed in the Styling section of Objects. These will simply be overwritten with the values in the TOML file.
+
Any new style attributes
+
If you want to add a rare style attribute that drawpyo hasn't defined or worked with yet, no worries! When you import the TOML library if there are new style attributes defined then they'll get added to the BasicObject and exported into the Draw.io file.
+
Using a Custom Library
+
To use a custom shape library it just needs to be imported then passed to the object definition function:
+
custom_library = drawpyo.diagram.import_shape_database(
+ file_name=r"path/to/toml_lib"
+ )
+
+new_obj = drawpyo.diagram.object_from_library(
+ library = custom_library,
+ obj_name = 'object_name_from_lib',
+ page=page,
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+