HW8 Complete
This commit is contained in:
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/.dylibs/libpng16.16.dylib
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/.dylibs/libpng16.16.dylib
vendored
Executable file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/.dylibs/libz.1.2.10.dylib
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/.dylibs/libz.1.2.10.dylib
vendored
Executable file
Binary file not shown.
1647
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__init__.py
vendored
Normal file
1647
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__init__.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_animation_data.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_animation_data.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_cm.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_cm.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_cm_listed.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_cm_listed.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_color_data.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_color_data.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_constrained_layout.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_constrained_layout.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_layoutbox.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_layoutbox.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_mathtext_data.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_mathtext_data.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_pylab_helpers.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_pylab_helpers.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_version.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/_version.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/afm.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/afm.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/animation.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/animation.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/artist.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/artist.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/axis.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/axis.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/backend_bases.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/backend_bases.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/backend_managers.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/backend_managers.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/backend_tools.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/backend_tools.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/bezier.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/bezier.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/blocking_input.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/blocking_input.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/category.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/category.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/cm.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/cm.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/collections.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/collections.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/colorbar.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/colorbar.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/colors.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/colors.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/container.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/container.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/contour.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/contour.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/dates.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/dates.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/docstring.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/docstring.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/dviread.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/dviread.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/figure.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/figure.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/font_manager.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/font_manager.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/fontconfig_pattern.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/fontconfig_pattern.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/gridspec.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/gridspec.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/hatch.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/hatch.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/image.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/image.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/legend.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/legend.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/legend_handler.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/legend_handler.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/lines.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/lines.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/markers.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/markers.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/mathtext.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/mathtext.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/mlab.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/mlab.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/offsetbox.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/offsetbox.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/patches.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/patches.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/path.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/path.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/patheffects.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/patheffects.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/pylab.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/pylab.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/pyplot.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/pyplot.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/quiver.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/quiver.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/rcsetup.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/rcsetup.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/sankey.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/sankey.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/scale.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/scale.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/spines.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/spines.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/stackplot.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/stackplot.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/streamplot.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/streamplot.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/table.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/table.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/texmanager.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/texmanager.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/text.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/text.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/textpath.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/textpath.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/ticker.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/ticker.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/tight_bbox.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/tight_bbox.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/tight_layout.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/tight_layout.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/transforms.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/transforms.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/type1font.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/type1font.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/units.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/units.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/widgets.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/__pycache__/widgets.cpython-37.pyc
vendored
Normal file
Binary file not shown.
260
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_animation_data.py
vendored
Normal file
260
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_animation_data.py
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
# Javascript template for HTMLWriter
|
||||
JS_INCLUDE = """
|
||||
<link rel="stylesheet"
|
||||
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/
|
||||
css/font-awesome.min.css">
|
||||
<script language="javascript">
|
||||
function isInternetExplorer() {
|
||||
ua = navigator.userAgent;
|
||||
/* MSIE used to detect old browsers and Trident used to newer ones*/
|
||||
return ua.indexOf("MSIE ") > -1 || ua.indexOf("Trident/") > -1;
|
||||
}
|
||||
|
||||
/* Define the Animation class */
|
||||
function Animation(frames, img_id, slider_id, interval, loop_select_id){
|
||||
this.img_id = img_id;
|
||||
this.slider_id = slider_id;
|
||||
this.loop_select_id = loop_select_id;
|
||||
this.interval = interval;
|
||||
this.current_frame = 0;
|
||||
this.direction = 0;
|
||||
this.timer = null;
|
||||
this.frames = new Array(frames.length);
|
||||
|
||||
for (var i=0; i<frames.length; i++)
|
||||
{
|
||||
this.frames[i] = new Image();
|
||||
this.frames[i].src = frames[i];
|
||||
}
|
||||
var slider = document.getElementById(this.slider_id);
|
||||
slider.max = this.frames.length - 1;
|
||||
if (isInternetExplorer()) {
|
||||
// switch from oninput to onchange because IE <= 11 does not conform
|
||||
// with W3C specification. It ignores oninput and onchange behaves
|
||||
// like oninput. In contrast, Mircosoft Edge behaves correctly.
|
||||
slider.setAttribute('onchange', slider.getAttribute('oninput'));
|
||||
slider.setAttribute('oninput', null);
|
||||
}
|
||||
this.set_frame(this.current_frame);
|
||||
}
|
||||
|
||||
Animation.prototype.get_loop_state = function(){
|
||||
var button_group = document[this.loop_select_id].state;
|
||||
for (var i = 0; i < button_group.length; i++) {
|
||||
var button = button_group[i];
|
||||
if (button.checked) {
|
||||
return button.value;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
Animation.prototype.set_frame = function(frame){
|
||||
this.current_frame = frame;
|
||||
document.getElementById(this.img_id).src =
|
||||
this.frames[this.current_frame].src;
|
||||
document.getElementById(this.slider_id).value = this.current_frame;
|
||||
}
|
||||
|
||||
Animation.prototype.next_frame = function()
|
||||
{
|
||||
this.set_frame(Math.min(this.frames.length - 1, this.current_frame + 1));
|
||||
}
|
||||
|
||||
Animation.prototype.previous_frame = function()
|
||||
{
|
||||
this.set_frame(Math.max(0, this.current_frame - 1));
|
||||
}
|
||||
|
||||
Animation.prototype.first_frame = function()
|
||||
{
|
||||
this.set_frame(0);
|
||||
}
|
||||
|
||||
Animation.prototype.last_frame = function()
|
||||
{
|
||||
this.set_frame(this.frames.length - 1);
|
||||
}
|
||||
|
||||
Animation.prototype.slower = function()
|
||||
{
|
||||
this.interval /= 0.7;
|
||||
if(this.direction > 0){this.play_animation();}
|
||||
else if(this.direction < 0){this.reverse_animation();}
|
||||
}
|
||||
|
||||
Animation.prototype.faster = function()
|
||||
{
|
||||
this.interval *= 0.7;
|
||||
if(this.direction > 0){this.play_animation();}
|
||||
else if(this.direction < 0){this.reverse_animation();}
|
||||
}
|
||||
|
||||
Animation.prototype.anim_step_forward = function()
|
||||
{
|
||||
this.current_frame += 1;
|
||||
if(this.current_frame < this.frames.length){
|
||||
this.set_frame(this.current_frame);
|
||||
}else{
|
||||
var loop_state = this.get_loop_state();
|
||||
if(loop_state == "loop"){
|
||||
this.first_frame();
|
||||
}else if(loop_state == "reflect"){
|
||||
this.last_frame();
|
||||
this.reverse_animation();
|
||||
}else{
|
||||
this.pause_animation();
|
||||
this.last_frame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Animation.prototype.anim_step_reverse = function()
|
||||
{
|
||||
this.current_frame -= 1;
|
||||
if(this.current_frame >= 0){
|
||||
this.set_frame(this.current_frame);
|
||||
}else{
|
||||
var loop_state = this.get_loop_state();
|
||||
if(loop_state == "loop"){
|
||||
this.last_frame();
|
||||
}else if(loop_state == "reflect"){
|
||||
this.first_frame();
|
||||
this.play_animation();
|
||||
}else{
|
||||
this.pause_animation();
|
||||
this.first_frame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Animation.prototype.pause_animation = function()
|
||||
{
|
||||
this.direction = 0;
|
||||
if (this.timer){
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
Animation.prototype.play_animation = function()
|
||||
{
|
||||
this.pause_animation();
|
||||
this.direction = 1;
|
||||
var t = this;
|
||||
if (!this.timer) this.timer = setInterval(function() {
|
||||
t.anim_step_forward();
|
||||
}, this.interval);
|
||||
}
|
||||
|
||||
Animation.prototype.reverse_animation = function()
|
||||
{
|
||||
this.pause_animation();
|
||||
this.direction = -1;
|
||||
var t = this;
|
||||
if (!this.timer) this.timer = setInterval(function() {
|
||||
t.anim_step_reverse();
|
||||
}, this.interval);
|
||||
}
|
||||
</script>
|
||||
"""
|
||||
|
||||
|
||||
# Style definitions for the HTML template
|
||||
STYLE_INCLUDE = """
|
||||
<style>
|
||||
.animation {
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
input[type=range].anim-slider {
|
||||
width: 374px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
.anim-buttons {
|
||||
margin: 8px 0px;
|
||||
}
|
||||
.anim-buttons button {
|
||||
padding: 0;
|
||||
width: 36px;
|
||||
}
|
||||
.anim-state label {
|
||||
margin-right: 8px;
|
||||
}
|
||||
.anim-state input {
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
</style>
|
||||
"""
|
||||
|
||||
|
||||
# HTML template for HTMLWriter
|
||||
DISPLAY_TEMPLATE = """
|
||||
<div class="animation">
|
||||
<img id="_anim_img{id}">
|
||||
<div class="anim-controls">
|
||||
<input id="_anim_slider{id}" type="range" class="anim-slider"
|
||||
name="points" min="0" max="1" step="1" value="0"
|
||||
oninput="anim{id}.set_frame(parseInt(this.value));"></input>
|
||||
<div class="anim-buttons">
|
||||
<button onclick="anim{id}.slower()"><i class="fa fa-minus"></i></button>
|
||||
<button onclick="anim{id}.first_frame()"><i class="fa fa-fast-backward">
|
||||
</i></button>
|
||||
<button onclick="anim{id}.previous_frame()">
|
||||
<i class="fa fa-step-backward"></i></button>
|
||||
<button onclick="anim{id}.reverse_animation()">
|
||||
<i class="fa fa-play fa-flip-horizontal"></i></button>
|
||||
<button onclick="anim{id}.pause_animation()"><i class="fa fa-pause">
|
||||
</i></button>
|
||||
<button onclick="anim{id}.play_animation()"><i class="fa fa-play"></i>
|
||||
</button>
|
||||
<button onclick="anim{id}.next_frame()"><i class="fa fa-step-forward">
|
||||
</i></button>
|
||||
<button onclick="anim{id}.last_frame()"><i class="fa fa-fast-forward">
|
||||
</i></button>
|
||||
<button onclick="anim{id}.faster()"><i class="fa fa-plus"></i></button>
|
||||
</div>
|
||||
<form action="#n" name="_anim_loop_select{id}" class="anim-state">
|
||||
<input type="radio" name="state" value="once" id="_anim_radio1_{id}"
|
||||
{once_checked}>
|
||||
<label for="_anim_radio1_{id}">Once</label>
|
||||
<input type="radio" name="state" value="loop" id="_anim_radio2_{id}"
|
||||
{loop_checked}>
|
||||
<label for="_anim_radio2_{id}">Loop</label>
|
||||
<input type="radio" name="state" value="reflect" id="_anim_radio3_{id}"
|
||||
{reflect_checked}>
|
||||
<label for="_anim_radio3_{id}">Reflect</label>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script language="javascript">
|
||||
/* Instantiate the Animation class. */
|
||||
/* The IDs given should match those used in the template above. */
|
||||
(function() {{
|
||||
var img_id = "_anim_img{id}";
|
||||
var slider_id = "_anim_slider{id}";
|
||||
var loop_select_id = "_anim_loop_select{id}";
|
||||
var frames = new Array({Nframes});
|
||||
{fill_frames}
|
||||
|
||||
/* set a timeout to make sure all the above elements are created before
|
||||
the object is initialized. */
|
||||
setTimeout(function() {{
|
||||
anim{id} = new Animation(frames, img_id, slider_id, {interval},
|
||||
loop_select_id);
|
||||
}}, 0);
|
||||
}})()
|
||||
</script>
|
||||
"""
|
||||
|
||||
|
||||
INCLUDED_FRAMES = """
|
||||
for (var i=0; i<{Nframes}; i++){{
|
||||
frames[i] = "{frame_dir}/frame" + ("0000000" + i).slice(-7) +
|
||||
".{frame_format}";
|
||||
}}
|
||||
"""
|
||||
1426
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_cm.py
vendored
Normal file
1426
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_cm.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1816
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_cm_listed.py
vendored
Normal file
1816
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_cm_listed.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1144
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_color_data.py
vendored
Normal file
1144
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_color_data.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
748
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_constrained_layout.py
vendored
Normal file
748
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_constrained_layout.py
vendored
Normal file
@@ -0,0 +1,748 @@
|
||||
"""
|
||||
This module provides the routine to adjust subplot layouts so that there are
|
||||
no overlapping axes or axes decorations. All axes decorations are dealt with
|
||||
(labels, ticks, titles, ticklabels) and some dependent artists are also dealt
|
||||
with (colorbar, suptitle, legend).
|
||||
|
||||
Layout is done via :meth:`~matplotlib.gridspec`, with one constraint per
|
||||
gridspec, so it is possible to have overlapping axes if the gridspecs
|
||||
overlap (i.e. using :meth:`~matplotlib.gridspec.GridSpecFromSubplotSpec`).
|
||||
Axes placed using ``figure.subplots()`` or ``figure.add_subplots()`` will
|
||||
participate in the layout. Axes manually placed via ``figure.add_axes()``
|
||||
will not.
|
||||
|
||||
See Tutorial: :doc:`/tutorials/intermediate/constrainedlayout_guide`
|
||||
|
||||
"""
|
||||
|
||||
# Development Notes:
|
||||
|
||||
# What gets a layoutbox:
|
||||
# - figure
|
||||
# - gridspec
|
||||
# - subplotspec
|
||||
# EITHER:
|
||||
# - axes + pos for the axes (i.e. the total area taken by axis and
|
||||
# the actual "position" argument that needs to be sent to
|
||||
# ax.set_position.)
|
||||
# - The axes layout box will also encompass the legend, and that is
|
||||
# how legends get included (axes legends, not figure legends)
|
||||
# - colorbars are siblings of the axes if they are single-axes
|
||||
# colorbars
|
||||
# OR:
|
||||
# - a gridspec can be inside a subplotspec.
|
||||
# - subplotspec
|
||||
# EITHER:
|
||||
# - axes...
|
||||
# OR:
|
||||
# - gridspec... with arbitrary nesting...
|
||||
# - colorbars are siblings of the subplotspecs if they are multi-axes
|
||||
# colorbars.
|
||||
# - suptitle:
|
||||
# - right now suptitles are just stacked atop everything else in figure.
|
||||
# Could imagine suptitles being gridspec suptitles, but not implemented
|
||||
#
|
||||
# Todo: AnchoredOffsetbox connected to gridspecs or axes. This would
|
||||
# be more general way to add extra-axes annotations.
|
||||
|
||||
import logging
|
||||
|
||||
import numpy as np
|
||||
|
||||
import matplotlib.cbook as cbook
|
||||
import matplotlib._layoutbox as layoutbox
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _in_same_column(colnum0min, colnum0max, colnumCmin, colnumCmax):
|
||||
return (colnumCmin <= colnum0min <= colnumCmax
|
||||
or colnumCmin <= colnum0max <= colnumCmax)
|
||||
|
||||
|
||||
def _in_same_row(rownum0min, rownum0max, rownumCmin, rownumCmax):
|
||||
return (rownumCmin <= rownum0min <= rownumCmax
|
||||
or rownumCmin <= rownum0max <= rownumCmax)
|
||||
|
||||
|
||||
def _axes_all_finite_sized(fig):
|
||||
"""
|
||||
helper function to make sure all axes in the
|
||||
figure have a finite width and height. If not, return False
|
||||
"""
|
||||
for ax in fig.axes:
|
||||
if ax._layoutbox is not None:
|
||||
newpos = ax._poslayoutbox.get_rect()
|
||||
if newpos[2] <= 0 or newpos[3] <= 0:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
######################################################
|
||||
def do_constrained_layout(fig, renderer, h_pad, w_pad,
|
||||
hspace=None, wspace=None):
|
||||
|
||||
"""
|
||||
Do the constrained_layout. Called at draw time in
|
||||
``figure.constrained_layout()``
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
||||
|
||||
fig : Figure
|
||||
is the ``figure`` instance to do the layout in.
|
||||
|
||||
renderer : Renderer
|
||||
the renderer to use.
|
||||
|
||||
h_pad, w_pad : float
|
||||
are in figure-normalized units, and are a padding around the axes
|
||||
elements.
|
||||
|
||||
hspace, wspace : float
|
||||
are in fractions of the subplot sizes.
|
||||
|
||||
"""
|
||||
|
||||
''' Steps:
|
||||
|
||||
1. get a list of unique gridspecs in this figure. Each gridspec will be
|
||||
constrained separately.
|
||||
2. Check for gaps in the gridspecs. i.e. if not every axes slot in the
|
||||
gridspec has been filled. If empty, add a ghost axis that is made so
|
||||
that it cannot be seen (though visible=True). This is needed to make
|
||||
a blank spot in the layout.
|
||||
3. Compare the tight_bbox of each axes to its `position`, and assume that
|
||||
the difference is the space needed by the elements around the edge of
|
||||
the axes (decorations) like the title, ticklabels, x-labels, etc. This
|
||||
can include legends who overspill the axes boundaries.
|
||||
4. Constrain gridspec elements to line up:
|
||||
a) if colnum0 != colnumC, the two subplotspecs are stacked next to
|
||||
each other, with the appropriate order.
|
||||
b) if colnum0 == colnumC, line up the left or right side of the
|
||||
_poslayoutbox (depending if it is the min or max num that is equal).
|
||||
c) do the same for rows...
|
||||
5. The above doesn't constrain relative sizes of the _poslayoutboxes at
|
||||
all, and indeed zero-size is a solution that the solver often finds more
|
||||
convenient than expanding the sizes. Right now the solution is to compare
|
||||
subplotspec sizes (i.e. drowsC and drows0) and constrain the larger
|
||||
_poslayoutbox to be larger than the ratio of the sizes. i.e. if drows0 >
|
||||
drowsC, then ax._poslayoutbox > axc._poslayoutbox * drowsC / drows0. This
|
||||
works fine *if* the decorations are similar between the axes. If the
|
||||
larger subplotspec has much larger axes decorations, then the constraint
|
||||
above is incorrect.
|
||||
|
||||
We need the greater than in the above, in general, rather than an equals
|
||||
sign. Consider the case of the left column having 2 rows, and the right
|
||||
column having 1 row. We want the top and bottom of the _poslayoutboxes to
|
||||
line up. So that means if there are decorations on the left column axes
|
||||
they will be smaller than half as large as the right hand axis.
|
||||
|
||||
This can break down if the decoration size for the right hand axis (the
|
||||
margins) is very large. There must be a math way to check for this case.
|
||||
|
||||
'''
|
||||
|
||||
invTransFig = fig.transFigure.inverted().transform_bbox
|
||||
|
||||
# list of unique gridspecs that contain child axes:
|
||||
gss = set()
|
||||
for ax in fig.axes:
|
||||
if hasattr(ax, 'get_subplotspec'):
|
||||
gs = ax.get_subplotspec().get_gridspec()
|
||||
if gs._layoutbox is not None:
|
||||
gss.add(gs)
|
||||
if len(gss) == 0:
|
||||
cbook._warn_external('There are no gridspecs with layoutboxes. '
|
||||
'Possibly did not call parent GridSpec with the'
|
||||
' figure= keyword')
|
||||
|
||||
if fig._layoutbox.constrained_layout_called < 1:
|
||||
for gs in gss:
|
||||
# fill in any empty gridspec slots w/ ghost axes...
|
||||
_make_ghost_gridspec_slots(fig, gs)
|
||||
|
||||
for nnn in range(2):
|
||||
# do the algorithm twice. This has to be done because decorators
|
||||
# change size after the first re-position (i.e. x/yticklabels get
|
||||
# larger/smaller). This second reposition tends to be much milder,
|
||||
# so doing twice makes things work OK.
|
||||
for ax in fig.axes:
|
||||
_log.debug(ax._layoutbox)
|
||||
if ax._layoutbox is not None:
|
||||
# make margins for each layout box based on the size of
|
||||
# the decorators.
|
||||
_make_layout_margins(ax, renderer, h_pad, w_pad)
|
||||
|
||||
# do layout for suptitle.
|
||||
suptitle = fig._suptitle
|
||||
do_suptitle = (suptitle is not None and
|
||||
suptitle._layoutbox is not None and
|
||||
suptitle.get_in_layout())
|
||||
if do_suptitle:
|
||||
bbox = invTransFig(
|
||||
suptitle.get_window_extent(renderer=renderer))
|
||||
height = bbox.y1 - bbox.y0
|
||||
if np.isfinite(height):
|
||||
# reserve at top of figure include an h_pad above and below
|
||||
suptitle._layoutbox.edit_height(height + h_pad * 2)
|
||||
|
||||
# OK, the above lines up ax._poslayoutbox with ax._layoutbox
|
||||
# now we need to
|
||||
# 1) arrange the subplotspecs. We do it at this level because
|
||||
# the subplotspecs are meant to contain other dependent axes
|
||||
# like colorbars or legends.
|
||||
# 2) line up the right and left side of the ax._poslayoutbox
|
||||
# that have the same subplotspec maxes.
|
||||
|
||||
if fig._layoutbox.constrained_layout_called < 1:
|
||||
# arrange the subplotspecs... This is all done relative to each
|
||||
# other. Some subplotspecs contain axes, and others contain
|
||||
# gridspecs the ones that contain gridspecs are a set proportion
|
||||
# of their parent gridspec. The ones that contain axes are
|
||||
# not so constrained.
|
||||
figlb = fig._layoutbox
|
||||
for child in figlb.children:
|
||||
if child._is_gridspec_layoutbox():
|
||||
# This routine makes all the subplot spec containers
|
||||
# have the correct arrangement. It just stacks the
|
||||
# subplot layoutboxes in the correct order...
|
||||
_arrange_subplotspecs(child, hspace=hspace, wspace=wspace)
|
||||
|
||||
for gs in gss:
|
||||
_align_spines(fig, gs)
|
||||
|
||||
fig._layoutbox.constrained_layout_called += 1
|
||||
fig._layoutbox.update_variables()
|
||||
|
||||
# check if any axes collapsed to zero. If not, don't change positions:
|
||||
if _axes_all_finite_sized(fig):
|
||||
# Now set the position of the axes...
|
||||
for ax in fig.axes:
|
||||
if ax._layoutbox is not None:
|
||||
newpos = ax._poslayoutbox.get_rect()
|
||||
# Now set the new position.
|
||||
# ax.set_position will zero out the layout for
|
||||
# this axis, allowing users to hard-code the position,
|
||||
# so this does the same w/o zeroing layout.
|
||||
ax._set_position(newpos, which='original')
|
||||
if do_suptitle:
|
||||
newpos = suptitle._layoutbox.get_rect()
|
||||
suptitle.set_y(1.0 - h_pad)
|
||||
else:
|
||||
if suptitle is not None and suptitle._layoutbox is not None:
|
||||
suptitle._layoutbox.edit_height(0)
|
||||
else:
|
||||
cbook._warn_external('constrained_layout not applied. At least '
|
||||
'one axes collapsed to zero width or height.')
|
||||
|
||||
|
||||
def _make_ghost_gridspec_slots(fig, gs):
|
||||
"""
|
||||
Check for unoccupied gridspec slots and make ghost axes for these
|
||||
slots... Do for each gs separately. This is a pretty big kludge
|
||||
but shouldn't have too much ill effect. The worst is that
|
||||
someone querying the figure will wonder why there are more
|
||||
axes than they thought.
|
||||
"""
|
||||
nrows, ncols = gs.get_geometry()
|
||||
hassubplotspec = np.zeros(nrows * ncols, dtype=bool)
|
||||
axs = []
|
||||
for ax in fig.axes:
|
||||
if (hasattr(ax, 'get_subplotspec')
|
||||
and ax._layoutbox is not None
|
||||
and ax.get_subplotspec().get_gridspec() == gs):
|
||||
axs += [ax]
|
||||
for ax in axs:
|
||||
ss0 = ax.get_subplotspec()
|
||||
if ss0.num2 is None:
|
||||
ss0.num2 = ss0.num1
|
||||
hassubplotspec[ss0.num1:(ss0.num2 + 1)] = True
|
||||
for nn, hss in enumerate(hassubplotspec):
|
||||
if not hss:
|
||||
# this gridspec slot doesn't have an axis so we
|
||||
# make a "ghost".
|
||||
ax = fig.add_subplot(gs[nn])
|
||||
ax.set_frame_on(False)
|
||||
ax.set_xticks([])
|
||||
ax.set_yticks([])
|
||||
ax.set_facecolor((1, 0, 0, 0))
|
||||
|
||||
|
||||
def _make_layout_margins(ax, renderer, h_pad, w_pad):
|
||||
"""
|
||||
For each axes, make a margin between the *pos* layoutbox and the
|
||||
*axes* layoutbox be a minimum size that can accommodate the
|
||||
decorations on the axis.
|
||||
"""
|
||||
fig = ax.figure
|
||||
invTransFig = fig.transFigure.inverted().transform_bbox
|
||||
pos = ax.get_position(original=True)
|
||||
tightbbox = ax.get_tightbbox(renderer=renderer)
|
||||
if tightbbox is None:
|
||||
bbox = pos
|
||||
else:
|
||||
bbox = invTransFig(tightbbox)
|
||||
|
||||
# this can go wrong:
|
||||
if not (np.isfinite(bbox.width) and np.isfinite(bbox.height)):
|
||||
# just abort, this is likely a bad set of co-ordinates that
|
||||
# is transitory...
|
||||
return
|
||||
# use stored h_pad if it exists
|
||||
h_padt = ax._poslayoutbox.h_pad
|
||||
if h_padt is None:
|
||||
h_padt = h_pad
|
||||
w_padt = ax._poslayoutbox.w_pad
|
||||
if w_padt is None:
|
||||
w_padt = w_pad
|
||||
ax._poslayoutbox.edit_left_margin_min(-bbox.x0 +
|
||||
pos.x0 + w_padt)
|
||||
ax._poslayoutbox.edit_right_margin_min(bbox.x1 -
|
||||
pos.x1 + w_padt)
|
||||
ax._poslayoutbox.edit_bottom_margin_min(
|
||||
-bbox.y0 + pos.y0 + h_padt)
|
||||
ax._poslayoutbox.edit_top_margin_min(bbox.y1-pos.y1+h_padt)
|
||||
_log.debug('left %f', (-bbox.x0 + pos.x0 + w_pad))
|
||||
_log.debug('right %f', (bbox.x1 - pos.x1 + w_pad))
|
||||
_log.debug('bottom %f', (-bbox.y0 + pos.y0 + h_padt))
|
||||
_log.debug('bbox.y0 %f', bbox.y0)
|
||||
_log.debug('pos.y0 %f', pos.y0)
|
||||
# Sometimes its possible for the solver to collapse
|
||||
# rather than expand axes, so they all have zero height
|
||||
# or width. This stops that... It *should* have been
|
||||
# taken into account w/ pref_width...
|
||||
if fig._layoutbox.constrained_layout_called < 1:
|
||||
ax._poslayoutbox.constrain_height_min(20, strength='weak')
|
||||
ax._poslayoutbox.constrain_width_min(20, strength='weak')
|
||||
ax._layoutbox.constrain_height_min(20, strength='weak')
|
||||
ax._layoutbox.constrain_width_min(20, strength='weak')
|
||||
ax._poslayoutbox.constrain_top_margin(0, strength='weak')
|
||||
ax._poslayoutbox.constrain_bottom_margin(0,
|
||||
strength='weak')
|
||||
ax._poslayoutbox.constrain_right_margin(0, strength='weak')
|
||||
ax._poslayoutbox.constrain_left_margin(0, strength='weak')
|
||||
|
||||
|
||||
def _align_spines(fig, gs):
|
||||
"""
|
||||
- Align right/left and bottom/top spines of appropriate subplots.
|
||||
- Compare size of subplotspec including height and width ratios
|
||||
and make sure that the axes spines are at least as large
|
||||
as they should be.
|
||||
"""
|
||||
# for each gridspec...
|
||||
nrows, ncols = gs.get_geometry()
|
||||
width_ratios = gs.get_width_ratios()
|
||||
height_ratios = gs.get_height_ratios()
|
||||
if width_ratios is None:
|
||||
width_ratios = np.ones(ncols)
|
||||
if height_ratios is None:
|
||||
height_ratios = np.ones(nrows)
|
||||
|
||||
# get axes in this gridspec....
|
||||
axs = []
|
||||
for ax in fig.axes:
|
||||
if (hasattr(ax, 'get_subplotspec')
|
||||
and ax._layoutbox is not None):
|
||||
if ax.get_subplotspec().get_gridspec() == gs:
|
||||
axs += [ax]
|
||||
rownummin = np.zeros(len(axs), dtype=np.int8)
|
||||
rownummax = np.zeros(len(axs), dtype=np.int8)
|
||||
colnummin = np.zeros(len(axs), dtype=np.int8)
|
||||
colnummax = np.zeros(len(axs), dtype=np.int8)
|
||||
width = np.zeros(len(axs))
|
||||
height = np.zeros(len(axs))
|
||||
|
||||
for n, ax in enumerate(axs):
|
||||
ss0 = ax.get_subplotspec()
|
||||
if ss0.num2 is None:
|
||||
ss0.num2 = ss0.num1
|
||||
rownummin[n], colnummin[n] = divmod(ss0.num1, ncols)
|
||||
rownummax[n], colnummax[n] = divmod(ss0.num2, ncols)
|
||||
width[n] = np.sum(
|
||||
width_ratios[colnummin[n]:(colnummax[n] + 1)])
|
||||
height[n] = np.sum(
|
||||
height_ratios[rownummin[n]:(rownummax[n] + 1)])
|
||||
|
||||
for nn, ax in enumerate(axs[:-1]):
|
||||
# now compare ax to all the axs:
|
||||
#
|
||||
# If the subplotspecs have the same colnumXmax, then line
|
||||
# up their right sides. If they have the same min, then
|
||||
# line up their left sides (and vertical equivalents).
|
||||
rownum0min, colnum0min = rownummin[nn], colnummin[nn]
|
||||
rownum0max, colnum0max = rownummax[nn], colnummax[nn]
|
||||
width0, height0 = width[nn], height[nn]
|
||||
alignleft = False
|
||||
alignright = False
|
||||
alignbot = False
|
||||
aligntop = False
|
||||
alignheight = False
|
||||
alignwidth = False
|
||||
for mm in range(nn+1, len(axs)):
|
||||
axc = axs[mm]
|
||||
rownumCmin, colnumCmin = rownummin[mm], colnummin[mm]
|
||||
rownumCmax, colnumCmax = rownummax[mm], colnummax[mm]
|
||||
widthC, heightC = width[mm], height[mm]
|
||||
# Horizontally align axes spines if they have the
|
||||
# same min or max:
|
||||
if not alignleft and colnum0min == colnumCmin:
|
||||
# we want the _poslayoutboxes to line up on left
|
||||
# side of the axes spines...
|
||||
layoutbox.align([ax._poslayoutbox,
|
||||
axc._poslayoutbox],
|
||||
'left')
|
||||
alignleft = True
|
||||
|
||||
if not alignright and colnum0max == colnumCmax:
|
||||
# line up right sides of _poslayoutbox
|
||||
layoutbox.align([ax._poslayoutbox,
|
||||
axc._poslayoutbox],
|
||||
'right')
|
||||
alignright = True
|
||||
# Vertically align axes spines if they have the
|
||||
# same min or max:
|
||||
if not aligntop and rownum0min == rownumCmin:
|
||||
# line up top of _poslayoutbox
|
||||
_log.debug('rownum0min == rownumCmin')
|
||||
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
|
||||
'top')
|
||||
aligntop = True
|
||||
|
||||
if not alignbot and rownum0max == rownumCmax:
|
||||
# line up bottom of _poslayoutbox
|
||||
_log.debug('rownum0max == rownumCmax')
|
||||
layoutbox.align([ax._poslayoutbox, axc._poslayoutbox],
|
||||
'bottom')
|
||||
alignbot = True
|
||||
###########
|
||||
# Now we make the widths and heights of position boxes
|
||||
# similar. (i.e the spine locations)
|
||||
# This allows vertically stacked subplots to have
|
||||
# different sizes if they occupy different amounts
|
||||
# of the gridspec: i.e.
|
||||
# gs = gridspec.GridSpec(3,1)
|
||||
# ax1 = gs[0,:]
|
||||
# ax2 = gs[1:,:]
|
||||
# then drows0 = 1, and drowsC = 2, and ax2
|
||||
# should be at least twice as large as ax1.
|
||||
# But it can be more than twice as large because
|
||||
# it needs less room for the labeling.
|
||||
#
|
||||
# For height, this only needs to be done if the
|
||||
# subplots share a column. For width if they
|
||||
# share a row.
|
||||
|
||||
drowsC = (rownumCmax - rownumCmin + 1)
|
||||
drows0 = (rownum0max - rownum0min + 1)
|
||||
dcolsC = (colnumCmax - colnumCmin + 1)
|
||||
dcols0 = (colnum0max - colnum0min + 1)
|
||||
|
||||
if not alignheight and drows0 == drowsC:
|
||||
ax._poslayoutbox.constrain_height(
|
||||
axc._poslayoutbox.height * height0 / heightC)
|
||||
alignheight = True
|
||||
elif _in_same_column(colnum0min, colnum0max,
|
||||
colnumCmin, colnumCmax):
|
||||
if height0 > heightC:
|
||||
ax._poslayoutbox.constrain_height_min(
|
||||
axc._poslayoutbox.height * height0 / heightC)
|
||||
# these constraints stop the smaller axes from
|
||||
# being allowed to go to zero height...
|
||||
axc._poslayoutbox.constrain_height_min(
|
||||
ax._poslayoutbox.height * heightC /
|
||||
(height0*1.8))
|
||||
elif height0 < heightC:
|
||||
axc._poslayoutbox.constrain_height_min(
|
||||
ax._poslayoutbox.height * heightC / height0)
|
||||
ax._poslayoutbox.constrain_height_min(
|
||||
ax._poslayoutbox.height * height0 /
|
||||
(heightC*1.8))
|
||||
# widths...
|
||||
if not alignwidth and dcols0 == dcolsC:
|
||||
ax._poslayoutbox.constrain_width(
|
||||
axc._poslayoutbox.width * width0 / widthC)
|
||||
alignwidth = True
|
||||
elif _in_same_row(rownum0min, rownum0max,
|
||||
rownumCmin, rownumCmax):
|
||||
if width0 > widthC:
|
||||
ax._poslayoutbox.constrain_width_min(
|
||||
axc._poslayoutbox.width * width0 / widthC)
|
||||
axc._poslayoutbox.constrain_width_min(
|
||||
ax._poslayoutbox.width * widthC /
|
||||
(width0*1.8))
|
||||
elif width0 < widthC:
|
||||
axc._poslayoutbox.constrain_width_min(
|
||||
ax._poslayoutbox.width * widthC / width0)
|
||||
ax._poslayoutbox.constrain_width_min(
|
||||
axc._poslayoutbox.width * width0 /
|
||||
(widthC*1.8))
|
||||
|
||||
|
||||
def _arrange_subplotspecs(gs, hspace=0, wspace=0):
|
||||
"""
|
||||
arrange the subplotspec children of this gridspec, and then recursively
|
||||
do the same of any gridspec children of those gridspecs...
|
||||
"""
|
||||
sschildren = []
|
||||
for child in gs.children:
|
||||
if child._is_subplotspec_layoutbox():
|
||||
for child2 in child.children:
|
||||
# check for gridspec children...
|
||||
if child2._is_gridspec_layoutbox():
|
||||
_arrange_subplotspecs(child2, hspace=hspace, wspace=wspace)
|
||||
sschildren += [child]
|
||||
# now arrange the subplots...
|
||||
for child0 in sschildren:
|
||||
ss0 = child0.artist
|
||||
nrows, ncols = ss0.get_gridspec().get_geometry()
|
||||
if ss0.num2 is None:
|
||||
ss0.num2 = ss0.num1
|
||||
rowNum0min, colNum0min = divmod(ss0.num1, ncols)
|
||||
rowNum0max, colNum0max = divmod(ss0.num2, ncols)
|
||||
sschildren = sschildren[1:]
|
||||
for childc in sschildren:
|
||||
ssc = childc.artist
|
||||
rowNumCmin, colNumCmin = divmod(ssc.num1, ncols)
|
||||
if ssc.num2 is None:
|
||||
ssc.num2 = ssc.num1
|
||||
rowNumCmax, colNumCmax = divmod(ssc.num2, ncols)
|
||||
# OK, this tells us the relative layout of ax
|
||||
# with axc
|
||||
thepad = wspace / ncols
|
||||
if colNum0max < colNumCmin:
|
||||
layoutbox.hstack([ss0._layoutbox, ssc._layoutbox],
|
||||
padding=thepad)
|
||||
if colNumCmax < colNum0min:
|
||||
layoutbox.hstack([ssc._layoutbox, ss0._layoutbox],
|
||||
padding=thepad)
|
||||
|
||||
####
|
||||
# vertical alignment
|
||||
thepad = hspace / nrows
|
||||
if rowNum0max < rowNumCmin:
|
||||
layoutbox.vstack([ss0._layoutbox,
|
||||
ssc._layoutbox],
|
||||
padding=thepad)
|
||||
if rowNumCmax < rowNum0min:
|
||||
layoutbox.vstack([ssc._layoutbox,
|
||||
ss0._layoutbox],
|
||||
padding=thepad)
|
||||
|
||||
|
||||
def layoutcolorbarsingle(ax, cax, shrink, aspect, location, pad=0.05):
|
||||
"""
|
||||
Do the layout for a colorbar, to not overly pollute colorbar.py
|
||||
|
||||
`pad` is in fraction of the original axis size.
|
||||
"""
|
||||
axlb = ax._layoutbox
|
||||
axpos = ax._poslayoutbox
|
||||
axsslb = ax.get_subplotspec()._layoutbox
|
||||
lb = layoutbox.LayoutBox(
|
||||
parent=axsslb,
|
||||
name=axsslb.name + '.cbar',
|
||||
artist=cax)
|
||||
|
||||
if location in ('left', 'right'):
|
||||
lbpos = layoutbox.LayoutBox(
|
||||
parent=lb,
|
||||
name=lb.name + '.pos',
|
||||
tightwidth=False,
|
||||
pos=True,
|
||||
subplot=False,
|
||||
artist=cax)
|
||||
|
||||
if location == 'right':
|
||||
# arrange to right of parent axis
|
||||
layoutbox.hstack([axlb, lb], padding=pad * axlb.width,
|
||||
strength='strong')
|
||||
else:
|
||||
layoutbox.hstack([lb, axlb], padding=pad * axlb.width)
|
||||
# constrain the height and center...
|
||||
layoutbox.match_heights([axpos, lbpos], [1, shrink])
|
||||
layoutbox.align([axpos, lbpos], 'v_center')
|
||||
# set the width of the pos box
|
||||
lbpos.constrain_width(shrink * axpos.height * (1/aspect),
|
||||
strength='strong')
|
||||
elif location in ('bottom', 'top'):
|
||||
lbpos = layoutbox.LayoutBox(
|
||||
parent=lb,
|
||||
name=lb.name + '.pos',
|
||||
tightheight=True,
|
||||
pos=True,
|
||||
subplot=False,
|
||||
artist=cax)
|
||||
|
||||
if location == 'bottom':
|
||||
layoutbox.vstack([axlb, lb], padding=pad * axlb.height)
|
||||
else:
|
||||
layoutbox.vstack([lb, axlb], padding=pad * axlb.height)
|
||||
# constrain the height and center...
|
||||
layoutbox.match_widths([axpos, lbpos],
|
||||
[1, shrink], strength='strong')
|
||||
layoutbox.align([axpos, lbpos], 'h_center')
|
||||
# set the height of the pos box
|
||||
lbpos.constrain_height(axpos.width * aspect * shrink,
|
||||
strength='medium')
|
||||
|
||||
return lb, lbpos
|
||||
|
||||
|
||||
def _getmaxminrowcolumn(axs):
|
||||
# helper to get the min/max rows and columns of a list of axes.
|
||||
maxrow = -100000
|
||||
minrow = 1000000
|
||||
maxax = None
|
||||
minax = None
|
||||
maxcol = -100000
|
||||
mincol = 1000000
|
||||
maxax_col = None
|
||||
minax_col = None
|
||||
|
||||
for ax in axs:
|
||||
subspec = ax.get_subplotspec()
|
||||
nrows, ncols, row_start, row_stop, col_start, col_stop = \
|
||||
subspec.get_rows_columns()
|
||||
if row_stop > maxrow:
|
||||
maxrow = row_stop
|
||||
maxax = ax
|
||||
if row_start < minrow:
|
||||
minrow = row_start
|
||||
minax = ax
|
||||
if col_stop > maxcol:
|
||||
maxcol = col_stop
|
||||
maxax_col = ax
|
||||
if col_start < mincol:
|
||||
mincol = col_start
|
||||
minax_col = ax
|
||||
return (minrow, maxrow, minax, maxax, mincol, maxcol, minax_col, maxax_col)
|
||||
|
||||
|
||||
def layoutcolorbargridspec(parents, cax, shrink, aspect, location, pad=0.05):
|
||||
"""
|
||||
Do the layout for a colorbar, to not overly pollute colorbar.py
|
||||
|
||||
`pad` is in fraction of the original axis size.
|
||||
"""
|
||||
|
||||
gs = parents[0].get_subplotspec().get_gridspec()
|
||||
# parent layout box....
|
||||
gslb = gs._layoutbox
|
||||
|
||||
lb = layoutbox.LayoutBox(parent=gslb.parent,
|
||||
name=gslb.parent.name + '.cbar',
|
||||
artist=cax)
|
||||
# figure out the row and column extent of the parents.
|
||||
(minrow, maxrow, minax_row, maxax_row,
|
||||
mincol, maxcol, minax_col, maxax_col) = _getmaxminrowcolumn(parents)
|
||||
|
||||
if location in ('left', 'right'):
|
||||
lbpos = layoutbox.LayoutBox(
|
||||
parent=lb,
|
||||
name=lb.name + '.pos',
|
||||
tightwidth=False,
|
||||
pos=True,
|
||||
subplot=False,
|
||||
artist=cax)
|
||||
for ax in parents:
|
||||
if location == 'right':
|
||||
order = [ax._layoutbox, lb]
|
||||
else:
|
||||
order = [lb, ax._layoutbox]
|
||||
layoutbox.hstack(order, padding=pad * gslb.width,
|
||||
strength='strong')
|
||||
# constrain the height and center...
|
||||
# This isn't quite right. We'd like the colorbar
|
||||
# pos to line up w/ the axes poss, not the size of the
|
||||
# gs.
|
||||
|
||||
# Horizontal Layout: need to check all the axes in this gridspec
|
||||
for ch in gslb.children:
|
||||
subspec = ch.artist
|
||||
nrows, ncols, row_start, row_stop, col_start, col_stop = \
|
||||
subspec.get_rows_columns()
|
||||
if location == 'right':
|
||||
if col_stop <= maxcol:
|
||||
order = [subspec._layoutbox, lb]
|
||||
# arrange to right of the parents
|
||||
if col_start > maxcol:
|
||||
order = [lb, subspec._layoutbox]
|
||||
elif location == 'left':
|
||||
if col_start >= mincol:
|
||||
order = [lb, subspec._layoutbox]
|
||||
if col_stop < mincol:
|
||||
order = [subspec._layoutbox, lb]
|
||||
layoutbox.hstack(order, padding=pad * gslb.width,
|
||||
strength='strong')
|
||||
|
||||
# Vertical layout:
|
||||
maxposlb = minax_row._poslayoutbox
|
||||
minposlb = maxax_row._poslayoutbox
|
||||
# now we want the height of the colorbar pos to be
|
||||
# set by the top and bottom of the min/max axes...
|
||||
# bottom top
|
||||
# b t
|
||||
# h = (top-bottom)*shrink
|
||||
# b = bottom + (top-bottom - h) / 2.
|
||||
lbpos.constrain_height(
|
||||
(maxposlb.top - minposlb.bottom) *
|
||||
shrink, strength='strong')
|
||||
lbpos.constrain_bottom(
|
||||
(maxposlb.top - minposlb.bottom) *
|
||||
(1 - shrink)/2 + minposlb.bottom,
|
||||
strength='strong')
|
||||
|
||||
# set the width of the pos box
|
||||
lbpos.constrain_width(lbpos.height * (shrink / aspect),
|
||||
strength='strong')
|
||||
elif location in ('bottom', 'top'):
|
||||
lbpos = layoutbox.LayoutBox(
|
||||
parent=lb,
|
||||
name=lb.name + '.pos',
|
||||
tightheight=True,
|
||||
pos=True,
|
||||
subplot=False,
|
||||
artist=cax)
|
||||
|
||||
for ax in parents:
|
||||
if location == 'bottom':
|
||||
order = [ax._layoutbox, lb]
|
||||
else:
|
||||
order = [lb, ax._layoutbox]
|
||||
layoutbox.vstack(order, padding=pad * gslb.width,
|
||||
strength='strong')
|
||||
|
||||
# Vertical Layout: need to check all the axes in this gridspec
|
||||
for ch in gslb.children:
|
||||
subspec = ch.artist
|
||||
nrows, ncols, row_start, row_stop, col_start, col_stop = \
|
||||
subspec.get_rows_columns()
|
||||
if location == 'bottom':
|
||||
if row_stop <= minrow:
|
||||
order = [subspec._layoutbox, lb]
|
||||
if row_start > maxrow:
|
||||
order = [lb, subspec._layoutbox]
|
||||
elif location == 'top':
|
||||
if row_stop < minrow:
|
||||
order = [subspec._layoutbox, lb]
|
||||
if row_start >= maxrow:
|
||||
order = [lb, subspec._layoutbox]
|
||||
layoutbox.vstack(order, padding=pad * gslb.width,
|
||||
strength='strong')
|
||||
|
||||
# Do horizontal layout...
|
||||
maxposlb = maxax_col._poslayoutbox
|
||||
minposlb = minax_col._poslayoutbox
|
||||
lbpos.constrain_width((maxposlb.right - minposlb.left) *
|
||||
shrink)
|
||||
lbpos.constrain_left(
|
||||
(maxposlb.right - minposlb.left) *
|
||||
(1-shrink)/2 + minposlb.left)
|
||||
# set the height of the pos box
|
||||
lbpos.constrain_height(lbpos.width * shrink * aspect,
|
||||
strength='medium')
|
||||
|
||||
return lb, lbpos
|
||||
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_contour.cpython-37m-darwin.so
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_contour.cpython-37m-darwin.so
vendored
Executable file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_image.cpython-37m-darwin.so
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_image.cpython-37m-darwin.so
vendored
Executable file
Binary file not shown.
732
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_layoutbox.py
vendored
Normal file
732
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_layoutbox.py
vendored
Normal file
@@ -0,0 +1,732 @@
|
||||
"""
|
||||
|
||||
Conventions:
|
||||
|
||||
"constrain_x" means to constrain the variable with either
|
||||
another kiwisolver variable, or a float. i.e. `constrain_width(0.2)`
|
||||
will set a constraint that the width has to be 0.2 and this constraint is
|
||||
permanent - i.e. it will not be removed if it becomes obsolete.
|
||||
|
||||
"edit_x" means to set x to a value (just a float), and that this value can
|
||||
change. So `edit_width(0.2)` will set width to be 0.2, but `edit_width(0.3)`
|
||||
will allow it to change to 0.3 later. Note that these values are still just
|
||||
"suggestions" in `kiwisolver` parlance, and could be over-ridden by
|
||||
other constrains.
|
||||
|
||||
"""
|
||||
|
||||
import itertools
|
||||
import kiwisolver as kiwi
|
||||
import logging
|
||||
import numpy as np
|
||||
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# renderers can be complicated
|
||||
def get_renderer(fig):
|
||||
if fig._cachedRenderer:
|
||||
renderer = fig._cachedRenderer
|
||||
else:
|
||||
canvas = fig.canvas
|
||||
if canvas and hasattr(canvas, "get_renderer"):
|
||||
renderer = canvas.get_renderer()
|
||||
else:
|
||||
# not sure if this can happen
|
||||
# seems to with PDF...
|
||||
_log.info("constrained_layout : falling back to Agg renderer")
|
||||
from matplotlib.backends.backend_agg import FigureCanvasAgg
|
||||
canvas = FigureCanvasAgg(fig)
|
||||
renderer = canvas.get_renderer()
|
||||
|
||||
return renderer
|
||||
|
||||
|
||||
class LayoutBox(object):
|
||||
"""
|
||||
Basic rectangle representation using kiwi solver variables
|
||||
"""
|
||||
|
||||
def __init__(self, parent=None, name='', tightwidth=False,
|
||||
tightheight=False, artist=None,
|
||||
lower_left=(0, 0), upper_right=(1, 1), pos=False,
|
||||
subplot=False, h_pad=None, w_pad=None):
|
||||
Variable = kiwi.Variable
|
||||
self.parent = parent
|
||||
self.name = name
|
||||
sn = self.name + '_'
|
||||
if parent is None:
|
||||
self.solver = kiwi.Solver()
|
||||
self.constrained_layout_called = 0
|
||||
else:
|
||||
self.solver = parent.solver
|
||||
self.constrained_layout_called = None
|
||||
# parent wants to know about this child!
|
||||
parent.add_child(self)
|
||||
# keep track of artist associated w/ this layout. Can be none
|
||||
self.artist = artist
|
||||
# keep track if this box is supposed to be a pos that is constrained
|
||||
# by the parent.
|
||||
self.pos = pos
|
||||
# keep track of whether we need to match this subplot up with others.
|
||||
self.subplot = subplot
|
||||
|
||||
# we need the str below for Py 2 which complains the string is unicode
|
||||
self.top = Variable(str(sn + 'top'))
|
||||
self.bottom = Variable(str(sn + 'bottom'))
|
||||
self.left = Variable(str(sn + 'left'))
|
||||
self.right = Variable(str(sn + 'right'))
|
||||
|
||||
self.width = Variable(str(sn + 'width'))
|
||||
self.height = Variable(str(sn + 'height'))
|
||||
self.h_center = Variable(str(sn + 'h_center'))
|
||||
self.v_center = Variable(str(sn + 'v_center'))
|
||||
|
||||
self.min_width = Variable(str(sn + 'min_width'))
|
||||
self.min_height = Variable(str(sn + 'min_height'))
|
||||
self.pref_width = Variable(str(sn + 'pref_width'))
|
||||
self.pref_height = Variable(str(sn + 'pref_height'))
|
||||
# margins are only used for axes-position layout boxes. maybe should
|
||||
# be a separate subclass:
|
||||
self.left_margin = Variable(str(sn + 'left_margin'))
|
||||
self.right_margin = Variable(str(sn + 'right_margin'))
|
||||
self.bottom_margin = Variable(str(sn + 'bottom_margin'))
|
||||
self.top_margin = Variable(str(sn + 'top_margin'))
|
||||
# mins
|
||||
self.left_margin_min = Variable(str(sn + 'left_margin_min'))
|
||||
self.right_margin_min = Variable(str(sn + 'right_margin_min'))
|
||||
self.bottom_margin_min = Variable(str(sn + 'bottom_margin_min'))
|
||||
self.top_margin_min = Variable(str(sn + 'top_margin_min'))
|
||||
|
||||
right, top = upper_right
|
||||
left, bottom = lower_left
|
||||
self.tightheight = tightheight
|
||||
self.tightwidth = tightwidth
|
||||
self.add_constraints()
|
||||
self.children = []
|
||||
self.subplotspec = None
|
||||
if self.pos:
|
||||
self.constrain_margins()
|
||||
self.h_pad = h_pad
|
||||
self.w_pad = w_pad
|
||||
|
||||
def constrain_margins(self):
|
||||
"""
|
||||
Only do this for pos. This sets a variable distance
|
||||
margin between the position of the axes and the outer edge of
|
||||
the axes.
|
||||
|
||||
Margins are variable because they change with the figure size.
|
||||
|
||||
Margin minimums are set to make room for axes decorations. However,
|
||||
the margins can be larger if we are mathicng the position size to
|
||||
other axes.
|
||||
"""
|
||||
sol = self.solver
|
||||
|
||||
# left
|
||||
if not sol.hasEditVariable(self.left_margin_min):
|
||||
sol.addEditVariable(self.left_margin_min, 'strong')
|
||||
sol.suggestValue(self.left_margin_min, 0.0001)
|
||||
c = (self.left_margin == self.left - self.parent.left)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
c = (self.left_margin >= self.left_margin_min)
|
||||
self.solver.addConstraint(c | 'strong')
|
||||
|
||||
# right
|
||||
if not sol.hasEditVariable(self.right_margin_min):
|
||||
sol.addEditVariable(self.right_margin_min, 'strong')
|
||||
sol.suggestValue(self.right_margin_min, 0.0001)
|
||||
c = (self.right_margin == self.parent.right - self.right)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
c = (self.right_margin >= self.right_margin_min)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
# bottom
|
||||
if not sol.hasEditVariable(self.bottom_margin_min):
|
||||
sol.addEditVariable(self.bottom_margin_min, 'strong')
|
||||
sol.suggestValue(self.bottom_margin_min, 0.0001)
|
||||
c = (self.bottom_margin == self.bottom - self.parent.bottom)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
c = (self.bottom_margin >= self.bottom_margin_min)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
# top
|
||||
if not sol.hasEditVariable(self.top_margin_min):
|
||||
sol.addEditVariable(self.top_margin_min, 'strong')
|
||||
sol.suggestValue(self.top_margin_min, 0.0001)
|
||||
c = (self.top_margin == self.parent.top - self.top)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
c = (self.top_margin >= self.top_margin_min)
|
||||
self.solver.addConstraint(c | 'required')
|
||||
|
||||
def add_child(self, child):
|
||||
self.children += [child]
|
||||
|
||||
def remove_child(self, child):
|
||||
try:
|
||||
self.children.remove(child)
|
||||
except ValueError:
|
||||
_log.info("Tried to remove child that doesn't belong to parent")
|
||||
|
||||
def add_constraints(self):
|
||||
sol = self.solver
|
||||
# never let width and height go negative.
|
||||
for i in [self.min_width, self.min_height]:
|
||||
sol.addEditVariable(i, 1e9)
|
||||
sol.suggestValue(i, 0.0)
|
||||
# define relation ships between things thing width and right and left
|
||||
self.hard_constraints()
|
||||
# self.soft_constraints()
|
||||
if self.parent:
|
||||
self.parent_constrain()
|
||||
# sol.updateVariables()
|
||||
|
||||
def parent_constrain(self):
|
||||
parent = self.parent
|
||||
hc = [self.left >= parent.left,
|
||||
self.bottom >= parent.bottom,
|
||||
self.top <= parent.top,
|
||||
self.right <= parent.right]
|
||||
for c in hc:
|
||||
self.solver.addConstraint(c | 'required')
|
||||
|
||||
def hard_constraints(self):
|
||||
hc = [self.width == self.right - self.left,
|
||||
self.height == self.top - self.bottom,
|
||||
self.h_center == (self.left + self.right) * 0.5,
|
||||
self.v_center == (self.top + self.bottom) * 0.5,
|
||||
self.width >= self.min_width,
|
||||
self.height >= self.min_height]
|
||||
for c in hc:
|
||||
self.solver.addConstraint(c | 'required')
|
||||
|
||||
def soft_constraints(self):
|
||||
sol = self.solver
|
||||
if self.tightwidth:
|
||||
suggest = 0.
|
||||
else:
|
||||
suggest = 20.
|
||||
c = (self.pref_width == suggest)
|
||||
for i in c:
|
||||
sol.addConstraint(i | 'required')
|
||||
if self.tightheight:
|
||||
suggest = 0.
|
||||
else:
|
||||
suggest = 20.
|
||||
c = (self.pref_height == suggest)
|
||||
for i in c:
|
||||
sol.addConstraint(i | 'required')
|
||||
|
||||
c = [(self.width >= suggest),
|
||||
(self.height >= suggest)]
|
||||
for i in c:
|
||||
sol.addConstraint(i | 150000)
|
||||
|
||||
def set_parent(self, parent):
|
||||
''' replace the parent of this with the new parent
|
||||
'''
|
||||
self.parent = parent
|
||||
self.parent_constrain()
|
||||
|
||||
def constrain_geometry(self, left, bottom, right, top, strength='strong'):
|
||||
hc = [self.left == left,
|
||||
self.right == right,
|
||||
self.bottom == bottom,
|
||||
self.top == top]
|
||||
for c in hc:
|
||||
self.solver.addConstraint(c | strength)
|
||||
# self.solver.updateVariables()
|
||||
|
||||
def constrain_same(self, other, strength='strong'):
|
||||
"""
|
||||
Make the layoutbox have same position as other layoutbox
|
||||
"""
|
||||
hc = [self.left == other.left,
|
||||
self.right == other.right,
|
||||
self.bottom == other.bottom,
|
||||
self.top == other.top]
|
||||
for c in hc:
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_left_margin(self, margin, strength='strong'):
|
||||
c = (self.left == self.parent.left + margin)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def edit_left_margin_min(self, margin):
|
||||
self.solver.suggestValue(self.left_margin_min, margin)
|
||||
|
||||
def constrain_right_margin(self, margin, strength='strong'):
|
||||
c = (self.right == self.parent.right - margin)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def edit_right_margin_min(self, margin):
|
||||
self.solver.suggestValue(self.right_margin_min, margin)
|
||||
|
||||
def constrain_bottom_margin(self, margin, strength='strong'):
|
||||
c = (self.bottom == self.parent.bottom + margin)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def edit_bottom_margin_min(self, margin):
|
||||
self.solver.suggestValue(self.bottom_margin_min, margin)
|
||||
|
||||
def constrain_top_margin(self, margin, strength='strong'):
|
||||
c = (self.top == self.parent.top - margin)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def edit_top_margin_min(self, margin):
|
||||
self.solver.suggestValue(self.top_margin_min, margin)
|
||||
|
||||
def get_rect(self):
|
||||
return (self.left.value(), self.bottom.value(),
|
||||
self.width.value(), self.height.value())
|
||||
|
||||
def update_variables(self):
|
||||
'''
|
||||
Update *all* the variables that are part of the solver this LayoutBox
|
||||
is created with
|
||||
'''
|
||||
self.solver.updateVariables()
|
||||
|
||||
def edit_height(self, height, strength='strong'):
|
||||
'''
|
||||
Set the height of the layout box.
|
||||
|
||||
This is done as an editable variable so that the value can change
|
||||
due to resizing.
|
||||
'''
|
||||
sol = self.solver
|
||||
for i in [self.height]:
|
||||
if not sol.hasEditVariable(i):
|
||||
sol.addEditVariable(i, strength)
|
||||
sol.suggestValue(self.height, height)
|
||||
|
||||
def constrain_height(self, height, strength='strong'):
|
||||
'''
|
||||
Constrain the height of the layout box. height is
|
||||
either a float or a layoutbox.height.
|
||||
'''
|
||||
c = (self.height == height)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_height_min(self, height, strength='strong'):
|
||||
c = (self.height >= height)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def edit_width(self, width, strength='strong'):
|
||||
sol = self.solver
|
||||
for i in [self.width]:
|
||||
if not sol.hasEditVariable(i):
|
||||
sol.addEditVariable(i, strength)
|
||||
sol.suggestValue(self.width, width)
|
||||
|
||||
def constrain_width(self, width, strength='strong'):
|
||||
'''
|
||||
Constrain the width of the layout box. `width` is
|
||||
either a float or a layoutbox.width.
|
||||
'''
|
||||
c = (self.width == width)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_width_min(self, width, strength='strong'):
|
||||
c = (self.width >= width)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_left(self, left, strength='strong'):
|
||||
c = (self.left == left)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_bottom(self, bottom, strength='strong'):
|
||||
c = (self.bottom == bottom)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_right(self, right, strength='strong'):
|
||||
c = (self.right == right)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def constrain_top(self, top, strength='strong'):
|
||||
c = (self.top == top)
|
||||
self.solver.addConstraint(c | strength)
|
||||
|
||||
def _is_subplotspec_layoutbox(self):
|
||||
'''
|
||||
Helper to check if this layoutbox is the layoutbox of a
|
||||
subplotspec
|
||||
'''
|
||||
name = (self.name).split('.')[-1]
|
||||
return name[:2] == 'ss'
|
||||
|
||||
def _is_gridspec_layoutbox(self):
|
||||
'''
|
||||
Helper to check if this layoutbox is the layoutbox of a
|
||||
gridspec
|
||||
'''
|
||||
name = (self.name).split('.')[-1]
|
||||
return name[:8] == 'gridspec'
|
||||
|
||||
def find_child_subplots(self):
|
||||
'''
|
||||
Find children of this layout box that are subplots. We want to line
|
||||
poss up, and this is an easy way to find them all.
|
||||
'''
|
||||
if self.subplot:
|
||||
subplots = [self]
|
||||
else:
|
||||
subplots = []
|
||||
for child in self.children:
|
||||
subplots += child.find_child_subplots()
|
||||
return subplots
|
||||
|
||||
def layout_from_subplotspec(self, subspec,
|
||||
name='', artist=None, pos=False):
|
||||
''' Make a layout box from a subplotspec. The layout box is
|
||||
constrained to be a fraction of the width/height of the parent,
|
||||
and be a fraction of the parent width/height from the left/bottom
|
||||
of the parent. Therefore the parent can move around and the
|
||||
layout for the subplot spec should move with it.
|
||||
|
||||
The parent is *usually* the gridspec that made the subplotspec.??
|
||||
'''
|
||||
lb = LayoutBox(parent=self, name=name, artist=artist, pos=pos)
|
||||
gs = subspec.get_gridspec()
|
||||
nrows, ncols = gs.get_geometry()
|
||||
parent = self.parent
|
||||
|
||||
# OK, now, we want to set the position of this subplotspec
|
||||
# based on its subplotspec parameters. The new gridspec will inherit.
|
||||
|
||||
# from gridspec. prob should be new method in gridspec
|
||||
left = 0.0
|
||||
right = 1.0
|
||||
bottom = 0.0
|
||||
top = 1.0
|
||||
totWidth = right-left
|
||||
totHeight = top-bottom
|
||||
hspace = 0.
|
||||
wspace = 0.
|
||||
|
||||
# calculate accumulated heights of columns
|
||||
cellH = totHeight / (nrows + hspace * (nrows - 1))
|
||||
sepH = hspace*cellH
|
||||
|
||||
if gs._row_height_ratios is not None:
|
||||
netHeight = cellH * nrows
|
||||
tr = float(sum(gs._row_height_ratios))
|
||||
cellHeights = [netHeight*r/tr for r in gs._row_height_ratios]
|
||||
else:
|
||||
cellHeights = [cellH] * nrows
|
||||
|
||||
sepHeights = [0] + ([sepH] * (nrows - 1))
|
||||
cellHs = np.add.accumulate(np.ravel(
|
||||
list(zip(sepHeights, cellHeights))))
|
||||
|
||||
# calculate accumulated widths of rows
|
||||
cellW = totWidth/(ncols + wspace * (ncols - 1))
|
||||
sepW = wspace*cellW
|
||||
|
||||
if gs._col_width_ratios is not None:
|
||||
netWidth = cellW * ncols
|
||||
tr = float(sum(gs._col_width_ratios))
|
||||
cellWidths = [netWidth * r / tr for r in gs._col_width_ratios]
|
||||
else:
|
||||
cellWidths = [cellW] * ncols
|
||||
|
||||
sepWidths = [0] + ([sepW] * (ncols - 1))
|
||||
cellWs = np.add.accumulate(np.ravel(list(zip(sepWidths, cellWidths))))
|
||||
|
||||
figTops = [top - cellHs[2 * rowNum] for rowNum in range(nrows)]
|
||||
figBottoms = [top - cellHs[2 * rowNum + 1] for rowNum in range(nrows)]
|
||||
figLefts = [left + cellWs[2 * colNum] for colNum in range(ncols)]
|
||||
figRights = [left + cellWs[2 * colNum + 1] for colNum in range(ncols)]
|
||||
|
||||
rowNum, colNum = divmod(subspec.num1, ncols)
|
||||
figBottom = figBottoms[rowNum]
|
||||
figTop = figTops[rowNum]
|
||||
figLeft = figLefts[colNum]
|
||||
figRight = figRights[colNum]
|
||||
|
||||
if subspec.num2 is not None:
|
||||
|
||||
rowNum2, colNum2 = divmod(subspec.num2, ncols)
|
||||
figBottom2 = figBottoms[rowNum2]
|
||||
figTop2 = figTops[rowNum2]
|
||||
figLeft2 = figLefts[colNum2]
|
||||
figRight2 = figRights[colNum2]
|
||||
|
||||
figBottom = min(figBottom, figBottom2)
|
||||
figLeft = min(figLeft, figLeft2)
|
||||
figTop = max(figTop, figTop2)
|
||||
figRight = max(figRight, figRight2)
|
||||
# These are numbers relative to 0,0,1,1. Need to constrain
|
||||
# relative to parent.
|
||||
|
||||
width = figRight - figLeft
|
||||
height = figTop - figBottom
|
||||
parent = self.parent
|
||||
cs = [self.left == parent.left + parent.width * figLeft,
|
||||
self.bottom == parent.bottom + parent.height * figBottom,
|
||||
self.width == parent.width * width,
|
||||
self.height == parent.height * height]
|
||||
for c in cs:
|
||||
self.solver.addConstraint(c | 'required')
|
||||
|
||||
return lb
|
||||
|
||||
def __repr__(self):
|
||||
args = (self.name, self.left.value(), self.bottom.value(),
|
||||
self.right.value(), self.top.value())
|
||||
return ('LayoutBox: %25s, (left: %1.3f) (bot: %1.3f) '
|
||||
'(right: %1.3f) (top: %1.3f) ') % args
|
||||
|
||||
|
||||
# Utility functions that act on layoutboxes...
|
||||
def hstack(boxes, padding=0, strength='strong'):
|
||||
'''
|
||||
Stack LayoutBox instances from left to right.
|
||||
`padding` is in figure-relative units.
|
||||
'''
|
||||
|
||||
for i in range(1, len(boxes)):
|
||||
c = (boxes[i-1].right + padding <= boxes[i].left)
|
||||
boxes[i].solver.addConstraint(c | strength)
|
||||
|
||||
|
||||
def hpack(boxes, padding=0, strength='strong'):
|
||||
'''
|
||||
Stack LayoutBox instances from left to right.
|
||||
'''
|
||||
|
||||
for i in range(1, len(boxes)):
|
||||
c = (boxes[i-1].right + padding == boxes[i].left)
|
||||
boxes[i].solver.addConstraint(c | strength)
|
||||
|
||||
|
||||
def vstack(boxes, padding=0, strength='strong'):
|
||||
'''
|
||||
Stack LayoutBox instances from top to bottom
|
||||
'''
|
||||
|
||||
for i in range(1, len(boxes)):
|
||||
c = (boxes[i-1].bottom - padding >= boxes[i].top)
|
||||
boxes[i].solver.addConstraint(c | strength)
|
||||
|
||||
|
||||
def vpack(boxes, padding=0, strength='strong'):
|
||||
'''
|
||||
Stack LayoutBox instances from top to bottom
|
||||
'''
|
||||
|
||||
for i in range(1, len(boxes)):
|
||||
c = (boxes[i-1].bottom - padding >= boxes[i].top)
|
||||
boxes[i].solver.addConstraint(c | strength)
|
||||
|
||||
|
||||
def match_heights(boxes, height_ratios=None, strength='medium'):
|
||||
'''
|
||||
Stack LayoutBox instances from top to bottom
|
||||
'''
|
||||
|
||||
if height_ratios is None:
|
||||
height_ratios = np.ones(len(boxes))
|
||||
for i in range(1, len(boxes)):
|
||||
c = (boxes[i-1].height ==
|
||||
boxes[i].height*height_ratios[i-1]/height_ratios[i])
|
||||
boxes[i].solver.addConstraint(c | strength)
|
||||
|
||||
|
||||
def match_widths(boxes, width_ratios=None, strength='medium'):
|
||||
'''
|
||||
Stack LayoutBox instances from top to bottom
|
||||
'''
|
||||
|
||||
if width_ratios is None:
|
||||
width_ratios = np.ones(len(boxes))
|
||||
for i in range(1, len(boxes)):
|
||||
c = (boxes[i-1].width ==
|
||||
boxes[i].width*width_ratios[i-1]/width_ratios[i])
|
||||
boxes[i].solver.addConstraint(c | strength)
|
||||
|
||||
|
||||
def vstackeq(boxes, padding=0, height_ratios=None):
|
||||
vstack(boxes, padding=padding)
|
||||
match_heights(boxes, height_ratios=height_ratios)
|
||||
|
||||
|
||||
def hstackeq(boxes, padding=0, width_ratios=None):
|
||||
hstack(boxes, padding=padding)
|
||||
match_widths(boxes, width_ratios=width_ratios)
|
||||
|
||||
|
||||
def align(boxes, attr, strength='strong'):
|
||||
cons = []
|
||||
for box in boxes[1:]:
|
||||
cons = (getattr(boxes[0], attr) == getattr(box, attr))
|
||||
boxes[0].solver.addConstraint(cons | strength)
|
||||
|
||||
|
||||
def match_top_margins(boxes, levels=1):
|
||||
box0 = boxes[0]
|
||||
top0 = box0
|
||||
for n in range(levels):
|
||||
top0 = top0.parent
|
||||
for box in boxes[1:]:
|
||||
topb = box
|
||||
for n in range(levels):
|
||||
topb = topb.parent
|
||||
c = (box0.top-top0.top == box.top-topb.top)
|
||||
box0.solver.addConstraint(c | 'strong')
|
||||
|
||||
|
||||
def match_bottom_margins(boxes, levels=1):
|
||||
box0 = boxes[0]
|
||||
top0 = box0
|
||||
for n in range(levels):
|
||||
top0 = top0.parent
|
||||
for box in boxes[1:]:
|
||||
topb = box
|
||||
for n in range(levels):
|
||||
topb = topb.parent
|
||||
c = (box0.bottom-top0.bottom == box.bottom-topb.bottom)
|
||||
box0.solver.addConstraint(c | 'strong')
|
||||
|
||||
|
||||
def match_left_margins(boxes, levels=1):
|
||||
box0 = boxes[0]
|
||||
top0 = box0
|
||||
for n in range(levels):
|
||||
top0 = top0.parent
|
||||
for box in boxes[1:]:
|
||||
topb = box
|
||||
for n in range(levels):
|
||||
topb = topb.parent
|
||||
c = (box0.left-top0.left == box.left-topb.left)
|
||||
box0.solver.addConstraint(c | 'strong')
|
||||
|
||||
|
||||
def match_right_margins(boxes, levels=1):
|
||||
box0 = boxes[0]
|
||||
top0 = box0
|
||||
for n in range(levels):
|
||||
top0 = top0.parent
|
||||
for box in boxes[1:]:
|
||||
topb = box
|
||||
for n in range(levels):
|
||||
topb = topb.parent
|
||||
c = (box0.right-top0.right == box.right-topb.right)
|
||||
box0.solver.addConstraint(c | 'strong')
|
||||
|
||||
|
||||
def match_width_margins(boxes, levels=1):
|
||||
match_left_margins(boxes, levels=levels)
|
||||
match_right_margins(boxes, levels=levels)
|
||||
|
||||
|
||||
def match_height_margins(boxes, levels=1):
|
||||
match_top_margins(boxes, levels=levels)
|
||||
match_bottom_margins(boxes, levels=levels)
|
||||
|
||||
|
||||
def match_margins(boxes, levels=1):
|
||||
match_width_margins(boxes, levels=levels)
|
||||
match_height_margins(boxes, levels=levels)
|
||||
|
||||
|
||||
_layoutboxobjnum = itertools.count()
|
||||
|
||||
|
||||
def seq_id():
|
||||
'''
|
||||
Generate a short sequential id for layoutbox objects...
|
||||
'''
|
||||
|
||||
global _layoutboxobjnum
|
||||
|
||||
return ('%06d' % (next(_layoutboxobjnum)))
|
||||
|
||||
|
||||
def print_children(lb):
|
||||
'''
|
||||
Print the children of the layoutbox
|
||||
'''
|
||||
print(lb)
|
||||
for child in lb.children:
|
||||
print_children(child)
|
||||
|
||||
|
||||
def nonetree(lb):
|
||||
'''
|
||||
Make all elements in this tree none... This signals not to do any more
|
||||
layout.
|
||||
'''
|
||||
if lb is not None:
|
||||
if lb.parent is None:
|
||||
# Clear the solver. Hopefully this garbage collects.
|
||||
lb.solver.reset()
|
||||
nonechildren(lb)
|
||||
else:
|
||||
nonetree(lb.parent)
|
||||
|
||||
|
||||
def nonechildren(lb):
|
||||
for child in lb.children:
|
||||
nonechildren(child)
|
||||
lb.artist._layoutbox = None
|
||||
lb = None
|
||||
|
||||
|
||||
def print_tree(lb):
|
||||
'''
|
||||
Print the tree of layoutboxes
|
||||
'''
|
||||
|
||||
if lb.parent is None:
|
||||
print('LayoutBox Tree\n')
|
||||
print('==============\n')
|
||||
print_children(lb)
|
||||
print('\n')
|
||||
else:
|
||||
print_tree(lb.parent)
|
||||
|
||||
|
||||
def plot_children(fig, box, level=0, printit=True):
|
||||
'''
|
||||
Simple plotting to show where boxes are
|
||||
'''
|
||||
import matplotlib
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
if isinstance(fig, matplotlib.figure.Figure):
|
||||
ax = fig.add_axes([0., 0., 1., 1.])
|
||||
ax.set_facecolor([1., 1., 1., 0.7])
|
||||
ax.set_alpha(0.3)
|
||||
fig.draw(fig.canvas.get_renderer())
|
||||
else:
|
||||
ax = fig
|
||||
|
||||
import matplotlib.patches as patches
|
||||
colors = plt.rcParams["axes.prop_cycle"].by_key()["color"]
|
||||
if printit:
|
||||
print("Level:", level)
|
||||
for child in box.children:
|
||||
if printit:
|
||||
print(child)
|
||||
ax.add_patch(
|
||||
patches.Rectangle(
|
||||
(child.left.value(), child.bottom.value()), # (x,y)
|
||||
child.width.value(), # width
|
||||
child.height.value(), # height
|
||||
fc='none',
|
||||
alpha=0.8,
|
||||
ec=colors[level]
|
||||
)
|
||||
)
|
||||
if level > 0:
|
||||
name = child.name.split('.')[-1]
|
||||
if level % 2 == 0:
|
||||
ax.text(child.left.value(), child.bottom.value(), name,
|
||||
size=12-level, color=colors[level])
|
||||
else:
|
||||
ax.text(child.right.value(), child.top.value(), name,
|
||||
ha='right', va='top', size=12-level,
|
||||
color=colors[level])
|
||||
|
||||
plot_children(ax, child, level=level+1, printit=printit)
|
||||
2544
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_mathtext_data.py
vendored
Normal file
2544
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_mathtext_data.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_path.cpython-37m-darwin.so
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_path.cpython-37m-darwin.so
vendored
Executable file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_png.cpython-37m-darwin.so
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_png.cpython-37m-darwin.so
vendored
Executable file
Binary file not shown.
130
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py
vendored
Normal file
130
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_pylab_helpers.py
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
"""
|
||||
Manage figures for pyplot interface.
|
||||
"""
|
||||
|
||||
import atexit
|
||||
import gc
|
||||
|
||||
|
||||
class Gcf(object):
|
||||
"""
|
||||
Singleton to manage a set of integer-numbered figures.
|
||||
|
||||
This class is never instantiated; it consists of two class
|
||||
attributes (a list and a dictionary), and a set of static
|
||||
methods that operate on those attributes, accessing them
|
||||
directly as class attributes.
|
||||
|
||||
Attributes:
|
||||
|
||||
*figs*:
|
||||
dictionary of the form {*num*: *manager*, ...}
|
||||
|
||||
*_activeQue*:
|
||||
list of *managers*, with active one at the end
|
||||
|
||||
"""
|
||||
_activeQue = []
|
||||
figs = {}
|
||||
|
||||
@classmethod
|
||||
def get_fig_manager(cls, num):
|
||||
"""
|
||||
If figure manager *num* exists, make it the active
|
||||
figure and return the manager; otherwise return *None*.
|
||||
"""
|
||||
manager = cls.figs.get(num, None)
|
||||
if manager is not None:
|
||||
cls.set_active(manager)
|
||||
return manager
|
||||
|
||||
@classmethod
|
||||
def destroy(cls, num):
|
||||
"""
|
||||
Try to remove all traces of figure *num*.
|
||||
|
||||
In the interactive backends, this is bound to the
|
||||
window "destroy" and "delete" events.
|
||||
"""
|
||||
if not cls.has_fignum(num):
|
||||
return
|
||||
manager = cls.figs[num]
|
||||
manager.canvas.mpl_disconnect(manager._cidgcf)
|
||||
cls._activeQue.remove(manager)
|
||||
del cls.figs[num]
|
||||
manager.destroy()
|
||||
gc.collect(1)
|
||||
|
||||
@classmethod
|
||||
def destroy_fig(cls, fig):
|
||||
"*fig* is a Figure instance"
|
||||
num = next((manager.num for manager in cls.figs.values()
|
||||
if manager.canvas.figure == fig), None)
|
||||
if num is not None:
|
||||
cls.destroy(num)
|
||||
|
||||
@classmethod
|
||||
def destroy_all(cls):
|
||||
# this is need to ensure that gc is available in corner cases
|
||||
# where modules are being torn down after install with easy_install
|
||||
import gc # noqa
|
||||
for manager in list(cls.figs.values()):
|
||||
manager.canvas.mpl_disconnect(manager._cidgcf)
|
||||
manager.destroy()
|
||||
|
||||
cls._activeQue = []
|
||||
cls.figs.clear()
|
||||
gc.collect(1)
|
||||
|
||||
@classmethod
|
||||
def has_fignum(cls, num):
|
||||
"""
|
||||
Return *True* if figure *num* exists.
|
||||
"""
|
||||
return num in cls.figs
|
||||
|
||||
@classmethod
|
||||
def get_all_fig_managers(cls):
|
||||
"""
|
||||
Return a list of figure managers.
|
||||
"""
|
||||
return list(cls.figs.values())
|
||||
|
||||
@classmethod
|
||||
def get_num_fig_managers(cls):
|
||||
"""
|
||||
Return the number of figures being managed.
|
||||
"""
|
||||
return len(cls.figs)
|
||||
|
||||
@classmethod
|
||||
def get_active(cls):
|
||||
"""
|
||||
Return the manager of the active figure, or *None*.
|
||||
"""
|
||||
if len(cls._activeQue) == 0:
|
||||
return None
|
||||
else:
|
||||
return cls._activeQue[-1]
|
||||
|
||||
@classmethod
|
||||
def set_active(cls, manager):
|
||||
"""
|
||||
Make the figure corresponding to *manager* the active one.
|
||||
"""
|
||||
oldQue = cls._activeQue[:]
|
||||
cls._activeQue = [m for m in oldQue if m != manager]
|
||||
cls._activeQue.append(manager)
|
||||
cls.figs[manager.num] = manager
|
||||
|
||||
@classmethod
|
||||
def draw_all(cls, force=False):
|
||||
"""
|
||||
Redraw all figures registered with the pyplot
|
||||
state machine.
|
||||
"""
|
||||
for f_mgr in cls.get_all_fig_managers():
|
||||
if force or f_mgr.canvas.figure.stale:
|
||||
f_mgr.canvas.draw_idle()
|
||||
|
||||
atexit.register(Gcf.destroy_all)
|
||||
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_qhull.cpython-37m-darwin.so
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_qhull.cpython-37m-darwin.so
vendored
Executable file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_tri.cpython-37m-darwin.so
vendored
Executable file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_tri.cpython-37m-darwin.so
vendored
Executable file
Binary file not shown.
21
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_version.py
vendored
Normal file
21
matPlotLib/env/lib/python3.7/site-packages/matplotlib/_version.py
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
# This file was generated by 'versioneer.py' (0.15) from
|
||||
# revision-control system data, or from the parent directory name of an
|
||||
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
||||
# of this file.
|
||||
|
||||
import json
|
||||
import sys
|
||||
|
||||
version_json = '''
|
||||
{
|
||||
"dirty": false,
|
||||
"error": null,
|
||||
"full-revisionid": "4a3f033fdd9d55aeb712bc4254a8fcf5f759d66c",
|
||||
"version": "3.1.3"
|
||||
}
|
||||
''' # END VERSION_JSON
|
||||
|
||||
|
||||
def get_versions():
|
||||
return json.loads(version_json)
|
||||
573
matPlotLib/env/lib/python3.7/site-packages/matplotlib/afm.py
vendored
Normal file
573
matPlotLib/env/lib/python3.7/site-packages/matplotlib/afm.py
vendored
Normal file
@@ -0,0 +1,573 @@
|
||||
"""
|
||||
This is a python interface to Adobe Font Metrics Files. Although a
|
||||
number of other python implementations exist, and may be more complete
|
||||
than this, it was decided not to go with them because they were
|
||||
either:
|
||||
|
||||
1) copyrighted or used a non-BSD compatible license
|
||||
|
||||
2) had too many dependencies and a free standing lib was needed
|
||||
|
||||
3) Did more than needed and it was easier to write afresh rather than
|
||||
figure out how to get just what was needed.
|
||||
|
||||
It is pretty easy to use, and requires only built-in python libs:
|
||||
|
||||
>>> from matplotlib import rcParams
|
||||
>>> import os.path
|
||||
>>> afm_fname = os.path.join(rcParams['datapath'],
|
||||
... 'fonts', 'afm', 'ptmr8a.afm')
|
||||
>>>
|
||||
>>> from matplotlib.afm import AFM
|
||||
>>> with open(afm_fname, 'rb') as fh:
|
||||
... afm = AFM(fh)
|
||||
>>> afm.string_width_height('What the heck?')
|
||||
(6220.0, 694)
|
||||
>>> afm.get_fontname()
|
||||
'Times-Roman'
|
||||
>>> afm.get_kern_dist('A', 'f')
|
||||
0
|
||||
>>> afm.get_kern_dist('A', 'y')
|
||||
-92.0
|
||||
>>> afm.get_bbox_char('!')
|
||||
[130, -9, 238, 676]
|
||||
|
||||
As in the Adobe Font Metrics File Format Specification, all dimensions
|
||||
are given in units of 1/1000 of the scale factor (point size) of the font
|
||||
being used.
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import re
|
||||
|
||||
|
||||
from ._mathtext_data import uni2type1
|
||||
from matplotlib.cbook import deprecated
|
||||
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _to_int(x):
|
||||
# Some AFM files have floats where we are expecting ints -- there is
|
||||
# probably a better way to handle this (support floats, round rather
|
||||
# than truncate). But I don't know what the best approach is now and
|
||||
# this change to _to_int should at least prevent mpl from crashing on
|
||||
# these JDH (2009-11-06)
|
||||
return int(float(x))
|
||||
|
||||
|
||||
def _to_float(x):
|
||||
# Some AFM files use "," instead of "." as decimal separator -- this
|
||||
# shouldn't be ambiguous (unless someone is wicked enough to use "," as
|
||||
# thousands separator...).
|
||||
if isinstance(x, bytes):
|
||||
# Encoding doesn't really matter -- if we have codepoints >127 the call
|
||||
# to float() will error anyways.
|
||||
x = x.decode('latin-1')
|
||||
return float(x.replace(',', '.'))
|
||||
|
||||
|
||||
def _to_str(x):
|
||||
return x.decode('utf8')
|
||||
|
||||
|
||||
def _to_list_of_ints(s):
|
||||
s = s.replace(b',', b' ')
|
||||
return [_to_int(val) for val in s.split()]
|
||||
|
||||
|
||||
def _to_list_of_floats(s):
|
||||
return [_to_float(val) for val in s.split()]
|
||||
|
||||
|
||||
def _to_bool(s):
|
||||
if s.lower().strip() in (b'false', b'0', b'no'):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def _sanity_check(fh):
|
||||
"""
|
||||
Check if the file looks like AFM; if it doesn't, raise `RuntimeError`.
|
||||
"""
|
||||
# Remember the file position in case the caller wants to
|
||||
# do something else with the file.
|
||||
pos = fh.tell()
|
||||
try:
|
||||
line = next(fh)
|
||||
finally:
|
||||
fh.seek(pos, 0)
|
||||
# AFM spec, Section 4: The StartFontMetrics keyword [followed by a
|
||||
# version number] must be the first line in the file, and the
|
||||
# EndFontMetrics keyword must be the last non-empty line in the
|
||||
# file. We just check the first line.
|
||||
if not line.startswith(b'StartFontMetrics'):
|
||||
raise RuntimeError('Not an AFM file')
|
||||
|
||||
|
||||
def _parse_header(fh):
|
||||
"""
|
||||
Reads the font metrics header (up to the char metrics) and returns
|
||||
a dictionary mapping *key* to *val*. *val* will be converted to the
|
||||
appropriate python type as necessary; e.g.:
|
||||
|
||||
* 'False'->False
|
||||
* '0'->0
|
||||
* '-168 -218 1000 898'-> [-168, -218, 1000, 898]
|
||||
|
||||
Dictionary keys are
|
||||
|
||||
StartFontMetrics, FontName, FullName, FamilyName, Weight,
|
||||
ItalicAngle, IsFixedPitch, FontBBox, UnderlinePosition,
|
||||
UnderlineThickness, Version, Notice, EncodingScheme, CapHeight,
|
||||
XHeight, Ascender, Descender, StartCharMetrics
|
||||
|
||||
"""
|
||||
header_converters = {
|
||||
b'StartFontMetrics': _to_float,
|
||||
b'FontName': _to_str,
|
||||
b'FullName': _to_str,
|
||||
b'FamilyName': _to_str,
|
||||
b'Weight': _to_str,
|
||||
b'ItalicAngle': _to_float,
|
||||
b'IsFixedPitch': _to_bool,
|
||||
b'FontBBox': _to_list_of_ints,
|
||||
b'UnderlinePosition': _to_float,
|
||||
b'UnderlineThickness': _to_float,
|
||||
b'Version': _to_str,
|
||||
# Some AFM files have non-ASCII characters (which are not allowed by
|
||||
# the spec). Given that there is actually no public API to even access
|
||||
# this field, just return it as straight bytes.
|
||||
b'Notice': lambda x: x,
|
||||
b'EncodingScheme': _to_str,
|
||||
b'CapHeight': _to_float, # Is the second version a mistake, or
|
||||
b'Capheight': _to_float, # do some AFM files contain 'Capheight'? -JKS
|
||||
b'XHeight': _to_float,
|
||||
b'Ascender': _to_float,
|
||||
b'Descender': _to_float,
|
||||
b'StdHW': _to_float,
|
||||
b'StdVW': _to_float,
|
||||
b'StartCharMetrics': _to_int,
|
||||
b'CharacterSet': _to_str,
|
||||
b'Characters': _to_int,
|
||||
}
|
||||
|
||||
d = {}
|
||||
for line in fh:
|
||||
line = line.rstrip()
|
||||
if line.startswith(b'Comment'):
|
||||
continue
|
||||
lst = line.split(b' ', 1)
|
||||
|
||||
key = lst[0]
|
||||
if len(lst) == 2:
|
||||
val = lst[1]
|
||||
else:
|
||||
val = b''
|
||||
|
||||
try:
|
||||
converter = header_converters[key]
|
||||
except KeyError:
|
||||
_log.error('Found an unknown keyword in AFM header (was %r)' % key)
|
||||
continue
|
||||
try:
|
||||
d[key] = converter(val)
|
||||
except ValueError:
|
||||
_log.error('Value error parsing header in AFM: %s, %s', key, val)
|
||||
continue
|
||||
if key == b'StartCharMetrics':
|
||||
return d
|
||||
raise RuntimeError('Bad parse')
|
||||
|
||||
|
||||
CharMetrics = namedtuple('CharMetrics', 'width, name, bbox')
|
||||
CharMetrics.__doc__ = """
|
||||
Represents the character metrics of a single character.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The fields do currently only describe a subset of character metrics
|
||||
information defined in the AFM standard.
|
||||
"""
|
||||
CharMetrics.width.__doc__ = """The character width (WX)."""
|
||||
CharMetrics.name.__doc__ = """The character name (N)."""
|
||||
CharMetrics.bbox.__doc__ = """
|
||||
The bbox of the character (B) as a tuple (*llx*, *lly*, *urx*, *ury*)."""
|
||||
|
||||
|
||||
def _parse_char_metrics(fh):
|
||||
"""
|
||||
Parse the given filehandle for character metrics information and return
|
||||
the information as dicts.
|
||||
|
||||
It is assumed that the file cursor is on the line behind
|
||||
'StartCharMetrics'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ascii_d : dict
|
||||
A mapping "ASCII num of the character" to `.CharMetrics`.
|
||||
name_d : dict
|
||||
A mapping "character name" to `.CharMetrics`.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This function is incomplete per the standard, but thus far parses
|
||||
all the sample afm files tried.
|
||||
"""
|
||||
required_keys = {'C', 'WX', 'N', 'B'}
|
||||
|
||||
ascii_d = {}
|
||||
name_d = {}
|
||||
for line in fh:
|
||||
# We are defensively letting values be utf8. The spec requires
|
||||
# ascii, but there are non-compliant fonts in circulation
|
||||
line = _to_str(line.rstrip()) # Convert from byte-literal
|
||||
if line.startswith('EndCharMetrics'):
|
||||
return ascii_d, name_d
|
||||
# Split the metric line into a dictionary, keyed by metric identifiers
|
||||
vals = dict(s.strip().split(' ', 1) for s in line.split(';') if s)
|
||||
# There may be other metrics present, but only these are needed
|
||||
if not required_keys.issubset(vals):
|
||||
raise RuntimeError('Bad char metrics line: %s' % line)
|
||||
num = _to_int(vals['C'])
|
||||
wx = _to_float(vals['WX'])
|
||||
name = vals['N']
|
||||
bbox = _to_list_of_floats(vals['B'])
|
||||
bbox = list(map(int, bbox))
|
||||
metrics = CharMetrics(wx, name, bbox)
|
||||
# Workaround: If the character name is 'Euro', give it the
|
||||
# corresponding character code, according to WinAnsiEncoding (see PDF
|
||||
# Reference).
|
||||
if name == 'Euro':
|
||||
num = 128
|
||||
if num != -1:
|
||||
ascii_d[num] = metrics
|
||||
name_d[name] = metrics
|
||||
raise RuntimeError('Bad parse')
|
||||
|
||||
|
||||
def _parse_kern_pairs(fh):
|
||||
"""
|
||||
Return a kern pairs dictionary; keys are (*char1*, *char2*) tuples and
|
||||
values are the kern pair value. For example, a kern pairs line like
|
||||
``KPX A y -50``
|
||||
|
||||
will be represented as::
|
||||
|
||||
d[ ('A', 'y') ] = -50
|
||||
|
||||
"""
|
||||
|
||||
line = next(fh)
|
||||
if not line.startswith(b'StartKernPairs'):
|
||||
raise RuntimeError('Bad start of kern pairs data: %s' % line)
|
||||
|
||||
d = {}
|
||||
for line in fh:
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
continue
|
||||
if line.startswith(b'EndKernPairs'):
|
||||
next(fh) # EndKernData
|
||||
return d
|
||||
vals = line.split()
|
||||
if len(vals) != 4 or vals[0] != b'KPX':
|
||||
raise RuntimeError('Bad kern pairs line: %s' % line)
|
||||
c1, c2, val = _to_str(vals[1]), _to_str(vals[2]), _to_float(vals[3])
|
||||
d[(c1, c2)] = val
|
||||
raise RuntimeError('Bad kern pairs parse')
|
||||
|
||||
|
||||
CompositePart = namedtuple('CompositePart', 'name, dx, dy')
|
||||
CompositePart.__doc__ = """
|
||||
Represents the information on a composite element of a composite char."""
|
||||
CompositePart.name.__doc__ = """Name of the part, e.g. 'acute'."""
|
||||
CompositePart.dx.__doc__ = """x-displacement of the part from the origin."""
|
||||
CompositePart.dy.__doc__ = """y-displacement of the part from the origin."""
|
||||
|
||||
|
||||
def _parse_composites(fh):
|
||||
"""
|
||||
Parse the given filehandle for composites information return them as a
|
||||
dict.
|
||||
|
||||
It is assumed that the file cursor is on the line behind 'StartComposites'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
composites : dict
|
||||
A dict mapping composite character names to a parts list. The parts
|
||||
list is a list of `.CompositePart` entries describing the parts of
|
||||
the composite.
|
||||
|
||||
Example
|
||||
-------
|
||||
A composite definition line::
|
||||
|
||||
CC Aacute 2 ; PCC A 0 0 ; PCC acute 160 170 ;
|
||||
|
||||
will be represented as::
|
||||
|
||||
composites['Aacute'] = [CompositePart(name='A', dx=0, dy=0),
|
||||
CompositePart(name='acute', dx=160, dy=170)]
|
||||
|
||||
"""
|
||||
composites = {}
|
||||
for line in fh:
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
continue
|
||||
if line.startswith(b'EndComposites'):
|
||||
return composites
|
||||
vals = line.split(b';')
|
||||
cc = vals[0].split()
|
||||
name, numParts = cc[1], _to_int(cc[2])
|
||||
pccParts = []
|
||||
for s in vals[1:-1]:
|
||||
pcc = s.split()
|
||||
part = CompositePart(pcc[1], _to_float(pcc[2]), _to_float(pcc[3]))
|
||||
pccParts.append(part)
|
||||
composites[name] = pccParts
|
||||
|
||||
raise RuntimeError('Bad composites parse')
|
||||
|
||||
|
||||
def _parse_optional(fh):
|
||||
"""
|
||||
Parse the optional fields for kern pair data and composites.
|
||||
|
||||
Returns
|
||||
-------
|
||||
kern_data : dict
|
||||
A dict containing kerning information. May be empty.
|
||||
See `._parse_kern_pairs`.
|
||||
composites : dict
|
||||
A dict containing composite information. May be empty.
|
||||
See `._parse_composites`.
|
||||
"""
|
||||
optional = {
|
||||
b'StartKernData': _parse_kern_pairs,
|
||||
b'StartComposites': _parse_composites,
|
||||
}
|
||||
|
||||
d = {b'StartKernData': {},
|
||||
b'StartComposites': {}}
|
||||
for line in fh:
|
||||
line = line.rstrip()
|
||||
if not line:
|
||||
continue
|
||||
key = line.split()[0]
|
||||
|
||||
if key in optional:
|
||||
d[key] = optional[key](fh)
|
||||
|
||||
return d[b'StartKernData'], d[b'StartComposites']
|
||||
|
||||
|
||||
@deprecated("3.0", alternative="the AFM class")
|
||||
def parse_afm(fh):
|
||||
return _parse_afm(fh)
|
||||
|
||||
|
||||
def _parse_afm(fh):
|
||||
"""
|
||||
Parse the Adobe Font Metrics file in file handle *fh*.
|
||||
|
||||
Returns
|
||||
-------
|
||||
header : dict
|
||||
A header dict. See :func:`_parse_header`.
|
||||
cmetrics_by_ascii : dict
|
||||
From :func:`_parse_char_metrics`.
|
||||
cmetrics_by_name : dict
|
||||
From :func:`_parse_char_metrics`.
|
||||
kernpairs : dict
|
||||
From :func:`_parse_kern_pairs`.
|
||||
composites : dict
|
||||
From :func:`_parse_composites`
|
||||
|
||||
"""
|
||||
_sanity_check(fh)
|
||||
header = _parse_header(fh)
|
||||
cmetrics_by_ascii, cmetrics_by_name = _parse_char_metrics(fh)
|
||||
kernpairs, composites = _parse_optional(fh)
|
||||
return header, cmetrics_by_ascii, cmetrics_by_name, kernpairs, composites
|
||||
|
||||
|
||||
class AFM(object):
|
||||
|
||||
def __init__(self, fh):
|
||||
"""Parse the AFM file in file object *fh*."""
|
||||
(self._header,
|
||||
self._metrics,
|
||||
self._metrics_by_name,
|
||||
self._kern,
|
||||
self._composite) = _parse_afm(fh)
|
||||
|
||||
def get_bbox_char(self, c, isord=False):
|
||||
if not isord:
|
||||
c = ord(c)
|
||||
return self._metrics[c].bbox
|
||||
|
||||
def string_width_height(self, s):
|
||||
"""
|
||||
Return the string width (including kerning) and string height
|
||||
as a (*w*, *h*) tuple.
|
||||
"""
|
||||
if not len(s):
|
||||
return 0, 0
|
||||
total_width = 0
|
||||
namelast = None
|
||||
miny = 1e9
|
||||
maxy = 0
|
||||
for c in s:
|
||||
if c == '\n':
|
||||
continue
|
||||
wx, name, bbox = self._metrics[ord(c)]
|
||||
|
||||
total_width += wx + self._kern.get((namelast, name), 0)
|
||||
l, b, w, h = bbox
|
||||
miny = min(miny, b)
|
||||
maxy = max(maxy, b + h)
|
||||
|
||||
namelast = name
|
||||
|
||||
return total_width, maxy - miny
|
||||
|
||||
def get_str_bbox_and_descent(self, s):
|
||||
"""Return the string bounding box and the maximal descent."""
|
||||
if not len(s):
|
||||
return 0, 0, 0, 0, 0
|
||||
total_width = 0
|
||||
namelast = None
|
||||
miny = 1e9
|
||||
maxy = 0
|
||||
left = 0
|
||||
if not isinstance(s, str):
|
||||
s = _to_str(s)
|
||||
for c in s:
|
||||
if c == '\n':
|
||||
continue
|
||||
name = uni2type1.get(ord(c), 'question')
|
||||
try:
|
||||
wx, _, bbox = self._metrics_by_name[name]
|
||||
except KeyError:
|
||||
name = 'question'
|
||||
wx, _, bbox = self._metrics_by_name[name]
|
||||
total_width += wx + self._kern.get((namelast, name), 0)
|
||||
l, b, w, h = bbox
|
||||
left = min(left, l)
|
||||
miny = min(miny, b)
|
||||
maxy = max(maxy, b + h)
|
||||
|
||||
namelast = name
|
||||
|
||||
return left, miny, total_width, maxy - miny, -miny
|
||||
|
||||
def get_str_bbox(self, s):
|
||||
"""Return the string bounding box."""
|
||||
return self.get_str_bbox_and_descent(s)[:4]
|
||||
|
||||
def get_name_char(self, c, isord=False):
|
||||
"""Get the name of the character, i.e., ';' is 'semicolon'."""
|
||||
if not isord:
|
||||
c = ord(c)
|
||||
return self._metrics[c].name
|
||||
|
||||
def get_width_char(self, c, isord=False):
|
||||
"""
|
||||
Get the width of the character from the character metric WX field.
|
||||
"""
|
||||
if not isord:
|
||||
c = ord(c)
|
||||
return self._metrics[c].width
|
||||
|
||||
def get_width_from_char_name(self, name):
|
||||
"""Get the width of the character from a type1 character name."""
|
||||
return self._metrics_by_name[name].width
|
||||
|
||||
def get_height_char(self, c, isord=False):
|
||||
"""Get the bounding box (ink) height of character *c* (space is 0)."""
|
||||
if not isord:
|
||||
c = ord(c)
|
||||
return self._metrics[c].bbox[-1]
|
||||
|
||||
def get_kern_dist(self, c1, c2):
|
||||
"""
|
||||
Return the kerning pair distance (possibly 0) for chars *c1* and *c2*.
|
||||
"""
|
||||
name1, name2 = self.get_name_char(c1), self.get_name_char(c2)
|
||||
return self.get_kern_dist_from_name(name1, name2)
|
||||
|
||||
def get_kern_dist_from_name(self, name1, name2):
|
||||
"""
|
||||
Return the kerning pair distance (possibly 0) for chars
|
||||
*name1* and *name2*.
|
||||
"""
|
||||
return self._kern.get((name1, name2), 0)
|
||||
|
||||
def get_fontname(self):
|
||||
"""Return the font name, e.g., 'Times-Roman'."""
|
||||
return self._header[b'FontName']
|
||||
|
||||
def get_fullname(self):
|
||||
"""Return the font full name, e.g., 'Times-Roman'."""
|
||||
name = self._header.get(b'FullName')
|
||||
if name is None: # use FontName as a substitute
|
||||
name = self._header[b'FontName']
|
||||
return name
|
||||
|
||||
def get_familyname(self):
|
||||
"""Return the font family name, e.g., 'Times'."""
|
||||
name = self._header.get(b'FamilyName')
|
||||
if name is not None:
|
||||
return name
|
||||
|
||||
# FamilyName not specified so we'll make a guess
|
||||
name = self.get_fullname()
|
||||
extras = (r'(?i)([ -](regular|plain|italic|oblique|bold|semibold|'
|
||||
r'light|ultralight|extra|condensed))+$')
|
||||
return re.sub(extras, '', name)
|
||||
|
||||
@property
|
||||
def family_name(self):
|
||||
"""The font family name, e.g., 'Times'."""
|
||||
return self.get_familyname()
|
||||
|
||||
def get_weight(self):
|
||||
"""Return the font weight, e.g., 'Bold' or 'Roman'."""
|
||||
return self._header[b'Weight']
|
||||
|
||||
def get_angle(self):
|
||||
"""Return the fontangle as float."""
|
||||
return self._header[b'ItalicAngle']
|
||||
|
||||
def get_capheight(self):
|
||||
"""Return the cap height as float."""
|
||||
return self._header[b'CapHeight']
|
||||
|
||||
def get_xheight(self):
|
||||
"""Return the xheight as float."""
|
||||
return self._header[b'XHeight']
|
||||
|
||||
def get_underline_thickness(self):
|
||||
"""Return the underline thickness as float."""
|
||||
return self._header[b'UnderlineThickness']
|
||||
|
||||
def get_horizontal_stem_width(self):
|
||||
"""
|
||||
Return the standard horizontal stem width as float, or *None* if
|
||||
not specified in AFM file.
|
||||
"""
|
||||
return self._header.get(b'StdHW', None)
|
||||
|
||||
def get_vertical_stem_width(self):
|
||||
"""
|
||||
Return the standard vertical stem width as float, or *None* if
|
||||
not specified in AFM file.
|
||||
"""
|
||||
return self._header.get(b'StdVW', None)
|
||||
1764
matPlotLib/env/lib/python3.7/site-packages/matplotlib/animation.py
vendored
Normal file
1764
matPlotLib/env/lib/python3.7/site-packages/matplotlib/animation.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1602
matPlotLib/env/lib/python3.7/site-packages/matplotlib/artist.py
vendored
Normal file
1602
matPlotLib/env/lib/python3.7/site-packages/matplotlib/artist.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__init__.py
vendored
Normal file
2
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__init__.py
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
from ._subplots import *
|
||||
from ._axes import *
|
||||
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/__init__.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/_axes.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/_axes.cpython-37.pyc
vendored
Normal file
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/_base.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/_base.cpython-37.pyc
vendored
Normal file
Binary file not shown.
Binary file not shown.
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/_subplots.cpython-37.pyc
vendored
Normal file
BIN
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/__pycache__/_subplots.cpython-37.pyc
vendored
Normal file
Binary file not shown.
8248
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_axes.py
vendored
Normal file
8248
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_axes.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
4485
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_base.py
vendored
Normal file
4485
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_base.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
466
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_secondary_axes.py
vendored
Normal file
466
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_secondary_axes.py
vendored
Normal file
@@ -0,0 +1,466 @@
|
||||
import collections
|
||||
import numpy as np
|
||||
import numbers
|
||||
|
||||
import warnings
|
||||
|
||||
import matplotlib.docstring as docstring
|
||||
import matplotlib.ticker as mticker
|
||||
import matplotlib.transforms as mtransforms
|
||||
import matplotlib.scale as mscale
|
||||
import matplotlib.cbook as cbook
|
||||
|
||||
from matplotlib.axes._base import _AxesBase
|
||||
|
||||
from matplotlib.ticker import (
|
||||
AutoLocator,
|
||||
AutoMinorLocator,
|
||||
FixedLocator,
|
||||
FuncFormatter,
|
||||
LogFormatterSciNotation,
|
||||
LogLocator,
|
||||
NullLocator,
|
||||
NullFormatter,
|
||||
ScalarFormatter
|
||||
)
|
||||
|
||||
from matplotlib.scale import Log10Transform
|
||||
|
||||
|
||||
def _make_secondary_locator(rect, parent):
|
||||
"""
|
||||
Helper function to locate the secondary axes.
|
||||
|
||||
A locator gets used in `Axes.set_aspect` to override the default
|
||||
locations... It is a function that takes an axes object and
|
||||
a renderer and tells `set_aspect` where it is to be placed.
|
||||
|
||||
This locator make the transform be in axes-relative co-coordinates
|
||||
because that is how we specify the "location" of the secondary axes.
|
||||
|
||||
Here *rect* is a rectangle [l, b, w, h] that specifies the
|
||||
location for the axes in the transform given by *trans* on the
|
||||
*parent*.
|
||||
"""
|
||||
_rect = mtransforms.Bbox.from_bounds(*rect)
|
||||
def secondary_locator(ax, renderer):
|
||||
# delay evaluating transform until draw time because the
|
||||
# parent transform may have changed (i.e. if window reesized)
|
||||
bb = mtransforms.TransformedBbox(_rect, parent.transAxes)
|
||||
tr = parent.figure.transFigure.inverted()
|
||||
bb = mtransforms.TransformedBbox(bb, tr)
|
||||
return bb
|
||||
|
||||
return secondary_locator
|
||||
|
||||
|
||||
class SecondaryAxis(_AxesBase):
|
||||
"""
|
||||
General class to hold a Secondary_X/Yaxis.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, orientation,
|
||||
location, functions, **kwargs):
|
||||
"""
|
||||
See `.secondary_xaxis` and `.secondary_yaxis` for the doc string.
|
||||
While there is no need for this to be private, it should really be
|
||||
called by those higher level functions.
|
||||
"""
|
||||
|
||||
self._functions = functions
|
||||
self._parent = parent
|
||||
self._orientation = orientation
|
||||
self._ticks_set = False
|
||||
|
||||
if self._orientation == 'x':
|
||||
super().__init__(self._parent.figure, [0, 1., 1, 0.0001], **kwargs)
|
||||
self._axis = self.xaxis
|
||||
self._locstrings = ['top', 'bottom']
|
||||
self._otherstrings = ['left', 'right']
|
||||
elif self._orientation == 'y':
|
||||
super().__init__(self._parent.figure, [0, 1., 0.0001, 1], **kwargs)
|
||||
self._axis = self.yaxis
|
||||
self._locstrings = ['right', 'left']
|
||||
self._otherstrings = ['top', 'bottom']
|
||||
# this gets positioned w/o constrained_layout so exclude:
|
||||
self._layoutbox = None
|
||||
self._poslayoutbox = None
|
||||
|
||||
self.set_location(location)
|
||||
self.set_functions(functions)
|
||||
|
||||
# styling:
|
||||
if self._orientation == 'x':
|
||||
otheraxis = self.yaxis
|
||||
else:
|
||||
otheraxis = self.xaxis
|
||||
|
||||
otheraxis.set_major_locator(mticker.NullLocator())
|
||||
otheraxis.set_ticks_position('none')
|
||||
|
||||
for st in self._otherstrings:
|
||||
self.spines[st].set_visible(False)
|
||||
for st in self._locstrings:
|
||||
self.spines[st].set_visible(True)
|
||||
|
||||
if self._pos < 0.5:
|
||||
# flip the location strings...
|
||||
self._locstrings = self._locstrings[::-1]
|
||||
self.set_alignment(self._locstrings[0])
|
||||
|
||||
def set_alignment(self, align):
|
||||
"""
|
||||
Set if axes spine and labels are drawn at top or bottom (or left/right)
|
||||
of the axes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
align :: string
|
||||
either 'top' or 'bottom' for orientation='x' or
|
||||
'left' or 'right' for orientation='y' axis
|
||||
|
||||
"""
|
||||
if align in self._locstrings:
|
||||
if align == self._locstrings[1]:
|
||||
# need to change the orientation.
|
||||
self._locstrings = self._locstrings[::-1]
|
||||
elif align != self._locstrings[0]:
|
||||
raise ValueError('"{}" is not a valid axis orientation, '
|
||||
'not changing the orientation;'
|
||||
'choose "{}" or "{}""'.format(align,
|
||||
self._locstrings[0], self._locstrings[1]))
|
||||
self.spines[self._locstrings[0]].set_visible(True)
|
||||
self.spines[self._locstrings[1]].set_visible(False)
|
||||
self._axis.set_ticks_position(align)
|
||||
self._axis.set_label_position(align)
|
||||
|
||||
def set_location(self, location):
|
||||
"""
|
||||
Set the vertical or horizontal location of the axes in
|
||||
parent-normalized co-ordinates.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
location : string or scalar
|
||||
The position to put the secondary axis. Strings can be 'top' or
|
||||
'bottom' for orientation='x' and 'right' or 'left' for
|
||||
orientation='y', scalar can be a float indicating the relative
|
||||
position on the parent axes to put the new axes, 0.0 being the
|
||||
bottom (or left) and 1.0 being the top (or right).
|
||||
"""
|
||||
|
||||
# This puts the rectangle into figure-relative coordinates.
|
||||
if isinstance(location, str):
|
||||
if location in ['top', 'right']:
|
||||
self._pos = 1.
|
||||
elif location in ['bottom', 'left']:
|
||||
self._pos = 0.
|
||||
else:
|
||||
raise ValueError("location must be '{}', '{}', or a "
|
||||
"float, not '{}'".format(location,
|
||||
self._locstrings[0], self._locstrings[1]))
|
||||
else:
|
||||
self._pos = location
|
||||
self._loc = location
|
||||
|
||||
if self._orientation == 'x':
|
||||
bounds = [0, self._pos, 1., 1e-10]
|
||||
else:
|
||||
bounds = [self._pos, 0, 1e-10, 1]
|
||||
|
||||
secondary_locator = _make_secondary_locator(bounds, self._parent)
|
||||
|
||||
# this locator lets the axes move in the parent axes coordinates.
|
||||
# so it never needs to know where the parent is explicitly in
|
||||
# figure co-ordinates.
|
||||
# it gets called in `ax.apply_aspect() (of all places)
|
||||
self.set_axes_locator(secondary_locator)
|
||||
|
||||
def apply_aspect(self, position=None):
|
||||
self._set_lims()
|
||||
super().apply_aspect(position)
|
||||
|
||||
def set_ticks(self, ticks, minor=False):
|
||||
"""
|
||||
Set the x ticks with list of *ticks*
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ticks : list
|
||||
List of x-axis tick locations.
|
||||
|
||||
minor : bool, optional
|
||||
If ``False`` sets major ticks, if ``True`` sets minor ticks.
|
||||
Default is ``False``.
|
||||
"""
|
||||
ret = self._axis.set_ticks(ticks, minor=minor)
|
||||
self.stale = True
|
||||
self._ticks_set = True
|
||||
return ret
|
||||
|
||||
def set_functions(self, functions):
|
||||
"""
|
||||
Set how the secondary axis converts limits from the parent axes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
functions : 2-tuple of func, or `Transform` with an inverse.
|
||||
Transform between the parent axis values and the secondary axis
|
||||
values.
|
||||
|
||||
If supplied as a 2-tuple of functions, the first function is
|
||||
the forward transform function and the second is the inverse
|
||||
transform.
|
||||
|
||||
If a transform is supplied, then the transform must have an
|
||||
inverse.
|
||||
|
||||
"""
|
||||
|
||||
if self._orientation == 'x':
|
||||
set_scale = self.set_xscale
|
||||
parent_scale = self._parent.get_xscale()
|
||||
else:
|
||||
set_scale = self.set_yscale
|
||||
parent_scale = self._parent.get_yscale()
|
||||
# we need to use a modified scale so the scale can receive the
|
||||
# transform. Only types supported are linear and log10 for now.
|
||||
# Probably possible to add other transforms as a todo...
|
||||
if parent_scale == 'log':
|
||||
defscale = 'functionlog'
|
||||
else:
|
||||
defscale = 'function'
|
||||
|
||||
if (isinstance(functions, tuple) and len(functions) == 2 and
|
||||
callable(functions[0]) and callable(functions[1])):
|
||||
# make an arbitrary convert from a two-tuple of functions
|
||||
# forward and inverse.
|
||||
self._functions = functions
|
||||
elif functions is None:
|
||||
self._functions = (lambda x: x, lambda x: x)
|
||||
else:
|
||||
raise ValueError('functions argument of secondary axes '
|
||||
'must be a two-tuple of callable functions '
|
||||
'with the first function being the transform '
|
||||
'and the second being the inverse')
|
||||
# need to invert the roles here for the ticks to line up.
|
||||
set_scale(defscale, functions=self._functions[::-1])
|
||||
|
||||
def draw(self, renderer=None, inframe=False):
|
||||
"""
|
||||
Draw the secondary axes.
|
||||
|
||||
Consults the parent axes for its limits and converts them
|
||||
using the converter specified by
|
||||
`~.axes._secondary_axes.set_functions` (or *functions*
|
||||
parameter when axes initialized.)
|
||||
|
||||
"""
|
||||
|
||||
self._set_lims()
|
||||
# this sets the scale in case the parent has set its scale.
|
||||
self._set_scale()
|
||||
super().draw(renderer=renderer, inframe=inframe)
|
||||
|
||||
def _set_scale(self):
|
||||
"""
|
||||
Check if parent has set its scale
|
||||
"""
|
||||
|
||||
if self._orientation == 'x':
|
||||
pscale = self._parent.xaxis.get_scale()
|
||||
set_scale = self.set_xscale
|
||||
if self._orientation == 'y':
|
||||
pscale = self._parent.yaxis.get_scale()
|
||||
set_scale = self.set_yscale
|
||||
if pscale == 'log':
|
||||
defscale = 'functionlog'
|
||||
else:
|
||||
defscale = 'function'
|
||||
|
||||
if self._ticks_set:
|
||||
ticks = self._axis.get_ticklocs()
|
||||
|
||||
# need to invert the roles here for the ticks to line up.
|
||||
set_scale(defscale, functions=self._functions[::-1])
|
||||
|
||||
# OK, set_scale sets the locators, but if we've called
|
||||
# axsecond.set_ticks, we want to keep those.
|
||||
if self._ticks_set:
|
||||
self._axis.set_major_locator(FixedLocator(ticks))
|
||||
|
||||
def _set_lims(self):
|
||||
"""
|
||||
Set the limits based on parent limits and the convert method
|
||||
between the parent and this secondary axes
|
||||
"""
|
||||
if self._orientation == 'x':
|
||||
lims = self._parent.get_xlim()
|
||||
set_lim = self.set_xlim
|
||||
trans = self.xaxis.get_transform()
|
||||
if self._orientation == 'y':
|
||||
lims = self._parent.get_ylim()
|
||||
set_lim = self.set_ylim
|
||||
trans = self.yaxis.get_transform()
|
||||
order = lims[0] < lims[1]
|
||||
lims = self._functions[0](np.array(lims))
|
||||
neworder = lims[0] < lims[1]
|
||||
if neworder != order:
|
||||
# flip because the transform will take care of the flipping..
|
||||
lims = lims[::-1]
|
||||
set_lim(lims)
|
||||
|
||||
def get_tightbbox(self, renderer, call_axes_locator=True):
|
||||
"""
|
||||
Return the tight bounding box of the axes.
|
||||
The dimension of the Bbox in canvas coordinate.
|
||||
|
||||
If *call_axes_locator* is *False*, it does not call the
|
||||
_axes_locator attribute, which is necessary to get the correct
|
||||
bounding box. ``call_axes_locator==False`` can be used if the
|
||||
caller is only intereted in the relative size of the tightbbox
|
||||
compared to the axes bbox.
|
||||
"""
|
||||
|
||||
bb = []
|
||||
|
||||
if not self.get_visible():
|
||||
return None
|
||||
|
||||
self._set_lims()
|
||||
locator = self.get_axes_locator()
|
||||
if locator and call_axes_locator:
|
||||
pos = locator(self, renderer)
|
||||
self.apply_aspect(pos)
|
||||
else:
|
||||
self.apply_aspect()
|
||||
|
||||
if self._orientation == 'x':
|
||||
bb_axis = self.xaxis.get_tightbbox(renderer)
|
||||
else:
|
||||
bb_axis = self.yaxis.get_tightbbox(renderer)
|
||||
if bb_axis:
|
||||
bb.append(bb_axis)
|
||||
|
||||
bb.append(self.get_window_extent(renderer))
|
||||
_bbox = mtransforms.Bbox.union(
|
||||
[b for b in bb if b.width != 0 or b.height != 0])
|
||||
|
||||
return _bbox
|
||||
|
||||
def set_aspect(self, *args, **kwargs):
|
||||
"""
|
||||
Secondary axes cannot set the aspect ratio, so calling this just
|
||||
sets a warning.
|
||||
"""
|
||||
cbook._warn_external("Secondary axes can't set the aspect ratio")
|
||||
|
||||
def set_xlabel(self, xlabel, fontdict=None, labelpad=None, **kwargs):
|
||||
"""
|
||||
Set the label for the x-axis.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
xlabel : str
|
||||
The label text.
|
||||
|
||||
labelpad : scalar, optional, default: None
|
||||
Spacing in points between the label and the x-axis.
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
**kwargs : `.Text` properties
|
||||
`.Text` properties control the appearance of the label.
|
||||
|
||||
See also
|
||||
--------
|
||||
text : for information on how override and the optional args work
|
||||
"""
|
||||
if labelpad is not None:
|
||||
self.xaxis.labelpad = labelpad
|
||||
return self.xaxis.set_label_text(xlabel, fontdict, **kwargs)
|
||||
|
||||
def set_ylabel(self, ylabel, fontdict=None, labelpad=None, **kwargs):
|
||||
"""
|
||||
Set the label for the x-axis.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ylabel : str
|
||||
The label text.
|
||||
|
||||
labelpad : scalar, optional, default: None
|
||||
Spacing in points between the label and the x-axis.
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
**kwargs : `.Text` properties
|
||||
`.Text` properties control the appearance of the label.
|
||||
|
||||
See also
|
||||
--------
|
||||
text : for information on how override and the optional args work
|
||||
"""
|
||||
if labelpad is not None:
|
||||
self.yaxis.labelpad = labelpad
|
||||
return self.yaxis.set_label_text(ylabel, fontdict, **kwargs)
|
||||
|
||||
def set_color(self, color):
|
||||
"""
|
||||
Change the color of the secondary axes and all decorators
|
||||
Parameters
|
||||
----------
|
||||
color : Matplotlib color
|
||||
"""
|
||||
|
||||
if self._orientation == 'x':
|
||||
self.tick_params(axis='x', colors=color)
|
||||
self.spines['bottom'].set_color(color)
|
||||
self.spines['top'].set_color(color)
|
||||
self.xaxis.label.set_color(color)
|
||||
else:
|
||||
self.tick_params(axis='y', colors=color)
|
||||
self.spines['left'].set_color(color)
|
||||
self.spines['right'].set_color(color)
|
||||
self.yaxis.label.set_color(color)
|
||||
|
||||
|
||||
_secax_docstring = '''
|
||||
Warnings
|
||||
--------
|
||||
|
||||
This method is experimental as of 3.1, and the API may change.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
location : string or scalar
|
||||
The position to put the secondary axis. Strings can be 'top' or
|
||||
'bottom', for x-oriented axises or 'left' or 'right' for y-oriented axises
|
||||
or a scalar can be a float indicating the relative position
|
||||
on the axes to put the new axes (0 being the bottom (left), and 1.0 being
|
||||
the top (right).)
|
||||
|
||||
functions : 2-tuple of func, or Transform with an inverse
|
||||
|
||||
If a 2-tuple of functions, the user specifies the transform
|
||||
function and its inverse. i.e.
|
||||
`functions=(lambda x: 2 / x, lambda x: 2 / x)` would be an
|
||||
reciprocal transform with a factor of 2.
|
||||
|
||||
The user can also directly supply a subclass of
|
||||
`.transforms.Transform` so long as it has an inverse.
|
||||
|
||||
See :doc:`/gallery/subplots_axes_and_figures/secondary_axis`
|
||||
for examples of making these conversions.
|
||||
|
||||
|
||||
Other Parameters
|
||||
----------------
|
||||
**kwargs : `~matplotlib.axes.Axes` properties.
|
||||
Other miscellaneous axes parameters.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ax : axes._secondary_axes.SecondaryAxis
|
||||
'''
|
||||
docstring.interpd.update(_secax_docstring=_secax_docstring)
|
||||
241
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_subplots.py
vendored
Normal file
241
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axes/_subplots.py
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
import functools
|
||||
import uuid
|
||||
|
||||
from matplotlib import cbook, docstring
|
||||
import matplotlib.artist as martist
|
||||
from matplotlib.axes._axes import Axes
|
||||
from matplotlib.gridspec import GridSpec, SubplotSpec
|
||||
import matplotlib._layoutbox as layoutbox
|
||||
|
||||
|
||||
class SubplotBase(object):
|
||||
"""
|
||||
Base class for subplots, which are :class:`Axes` instances with
|
||||
additional methods to facilitate generating and manipulating a set
|
||||
of :class:`Axes` within a figure.
|
||||
"""
|
||||
|
||||
def __init__(self, fig, *args, **kwargs):
|
||||
"""
|
||||
*fig* is a :class:`matplotlib.figure.Figure` instance.
|
||||
|
||||
*args* is the tuple (*numRows*, *numCols*, *plotNum*), where
|
||||
the array of subplots in the figure has dimensions *numRows*,
|
||||
*numCols*, and where *plotNum* is the number of the subplot
|
||||
being created. *plotNum* starts at 1 in the upper left
|
||||
corner and increases to the right.
|
||||
|
||||
If *numRows* <= *numCols* <= *plotNum* < 10, *args* can be the
|
||||
decimal integer *numRows* * 100 + *numCols* * 10 + *plotNum*.
|
||||
"""
|
||||
|
||||
self.figure = fig
|
||||
|
||||
if len(args) == 1:
|
||||
if isinstance(args[0], SubplotSpec):
|
||||
self._subplotspec = args[0]
|
||||
else:
|
||||
try:
|
||||
s = str(int(args[0]))
|
||||
rows, cols, num = map(int, s)
|
||||
except ValueError:
|
||||
raise ValueError('Single argument to subplot must be '
|
||||
'a 3-digit integer')
|
||||
self._subplotspec = GridSpec(rows, cols,
|
||||
figure=self.figure)[num - 1]
|
||||
# num - 1 for converting from MATLAB to python indexing
|
||||
elif len(args) == 3:
|
||||
rows, cols, num = args
|
||||
rows = int(rows)
|
||||
cols = int(cols)
|
||||
if isinstance(num, tuple) and len(num) == 2:
|
||||
num = [int(n) for n in num]
|
||||
self._subplotspec = GridSpec(
|
||||
rows, cols,
|
||||
figure=self.figure)[(num[0] - 1):num[1]]
|
||||
else:
|
||||
if num < 1 or num > rows*cols:
|
||||
raise ValueError(
|
||||
f"num must be 1 <= num <= {rows*cols}, not {num}")
|
||||
self._subplotspec = GridSpec(
|
||||
rows, cols, figure=self.figure)[int(num) - 1]
|
||||
# num - 1 for converting from MATLAB to python indexing
|
||||
else:
|
||||
raise ValueError(f'Illegal argument(s) to subplot: {args}')
|
||||
|
||||
self.update_params()
|
||||
|
||||
# _axes_class is set in the subplot_class_factory
|
||||
self._axes_class.__init__(self, fig, self.figbox, **kwargs)
|
||||
# add a layout box to this, for both the full axis, and the poss
|
||||
# of the axis. We need both because the axes may become smaller
|
||||
# due to parasitic axes and hence no longer fill the subplotspec.
|
||||
if self._subplotspec._layoutbox is None:
|
||||
self._layoutbox = None
|
||||
self._poslayoutbox = None
|
||||
else:
|
||||
name = self._subplotspec._layoutbox.name + '.ax'
|
||||
name = name + layoutbox.seq_id()
|
||||
self._layoutbox = layoutbox.LayoutBox(
|
||||
parent=self._subplotspec._layoutbox,
|
||||
name=name,
|
||||
artist=self)
|
||||
self._poslayoutbox = layoutbox.LayoutBox(
|
||||
parent=self._layoutbox,
|
||||
name=self._layoutbox.name+'.pos',
|
||||
pos=True, subplot=True, artist=self)
|
||||
|
||||
def __reduce__(self):
|
||||
# get the first axes class which does not inherit from a subplotbase
|
||||
axes_class = next(
|
||||
c for c in type(self).__mro__
|
||||
if issubclass(c, Axes) and not issubclass(c, SubplotBase))
|
||||
return (_picklable_subplot_class_constructor,
|
||||
(axes_class,),
|
||||
self.__getstate__())
|
||||
|
||||
def get_geometry(self):
|
||||
"""get the subplot geometry, e.g., 2,2,3"""
|
||||
rows, cols, num1, num2 = self.get_subplotspec().get_geometry()
|
||||
return rows, cols, num1 + 1 # for compatibility
|
||||
|
||||
# COVERAGE NOTE: Never used internally or from examples
|
||||
def change_geometry(self, numrows, numcols, num):
|
||||
"""change subplot geometry, e.g., from 1,1,1 to 2,2,3"""
|
||||
self._subplotspec = GridSpec(numrows, numcols,
|
||||
figure=self.figure)[num - 1]
|
||||
self.update_params()
|
||||
self.set_position(self.figbox)
|
||||
|
||||
def get_subplotspec(self):
|
||||
"""get the SubplotSpec instance associated with the subplot"""
|
||||
return self._subplotspec
|
||||
|
||||
def set_subplotspec(self, subplotspec):
|
||||
"""set the SubplotSpec instance associated with the subplot"""
|
||||
self._subplotspec = subplotspec
|
||||
|
||||
def get_gridspec(self):
|
||||
"""get the GridSpec instance associated with the subplot"""
|
||||
return self._subplotspec.get_gridspec()
|
||||
|
||||
def update_params(self):
|
||||
"""update the subplot position from fig.subplotpars"""
|
||||
|
||||
self.figbox, self.rowNum, self.colNum, self.numRows, self.numCols = \
|
||||
self.get_subplotspec().get_position(self.figure,
|
||||
return_all=True)
|
||||
|
||||
def is_first_col(self):
|
||||
return self.colNum == 0
|
||||
|
||||
def is_first_row(self):
|
||||
return self.rowNum == 0
|
||||
|
||||
def is_last_row(self):
|
||||
return self.rowNum == self.numRows - 1
|
||||
|
||||
def is_last_col(self):
|
||||
return self.colNum == self.numCols - 1
|
||||
|
||||
# COVERAGE NOTE: Never used internally.
|
||||
def label_outer(self):
|
||||
"""Only show "outer" labels and tick labels.
|
||||
|
||||
x-labels are only kept for subplots on the last row; y-labels only for
|
||||
subplots on the first column.
|
||||
"""
|
||||
lastrow = self.is_last_row()
|
||||
firstcol = self.is_first_col()
|
||||
if not lastrow:
|
||||
for label in self.get_xticklabels(which="both"):
|
||||
label.set_visible(False)
|
||||
self.get_xaxis().get_offset_text().set_visible(False)
|
||||
self.set_xlabel("")
|
||||
if not firstcol:
|
||||
for label in self.get_yticklabels(which="both"):
|
||||
label.set_visible(False)
|
||||
self.get_yaxis().get_offset_text().set_visible(False)
|
||||
self.set_ylabel("")
|
||||
|
||||
def _make_twin_axes(self, *args, **kwargs):
|
||||
"""
|
||||
Make a twinx axes of self. This is used for twinx and twiny.
|
||||
"""
|
||||
if 'sharex' in kwargs and 'sharey' in kwargs:
|
||||
# The following line is added in v2.2 to avoid breaking Seaborn,
|
||||
# which currently uses this internal API.
|
||||
if kwargs["sharex"] is not self and kwargs["sharey"] is not self:
|
||||
raise ValueError("Twinned Axes may share only one axis")
|
||||
# The dance here with label is to force add_subplot() to create a new
|
||||
# Axes (by passing in a label never seen before). Note that this does
|
||||
# not affect plot reactivation by subplot() as twin axes can never be
|
||||
# reactivated by subplot().
|
||||
sentinel = str(uuid.uuid4())
|
||||
real_label = kwargs.pop("label", sentinel)
|
||||
twin = self.figure.add_subplot(
|
||||
self.get_subplotspec(), *args, label=sentinel, **kwargs)
|
||||
if real_label is not sentinel:
|
||||
twin.set_label(real_label)
|
||||
self.set_adjustable('datalim')
|
||||
twin.set_adjustable('datalim')
|
||||
if self._layoutbox is not None and twin._layoutbox is not None:
|
||||
# make the layout boxes be explicitly the same
|
||||
twin._layoutbox.constrain_same(self._layoutbox)
|
||||
twin._poslayoutbox.constrain_same(self._poslayoutbox)
|
||||
self._twinned_axes.join(self, twin)
|
||||
return twin
|
||||
|
||||
|
||||
# this here to support cartopy which was using a private part of the
|
||||
# API to register their Axes subclasses.
|
||||
|
||||
# In 3.1 this should be changed to a dict subclass that warns on use
|
||||
# In 3.3 to a dict subclass that raises a useful exception on use
|
||||
# In 3.4 should be removed
|
||||
|
||||
# The slow timeline is to give cartopy enough time to get several
|
||||
# release out before we break them.
|
||||
_subplot_classes = {}
|
||||
|
||||
|
||||
@functools.lru_cache(None)
|
||||
def subplot_class_factory(axes_class=None):
|
||||
"""
|
||||
This makes a new class that inherits from `.SubplotBase` and the
|
||||
given axes_class (which is assumed to be a subclass of `.axes.Axes`).
|
||||
This is perhaps a little bit roundabout to make a new class on
|
||||
the fly like this, but it means that a new Subplot class does
|
||||
not have to be created for every type of Axes.
|
||||
"""
|
||||
if axes_class is None:
|
||||
axes_class = Axes
|
||||
try:
|
||||
# Avoid creating two different instances of GeoAxesSubplot...
|
||||
# Only a temporary backcompat fix. This should be removed in
|
||||
# 3.4
|
||||
return next(cls for cls in SubplotBase.__subclasses__()
|
||||
if cls.__bases__ == (SubplotBase, axes_class))
|
||||
except StopIteration:
|
||||
return type("%sSubplot" % axes_class.__name__,
|
||||
(SubplotBase, axes_class),
|
||||
{'_axes_class': axes_class})
|
||||
|
||||
|
||||
# This is provided for backward compatibility
|
||||
Subplot = subplot_class_factory()
|
||||
|
||||
|
||||
def _picklable_subplot_class_constructor(axes_class):
|
||||
"""
|
||||
This stub class exists to return the appropriate subplot class when called
|
||||
with an axes class. This is purely to allow pickling of Axes and Subplots.
|
||||
"""
|
||||
subplot_class = subplot_class_factory(axes_class)
|
||||
return subplot_class.__new__(subplot_class)
|
||||
|
||||
|
||||
docstring.interpd.update(Axes=martist.kwdoc(Axes))
|
||||
docstring.dedent_interpd(Axes.__init__)
|
||||
|
||||
docstring.interpd.update(Subplot=martist.kwdoc(Axes))
|
||||
2497
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axis.py
vendored
Normal file
2497
matPlotLib/env/lib/python3.7/site-packages/matplotlib/axis.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
3345
matPlotLib/env/lib/python3.7/site-packages/matplotlib/backend_bases.py
vendored
Normal file
3345
matPlotLib/env/lib/python3.7/site-packages/matplotlib/backend_bases.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
423
matPlotLib/env/lib/python3.7/site-packages/matplotlib/backend_managers.py
vendored
Normal file
423
matPlotLib/env/lib/python3.7/site-packages/matplotlib/backend_managers.py
vendored
Normal file
@@ -0,0 +1,423 @@
|
||||
import logging
|
||||
|
||||
import matplotlib.cbook as cbook
|
||||
import matplotlib.widgets as widgets
|
||||
from matplotlib.rcsetup import validate_stringlist
|
||||
import matplotlib.backend_tools as tools
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ToolEvent(object):
|
||||
"""Event for tool manipulation (add/remove)."""
|
||||
def __init__(self, name, sender, tool, data=None):
|
||||
self.name = name
|
||||
self.sender = sender
|
||||
self.tool = tool
|
||||
self.data = data
|
||||
|
||||
|
||||
class ToolTriggerEvent(ToolEvent):
|
||||
"""Event to inform that a tool has been triggered."""
|
||||
def __init__(self, name, sender, tool, canvasevent=None, data=None):
|
||||
ToolEvent.__init__(self, name, sender, tool, data)
|
||||
self.canvasevent = canvasevent
|
||||
|
||||
|
||||
class ToolManagerMessageEvent(object):
|
||||
"""
|
||||
Event carrying messages from toolmanager.
|
||||
|
||||
Messages usually get displayed to the user by the toolbar.
|
||||
"""
|
||||
def __init__(self, name, sender, message):
|
||||
self.name = name
|
||||
self.sender = sender
|
||||
self.message = message
|
||||
|
||||
|
||||
class ToolManager(object):
|
||||
"""
|
||||
Manager for actions triggered by user interactions (key press, toolbar
|
||||
clicks, ...) on a Figure.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
figure : `Figure`
|
||||
keypresslock : `widgets.LockDraw`
|
||||
`LockDraw` object to know if the `canvas` key_press_event is locked
|
||||
messagelock : `widgets.LockDraw`
|
||||
`LockDraw` object to know if the message is available to write
|
||||
"""
|
||||
|
||||
def __init__(self, figure=None):
|
||||
_log.warning('Treat the new Tool classes introduced in v1.5 as '
|
||||
'experimental for now, the API will likely change in '
|
||||
'version 2.1 and perhaps the rcParam as well')
|
||||
|
||||
self._key_press_handler_id = None
|
||||
|
||||
self._tools = {}
|
||||
self._keys = {}
|
||||
self._toggled = {}
|
||||
self._callbacks = cbook.CallbackRegistry()
|
||||
|
||||
# to process keypress event
|
||||
self.keypresslock = widgets.LockDraw()
|
||||
self.messagelock = widgets.LockDraw()
|
||||
|
||||
self._figure = None
|
||||
self.set_figure(figure)
|
||||
|
||||
@property
|
||||
def canvas(self):
|
||||
"""Canvas managed by FigureManager."""
|
||||
if not self._figure:
|
||||
return None
|
||||
return self._figure.canvas
|
||||
|
||||
@property
|
||||
def figure(self):
|
||||
"""Figure that holds the canvas."""
|
||||
return self._figure
|
||||
|
||||
@figure.setter
|
||||
def figure(self, figure):
|
||||
self.set_figure(figure)
|
||||
|
||||
def set_figure(self, figure, update_tools=True):
|
||||
"""
|
||||
Bind the given figure to the tools.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
figure : `.Figure`
|
||||
update_tools : bool
|
||||
Force tools to update figure
|
||||
"""
|
||||
if self._key_press_handler_id:
|
||||
self.canvas.mpl_disconnect(self._key_press_handler_id)
|
||||
self._figure = figure
|
||||
if figure:
|
||||
self._key_press_handler_id = self.canvas.mpl_connect(
|
||||
'key_press_event', self._key_press)
|
||||
if update_tools:
|
||||
for tool in self._tools.values():
|
||||
tool.figure = figure
|
||||
|
||||
def toolmanager_connect(self, s, func):
|
||||
"""
|
||||
Connect event with string *s* to *func*.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
s : String
|
||||
Name of the event
|
||||
|
||||
The following events are recognized
|
||||
|
||||
- 'tool_message_event'
|
||||
- 'tool_removed_event'
|
||||
- 'tool_added_event'
|
||||
|
||||
For every tool added a new event is created
|
||||
|
||||
- 'tool_trigger_TOOLNAME`
|
||||
Where TOOLNAME is the id of the tool.
|
||||
|
||||
func : function
|
||||
Function to be called with signature
|
||||
def func(event)
|
||||
"""
|
||||
return self._callbacks.connect(s, func)
|
||||
|
||||
def toolmanager_disconnect(self, cid):
|
||||
"""
|
||||
Disconnect callback id *cid*.
|
||||
|
||||
Example usage::
|
||||
|
||||
cid = toolmanager.toolmanager_connect('tool_trigger_zoom', onpress)
|
||||
#...later
|
||||
toolmanager.toolmanager_disconnect(cid)
|
||||
"""
|
||||
return self._callbacks.disconnect(cid)
|
||||
|
||||
def message_event(self, message, sender=None):
|
||||
"""Emit a `ToolManagerMessageEvent`."""
|
||||
if sender is None:
|
||||
sender = self
|
||||
|
||||
s = 'tool_message_event'
|
||||
event = ToolManagerMessageEvent(s, sender, message)
|
||||
self._callbacks.process(s, event)
|
||||
|
||||
@property
|
||||
def active_toggle(self):
|
||||
"""Currently toggled tools."""
|
||||
return self._toggled
|
||||
|
||||
def get_tool_keymap(self, name):
|
||||
"""
|
||||
Get the keymap associated with the specified tool.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : string
|
||||
Name of the Tool
|
||||
|
||||
Returns
|
||||
-------
|
||||
list : list of keys associated with the Tool
|
||||
"""
|
||||
|
||||
keys = [k for k, i in self._keys.items() if i == name]
|
||||
return keys
|
||||
|
||||
def _remove_keys(self, name):
|
||||
for k in self.get_tool_keymap(name):
|
||||
del self._keys[k]
|
||||
|
||||
def update_keymap(self, name, *keys):
|
||||
"""
|
||||
Set the keymap to associate with the specified tool.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : string
|
||||
Name of the Tool
|
||||
keys : keys to associate with the Tool
|
||||
"""
|
||||
|
||||
if name not in self._tools:
|
||||
raise KeyError('%s not in Tools' % name)
|
||||
|
||||
self._remove_keys(name)
|
||||
|
||||
for key in keys:
|
||||
for k in validate_stringlist(key):
|
||||
if k in self._keys:
|
||||
cbook._warn_external('Key %s changed from %s to %s' %
|
||||
(k, self._keys[k], name))
|
||||
self._keys[k] = name
|
||||
|
||||
def remove_tool(self, name):
|
||||
"""
|
||||
Remove tool named *name*.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : string
|
||||
Name of the Tool
|
||||
"""
|
||||
|
||||
tool = self.get_tool(name)
|
||||
tool.destroy()
|
||||
|
||||
# If is a toggle tool and toggled, untoggle
|
||||
if getattr(tool, 'toggled', False):
|
||||
self.trigger_tool(tool, 'toolmanager')
|
||||
|
||||
self._remove_keys(name)
|
||||
|
||||
s = 'tool_removed_event'
|
||||
event = ToolEvent(s, self, tool)
|
||||
self._callbacks.process(s, event)
|
||||
|
||||
del self._tools[name]
|
||||
|
||||
def add_tool(self, name, tool, *args, **kwargs):
|
||||
"""
|
||||
Add *tool* to `ToolManager`.
|
||||
|
||||
If successful, adds a new event ``tool_trigger_{name}`` where
|
||||
``{name}`` is the *name* of the tool; the event is fired everytime the
|
||||
tool is triggered.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of the tool, treated as the ID, has to be unique.
|
||||
tool : class_like, i.e. str or type
|
||||
Reference to find the class of the Tool to added.
|
||||
|
||||
Notes
|
||||
-----
|
||||
args and kwargs get passed directly to the tools constructor.
|
||||
|
||||
See Also
|
||||
--------
|
||||
matplotlib.backend_tools.ToolBase : The base class for tools.
|
||||
"""
|
||||
|
||||
tool_cls = self._get_cls_to_instantiate(tool)
|
||||
if not tool_cls:
|
||||
raise ValueError('Impossible to find class for %s' % str(tool))
|
||||
|
||||
if name in self._tools:
|
||||
cbook._warn_external('A "Tool class" with the same name already '
|
||||
'exists, not added')
|
||||
return self._tools[name]
|
||||
|
||||
tool_obj = tool_cls(self, name, *args, **kwargs)
|
||||
self._tools[name] = tool_obj
|
||||
|
||||
if tool_cls.default_keymap is not None:
|
||||
self.update_keymap(name, tool_cls.default_keymap)
|
||||
|
||||
# For toggle tools init the radio_group in self._toggled
|
||||
if isinstance(tool_obj, tools.ToolToggleBase):
|
||||
# None group is not mutually exclusive, a set is used to keep track
|
||||
# of all toggled tools in this group
|
||||
if tool_obj.radio_group is None:
|
||||
self._toggled.setdefault(None, set())
|
||||
else:
|
||||
self._toggled.setdefault(tool_obj.radio_group, None)
|
||||
|
||||
# If initially toggled
|
||||
if tool_obj.toggled:
|
||||
self._handle_toggle(tool_obj, None, None, None)
|
||||
tool_obj.set_figure(self.figure)
|
||||
|
||||
self._tool_added_event(tool_obj)
|
||||
return tool_obj
|
||||
|
||||
def _tool_added_event(self, tool):
|
||||
s = 'tool_added_event'
|
||||
event = ToolEvent(s, self, tool)
|
||||
self._callbacks.process(s, event)
|
||||
|
||||
def _handle_toggle(self, tool, sender, canvasevent, data):
|
||||
"""
|
||||
Toggle tools, need to untoggle prior to using other Toggle tool.
|
||||
Called from trigger_tool.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
tool : Tool object
|
||||
sender : object
|
||||
Object that wishes to trigger the tool
|
||||
canvasevent : Event
|
||||
Original Canvas event or None
|
||||
data : Object
|
||||
Extra data to pass to the tool when triggering
|
||||
"""
|
||||
|
||||
radio_group = tool.radio_group
|
||||
# radio_group None is not mutually exclusive
|
||||
# just keep track of toggled tools in this group
|
||||
if radio_group is None:
|
||||
if tool.name in self._toggled[None]:
|
||||
self._toggled[None].remove(tool.name)
|
||||
else:
|
||||
self._toggled[None].add(tool.name)
|
||||
return
|
||||
|
||||
# If the tool already has a toggled state, untoggle it
|
||||
if self._toggled[radio_group] == tool.name:
|
||||
toggled = None
|
||||
# If no tool was toggled in the radio_group
|
||||
# toggle it
|
||||
elif self._toggled[radio_group] is None:
|
||||
toggled = tool.name
|
||||
# Other tool in the radio_group is toggled
|
||||
else:
|
||||
# Untoggle previously toggled tool
|
||||
self.trigger_tool(self._toggled[radio_group],
|
||||
self,
|
||||
canvasevent,
|
||||
data)
|
||||
toggled = tool.name
|
||||
|
||||
# Keep track of the toggled tool in the radio_group
|
||||
self._toggled[radio_group] = toggled
|
||||
|
||||
def _get_cls_to_instantiate(self, callback_class):
|
||||
# Find the class that corresponds to the tool
|
||||
if isinstance(callback_class, str):
|
||||
# FIXME: make more complete searching structure
|
||||
if callback_class in globals():
|
||||
callback_class = globals()[callback_class]
|
||||
else:
|
||||
mod = 'backend_tools'
|
||||
current_module = __import__(mod,
|
||||
globals(), locals(), [mod], 1)
|
||||
|
||||
callback_class = getattr(current_module, callback_class, False)
|
||||
if callable(callback_class):
|
||||
return callback_class
|
||||
else:
|
||||
return None
|
||||
|
||||
def trigger_tool(self, name, sender=None, canvasevent=None, data=None):
|
||||
"""
|
||||
Trigger a tool and emit the ``tool_trigger_{name}`` event.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : string
|
||||
Name of the tool
|
||||
sender : object
|
||||
Object that wishes to trigger the tool
|
||||
canvasevent : Event
|
||||
Original Canvas event or None
|
||||
data : Object
|
||||
Extra data to pass to the tool when triggering
|
||||
"""
|
||||
tool = self.get_tool(name)
|
||||
if tool is None:
|
||||
return
|
||||
|
||||
if sender is None:
|
||||
sender = self
|
||||
|
||||
self._trigger_tool(name, sender, canvasevent, data)
|
||||
|
||||
s = 'tool_trigger_%s' % name
|
||||
event = ToolTriggerEvent(s, sender, tool, canvasevent, data)
|
||||
self._callbacks.process(s, event)
|
||||
|
||||
def _trigger_tool(self, name, sender=None, canvasevent=None, data=None):
|
||||
"""Actually trigger a tool."""
|
||||
tool = self.get_tool(name)
|
||||
|
||||
if isinstance(tool, tools.ToolToggleBase):
|
||||
self._handle_toggle(tool, sender, canvasevent, data)
|
||||
|
||||
# Important!!!
|
||||
# This is where the Tool object gets triggered
|
||||
tool.trigger(sender, canvasevent, data)
|
||||
|
||||
def _key_press(self, event):
|
||||
if event.key is None or self.keypresslock.locked():
|
||||
return
|
||||
|
||||
name = self._keys.get(event.key, None)
|
||||
if name is None:
|
||||
return
|
||||
self.trigger_tool(name, canvasevent=event)
|
||||
|
||||
@property
|
||||
def tools(self):
|
||||
"""A dict mapping tool name -> controlled tool."""
|
||||
return self._tools
|
||||
|
||||
def get_tool(self, name, warn=True):
|
||||
"""
|
||||
Return the tool object, also accepts the actual tool for convenience.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str, ToolBase
|
||||
Name of the tool, or the tool itself
|
||||
warn : bool, optional
|
||||
If this method should give warnings.
|
||||
"""
|
||||
if isinstance(name, tools.ToolBase) and name.name in self._tools:
|
||||
return name
|
||||
if name not in self._tools:
|
||||
if warn:
|
||||
cbook._warn_external("ToolManager does not control tool "
|
||||
"%s" % name)
|
||||
return None
|
||||
return self._tools[name]
|
||||
1149
matPlotLib/env/lib/python3.7/site-packages/matplotlib/backend_tools.py
vendored
Normal file
1149
matPlotLib/env/lib/python3.7/site-packages/matplotlib/backend_tools.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user