Archives

Categories

Meta

This series of blog posts details the creation of a custom Qt application containing an interactive matplotlib widget and a plot selection list, which controls the currently displayed figure. In Part 1, we constructed our application framework and layout using Qt Designer. Part 2 of this series explored the custom subclass creation that was necessary to add custom logic to our application. In this installment, we will look at adding multiple figures to our application and including their names in the list widget. In addition, we will write some code to change the current figure by selecting from the names in the list widget. The final versions of the Qt Designer UI file and the “custommpl.py” script can be downloaded here.

Adding Items to the List

Adding text to our list is simple. Our list widget, which we called mplfigs, is an instance of the QListWidget class. This class has an addItem method which adds the given string argument to the list. Remember that if we also want to be able to switch figures by selecting names from the list, so to get us started, let’s modify the Main class’s __init__ method and add a new method calledaddfig.

1

2

3

4

5

6

7

8

def__init__(self,):

super(Main,self).__init__()

self.setupUi(self)

self.fig_dict={}

defaddfig(self,name,fig):

self.fig_dict[name]=fig

self.mplfigs.addItem(name)

Now any new instances of our application will contain an empty dictionary called fig_dict, which we will use to store our Figure instances by name. The new addfig method takes a name string argument and a Figure instance. The Figure is added to the dictionary under the name key, which is also added to our list widget. To see how this works, change the condition code block at the end of the program as follows. The resulting application window is shown below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

if__name__=='__main__':

importsys

fromPyQt4 importQtGui

importnumpy asnp

fig1=Figure()

ax1f1=fig1.add_subplot(111)

ax1f1.plot(np.random.rand(5))

app=QtGui.QApplication(sys.argv)

main=Main()

main.addmpl(fig1)

main.addfig('Figure 1',fig1)

main.show()

sys.exit(app.exec_())

To add a new figure, call rmmpl to remove the old figure then use addmpl and addfig to add the next figure. The plot will update and the new names will be added to the list; however, our application will have no way of knowing how to change the plots when you select names from the list.

Changing Plots Using the List

To connect the names in the list to the figure updating code, we need to take advantage of Qt’s signal and slot architecture. The main Qt documentation has a very nice explanation of this concept, so I’ll just give a very brief overview here. Essentially, any “events” that occurs in a widget trigger a particular “signal”, which is defined by the widget. In our example, when an item in our list widget is selected, it triggers an itemClicked signal from the list, which emits a QListWidgetItem instance. Initially, the signal is not directed anywhere, so nothing happens. However, we can connect this signal to another widget’s slot, which is a (potentially custom) method that handles the emitted information. In our case, when the itemClicked signal is triggered, we want to remove the old figure (rmmpl) and add the figure (addmpl) defined by the emitted QListWidgetItem name. To make this possible, we “connect” the itemClicked signal to a new method that we’ll call changefig. This is more clearly seen in example code.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

classMain(QMainWindow,Ui_MainWindow):

def__init__(self,):

super(Main,self).__init__()

self.setupUi(self)

self.fig_dict={}

self.mplfigs.itemClicked.connect(self.changefig)

fig=Figure()

self.addmpl(fig)

defchangefig(self,item):

text=item.text()

self.rmmpl()

self.addmpl(self.fig_dict[text])

A few changes have been made to our initialization method. First of all, we connected the itemClicked signal to a new method called changefig. Remember that when this signal is triggered it emits a QListWidgetItem as well, so changefig must accept one argument, which is an instance of the list item. List widget items define a text method, which simple returns the text of the selected item. Once we know the item text, we can remove the old figure and display a new one based on the name defined by the selected text.

Notice that an empty figure instance was added to our plotting window in the initialization method. This is necessary because our first call to changefig will try to remove a previously displayed figure, which will throw an error if one is not displayed. The empty figure serves as a placeholder so the changefig method functions properly.

To test this, let’s add a couple of Figure instances to our application to see what it does. We’ll do this in the conditional code block at the end of the script.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

if__name__=='__main__':

importsys

fromPyQt4 importQtGui

importnumpy asnp

fig1=Figure()

ax1f1=fig1.add_subplot(111)

ax1f1.plot(np.random.rand(5))

fig2=Figure()

ax1f2=fig2.add_subplot(121)

ax1f2.plot(np.random.rand(5))

