Repository: plotly/plotly.py

Issue:
How to convert long mpl annotations that modify the figure's margins
See

http://nbviewer.ipython.org/github/etpinard/plotly-misc-nbs/blob/etienne/matplotlylib/annotations-test.ipynb#2.-Long-annotations-and-margins

mpl modifies the figure's margins when one long annotation is placed on a figure, plotly does not.

How should we handle this?



Discussion:
Alright, so, there's no simple way to tell from mpl upon figure opening if the figure is going to need to be bigger. However, the reason you see the long annotation is b.c. you're using mpl in IPython! Try this:
http://nbviewer.ipython.org/gist/theengineear/61fc798db51672299785

You'll note that the GUI that opens clips off the text just like Plotly would, and that's because that's just where the figure ends!

This may not be a real issue. I might suggest we throw a warning when an annotation runs over the edge of a plot in matplotylib. 

What do you think?

Oh wow! I did not see that coming!

Randal's figure rendered with `.show()` yields:

![screenshot from 2014-07-04 15 25 08](https://cloud.githubusercontent.com/assets/6675409/3484636/fdf34e44-03b0-11e4-905f-72dc6e190919.png)

But, with `plt.savefig()` and within the notebook, the figure's margins are adjusted.

I suspect that `plt.savefig()` has no affect on the mpl object. 

I think issuing a warning is the right call.

The warning should make a reference to the Margin object and the Annotation object(s) that caused the issue.

Moreover, maybe we include a few words about how `plt.savefig()` and IPython NBs _adjust_ the margins so that matplotlylib user can correct their mpl code accordingly. 

~~I don't know if the NB actually adjusts anything, the margins are still the same, it's just that the background of the notebook is white, so there's extra canvas to draw on perhaps? i'm not sure how mpl draws in a NB.~~ Nevermind, yeah IPython definitely adjust accordingly.

Yeah, i'll just work on a warning.


Resolving patch:
diff --git a/plotly/matplotlylib/mpltools.py b/plotly/matplotlylib/mpltools.py
--- a/plotly/matplotlylib/mpltools.py
+++ b/plotly/matplotlylib/mpltools.py
@@ -35,6 +35,21 @@ def check_bar_match(old_bar, new_bar):
         return False
 
 
+def check_corners(inner_obj, outer_obj):
+    inner_corners = inner_obj.get_window_extent().corners()
+    outer_corners = outer_obj.get_window_extent().corners()
+    if inner_corners[0][0] < outer_corners[0][0]:
+        return False
+    elif inner_corners[0][1] < outer_corners[0][1]:
+        return False
+    elif inner_corners[3][0] > outer_corners[3][0]:
+        return False
+    elif inner_corners[3][1] > outer_corners[3][1]:
+        return False
+    else:
+        return True
+
+
 def convert_affine_trans(dpi=None, aff=None):
     if aff is not None and dpi is not None:
         try:
diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py
--- a/plotly/matplotlylib/renderer.py
+++ b/plotly/matplotlylib/renderer.py
@@ -498,6 +498,12 @@ def draw_text(self, **props):
 
         """
         self.msg += "    Attempting to draw an mpl text object\n"
+        if not mpltools.check_corners(props['mplobj'], self.mpl_fig):
+            warnings.warn("\n"
+                          "The annotation you're trying to draw lies outside "
+                          "the given figure size. Therefore, the resulting "
+                          "Plotly figure may not be large enough to view the "
+                          "full text.")
         align = props['mplobj']._multialignment
         if not align:
             align = props['style']['halign'] # mpl default


Test patch: