Django Matplotlib Animation embed in templates - django

Hi so I am using matplot lib in my django project. And I am able to embed a graph in my template/webpage. I need some help now on being able to animate a graph.
The graph is stored as a csv file with the location in my model. I want the graphs to be built dynamically. Now I have that. But I want them to be an animation. How would I go about doing this? I have to use matplotlib btw.
I assume make a video? I've seen people embed videos, but I was hoping to using the actual animation features of matplotlib such as:
http://pythonprogramming.net/python-matplotlib-live-updating-graphs/
Here is how I render the graph in my view:
def render_graph(request, graph_id=None):
graph = get_object_or_404(models.Graph, pk=graph_id) #grabs actual graph
data = np.genfromtxt(graph.data, delimiter=',', names=['x','y']) #extract data from cvs after x and y
fig = Figure()
ax = fig.add_subplot(111)
ax.plot(data['x'], data['y'], label=graph.name)
canvas=FigureCanvas(fig)
response = HttpResponse(content_type='image/png')
canvas.print_png(response)
return(response)

have you considered using d3 (d3js.org)? Might give better results.

Related

Plotting Image with Plotly in Django

Hi community maybe you can help me. The last couple of days I was trying to find a solution to plot an image in Django with plotly because I need a 2nd trace with a scatter on top of it and additional a slider wo move around. But first things first. In order to plot an image from an URL I've put in the following in views.py in my Django app
views.py
from skimage import io
def slide_plot(centroid=1):
#steps = Ypixels.objects.filter(centroid__in=[centroid]).order_by('step').values_list('step', falt=True).distinct()
#CentroidCount.objects.filter(centroid__in=[centroid]).order_by('id_observation').values_list('id_observation', flat=True).distinct()
url = 'https://www.cs.technik.fhnw.ch/iris/sji_png/images/20140910_112825_3860259453/20140910_112825_3860259453_1400_1176.jpg'
img_array = io.imread(url)
image = go.Image(
source=url
)
layout = go.Layout(
title='Appearances for Centroids',
xaxis=dict(
title='Step',
),
paper_bgcolor='rgba(0,0,0,0)',
plot_bgcolor='rgba(0,0,0,0)',
yaxis={
'title':'occurences'
},
)
data = [image]
fig = go.Figure(data=data, layout=layout)
plot_test = plot(fig, include_plotlyjs=False, output_type='div')
return plot_test
once this is resolved I can move to the next step creating the scatter trace.
Any help would be appreciated

Bokeh + Holoviews + Datashader on Django

We are trying to build a web app--Dashboard-- to show different interactive(including click callback, fetch new data etc) charts with Bokeh + Holoviews + Datashader on DJango.
Since data is very large and could have 10+ million points we are using datashader. We can have a static html from backend from Bokeh + Holoviews + Datashader from Backend and pass it to front end using Django REST api as :
views.py
import numpy as np
import holoviews as hv
import datashader as ds
from dask import dataframe as dd
from bokeh.io import show, curdoc
from bokeh.layouts import layout
from bokeh.models import Slider, Button
from holoviews.operation.datashader import datashade
renderer = hv.renderer('bokeh').instance(mode='server')
def home(request):
def plot_info(y_col):
from vaex import dataframe as datafm
df_dask = dd.read_parquet(r"C:\Dropbox\1mln.parquet", engine='pyarrow',
columns=['nest11', 'nest21', 'first_element', 'second_element', 'timestamp'])
df_dask['timestamp'] = dd.to_datetime(df_dask.timestamp, unit='ns')
return hv.Curve((df_dask['timestamp'], df_dask[y_col]))
def bearer():
stream = hv.streams.Stream.define('y-axis', y_col="nest11")()
dmap = hv.DynamicMap(plot_info, streams=[stream])
vmap = datashade(dmap).opts(width=1200, height=600, responsive=True)
html = renderer.static_html(vmap)
return html
context = {
'seq_num': bearer(),
}
return render(request, 'home/welcome.html', context)
Works fine. However Since we used Datashader, data is aggregated and converted in static html when we zoom in we would not get the data which we are looking for at from end side. For that, my guess is we need Bokeh server.
My doubts are :(since use of Datashader is must for large dataset)
How can i use Bokeh server along with Django REST apis ? Also i want to have a customized html page at front end so i am using Django template.
Is there an alternative to Django for REST apis development with Bokeh + Datashader ?
Does Bokeh support REST APIs ? how ? pls share some examples of REST APIs and callbacks ? for example I've a Dashboard and when i click one chart, I should get more details about the chart and play around those charts in dashboard ? dropdown etc
I would strongly suggest using Panel which is built on top of Bokeh and supports HoloViews. For Django integration have a look at these docs.
/ 3. The Bokeh server is built on Tornado, which means it can be easily extended, e.g. in the next release of Panel (0.10) you will be able to easily register custom REST APIs to be served alongside your app. There aren't any examples yet since it's not released but I'll be working on a few examples in time for the next release which is due in about two weeks.

