py-gnuplot
***********

py-gnuplot is a Python plot tools based on Gnuplot.

To install easily::

    pip install -U py-gnuplot

Or to install by source code::

    python install py-gnuplot

1. Introduction
===============

Gnuplot is a portable command-line driven graphing utility for Linux, OS/2, MS
Windows, OSX, VMS, and many other platforms.

But it seems gnuplot has its own grammer and couldn't be easily called in
python. On the other hand we generage many data that need to be plotted in
python, but we have barrier to pass the data to gnuplot. Matplotlib/mplfiance
could plot the data generaged in python, but how about leveraging the power of
gnuplot?

For example, for finance data, we can plot it in Gnuplot, we can also plot it
directly in python in the exactly same result: `5.2 multiplot`_:

.. image:: http://gnuplot.sourceforge.net/demo/finance.13.png

The py-gnuplot include two parts:

    * gnuplot: the exact python implementation of gnuplot, it has the same
      functions as gnuplot, we can plot the file and function as in gnuplot;
    * pyplot: We can plot the pandas dataframe generated in python, it process
      the python generated data;

For functions and file data, it's fit to use gnuplot submodule to plot the
data as in gnuplot. For python generated data, especially `pandas`_ dataframe,
it's easy to use pyplot submodule to plot the data;

.. _pandas: https://pandas.pydata.org/

For each submodule, we both have two means to call the functions:

    * object-oriented interface: Via class Gnuplot and you will always have a
      Gnuplot object. 
    * Easy way: Via global class-less functions, almost every function could
      plot what you want..

object-oriented interface is straightworward and it is simple interepretation
for Gnuplot script and easy to understand if you are familar with Gnuplot. But
it's a little complex to plot data, especially the panda data in the memory.

For easy use and for users who are not very familar with Gnuplot, we develop
the sub module pyplot for easily plotting the data, it refer to the syntax of
matplotlib and mplfinance, the syntax is easy to understand and you needn't
know too much about gnuplot syntax;

It's recommended to use Easy way since it's easy understand based on the
python's point of view.

2. object-oriented interface and Easy way
=========================================

As describe above, object-oriented interface is simple and easy to understand
as gnuplot's logic. Easy way plot the data in python way.

2.1 object-oriented interface
------------------------------

object-oriented interface is a simple wrapper for gnuplot, you can convert the
gnuplot script to py-gnuplot script line by line in py-gnuplot.gnuplot module.
For example we can convert gnuplot demo script: `simple.dem`_ to python script
easily by wrapping them with cmd(''), you can see it's straightforward and is
1:1 mapping:

module gnuplot has an object-oriented interface (via class gnuplotlib) and you
must allocate a gnuplot object before you use it.

.. _simple.dem: http://gnuplot.sourceforge.net/demo/simple.1.gnu
.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot
    g = gnuplot.Gnuplot()
    g.cmd('set terminal pngcairo font "arial,10" fontscale 1.0 size 600, 400')
    g.cmd('set output "simple.1.png"')
    g.cmd('set key fixed left top vertical Right noreverse enhanced autotitle box lt black linewidth 1.000 dashtype solid')
    g.cmd('set style increment default')
    g.cmd('set samples 50, 50')
    g.cmd('set title "Simple Plots" ')
    g.cmd('set title  font ",20" norotate')
    g.cmd('plot [-10:10] sin(x),atan(x),cos(atan(x))')

The generated output is as following:

.. image:: http://gnuplot.sourceforge.net/demo/simple.1.png

Meanwhile we provide more complex wrapper and you can think plot action as a
plot() method and others are set() method, it also works as following:

.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot

    g = gnuplot.Gnuplot()
    g.set(terminal = 'pngcairo font "arial,10" fontscale 1.0 size 600, 400',
            output = '"simple.1.png"',
            key = 'fixed left top vertical Right noreverse enhanced autotitle box lt black linewidth 1.000 dashtype solid',
            style = 'increment default',
            samples = '50, 50',
            title = '"Simple Plots" font ",20" norotate')
    g.plot('[-10:10] sin(x),atan(x),cos(atan(x))')

It's equivalent to method 1 but seems muck like a python script.

2.2 easy way
--------------

The recommended way is simple and easy to understand in python way:

.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot

    gnuplot.plot('[-10:10] sin(x),atan(x),cos(atan(x))',
            terminal = 'pngcairo font "arial,10" fontscale 1.0 size 600, 400',
            output = '"simple.1.png"',
            key = 'fixed left top vertical Right noreverse enhanced autotitle box lt black linewidth 1.000 dashtype solid',
            style = 'increment default',
            samples = '50, 50',
            title = '"Simple Plots" font ",20" norotate')

