Václav Bočan
Václav Bočan

Reputation: 89

How to align annotation to the edge of whole figure in plotly?

I know how to align annotation respective to the plotting area (using xref="paper"). I want to place the annotation to right bottom corner of the whole figure. Absolute or relative offset does not work, since the width of the margin outside the plotting area is changing among several figures, depending on their content. Is there a way how to do it? Thanks a ton.

Edit: Example code

import plotly.express as px

fig = px.scatter(x=[1, 2, 3], y=[1, 2, 3], title="Try panning or zooming!")

fig.add_annotation(text="Absolutely-positioned annotation",
                  xref="paper", yref="paper",
                  x=0.3, y=0.3, showarrow=False)

fig.show()

This annotation is positioned respectively to the origin of the plot, not respectively to the plot edges. enter image description here

Upvotes: 4

Views: 1279

Answers (2)

keventhen4
keventhen4

Reputation: 443

So the thing is that you technically can't automatically calculate and position annotations at a perfect spot in the corner of the figure for every plot (outside of the plot, but inside the figure).

The problem is that to do so, you would need to be able to get the dimensions of every plot, which could be undefined when you do not specify a width or height (autosizing will automatically calculate dimensions when the plot is shown). And even if you could do this, when you resize the window/page the annotation's location will change, and no longer be in the corner as you wanted it to be. Refer here for a proper explanation.

However, you could work around this by embedding the plotly plot inside an app/frame, and add the text to that frame instead of the plot itself. Here is a solution to a similar question asked by someone else from before that uses the jinja2 module's Template object to embed the plot (though it creates HTML code which you will then need to separately render).

Using the same method, you could implement a frame into the example plot like so:

import plotly.express as px
from jinja2 import Template

fig = px.scatter(x=[1, 2, 3], y=[1, 2, 3], title="Try panning or zooming!")

# Your annotation code and figure showing
'''
fig.add_annotation(text="Absolutely-positioned annotation",
                  xref="paper", yref="paper",
                  x=1, y=-0.1, showarrow=False)

fig.show()
'''

version_number = 'Absolutely-positioned annotation' #Your text to be displayed
fig_html = {"fig":fig.to_html(full_html=False, include_plotlyjs='cdn')} #Convert your plot to HTML to embed

# HTML Frame to embed the figure and text
frame = """<!DOCTYPE html>
<html>
<body>
{{ fig }}
<p style="font-size:15px; position:fixed; bottom:0; right:0;">{{ version_number }}</p>
</body>
</html>"""

j2_template = Template(frame) #Create the Template object for our frame
plot = j2_template.render(fig_html,version_number=version_number) #Embed the plot and text into the frame

At this point you have yourself HTML code with your plot and the text you desire. To render it, use any module capable of rendering HTML code, or write it to an HTML file and open that instead.

Example:

from flask import Flask, render_template_string

app = Flask(__name__)

@app.route('/')
def home():
    return render_template_string(plot) #variable containing HTML from previous code

if __name__ == '__main__':
    app.run(debug=True)

Upvotes: 2

amance
amance

Reputation: 1770

You could try this

fig = px.scatter(x=[1, 2, 3], y=[1, 2, 3], title="Try panning or zooming!")

fig.add_annotation(text="Absolutely-positioned annotation",
                   xref='paper', yref='paper',
                   x=0.95, y=-0.1, showarrow=False)

enter image description here

Upvotes: 0

Related Questions