Prosta aplikacja Django prezentująca dane z PyEphem

W tym artykule stworzymy prostą aplikację Django prezentującą dane pochodzące z modułu PyEphem. Aplikacja będzie tworzyła wykresy rozmiarów kątowych, czy jasności obiektu, oraz zestawiała inne ciekawe dane. Tworzymy aplikację django w naszym istniejącym projekcie:
python manage.py startapp astroephem
U mnie aplikacja będzie w podkatalogu "diamandas" (diamandas.astroephem). W settings.py:
  • Dodaję katalog z szablonami aplikacji: 'diamandas/astroephem/templates',
  • Dodaję aplikację do INSTALLED_APPS 'diamandas.astroephem',
Do urls.py dodaję mapowanie dla URLi aplikacji:
(r'^ephem/', include('diamandas.astroephem.URLconf')),
Gdzie diamandas.astroephem.URLconf oznacza plik diamandas/astroephem/URLconf.py mapujący widoki aplikacji na URLe zaczynające się od ephem:
from django.conf.urls.defaults import *

urlpatterns = patterns('diamandas.astroephem',
	(r'^/?$', 'views.show_index'),
)
Zaczynamy od głównych widoków w views:
#!/usr/bin/python
# Diamanda Application Set

from django.shortcuts import render_to_response
from django.conf import settings
from django.template import RequestContext
from django.http import HttpResponseRedirect,HttpResponse

def show_index(request):
        """
        Show the main page
        """
        return render_to_response(
            'astroephem/show_index.html',
            {},
            context_instance=RequestContext(request))

def show_object(request, object):
        """
        Show object page
        """
        return render_to_response(
            'astroephem/show_object.html',
            {},
            context_instance=RequestContext(request))
Strona główna listuje planety i inne obiekty podlinkowane pod widok "show_object" (gdzie argument "object" jest zwykłym łańcuchem):
(r'^obj/(?P<object>[\w\-_]+)/$', 'views.show_object'),
(r'^/?$', 'views.show_index'),
A szablon główny (najważniejsza jego część) wygląda tak:
<h4>Wybierz obiekt</h4>
<ul>
    <li><a href="/ephem/obj/merkury/">Merkury</a></li>
    <li><a href="/ephem/obj/wenus/">Wenus</a></li>
    <li><a href="/ephem/obj/mars/">Mars</a></li>
    <li><a href="/ephem/obj/jowisz/">Jowisz</a></li>
    <li><a href="/ephem/obj/saturn/">Saturn</a></li>
    <li><a href="/ephem/obj/uran/">Uran</a></li>
    <li><a href="/ephem/obj/neptun/">Neptun</a></li>
    <li><a href="/ephem/obj/pluton/">Pluton</a></li>
</ul>
<ul>
    <li><a href="/ephem/obj/moon/">Księżyc</a></li>