This generates exact the same output but is more simple and seems muck like a
python script.

3. gnuplot and pyplot
======================

In brief, gnuplot submodule is for plotting functions and data in file, while
pyplot submodule is for plotting python itself generated data in pandas
dataframe format.

3.1 Sub module gnuplot: the original gnuplot
--------------------------------------------

gnuplot demo script: `surface2.dem`_ could be writen as python script as
following:

.. _surface2.dem: http://gnuplot.sourceforge.net/demo/simple.1.gnu

.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot

    gnuplot.splot('cos(u)+.5*cos(u)*cos(v),sin(u)+.5*sin(u)*cos(v),.5*sin(v) with lines',
            '1+cos(u)+.5*cos(u)*cos(v),.5*sin(v),sin(u)+.5*sin(u)*cos(v) with lines',
            terminal = 'pngcairo enhanced font "arial,10" fontscale 1.0 size 600, 400 ',
            output = '"surface2.9.png"',
            dummy = 'u, v',
            key = 'bmargin center horizontal Right noreverse enhanced autotitle nobox',
            style = ['increment default','data lines'],
            parametric = '',
            view = '50, 30, 1, 1',
            isosamples = '50, 20',
            hidden3d = 'back offset 1 trianglepattern 3 undefined 1 altdiagonal bentover',
            xyplane = 'relative 0',
            title = '"Interlocking Tori" ',
            urange = '[ -3.14159 : 3.14159 ] noreverse nowriteback',
            vrange = '[ -3.14159 : 3.14159 ] noreverse nowriteback')

And the generated output is as following:

.. image:: http://gnuplot.sourceforge.net/demo/surface2.9.png

3.2 Sub module pyplot: plot the python generated data
-----------------------------------------------------

Sub module gnuplot is straightworward and easy to understand but a little
complex. It's simple intepretion for Gnuplot script so you must understand
Gnuplot deeply at first.

For easy use and for users who are not very familar with Gnuplot, we develop a
new sub module for easily plotting the data, it refer to the syntax of matplotlib
and mplfinance, the syntax is easy to understand and you needn't know too much
about gnuplot syntax;

Meanwhile, sub module gnuplot is object oriented and you must allocate a
gnuplot object before you use it while submodule pyplot don't need that.
Submodule pyplot need that the data should be panda dataframe format. Let's
see the example `histograms.1.gnu`_ from gnuplot demo, the python sciprt is as
following:

.. _histograms.1.gnu: http://gnuplot.sourceforge.net/demo/histograms.1.gnu

.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot
    import pandas as pd

    df = pd.read_csv('immigration.dat', index_col = 0, sep='\t', comment='#')
    pyplot.plot(df,
            'using 2:xtic(1), for [i=3:22] "" using i ',
            terminal = 'pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 600, 400 ',
            output = '"histograms.1.png"',
            key = 'fixed right top vertical Right noreverse noenhanced autotitle nobox',
            style = 'data linespoints',
            datafile = ' missing "-"',
            xtics = 'border in scale 1,0.5 nomirror rotate by -45 autojustify norangelimit',
            title = '"US immigration from Europe by decade"')

And the generated output is as following:

.. image:: http://gnuplot.sourceforge.net/demo/histograms.1.png


4. Plot methods
==================

4.1 methods in gnuplot
-----------------------

4.2 methods in pyplot
-----------------------

pyplot is easy to use and it only has a few functions, all the configuration
are passed as function parameter.

pyplot take pandas dataframe as data.

plot(df, \*args, \*\*kwargs)
+++++++++++++++++++++++++++++

@ df: The data that need to plot. it should be pandas dataframe format.
In gnuplot we pass the data as a function or data file. But normally in
python script, we normally get the data in the memory, not in the file. So
we develop the submodule to plot the data in memory, we should pass the df
in pandas dataframe format, for example::

    df = pd.read_csv('immigration.dat', index_col = 0,
                    sep='\t', comment='#')
    pyplot.plot(df, ...)

@ args: The plot command we need to plot. Gnuplot plot data like that::

    plot 'finance.dat' using 0:2:3:4:5 notitle with financebars lt 8, \
         'finance.dat' using 0:9 notitle with lines lt 3, \
         'finance.dat' using 0:10 notitle with lines lt 1, \
         'finance.dat' using 0:11 notitle with lines lt 2