ax2f2=fig2.add_subplot(122)

ax2f2.plot(np.random.rand(10))

fig3=Figure()

ax1f3=fig3.add_subplot(111)

ax1f3.pcolormesh(np.random.rand(20,20))

app=QtGui.QApplication(sys.argv)

main=Main()

main.addfig('One plot',fig1)

main.addfig('Two plots',fig2)

main.addfig('Pcolormesh',fig3)

main.show()

sys.exit(app.exec_())

At first, when you run this code, you will be presented with a blank plotting window; however, select one of the plot names from the list widget and see what happens.

SUCCESS!!!

Running Our Application from IPython

IPython is an extremely popular and powerful tool for interactive data analysis. In addition, it is well designed to work with external GUI event loops, which makes it possible to run custom applications as well. To get this to work, we must tell IPython that we will be running an external Qt GUI using the %gui qt cell magic (version >2.4 of IPython). With IPython started, we can start our GUI application in the following manner.

1

%gui qt

1

2

3

importnumpy asnp

frommatplotlib.figure importFigure

fromcustommpl importMain

1

2

main=Main()

main.show()

This will display our GUI with an empty plot window and figure list. We can recreate our example above by generating each figure and adding them to our application.

1

2

3

4

fig1=Figure()

ax1f1=fig1.add_subplot(111)

ax1f1.plot(np.random.rand(5))

main.addfig('One plot',fig1)

In this way, you can interactively process the data then add new figures to the GUI application as needed. This technique also works with IPython’s qtconsole and locally-hosted notebooks.

In this second blog post, I’m going to add some of the custom logic to the application GUI that was constructed using Qt Designer in the Part 1. We’ll be using Python (version 3.4), PyQt (version 4.10.4), and matplotlib (version 1.4.3), but this code should work with Python 2.7 as well. I’ve found that these packages are most easily installed using Continuum Analytics’ Anaconda Python Distribution.

To begin, create an empty Python file called “custommpl.py” that will contain all the code in this example. This file should be located in the same directory as the UI file “window.ui” from Part 1. The final version of this Python file is included in the project zip package.

Imports

The necessary imports are the first element of our program and are shown below.

1

2

3

4

5

6

fromPyQt4.uic importloadUiType

frommatplotlib.figure importFigure

frommatplotlib.backends.backend_qt4agg import(

FigureCanvasQTAgg asFigureCanvas,

NavigationToolbar2QT asNavigationToolbar)

Let’s examine the matplotlib imports first. Notice that the generic pyplot module is not imported — do not use the functions from this module. The pyplot module defines wrapper functions that are meant to automate the creation of the interactive plotting window, and they will most likely cause problems for any custom GUI object. TheFigure class imported above is a very generic plotting container for all aspects of our plot. Instances of this object have the same methods as the figure objects created using pyplot.figure. In addition, we’ve also imported FigureCanvasQTAgg and the NavigationToolbar2QTfrom the PyQt4 backend module. These are both custom Qt widgets. A canvas contains and displays a Figure instance, and a navigation toolbar is the widget containing the buttons for interacting with the plot.

The loadUiType function requires a single argument, the name of a Designer UI file, and returns a tuple of the appropriate application classes. This can be done directly after the imports, as shown below.

1

Ui_MainWindow,QMainWindow=loadUiType('window.ui')

In this case, the return tuple contains two class definitions. The first is our custom GUI application class, set to the Ui_MainWindow variable. The second is the base class for our custom GUI application, which in this case is PyQt4.QtGui.QMainWindow. The base class type is defined by the widget we first created with Designer. Note: These are not instances of these classes, but the class definitions themselves. They are meant to serve as superclasses to our new application logic class, which we’ll create next.

This usage differs from many other examples. For tutorials typically convert the UI file to a Python module using the pyuic4 utility (see Part 1 for details), and then import that module into a new script, i.e. from window import Ui_MainWindow. The downside of this approach is that, in addition to generating an extra file, others might be tempted to modify the Python module directly. If the application design is changes, which updates the UI file, then the pyuic4 conversion will destroy any custom modifications to the Python module. By using the UI file directly, as I’ve done above, it will not be possible to inadvertently alter the GUI design code.

The Minimal Subclass