</ul>
Ustawiłem sztywną listę elementów, jaka będzie obsługiwana przez widok show_object. Dla każdego z nich zastosuję odpowiedni obiekt/planetę w PyEphem. Widok show_object po zmodyfikowaniu wygląda tak:
def show_object(request, object):
        """
        Show object page
        """
        now = datetime.now()
        # use ephem planet/moon per given object slug
        if object == 'merkury':
            object = ephem.Mercury()
            name = 'Merkury'
        elif object == 'wenus':
            object = ephem.Venus()
            name = 'Wenus'
        elif object == 'mars':
            object = ephem.Mars()
            name = 'Mars'
        elif object == 'jowisz':
            object = ephem.Jupiter()
            name = 'Jowisz'
        elif object == 'saturn':
            object = ephem.Saturn()
            name = 'Saturn'
        elif object == 'uran':
            object = ephem.Uranus()
            name = 'Uran'
        elif object == 'neptun':
            object = ephem.Neptune()
            name = 'Neptun'
        elif object == 'pluton':
            object = ephem.Pluto()
            name = 'Pluton'
        elif object == 'moon':
            object = ephem.Moon()
            name = u'Księżyc'
        
        # Polskie tłumaczenia konpagestelacji
        const = {
            'Aries': 'Baran',
            'Taurus': 'Byk',
            'Gemini': 'Bliźnięta',
            'Cancer': 'Rak',
            'Leo': 'Lew',
            'Virgo': 'Panna',
            'Libra': 'Waga',
            'Scorpius': 'Skorpion',
            'Ophiuchus': 'Wężownik',
            'Sagittarius': 'Strzelec',
            'Capricornus': 'Koziorożec',
            'Aquarius': 'Wodnik',
            'Pisces': 'Ryby',
        }
        
        # wyliczamy dane dla Warszawy
        city = ephem.Observer()
        city.lat = '52.15'
        city.long = '21.01'
        city.elevation = 115
        object.compute(city)
        
        # zbieramy dane dla obecnej daty/czasu
        constellation = ephem.constellation(object)[1]
        if constellation in const.keys():
            constellation = const[constellation]
        data = {'name': name, 'rising': city.next_rising(object), 'transit': city.next_transit(object),
                'setting': city.next_setting(object), 'az': object.az, 'alt': object.alt, 'mag': object.mag,
                'constellation': constellation, 'ra': object.ra, 'dec': object.dec,
                'current_date': now, 'size': object.size, 'distance': object.earth_distance }
        
        # rozmiar i jasność w najbliższych dniach/miesiącach
        days = []
        size = []
        mag = []
        
        future_object = object
        future_city = city
        future = now
        max_size = 0
        min_size = 0
        max_mag = 0
        min_mag = 0
        for i in range(1,20):
                d = list(future.timetuple())
                future_city.date = '%s/%s/%s' % (d[0], d[1], d[2])
                future_object.compute(future_city)
                if i%3 == 0:
                    days.append(str(future_city.date).split(' ')[0])
                size.append(float(str(future_object.size)[:4]))
                mag.append(future_object.mag)
                
                if max_size < future_object.size:
                    max_size = future_object.size
                if max_mag < future_object.mag:
                    max_mag = future_object.mag
                
                if min_mag > future_object.mag:
                    min_mag = future_object.mag
                if min_size > future_object.size:
                    min_size = future_object.size
                
                future = future + timedelta(days=5)
        
        # wykres rozmiaru
        chart = SimpleLineChart(670, 250, y_range=[min_size-1, max_size+1])
        chart.add_data(size)
        chart.set_colours(['0000FF'])
        chart.fill_linear_stripes(Chart.CHART, 0, 'CCCCCC', 0.2, 'FFFFFF', 0.2)
        chart.set_grid(0, 25, 5, 5)
        size.reverse()
        chart.set_axis_labels(Axis.LEFT, size)
        dlabels = chart.set_axis_labels(Axis.BOTTOM, days)
        chart.set_axis_positions(dlabels, [5])
        index = chart.set_axis_labels(Axis.TOP, ['Rozmiar %s (arcsec)' % name])
        chart.set_axis_positions(index, [50])
        chart.set_axis_style(index, '202020', font_size=14, alignment=0)
        size_chart = chart.get_url()
        
        # wykres jasności
        chart = SimpleLineChart(670, 250, y_range=[min_mag-1, max_mag+1])
        chart.add_data(mag)
        chart.set_colours(['0000FF'])
        chart.fill_linear_stripes(Chart.CHART, 0, 'CCCCCC', 0.2, 'FFFFFF', 0.2)
        chart.set_grid(0, 25, 5, 5)
        mag.reverse()
        chart.set_axis_labels(Axis.LEFT, mag)
        dlabels = chart.set_axis_labels(Axis.BOTTOM, days)
        chart.set_axis_positions(dlabels, [5])
        index = chart.set_axis_labels(Axis.TOP, ['Jasność %s (mag)' % name])
        chart.set_axis_positions(index, [50])
        chart.set_axis_style(index, '202020', font_size=14, alignment=0)
        mag_chart = chart.get_url()
        
        # koniec
        return render_to_response(
            'astroephem/show_object.html',
            {'data': data, 'size_chart': size_chart, 'mag_chart': mag_chart},
            context_instance=RequestContext(request))
A szablon show_object.html wygląda tak:
{% block content %}
<h2>{{ data.name }}</h2>
Dane dla Warszawy (52.15, 21.01; 115 m n.p.m) wyliczone za pomocą PyEphem.
<ul>
<li><b>Najbliższy wschód</b>: {{ data.rising }}</li>
<li><b>Najbliższe górowanie</b>: {{ data.transit }}</li>
<li><b>Najbliższy zachód</b>: {{ data.setting }}</li>
</ul>
<h4>Obecnie położenie ({{ data.current_date|date:"Y.m.d H:i" }})</h4>
<ul>
<li><b>Wysokość</b>: {{ data.alt }}</li>
<li><b>Azymut</b>: {{ data.az }}</li>
<li><b>Deklinacja</b>: {{ data.dec }}</li>
<li><b>Rektascencja</b>: {{ data.ra }}</li>
<li><b>Konstelacja</b>: {{ data.constellation }}</li>
<li><b>Jasność</b>: {{ data.mag }} mag</li>
<li><b>Rozmiar/Średnica</b>: {{ data.size }} sekund łuki</li>
<li><b>Odległość od Ziemi</b>: {{ data.distance }} AU</li>
</ul>

<h4>Prognoza</h4>
<div style="text-align:center;">
<img src="{{ size_chart }}" alt="Wykres rozmiaru {{ data.name }}" />
<img src="{{ mag_chart }}" alt="Wykres jasności {{ data.name }}" />
</div>
{% endblock %}
Aplikację można na żywo zobaczyć na www.nauka.rk.edu.pl. Wykresy generowane są za pomocą pygooglechar, które są proste w użyciu, jednak mogą obsłużyć ograniczoną ilość danych (przesyłanych w GET), jak i nie są zbyt dokładne ilościowo. Aplikację można rozbudować o możliwość określenia czasu i miejsca obserwacji, czy też zastosować matplotlib do generowania lepszych wykresów.
RkBlog

Django, 28 November 2009

Comment article
Comment article RkBlog main page Search RSS Contact