Python reportlab - How to draw something on the last page of a SimpleDocTemplate?

I'm trying to create an invoice with the python reportlab library in a Django view.
But now my question:
How can I write/draw something at the bottom (that's important!) of the last page? (Which may also be the first one, depending on how long the table is.)
My idea was to just get the last page's canvas and draw the footer on it (I added a Spacer so I can be sure that there's enough space for it. This would work, but I can't get the last page's canvas.)
buffer = BytesIO()
doc = SimpleDocTemplate(buffer, rightMargin=10*mm, leftMargin=10*mm, topMargin=10*mm, bottomMargin=0*mm)
elements = [Spacer(1,75*mm),get_table(),Spacer(1,108*mm)]
# get_table() returns a Table object
doc.build(elements, onFirstPage=draw_header)
# draw_header draws the header on the canvas
draw_invoice(CANVAS) # here's my problem
buffer.seek(0)
return FileResponse(buffer, as_attachment=False, filename='invoice.pdf')
Is there a way to get the canvas of the last page after building the doc and modify it? Or is there an other way to solve my problem?
Here's a scratch of what I'm trying to do: (The table could also go over more than 2 pages, the footer just has to be on the bottom of the earliest possible page, but after the table.)
I had several problems with reportlab, yes, it is a great tool to generate pdf but most of the times I had to override functions and creating subclass from basedoctemplate.
What I would do is create a pagetemplate that include that info, then swith to it before to finish the document with a Pagebreak().
class MyDocTemplate(BaseDocTemplate):
def __init__(self, data, filename, **kw):
self.data = data
self.allowSplitting = 0
BaseDocTemplate.__init__(self, filename, **kw)
#Frame bottom, limited to your work area
frame_bottom = Frame(self.leftMargin, self.bottomMargin, self.width/2, self.height/2 - 20*mm,
page_height_landscape - 2 * self.bottomMargin,
id='landscape', showBoundary=0)
# Definicion de templates
template_last_page = PageTemplate('last_page', frames=frame_b,
onPage=lastpage)
After that you can add your template_last_page to your doc. Then after to reach the final of the document use the method nextpagetemplate("your template"), then Pagebreak().
If you donĀ“t use subclasses from the library is very limitated sometimes. I bought a reportlab book, Reportlab: Processing with Python, help me a lot with these kind of problems.
Regards.
I was able to find my own solution:
I created my own Flowable and added it with a TopPadder to the other Flowables. I had to put a Spacer between because otherways my Flowable was sometimes overlapping with the Table.

Dynamically change the shape of bokeh Figure

I am building a web app that will display images as part of a data analysis pipeline. For this, I need to dynamically change the width and height of a Figure object in bokeh.
With the following code, the shape of the Figure is changed, but the change only takes effect after I resize my browser window, even if the browser window resize is ever so small.
import bokeh.plotting
import bokeh.models
import bokeh.layouts
# set up the interface
fig1 = bokeh.plotting.figure()
button = bokeh.models.Button(label='scramble')
# define a callback and connect it
def callback():
fig1.width = int(fig1.width * .8)
button.on_click(callback)
# add everything to the document
bokeh.plotting.curdoc().add_root(bokeh.layouts.column(button, fig1))
Is there some update method which I need to run? I have read about "next tick callbacks" but I don't understand if that is relevant.
The above behavior occurs both with firefox and chromium on my gnome system.
The reason this is happening is because the layout is not getting updated. Although your code changes the figure's property value you have to recompute all values in the Document solver for an actual resize to happen.
Here is the line in BokehJS where the resize hook happens:
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/document.coffee#L92
After resize is called at the document level, resize objects re-render:
https://github.com/bokeh/bokeh/blob/master/bokehjs/src/coffee/models/layouts/layout_dom.coffee#L61
The problem is that there's not currently, to the best of my knowledge, an exposed way to re-trigger the document resize event.
However you can do it client side. Here's working code using CustomJS:
test.py
from bokeh.io import show
from bokeh.layouts import column
from bokeh.models import Button, CustomJS
from bokeh.plotting import figure
fig = figure()
button = Button(label='scramble')
button.callback = CustomJS(args=dict(fig=fig), code="""
var old_width = fig.width;
var doc = fig.document;
fig.width = old_width * 0.8;
doc.resize();
""")
col = column(button, fig)
show(col)
This can be run with python test.py.
Note you could also do this with bokeh server replacing the last line show(col) with curdoc().add_root(col), but I didn't do that to emphasize that this is a client-side solution.
There is a way to dynamically resize bokeh charts with built in functionality. For example,
fig = plotting.figure(width=1200, height=900, title="Dynamic plot".format(chartType), sizing_mode='scale_width')
The key option being sizing_mode='scale_width'
The width and height commands serve as initial values. There are other options for sizing_mode so I would look into that.