Now we are ready to create a minimal subclass to run our GUI application. To start, we define a new class, called Main, that inherits from QMainWindow and Ui_MainWindow. Initialization of this class should call the __init__ method of QMainWindow as well as the setupUi method, which is defined in all Designer-created GUI applications.

1

2

3

4

5

6

7

8

9

10

11

12

13

classMain(QMainWindow,Ui_MainWindow):

def__init__(self,):

super(Main,self).__init__()

self.setupUi(self)

if__name__=='__main__':

importsys

fromPyQt4 importQtGui

app=QtGui.QApplication(sys.argv)

main=Main()

main.show()

sys.exit(app.exec_())

To generate a functional GUI, a conditional code block is added to the end of the script. The leading if statement is telling Python to process this code block only if the program is run directly (e.g. $ python custommpl.py) rather than being imported into a different Python program (e.g. import custommpl). QApplication starts a Qt GUI event loop, which is a necessary prerequisite to running any Qt GUI applications. InstantiatingMain creates our custom application, but on its own, this will not display the GUI. This is accomplished by calling the show method. The sys.exit line simply ensures that the GUI event loop is closed properly when we quit the program. Running this file from the command line should produce the following window.

Great! We’ve successfully created our first GUI! But at this point, it doesn’t do anything…

Adding a Plot

Next, add a new method, addmpl, to our Main class that inserts a plotting Figure instance into our matplotlib container.

1

2

3

4

5

6

7

8

9

classMain(QMainWindow,Ui_MainWindow):

def__init__(self,):

super(Main,self).__init__()

self.setupUi(self)

defaddmpl(self,fig):

self.canvas=FigureCanvas(fig)

self.mplvl.addWidget(self.canvas)

self.canvas.draw()

The second line creates a FigureCanvas widget instance to contain our plot. This is stored as a Main instance attributed called canvas. Next, we need to remember a little information about our matplotlib container widget, which we created in Part 1. Recall that we enforced a vertical layout for any encapsulated widgets in mplwindow and named this vertical layout mplvl. This is attribute is a QVBoxLayout instance, which has an addWidget method for adding new vertically-aligned widgets into the container widget. We’ll use this method to upload our Figure widget. Calling the draw method on the canvas to renders the plot.

Side Note: The canvas object could have been added directly to our mplwindow container widget without using the vertical layout. This is done by setting the parent widget of the canvas: self.canvas.setParent(self.mplwindow). However, in this case, the figure will not expand to fit the container widget, and it will not resize with the window. In addition to vertically stacking widgets, the vertical layout instance ensures that the widgets is manages are properly stretched to fit the available area.

As a test, create a simple Figure instance in the conditional code block at the end of the module. Add this plot to the GUI using our new addmpl method (line 12). The code and resulting plot are show below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

if__name__=='__main__':

importsys

fromPyQt4 importQtGui

importnumpy asnp

fig1=Figure()

ax1f1=fig1.add_subplot(111)

ax1f1.plot(np.random.rand(5))

app=QtGui.QApplication(sys.argv)

main=Main()

main.addmpl(fig1)

main.show()

sys.exit(app.exec_())

Adding a Toolbar

Although we’ve successfully added a plot to our application, there is currently no way to interact with the data. This is where the NavigationToolbar comes into play. Adding the toolbar to our plot involves a simple modification to the addmpl method.

1

2

3

4

5

6

7

defaddmpl(self,fig):

self.canvas=FigureCanvas(fig)

self.mplvl.addWidget(self.canvas)

self.canvas.draw()

self.toolbar=NavigationToolbar(self.canvas,

self.mplwindow,coordinates=True)

self.mplvl.addWidget(self.toolbar)

The NavigationToolbar construction should be straightforward (lines 5-6). First, you need to connect this toolbar with canvas containing the axes and data. The second argument is the parent widget that will house this toolbar, which in this case is our mplwindow widget. The coordinates keyword argument controls the display of the cursor coordinates when the mouse is hovered over an axes. Finally, the toolbar widget is added into the vertical layout widget mplvl in the same way as the canvas. Because the toolbar was the second widget added, it will be placed under the plot window. The final version of this application is shown below.

To try something different, we can make the toolbar a detachable widget on the main window by using the following code. Compare the code below with the first example.

1

2

3

4

5

6

7

defaddmpl(self,fig):

self.canvas=FigureCanvas(fig)