Now we omit the command "plot" and data "finance.dat" since we have
already pass them in the function name and the first parameter "df", we
pass the command as a list of command as following::

    pyplot.plot(df,
                'using 0:2:3:4:5 notitle with financebars lt 8',
                'using 0:9 notitle with lines lt 3',
                'using 0:10 notitle with lines lt 1',
                'using 0:11 notitle with lines lt 2',
                ...)

@ kwargs: As we know The set command is
used to set lots of options before plot, splot, or replot command is
given. We skip the 'set' keyword and use the options name as the key, the
following part is used the attribute value, for example we use the
following line to set the xtics in gnuplot::

    set xtics border in scale 1,0.5 nomirror rotate by -45 autojustify norangelimit

Then in the function, we will use::

    xtics = 'border in scale 1,0.5 nomirror rotate by -45 autojustify norangelimit'

as a parameters. Some options order sensitive, so we need the python
version > 3.7, which seems to pass the function parameter in order. Or there will
some issue and cause exception::

    pyplot.plot(df,
                'using 0:2:3:4:5 notitle with financebars lt 8',
                ...,
                xtics = 'border in scale 1,0.5 nomirror rotate by -45 autojustify norangelimit',
                ...)

splot(df, \*args, \*\*kwargs)
+++++++++++++++++++++++++++++

The parameter are same as plot(), the only difference is it use "splot" to
plot insteading of "plot".

make_subplot(df, \*args, \*\*kwargs)
+++++++++++++++++++++++++++++++++++++

The parameter definition is the same as plot()/splot, but it doesn't plot
the df really, it only return the plot dictionay for later multiplot()
use.

It is much like mplfinance.add_plot(), it only add the subplot command for
further call::

    sub1 = pyplot.make_subplot(df,
            'using 0:2:3:4:5 notitle with candlesticks lt 8',
            'using 0:9 notitle with lines lt 3',
            logscale = 'y',
            yrange = '[75:105]',
            ytics = '(105, 100, 95, 90, 85, 80)',
            xrange = '[50:253]',
            grid = 'xtics ytics',
            lmargin = '9',
            rmargin = '2',
            format = 'x ""',
            xtics = '(66, 87, 109, 130, 151, 174, 193, 215, 235)',
            title = '"Change to candlesticks"',
            size = ' 1, 0.7',
            origin = '0, 0.3',
            bmargin = '0',
            ylabel = '"price" offset 1',
            label = ['1 "Acme Widgets" at graph 0.5, graph 0.9 center front',
                '2 "Courtesy of Bollinger Capital" at graph 0.01, 0.07',
                '3 "  www.BollingerBands.com" at graph 0.01, 0.03']
            )

multiplot(\*args, \*\*kwargs)
++++++++++++++++++++++++++++++++++

The multiplot set the setting in kwargs at first, and then call the
subplot in args to multiplot.

@args: It is the list of subplot generated by make_subplot(), it would be
called one by one.

@kwargs: The global setting for multiplot;

For example::

    pyplot.multiplot(sub1, sub2,
            output = '"history.%s.png"' %(code),
            term = 'pngcairo size 1920,1080 font ",11"')

multisplot(\*args, \*\*kwargs)
++++++++++++++++++++++++++++++++++

To be implemented.

5. More examples
================

5.1 splot
---------

module gnuplot has an object-oriented interface (via class gnuplotlib) and you
must allocate a gnuplot object before you use it.

.. _simple.dem: http://gnuplot.sourceforge.net/demo/simple.1.gnu
.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot
    g = gnuplot.Gnuplot()
    g.cmd('set terminal pngcairo font "arial,10" fontscale 1.0 size 600, 400')
    g.cmd('set output "simple.1.png"')
    g.cmd('set key fixed left top vertical Right noreverse enhanced autotitle box lt black linewidth 1.000 dashtype solid')
    g.cmd('set style increment default')
    g.cmd('set samples 50, 50')
    g.cmd('set title "Simple Plots" ')
    g.cmd('set title  font ",20" norotate')
    g.cmd('plot [-10:10] sin(x),atan(x),cos(atan(x))')

The generated output is as following:

.. image:: http://gnuplot.sourceforge.net/demo/simple.1.png

5.2 multiplot
-------------

we convert the gnuplot demo script: `finance.dem`_ to the final python script:

.. _finance.dem: http://gnuplot.sourceforge.net/demo/finance.13.gnu