Rendering spatial data of GeoQuerySet in a custom view on GeoDjango

I have just started my first project on GeoDjango.
As a matter of fact, with GeoDjango powered Admin application we all have a great possibility to view/edit spatial data, associated with the current object.
The problem is that after the objects having been populated I need to render several objects' associated geometry at once on a single map. I might implement it as a model action, redirecting to a custom view. I just don't know, how to include the OpenLayers widget in the view and how to render there my compound geometry from my GeoQuerySet.
I would be very thankful for any hint from an experienced GeoDjango programmer.
Two halves of this question:
How do I generate Geographic data that OpenLayers can read via Django?
How do I consume this data with OpenLayers?
Generating Geographic Data
There are several different ways to generate geographic data in Django. Built in, you can use the .kml() or .json() methods on a queryset; doing so causes each returned instance to have a .json or .kml property which has the KML or JSON of the Geometry generated as a string.
You can then use this output in templates that use the {{feature.kml}} or {{feature.json}}. (The latter is somewhat difficult, because you would have to manually do the JSON encoding before it hit the template, a bit of an odd situation.)
Another option is to use a library to help you: specifically, vectorformats. (Google "featureserver vectorformats" for information, since I can only include one hyperlink.) Installed via PyPI/easy_install vectorformats, you can use the Django format:
>>> from vectorformats.Formats import Django, GeoJSON
>>> qs = Model.objects.filter(city="Cambridge")
>>> djf = Django.Django(geodjango="geometry", properties=['city', 'state'])
>>> geoj = GeoJSON.GeoJSON()
>>> s = geoj.encode(djf.decode(qs))
>>> print s
This string can be returned via an HTTPResponse to return a GeoJSON object. So, your view would wrap these 4 lines in a bit that generated a queryset (qs, here), and then returned an HttpResponse with the string.
Consuming Data
OpenLayers has 'format' objects which can read data: There are formats for GeoJSON and KML, as well as others.
You can load the data using standard XMLHttpRequest mechanisms then parse them with a format:
var f = new OpenLayers.Format.GeoJSON();
var features = f.read(req.responseText);
layer.addFeatures(features);
Alternatively, you can use the built in Protocol support to load remote data:
map = new OpenLayers.Map('map');
var wms = new OpenLayers.Layer.WMS(
"OpenLayers WMS", "http://labs.metacarta.com/wms/vmap0",
{layers: 'basic'}
);
var layer = new OpenLayers.Layer.Vector("GML", {
strategies: [new OpenLayers.Strategy.Fixed()],
protocol: new OpenLayers.Protocol.HTTP({
url: "/django/view/json/",
format: new OpenLayers.Format.GeoJSON()
})
});
map.addLayers([wms, layer]);
map.zoomToExtent(new OpenLayers.Bounds(
-3.92, 44.34, 4.87, 49.55
));
You can see in this example, that the 'url' points to your Django view; all the loading of data and parsing it according to the provided format is included. (You can see a similar example in the OpenLayers example for fixed behavior/http protocol.)
Putting it Together
Create a Django view, using vectorformats to return your data as GeoJSON
Create a separate view, which returns an HTML page like the OpenLayers example linked, with the modifications shown in the code sample.
That view serves the HTML page that loads your GeoJSON data and parses it.