Plotting Data
-------------

The TOM Toolkit provides a few basic plots, such as photometry, spectroscopy and
target distribution. Sometimes it would be useful to visualize data in a different
way.

In this tutorial you will learn how to build and display a very simple plot
in our TOM: number of reduced data per target. The end result will demonstrate
how to create a [plot.ly](https://plot.ly) plot with data from our TOM. You will
even package the code in it's own app so we can share it with other TOM users that
might find it useful.

If you haven't already read the documentation on [customizing
templates](/customization/customize_templates) you should read it first. You'll need to
edit a template in order to view your new plot somewhere.

First, start a new app in our project to house the new plot (and perhaps
other additions!):

    ./manage.py startapp myplots

This will create a new [Django
app](https://docs.djangoproject.com/en/2.1/intro/tutorial01/#creating-the-polls-app) in your project
named myplots:

    myplots
    ├── admin.py
    ├── apps.py
    ├── __init__.py
    ├── migrations
    │   └── __init__.py
    ├── models.py
    ├── tests.py
    └── views.py

    1 directory, 7 files

Note you don't necessarily have to start a new app. If you've already started an
app that you'd like to reuse, that works too.

Now install the new app into your project's settings.py file:

```python
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    ...
    'myplots',
]
```

Now that the `myplots` app is installed, create the directories necessary to
contain your new plot:

    mkdir -p myplots/templates/myplots
    mkdir myplots/templatetags

The templates directory will contain the html template you can include in other
templates to display your plot. The templatetags directory will contain the python
code to construct the plot.ly plot.

Start by creating the
[templatetags](https://docs.djangoproject.com/en/2.1/howto/custom-template-tags/)
file:

    touch myplots/templatetags/myplots_tags.py

Edit this file, starting with the necessary imports:

```python
from plotly import offline
import plotly.graph_objs as go
from django import template

from tom_targets.models import Target
```

The `plotly` imports are needed for building an offline plot. The django
`template` import gives access to the template library, which will allow for
registering the template tag. Finally, the TOM  Toolkit `Target` class will allow
access to the `Target` model (for querying).

Next, add the boiler plate code for a template tag:

```python
register = template.Library()


@register.inclusion_tag('myplots/targets_reduceddata.html')
def targets_reduceddata(targets=Target.objects.all()):
```

First we instantiate the `register` decorator. You don't need to know much about
this other that it allows us to register functions as templatetags. The function
`targets_reduceddata` is decorated with the `register` decorator, which takes as
an argument the template to render. The function definition takes in a queryset of
`Target`s as a keyword argument, but if none are supplied, defaults to all `Target`s
in the database.

Next, add the function body:

```python
    # order targets by creation date
    targets = targets.order_by('-created')
    # x axis: target names. y axis: datum count
    data = [go.Bar(
        x=[target.name for target in targets],
        y=[target.reduceddatum_set.count() for target in targets]
    )]
    # Create the plot
    figure = offline.plot(go.Figure(data=data), output_type='div', show_link=False)
    # Add plot to the template context
    return {'figure': figure}
```

As the comments describe, the function code iterates over each `Target` in the
`targets` queryset adding the target name and datum count as x/y values to the
`Bar` data structure. Check out the [plot.ly bar chart
documentation](https://plot.ly/python/bar-charts/) for more information about the
options available to you. As an exercise, try changing the values in the y axis.
Or you could use a different chart type.

Finally, the code adds the plot.ly plot to the template rendering context. Next we
will create this template where this context will be rendered.

Create the file, making sure it matches the template name specified in the
template tag definition beforehand:

    touch myplots/templates/myplots/targets_reduceddata.html

This file contains the simple contents:

    {% raw %}
    {{ figure|safe }}
    {% endraw %}

All this template does is output the `figure` variable, which is the html
generated from plotly in the templatetag. We also tell django that the output is
safe, so that it doesn't escape the html. That's it.

**Note:** If you're running the development server, restart it now. Django doesn't
automatically pick up new templatetags.

Now that the templatetag and template are complete, we can use it in any template.
You might have your own templates which you'd like to add the plot to, or perhaps
you've customized one of the TOM supplied templates as per the [customizing
templates](/customization/customize_templates) documentation. Either way, including the
templatetag works the same way. At the top of the template (after any 'extends')
load the new tag library:

    {% raw %}
    {% load myplots_tags %}
    {% endraw %}

Now insert the templatetag somewhere in the template where you'd like it to
appear:

    {% raw %}
    {% targets_reduceddata %}
    {% endraw %}

If your parent template already has a queryset of targets available in the context
(for example, a target list page) you can pass it in to be used in your plot:

    {% raw %}
    {% targets_reduceddata targets %}
    {% endraw %}

Otherwise the plot will simply use all targets in your database. Either way, you
should end up with something like this:

![](/_static/plotting_data_doc/plot.png)

That's it! Plot.ly provides a wide range of plotting capabilities, you should
reference [the documentation](https://plot.ly/python/) for more information. It
would also be helpful to  read [Django's
ORM](https://docs.djangoproject.com/en/2.1/topics/db/) to become familiarized with
wide range of methods of querying data.