.. code-block:: python

    #!/usr/bin/env python3
    #coding=utf8
    from pygnuplot import gnuplot, pyplot
    import pandas as pd


    # 10 May 2005
    # 
    # Though gnuplot is primarily a scientific plotting program, it can do a great
    # job of plotting finance charts as well. The primary challenge is the irregular
    # nature of financial time series. Stocks don't trade every day, so when you set
    # the x-axis to time gaps appear for non-trading days. Investors and traders
    # generally prefer that these gaps be omitted. Another challenge is that finance
    # charts are best presented in semi-log form (log y-axis, linear x-axis),
    # but gnuplot wants to span decades in its log scaling, something that stocks
    # rarely do. These and other challenges are met in finance.dem, a short 
    # demonstration script that proves that gnuplot can really shine in this area.
    # 
    # gnuplot plays a central role in our work. Almost all the graphs in "Bollinger
    # on Bollinger Bands" were plotted by gnuplot, many gnuplot visuals have
    # appeared on CNBC, our in-house analytics use gnuplot for visual display and
    # The Capital Growth Letter relies heavily on gnuplot for its charts.  
    # 
    # Finally, gnuplot is yet another successful demonstration of a powerful idea,
    # open source programming. Thanks to all who made gnuplot possible from the
    # earliest days to the present and to all those who will contribute in the
    # future. (Special thanks to Hans-Bernhard Broeker whose patience helped me to
    # climb the grade and to Ethan Merritt whose recent contributions have been
    # invaluable to our work.)
    # 
    # John Bollinger
    # www.BollingerBands.com 

    # a demonstration of gnuplot finance plot styles
    # by John Bollinger, CFA, CMT
    # www.BollingerBands.com
    # BBands@BollingerBands.com

    # data and indicators in finance.dat
    # data file layout: 
    # date, open, high, low, close, volume,
    # 50-day moving average volume, Intraday Intensity, 
    # 20-day moving average close, 
    # upper Bollinger Band, lower Bollinger Band 


    df = pd.read_csv('finance.dat', sep='\t', index_col = 0, parse_dates = True,
            names = ['date', 'open','high','low','close', 'volume','volume_m50',
                'intensity','close_ma20','upper','lower '])
    sub1 = pyplot.make_subplot(df,
            'using 0:2:3:4:5 notitle with candlesticks lt 8',
            'using 0:9 notitle with lines lt 3',
            'using 0:10 notitle with lines lt 1',
            'using 0:11 notitle with lines lt 2',
            'using 0:8 axes x1y2 notitle with lines lt 4',
            logscale = 'y',
            yrange = '[75:105]',
            ytics = '(105, 100, 95, 90, 85, 80)',
            xrange = '[50:253]',
            grid = 'xtics ytics',
            lmargin = '9',
            rmargin = '2',
            format = 'x ""',
            xtics = '(66, 87, 109, 130, 151, 174, 193, 215, 235)',
            title = '"Change to candlesticks"',
            size = ' 1, 0.7',
            origin = '0, 0.3',
            bmargin = '0',
            ylabel = '"price" offset 1',
            label = ['1 "Acme Widgets" at graph 0.5, graph 0.9 center front',
                '2 "Courtesy of Bollinger Capital" at graph 0.01, 0.07',
                '3 "  www.BollingerBands.com" at graph 0.01, 0.03']
            )

    sub2 = pyplot.make_subplot(df,
            'using 0:($6/10000) notitle with impulses lt 3',
            'using 0:($7/10000) notitle with lines lt 1',
            bmargin = '',
            size = '1.0, 0.3',
            origin = '0.0, 0.0',
            tmargin = '0',
            nologscale = 'y',
            autoscale = 'y',
            format = ['x', 'y "%1.0f"'],
            ytics = '500',
            xtics = '("6/03" 66, "7/03" 87, "8/03" 109, "9/03" 130, "10/03" 151, "11/03" 174, "12/03" 193, "1/04" 215, "2/04" 235)',
            ylabel = '"volume (0000)" offset 1')

    pyplot.multiplot(sub1, sub2,
            output = '"finance.13.png"',
            term = 'pngcairo font "arial,10" fontscale 1.0 size 900, 600')

And this the generated output:

.. image:: http://gnuplot.sourceforge.net/demo/finance.13.png

5. Q/A
======

6. Changelog
============

0.1:

    Initial upload

0.2:

    Update the README document. 

0.3:

    Update the Project description. 

7. TODO
============

The 0.1 release only support plot/multiplot, will support splot/multisplot the
next release
