Tutorial: Writing your own Script

This tutorial is intended as a walk-through for the creation of a custom script in ARTview. It is also useful to understand how to use the ARTview package. It covers the basics of starting components and how to make them interact with each other.

The Basics

Artview runs with PyQt4, therefore before using any component you need to start a Qt application, but do that with artview, not directly in PyQt4. After defining what you want, you need to get it to run, otherwise windows will not respond. Your basic script will look like this:

import artview

# start pyqt
app = artview.core.QtGui.QApplication([])

###########################
#     do something        #
###########################

# start program
app.exec_() # lock until all windows are closed

So what to do between those line? The simplest thing you can do is start a single instance Component (or plugin), for instance Menu:

import artview

# start pyqt
app = artview.core.QtGui.QApplication([])

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# start program
app.exec_() # lock until all windows are closed

The above will open a Menu instance with name “Menu”. Note: giving every new instance a different name is important for identifying them afterward.

A slightly more useful component is a RadarDisplay, but this needs a pyart.core.Radar instance. Luckily Py-ART has examples we can use:

import artview

# start pyqt
app = artview.core.QtGui.QApplication([])

# get example radar from pyart
import pyart
radar = pyart.testing.make_target_radar()

# start shared variables
Vradar = artview.core.Variable(radar)
Vfield = artview.core.Variable('reflectivity')
Vtilt = artview.core.Variable(0) #  first sweep

# start display
display = artview.components.RadarDisplay(Vradar, Vfield, Vtilt,
                               name="DisplayRadar")

# start program
app.exec_() # lock until all windows are closed

Now things start to get more complicated. The question is: Why we can’t pass the radar instance directly to RadarDisplay, but rather need to put it inside a Variable instance?

We want our display(s) to be able to share this radar instance with other components. In C programming this could be done using pointers, and here we employ a kind of equivalent for Python. More about that in the next section.

Shared Variables

The use of shared variables is an important part of ARTview, all attributes that expect a Variable instance are indicated by a capital V. Let’s see how this works.

Using Menu we can open radar files and put them in Menu.Vradar. Since this is a visualization package we want to plot this files.

This is simple. Instead of creating a new Variable we take it from Menu and pass it to RadarDisplay:

import artview

# start pyqt
app = artview.core.QtGui.QApplication([])

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# get Vradar from menu
Vradar = menu.Vradar

# start the other shared variables
Vfield = artview.core.Variable('reflectivity')
Vtilt = artview.core.Variable(0) #  first sweep

# start display
display = artview.components.RadarDisplay(Vradar, Vfield, Vtilt,
                               name="DisplayRadar")

# start program
app.exec_() # lock until all windows are closed

So now we have the most simple script one would want.

Menu opens a file and RadarDisplay plots it.

But ARTview is much more powerful. Suppose you want to compare two fields of the same radar side-by-side. Simply add another display:

import artview

# start pyqt
app = artview.core.QtGui.QApplication([])

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# DISPLAY 1

# get Vradar from menu
Vradar1 = menu.Vradar

# start the other shared variables
Vfield1 = artview.core.Variable('reflectivity')
Vtilt1 = artview.core.Variable(0) #  first sweep

# start display
display1 = artview.components.RadarDisplay(Vradar1, Vfield1, Vtilt1,
                                name="DisplayRadar")

# DISPLAY 2

# get Vradar from menu
Vradar2 = menu.Vradar
# or equivalently
Vradar2 = Vradar1

# start the other shared variables
Vfield2 = artview.core.Variable('radial_velocity')
Vtilt2 = artview.core.Variable(0) #  first sweep

# start display
display = artview.components.RadarDisplay(Vradar2, Vfield2, Vtilt2,
                               name="DisplayRadar")

# start program
app.exec_() # lock until all windows are closed

This script will open 1 Menu and 2 RadarDisplay instance. Both show the same file, but different fields.