self.mplvl.addWidget(self.canvas)

self.canvas.draw()

self.toolbar=NavigationToolbar(self.canvas,

self,coordinates=True)

self.addToolBar(self.toolbar)

Changing plots

In order to change plots, we’re going to do something a little different. In principle, we could use the matplotlibaxes instances to modify the displayed data directly. However, this makes it hard to change the plot type/shape/number of the subplots. Instead, we will define a new method called rmmpl inside our Main class that completely removes the current plot and toolbar widget. New figures can then be added by calling the addmpl method with a new Figure instance. The advantage here is that Figure instances retain all of their plotting and layout information, so we don’t have to recreate these aspect with each plot change. Below is our code.

1

2

3

4

5

defrmmpl(self,):

self.mplvl.removeWidget(self.canvas)

self.canvas.close()

self.mplvl.removeWidget(self.toolbar)

self.toolbar.close()

This should be pretty easy to understand. The removeWidget method removes the canvas and toolbar from our vertical layout instance. Calling theclose method on these widgets ensures that they are no longer displayed in the application window. If we don’t do this, new widgets will be overlaid on the previous plots, which causes problems.

To see how this might work, change the conditional code as shown below. Hit Enter in the terminal to break out of the input and switch plots. The second plot should look something like the one shown below.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

if__name__=='__main__':

importsys

fromPyQt4 importQtGui

importnumpy asnp

fig1=Figure()

ax1f1=fig1.add_subplot(111)

ax1f1.plot(np.random.rand(5))

fig2=Figure()

ax1f2=fig2.add_subplot(121)

ax1f2.plot(np.random.rand(5))

ax2f2=fig2.add_subplot(122)

ax2f2.plot(np.random.rand(10))

app=QtGui.QApplication(sys.argv)

main=Main()

main.addmpl(fig1)

main.show()

input()

main.rmmpl()

main.addmpl(fig2)

sys.exit(app.exec_())

Now we’ve created a very simple plotting window, to which we can dynamically change the displayed Figure instances, the final step in this process will be to add the figures to our list widget so users can easily switch plots by simply selecting a new different title in the list. Coding that behavior is straightforward, but will be covered in detail in new next post.

Designer is a graphical tool for building complex Qt4 GUI applications. In this post, I will use Designer to construct a simple GUI application, and in the following posts, I’ll use Python, matplotlib, and PyQt4 to add the necessary application logic to display an interactive data plot and a plot selection list. The final result is shown below.

One thing to keep in mind, Designer’s purpose is to help with GUI construction and widget layout. Application logic must be added in a separate step. That means that ultimately this example will differ from other Qt embedding examples in that we will end up with two files: the first, “window.ui”, defines our overall GUI design, and the second, “custommpl.py”, contains the custom application logic. A zip package of the completed files can be downloaded here.

Designing the Layout

A first step is to analyze the look of the GUI and decide how you will implement this with Designer. Although there are a number of ways to construct this layout, we will define a model that includes five major elements, with a generic graphical display shown below: 1) the main window holds everything together (black), 2) a list of figures (red), 3) a matplotlib container (blue), 4) a data plot (green), and 5) a navigation toolbar (purple).

There are two major layouts to consider in our application. First, the matplotlib container and figure list are horizontally aligned inside of the main window, with the figure list taking up less overall space. Second, the data plot and toolbar are vertically aligned inside of the matplotlib container.

With this list of widgets and layouts in hand, let’s try to create this application framework in Designer.

The Designer Window

Upon starting Designer, you will be presented with a creation dialog. Select “Main Window” and click “Create”. You should now see something very close to the screen shot shown below. The “Main Window” that we’ve just created is going to act as an overall application container widget, in other words the black box in the generic figure above.

This Designer window has four major elements that will be important for this tutorial.

The blank, untitled “MainWindow” instance in the center of the screen is our application window. We will add widgets to this window to create our GUI layout. At this point, adjust the size of this window until it is approximately the size that you’d like to see for your final application.

The “Widget Box” (left) contains all of the default Qt widgets that we can add to our MainWindow. To add a widget, click and drag the item into the MainWindow.

The “Object Inspector” (top right) presents a tree of all the widgets that are currently present in our MainWindow. Use this to select and modify individual widgets. The Object indentation level indicates which widgets are contained inside other widgets. For example, the MainWindow widget currently contains centralwidget, menubar, and statusbar widgets.

