User Guide ========== .. contents:: :local: KickStart --------- Lets see how to insert a simple Matplotlib graph in an existing Django webpsite using Plottings. First, use the command ``pip`` to install the package to your local development environment: .. code:: pip install django-plottings Then add the module to the ``INSTALLED_APPS`` in the ``settings.py`` file of your project. .. code:: INSTALLED_APPS = [ ... 'plottings', ... ] Let's see how to render a plot to be passed to a template as context variable. First we need to import Matplotlib and the PNGValue class of Django Plottings to the ``views.py`` module of your app, and disable rendering to the screen: .. code:: python import numpy as np import matplotlib.pyplot as plt from plottings import PNGValuePlot from django.shortcuts import render matplotlib.use("Agg") Then create the class that renders the plot: .. code:: python class SimplePlotToValue(PNGValuePlot): def plotter_function(self, data, **options): np.random.seed(2) fig, ax = plt.subplots() ax.plot(np.random.rand(20), '-o', ms=20, lw=2, alpha=0.7, mfc='orange') ax.grid() return figure def plot(request, **kwargs): return render(request, "plot.html", {"plot": SimplePlotToValue()} Setup the template ``plot.html`` in your apps template directory: .. code::

My plot

{{ plot }} And finally add a route to your plot view in your apps ``url.py`` .. code:: python from django.urls import path from . import views urlpatterns = [ path("plot", views.plot, name="plot"), ] Now you can run it from your Python environment: .. code:: ./manage.py runserver And now open your browser and point it to your local app and then you should view the plot in your screen. How to build a Plot ------------------- The plotting process is mainly done with the use of plotting classes each one specialized in one type of output format and kind of rendering. Available formats are two: **SVG** and **PNG** and they can be rendered as **View**, **Value** or **File**, this gives us a family of six plotting classes: - *PNGViewPlot*: A cached Django View class that returns a PNG. - *SVGViewPlot*: A cached Django View class that returns an SVGZ file. - *PNGFilePlot*: Builds a Django File object containing a PNG image to be saved to storage. Useful to run it in background jobs. - *SVGFilePlot*: Builds a Django File object containing a SVGZ image to be saved to storage. Useful to run it in background jobs. - *PNGValuePlot*: A cached python variable containing a plot object ready to be rendered within a template as a PNG image encoded in *Base64*. - *SVGValuePlot*: A cached python variable containing a plot object ready to be rendered within a template as an inlined SVG image. These classes share all the same plotting methods that are: - An static method ``plotter_function(data, **options)``, that returns a Matplotlib ``figure`` object. The idea is not to implement the function here but to bring it from an interactive development environment like iPython Jupyter Notebooks. - A method ``get_plot_data()`` that is used to provide data to the ``plotter_function()``. - Another method ``get_plot_options()`` that returns a dictionary of values ready to be passed as named arguments to the ``plotter_function()`` to customize its behaviour. So to build a graph you have to first select the plotting class you want to use then copy&paste the ``plotter_function()`` and refactor it to obtain data from the ``data`` parameter and personalization from the named arguments. Then implement how to obtain the data from Django models or whatever and build the ``get_plot_data()`` and collect the options with ``get_plot_options()``. These steps might be different in a **View** class than in the **Value** and **File** classes. Plotting to a View ------------------ Django Views are initialized each request and values are stored in the object as the object attributes ``request``, ``args``, ``kwargs``. So the methods ``get_plot_options()`` and ``get_plot_data()`` must access these three attributes to build a response plot. .. code:: python class ActivitiesPlot(PNGViewPlot): def get_plot_options(self): return {"color": request.GET.get("color", "blue")} def get_plot_data(self): activities = self.request.user.get_activities() return [ x.date for x in activities ] Plotting to a Value ------------------- The **Value** class should be declared with the ``__init__()`` initialization method with the parameters needed to set the object attributes required by the ``get_plot_data()`` and ``get_plot_options()`` to pass the right parameters to the plotting function to render the image accordingly. .. code:: python class ActivitiesPlot(PNGValuePlot): def __init__(self, activities, color="blue"): self.activities = activities self.color = color def get_plot_options(self): return {"color": self.color} def get_plot_data(self): return [ x.date for x in self.activities ] Then the class is initialized within the view function or ``get_context_data()`` of the View object. The resulting plot object is passed to the template as another value to be rendered. .. code:: python def activities_view(request, *args, **kwargs): activities = request.user.get_activities() a_plot = ActivitiesPlot(activities) return render(request, "activities.html", {"a_plot": a_plot}) Plotting to a File ------------------ The **File** class should be declared with the ``__init__()`` initialization method with the parameters needed to set the object attributes required by the ``get_plot_data()`` and ``get_plot_options()`` to pass the right parameters to the plotting function to render the image accordingly. .. code:: python class ActivitiesPlot(PNGFilePlot): def __init__(self, activities, color="blue"): self.activities = activities self.color = color def get_plot_options(self): return {"color": self.color} def get_plot_data(self): return [ x.date for x in self.activities ] To render the plot when its needed you just have to call the object with the and asign it to a model field and then save it to store the plot in storage and the reference to it in the database: .. code:: python def task_save_activities(user_id): user = User.objects.get(id=user_id) activities = user.get_activities() a_plot = ActivitiesPlot(activities) user.activities_plot = a_plot.as_file() user.save() Caching ------- Caching is implemented in the **View** and **Value** classes. You only need to implement the ``get_cache_key()`` method that returns an identifying value of your plot and to set the timeout you have to set the class attribute ``cache_timeout`` to the number of seconds of your choosing. .. code:: python class ActivitiesPlot(PNGViewPlot): cache_timeout = 60 * 60 * 24 # Reload every 24h def get_cache_key(self): return f"activities_plot_{self.request.user.id}" Post Processing --------------- To modify the rendered image there is the ``process_image()`` method that takes an image in memory file and returns another. Good Practices -------------- It's a good idea to have the code split in separated files in the Django app directory. The initial propossal is to place all matplotlib, numpy, pandas... code in ``plots.py`` file. And don't forget to ``matplotlib.use("Agg")``.