Search code examples
pythondjangoplotmpld3

Why is this plot not displaying in template but works fine if URL is viewed directly in Django app?


My problem

I'm creating an interactive plot in my Django app. I have created a view for a plotting template and a view that generates only the plot itself so that I can use <img src= "{% url 'ozmod:plot' %}"/> to render the plot with the fancy plotting template.

If I navigate to the URL I've assigned to the plotting template view I see a broken image link but the navbar and everything is extended fine. If I navigate directly to the URL for just the plot, the plot is displayed fine but, of course, the navbar and everything from page.html is not extended. I have included screen grabs of my error and my code:

views.py

class PlotView(generic.TemplateView):
    template_name = 'ozmod/plot.html'

def RunOZCOT(request):
    fig = plt.figure()
    x = range(20)
    y = [i for i in range(20)]
    random.shuffle(y)
    plot = plt.plot(x,y)
    g = mpld3.fig_to_html(fig)
    return HttpResponse(g)

urls.py

app_name = 'ozmod'
urlpatterns = [
    path('', views.HomePageView.as_view(), name='home'),
    path('metfiles/', views.MetIndexView.as_view(), name='metindex'),
    path('metfiles/<int:pk>/', views.DetailView.as_view(), name='detail'),
    path('runmodel/', views.PlotView.as_view(), name = 'runmodel'),
    path('plot/', views.RunOZCOT, name = 'plot'),
]

plot.html

{% extends "ozmod/page.html" %}

{% block content %}

<img src= "{% url 'ozmod:plot' %}"/> 
<!-- http://myserver:8000/ozmod/plot/ -->

{% endblock %}

page.html ... abbreviated for clarity

{% load static %}

<!DOCTYPE html>
<head>
  <title>OZCOT interactive</title>
</head>
<body>

<ul class="nav nav-pills">
  <li class="{% if request.resolver_match.url_name == "home" %}active{% endif %}"><a href="{% url 'ozmod:home' %}">Home</a></li>
  <li class="{% if request.resolver_match.url_name == "metindex" %}active{% endif %}"><a href="{% url 'ozmod:metindex' %}">MetIndex</a></li>
  <li class="{% if request.resolver_match.url_name == "runmodel" %}active{% endif %}"><a href="{% url 'ozmod:runmodel' %}">Plot</a></li>
</ul>

<div class="container-fluid text-center">
    {% block content %}{% endblock content %}
</div>

<nav class="navbar navbar-default navbar-fixed-bottom">
        <div class="container">
            <p>This is a test</p>
        </div>
      </nav>

</body>
</html>

This is what myserver:8000/ozmod/runmodel/ looks like

enter image description here

This is what myserver:8000/ozmod/plot/ looks like

enter image description here

What's missing?

So the plot works fine but will not display when I reference the url serving that view in the main plotting template. What am I missing?


EDIT: 2018-03-23

Use <embed> not <img>.

The problem was with the use of <img> rather than <embed>. With embed the interactive features remain responsive.

Correct views.py:

{% extends "ozmod/page.html" %}

{% block content %}

<embed src="{% url 'ozmod:plot' %}" width="800" height="600">

{% endblock %}

Result:

enter image description here


Solution

  • I don't really understand what mpld3.fig_to_html() does - the documentation is very sparse and I don't know anything about matplotlib or mpld3 - but it seems that it is returning some kind of HTML. That can't work as the src of an image, which is expecting a single file in an image format (gif/png/jpeg etc).

    You need to use matplotlib to save the plot in that format and return it in the HttpResponse. Something like (bearing in mind I don't know the library at all):

    plot = plt.plot(x,y)
    response = HttpResponse()
    plot.savefig(response)
    return response