The “Property Editor”, just below the “Object Inspector”, is an editable list of properties for the currently selected widget.

Building the Framework

To start building our application, let’s add the two widgets that should be contained in the MainWindow: the figure list and the matplotlib container. To do this, drag and drop a “List Widget” (under Item Widgets) to the right side of the MainWindow and a generic Widget (under Containers) to the left hand side. These widgets will have some default size, which will not look correct.

Manual adjustment of the widgets size and position is unnecessary. This is done automatically by applying the appropriate layout to the MainWindow container widget. Right click on the MainWindow and select “Lay Out”. You can select either “Lay Out Horizontally” or “Layout in a Grid”, both of which will have the same effect.

This stretches both widgets until they completely fill the window; unfortunately, they will not be the correct shape. Size adjustments are made by changing several widget properties. First of all, select the List Widget (either by clicking on it in the MainWindow or selecting it from the Object Inspector) and set the following properties in the Property Editor:

sizePolicy->Horizontal Policy->Maximum

maximumSize->Width->200

Next, select the matplotlib container widget and set this property:

sizePolicy->Horizontal Policy->Expanding

At this point, our application window should look very much like our final product. However, we still need to setup the contents of our matplotlib container widget.

Adding the data plot and toolbar to the matplotlib container is best done as part of the application logic, but a vertical alignment should be enforced for the widgets contained in the matplotlib container. Unfortunately, a little hack is necessary to set the layout inside our matplotlib container. First of all, drag and drop a temporary widget (it doesn’t matter what you choose) into the matplotlib container. Now right click on the matplotlib container and set the “Lay Out” to “Lay Out Vertically”. With the layout set, you can delete the temporary widget from the plotting widget container.

Naming the Widgets

As a final step, we are going to change the names of some of the application elements. Ultimately, this application framework is going to be compiled into a Python class, and each of the widget and layout elements will be added as attributes of this class. The default attribute names are very generic “widget”, “listWidget”, etc., and renaming these widgets in Designer changes the attribute names as defined inside the main window class. This is not strictly necessary, but it will probably make it easier to keep track of the elements in a much larger GUI application. The widget names are shown in the “Object” column of the “Object Inspector”. To change the names, simply double-click the name and type in the new one. For this application, make the following name changes:

listWidget->mplfigs

widget->mplwindow

The layouts are also named attributes of our application, and it will be useful to change at least the name of the vertical alignment layout of “mplwindow”. Select the “mplwindow” widget in the Object Inspector, and scroll through the properties until you find the “Layout” section. Change the layoutName property from “verticalLayout” to “mplvl”.

Saving the Application

With the application design complete, save this project as “window.ui”. UI files are language-agnostic XML representations of our GUI. If you need to make changes to your layout in the future, reopen the UI file with Designer and make the necessary changes. In the next post, we’ll go over how to programmatically extract out our MainWindow class from the UI file and create a subclass with the appropriate logic.

PyQt4 ships with a command line utility script called pyuic4, which converts UI files into Python module files. Below is an example of the command line invocation of this script.

1

$pyuic window.ui>window.py

This is useful if you want to see how the MainWindow class and its attributes are defined in Python code; however, this step is unnecessary. Be Warned! Designer can not open Python module files, so you should never delete the UI file. Also, do not directly modify the resulting Python module. If you make layout changes to the UI file, the pyuic4 conversion process will overwrite your modified window module. To add additional logic to your MainWindow class, write a separate module file that defines a subclass of the MainWindow object. (See the next post.)

Output Box

I wanted to have a nice box that wraps all of the output from any of the code presented in the examples. This was fairly easy to accomplish by wrapping output in a division with the class “pyout”, i.e. <div class=”pyout”>…</div>. Then, I updated my CSS file to include the following:

1

2

3

4

5

6

7

8

9

10

div.pyout {

border-style:dotted;

border-width:1px;

font-family:Monaco,'MonacoRegular','Courier New',monospace;

font-size:12px;

font-weight:normal;

line-height:normal;

margin-bottom:1em;

padding:0.5em;

}

This makes a nice dotted border around all of the code output.

Output Text