However, we have actually made a mistake. Because the Displays use different sweeps (Vtilt) - that is, they start with the same tilt but the user changes the sweep of the first - this will not change the second. We’d like them to change together.

To get that behavior, we just need to change one line. Instead of creating a new Vtilt Variable, use the old one:

import artview

# start pyqt
app = artview.core.QtGui.QApplication([])

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# DISPLAY 1

# get Vradar from menu
Vradar1 = menu.Vradar

# start the other shared variables
Vfield1 = artview.core.Variable('reflectivity')
Vtilt1 = artview.core.Variable(0) #  first sweep

# start display
display1 = artview.components.RadarDisplay(Vradar1, Vfield1, Vtilt1,
                                name="DisplayRadar")

# DISPLAY 2

# get Vradar from menu
Vradar2 = menu.Vradar
# or equivalently
Vradar2 = Vradar1

# start the other shared variables
Vfield2 = artview.core.Variable('radial_velocity')
# wrong: Vtilt2 = artview.core.Variable(0)
# correct:
Vtilt2 = Vtilt1

# start display
display2 = artview.components.RadarDisplay(Vradar2, Vfield2, Vtilt2,
                                name="DisplayRadar")

# start program
app.exec_() # lock until all windows are closed

Graphical Tools

In the previous section we made a script with two displays sharing Vradar and Vtilt but not sharing Vfield, we will leave this as an exercise to explore other potential sharing configurations.

There is the possibility that you don’t know the kind of sharing that you want. AND you don’t want to keep changing your script every time. There is a tool that allows the user to modify the sharing behavior of Components, that is to link/unlink variables between components (e.g. Displays). This is LinkSharedVariables. To get it running just add the following line to your script:

control = artview.components.LinkSharedVariables()

Now we got 4 independent windows floating around our Desktop. To avoid this Menu has the method addLayoutWidget, which offers the ability to put additional Components inside the Menu window.

For instance like this:

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# start Control
control = artview.components.LinkSharedVariables()

# put control inside Menu
menu.addLayoutWidget(control)

Ok, maybe you don’t want to put components inside menu. Your problem is that you would like to close all windows at once and not each individually. For this we leverage the fact that PyQt closes all children instances (windows) of an existing (parent) window. A good policy is to pass menu as the parent for all other components (components always accept a parent key)

For instance:

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# start Control
control = artview.components.LinkSharedVariables(parent=menu)

Yay, we know how to close windows! What about opening new ones?

This is a bit more complicated. Some components can just be started as a priori in the script. But some components like RadarDisplay and LinkSharedVariables have the GUIstart method and can be started by the user at execution time. To do this, use the Menu method addComponent. For instance

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# start Control
menu.addComponent(artview.components.RadarDisplay)

Now you find Display in the components sub-menu and can start a new one there.

Plug-ins

Plug-ins are defined as user specific components that don’t interfere in the over all working of ARTview. They are found in the artview/plugins folder and accessed in artview.plugins. For specific information on what each plug-in does please see the reference-manual. By default we ask that all plug-ins have the GUIstart method. Therefore to access them at execution time add the following at your script:

# start Menu
menu = artview.components.Menu(DirIn="/", name="Menu")

# add plugins
for plugin in artview.plugins._plugins:
    menu.addComponent(plugin)

For more on Plug-ins see Tutorial: Writing your own Plugin

Official Scripts

ARTview has a artview/scripts folder where some “official” scripts are found, including the standard startup that is executed with the artview command. It’s not particularly recommended to put your script there as some details on how that folder works may change with time. If you’d like to see your script included in the future, please submit an Issue at the code repository or introduce a pull request of your modified code.

However, if you want to put your script there you should do two things:

  • Put your script inside a run function def run(DirIn='./', filename=None, field=None):
  • Don’t import artview, but its parts relatively, that is: from .. import core, components, plugins

Doing this you may find your script according to its file name in artview.scripts