Next, to precede all output boxes with the text “Output:” is a little trickier. I could have added this text to every “pyout” division, but that would have been tedious and error prone. Fortunately, jQuery has a wrap function that wraps a given element in another set of tags. In this way, I could wrap all of my “pyout” boxes with another division containing the “Output:” text.

First of all, I wrote a custom JS script that wraps the “pyout” division. In my child theme folder, I created a file called “wrapper.js” that included the following code:

1

2

3

4

jQuery(".pyout").wrap(function(){

return'<div class="pyoutwrap">Output:<br></div>'

}

);

All “pyout” boxes are now surrounded by another division classed as “pyoutwrap”. Modifying my theme’s CSS file as below makes the “Output:” text bold and slightly larger than the actual code output.

1

2

3

4

5

6

div.pyoutwrap {

font-family:Monaco,'MonacoRegular','Courier New',monospace;

font-size:14px;

font-weight:bold;

margin-bottom:1em;

}

Making these changes has no immediate effect, though, because you need to register this JS script with WordPress for it to be activated. This is accomplished by adding a couple of lines to “functions.php”, which is shown below in its entirety.

Much of this code was covered in the section on child themes from my previous post; however, notice that a new function wp_enqueue_script incorporates my new JS file into my site. A couple of the arguments to this function are very important, so they will all be described here. The first argument is simply the name with which I would like to register this script with WordPress. The second argument is the file location, making sure this is the full path by prefixing get_stylesheet_directory_uri(). The array argument ensures that jQuery is loaded before this script, otherwise things won’t work correctly. The string is just a version number, which is unnecessary, so I just put in a placeholder of ‘1.0’. The final argument, true, is critical. It puts this script at the end of the HTML, just before the closing </body> tag. In this way, the function is executed after the entire page is loaded. Otherwise, the script is loaded into the HTML head and is executed before the body, including my “pyout” box, is loaded.

Input Text

I followed a very similar procedure to add “Input:” before all of my code samples. Again, I used jQuery’s wrap function on all “crayon-syntax” classes. Below is the additional function call in “wrapper.js” and some new styling in “style.css”, respectively. I also changed Crayon’s “Top Margin” to “0px”, which can be done through Crayon’s Settings page.

1

2

3

jQuery(".crayon-syntax").wrap(

'<div class="pyinwrap">Input:<br></div>'

);

1

2

3

4

5

6

7

div.pyinwrap {

font-family:Monaco,'MonacoRegular','Courier New',monospace;

font-size:14px;

font-weight:bold;

margin-bottom:0.5em;

margin-top:1em;

}

Although this method works just fine, it wraps every Crayon code instance with the “pyinwrap”. That means that even non-Python code blocks will be prefaced with “Input:”. For now, this is going to be the best solution until I can figure out how to add Python-specific wrappers.

In Action

Now that everything is set, all of my Python input and output has a similar appearance to an IPython notebook session. (Not perfect, but close enough.)

I wanted to write this as one class, so that I could easily store and compare several different files processed in this way. One way to do this would be to separate the different components into their own classes, and then use these as base classes for unifying derived class. For example, one could write the following type of code:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

# File reading objects

classReadBase(object):

defreadfile(self,):

print("Reading data.")

# File processing

classProcBase(object):

defprocdata(self,):

print("Referencing data.")

# Fitting data

classFitBase(object):

deffitdata(self,):

print("Fitting data.")

# Derived class

classEverything(ReadBase,ProcBase,FitBase):

pass

test=Everything()

test.readfile()

test.procdata()

test.fitdata()

Reading data.
Referencing data.
Fitting data.

The trouble, though, was that each of these steps could be done in several very different ways. For example, there are potentially many different file types that one might want to process, even though the imported data is of the same type. One approach to this problem would be to write a file loading class for every file type. However, you now have to write a derived class for every possible file type class. It gets worse when the other steps have multiple different parts as well. If you have 3 file types, 3 referencing types, and 3 fitting types, that’s (3*3*3=) 27 total derived types!

Python’s type function to the rescue

Python has a built-in function type, which I’ve always used in the past to determine the object type for a particular variable.

1

type('Hello World!')

<class ‘str’>

However, this function has a second use as well, which takes three arguments. This form is type(name, bases, dict), and it returns a new object named name with bases as the superclasses. dict is a dictionary of class attributes you’d like to set for this new class.

This is very powerful, because now we can write a class generator function that takes some flags and outputs the appropriate class. Below is an example that is similar to that shown above except that it uses several different types of Read and Processing classes. (I’ve left out fitting, but you get the picture.)

I purchased this website many years ago with the intention of starting my own blog. At the time, I was teaching myself Python, and I thought it wouldn’t be that hard to write my own custom website using CGI and MySQL. Please don’t ever do this! Although I learned quite a bit about web servers, HTML, CSS, and SQL databases, it was way too much work, and my blog never took off.

Fast forward to 2015. After receiving yet another auto-payment notification for my unused website, I decide the time has finally come to make use of it. Fortunately, my hosting provider has an auto-install option for a WordPress blog. WordPress is popular. It’s apparently easy to use… Let’s give this a try.

One thing I’d like to write about is Python programming for data analysis with included examples. I’m a heavy user of IPythonnotebooks for data analysis, so I’d like to be able to incorporate some of the notebook display features into my blog. Unfortunately, a web search for some ideas on uploading notebooks to WordPress was surprisingly unhelpful given WordPress’s popularity.

IPython provides a tool, nbconvert, which can convert notebook files directly to HTML. This is great because you can easily send a webpage of an analysis to a colleague, for example. It is also the basis of the NBViewer website. This might make a good starting point; however, one of my biggest problems with the IPython notebook is that markdown cells are not spell-checked. My spelling skills are atrocious, so my notebooks are always rife with errors. Knowing this, I was reluctant to upload notebooks directly and decided to pursue other options.

Ultimately, I found a bunch of plugins and hacks that gave me much of the display functionality for emulating the look and feel of the IPython notebook. My adventures are documented below in case others might find this useful.

Code Highlighting

This was the easiest part of the whole process. There are many syntax highlighters available as WordPress plugins. I took a quick look at a couple of “Top ### Code Highlighting” pages for inspiration, but it seemed like all the highlight plugins are fairly similar. I finally chose Crayon, not for any particular reason, except that it was pretty high up on many of the top lists. The default display properties were not optimal for my taste, so I modified several options through the “Settings” link under Crayon on the Plugins admin page. The changes are as follows: 1) Display the Toolbar to “Never”, 2) Enable plain code view and display to “Disable Mouse Events”, 3) and Language Fallback to “Python”.

Now, my “Add Post” editor contains a Crayon button, which opens a source code import window, from which I can also alter any of the numerous global display options. To add some code from a notebook, simply copy-and-paste it into the Crayon source code window. Once inserted, the source code is wrapped in the appropriate pre tags. For example, the following highlighted Python code

1

print('hello')

Appears as this in the Text editor window after insertion with Crayon:

<pre class="lang:python decode:true " >print('hello')</pre>

Creating a Child Theme

After some experimentation, I realized that I was going to need to modify my site theme with some custom CSS, at the minimum. I read up on this topic on the web, and most people recommend that you create a Child Theme when doing any customization. A child theme is essentially an overlay on top of another base (Parent) theme. There are a couple of advantages here. First, if the underlying theme is updated, you won’t lose your customizations. In addition, the child overlay is a fairly minimal set of files, so you could transfer your changes to a new theme with very little effort. The WordPress documentation on Child Themes is a pretty decent place to find step-by-step information.

As of this writing, this site is using the default “twentyfifteen” theme. In my themes folder, wp-content/themes, I created a new theme folder called twentyfifteen-child that contains two files: style.css and functions.php.

The functions.php file simply contains a function theme_enqueue_styles that loads the main style sheet from the underlying parent theme. My file is shown below:

The style.css file is simply your custom style sheet that must contain a comment header with a tag Template that names the underlying parent theme. I simply copied the parent theme style.css file and added the “Template” line. My file is shown below:

Use it to make something cool, have fun, and share what you've learned with others.

*/

Then I simply changed to the “twentyfifteen-child” theme from the WordPress theme manager.

Pandas DataFrame Tables

Pandas is a powerful data analysis library for Python. Among other things, Pandas provides a tabular data structure called DataFrame, which is very similar to the equivalently named structure in R. In IPython’s notebook and Qt Console interface, Pandas DataFrames are printed as nice HTML tables. For example, below is a chunk of code and the IPython output.

1

2

3

4

5

6

7

8

9

10

importnumpy asnp

importpandas aspd

ints=np.random.random_integers(1,10,size=(3,2))

a=['A','B','C']

b=['D','A','E']

df=pd.DataFrame(ints,columns=['one','two'])

df[0]=a

df['b']=b

df

one

two

0

b

0

5

1

A

D

1

8

9

B

A

2

9

3

C

E

Emulating this was a little tricky. As a first step, convert your notebook to HTML:

$ ipython nbconvert test_notebook.ipynb

Open the resulting HTML file in a text editor. There is a ton of boilerplate junk here, but you can easily find the table by searching for “<table”. Copy all of the text up to and including the closing </table> tag, and paste this into the Text Post editor. This won’t work in the Visual editor, which does some conversions behind the scenes. Make sure the table class is set to “dataframe”. Wrap the table in a div with the class name “dftable”. Here is the raw HTML for the above table:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

<div class="dftable">

<table class="dataframe"border="1">

<thead>

<tr style="text-align: right;">

<th></th>

<th>one</th>

<th>two</th>

<th>0</th>

<th>b</th>

</tr>

</thead>

<tbody>

<tr>

<th>0</th>

<td>5</td>

<td>1</td>

<td>A</td>

<td>D</td>

</tr>

<tr>

<th>1</th>

<td>8</td>

<td>9</td>

<td>B</td>

<td>A</td>

</tr>

<tr>

<th>2</th>

<td>9</td>

<td>3</td>

<td>C</td>

<td>E</td>

</tr>

</tbody>

</table>

</div>

Next, I modified the CSS file of my Child Theme (style.css) to alter the default appearance of this class of table and the surrounding div.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

div.dftable {

max-height:500px;

max-width:1000px;

/* Use scroll bars for large content */

overflow:auto;

/* Don't wrap cell content */

white-space:nowrap;

font-family:Monaco,'MonacoRegular','Courier New',monospace;

font-size:12px;

}

table.dataframe {

/* Let cell width expand to contents */

table-layout:auto;

/* Don't stretch the width to fit the column */

width:auto;

}

Perhaps not the most elegant solution, but it does the trick.

Matplotlib Figures

IPython can display Matplotlib figures inline with the rest of the code and output. On export to HTML, the image is embedded into the raw HTML in base64 encoded text. Again, this is great when sharing the HTML files with collaborators, because everything is contained in one file. However, WordPress doesn’t handle this elegantly. In this case, using Matplotlib’s savefig command will create a hard copy version of the figure in addition to inlining it in the notebook. For example, the following set of commands will produce a very simple plot in a notebook along with a PNG of the same figure called “testing.png”:

1

2

3

4

5

6

importmatplotlib.pyplot asplt

%matplotlibinline

plt.plot([1,3,2],'o-')

plt.savefig('testing.png')

To emulate an IPython notebook with the inline set, I’ll probably just drop the savefig calls when transferring the code into my post. Then I can simply use the “Add Media” button in my post editor to upload and include the figure. An advantage of this procedure is that the figures are given their own URL, which people can reference in the future.

MathJax

Again, there are a bunch of MathJax plugins available for WordPress. I chose “Simple MathJax” because it sounded… simple. And it seemed to best emulate the way MathJax behaves in IPython notebook markdown cells. Once installed and enabled, I can can add inline MathJax by using a single \$ sign. For example, \$\frac{1}{2}\$ will be rendered as $\frac{1}{2}$. Block equations can be included with the double dollar sign \$\$, such that \$\$\alpha^{2}\$\$ is rendered as $$\alpha^{2}$$

EDIT: This following paragraph is no longer necessary. I filed a PR with these changes to this plugin. It has been merged into master. I’ll leave this here for reference, though.

One issue is that the escaping the dollar sign is not supported by default. In order to set this, go to the Plugins page and select “Edit” under Simple MathJax. This opens a text editor for modifying this plugin. Search for the following line:

Now your should be able to add dollar signs to your post by preceding them with \, such as \$.

Final Thoughts

That covers most things that I want to do for the time being. However, I’ll probably come back to this topic again once I get frustrated with some other odd behavior of my site. I hope others find this useful. Leave me a comment if you want me to add/clarify anything.

Follow-up

I wrote a second post that shows how to add “Input:”/”Output:” text before all code boxes.