Skip to content

Commit

Permalink
Merge pull request #268 from wpfff/fix/docs
Browse files Browse the repository at this point in the history
Fix/docs
  • Loading branch information
wpfff committed Mar 12, 2022
2 parents fa0538f + e3808be commit b7abe3c
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 120 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,6 @@ dmypy.json

# Pyre type checker
.pyre/

# sphinx outputs
doc/_build/*
20 changes: 20 additions & 0 deletions doc/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Minimal makefile for Sphinx documentation
#

# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = .
BUILDDIR = _build

# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

.PHONY: help Makefile

# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
10 changes: 7 additions & 3 deletions doc/concepts/index.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
Elementary concepts
===================
Working principles of plottr
============================

This section documents how plottr works internally.
It should enable anyone who's interested in writing their own components
to get the basic ideas and find their way through the code.

.. toctree::
:maxdepth: 2
:caption: Contents:

nodes
data
nodes
117 changes: 117 additions & 0 deletions doc/concepts/nodes.bak.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
.. documentation for nodes and flowchart.
Nodes and Flowcharts
====================

Contents
--------

* `Setting up flowcharts`_
* `Create you own nodes`_



The basic concept of modular data analyis as we use it in plottr consists of `Nodes` that are connected directionally to form a `Flowchart`. This terminology is adopted from the great `pyqtgraph <http://www.pyqtgraph.org>`_ project; we currently use their `Node` and `Flowchart` API under the hood as well. Executing the flowchart means that data flows through the nodes via connections that have been made between them, and gets modified in some way by each node along the way. The end product is then the fully processed data. This whole process is typically on-demand: If a modification of the data flow occurs somewhere in the flowchart -- e.g., due to user input -- then only 'downstream' nodes need to re-process data in order to keep the flowchart output up to date.


.. _Setting up flowcharts:

Setting up flowcharts
---------------------

TBD.

.. _Create you own nodes:

Creating custom nodes
---------------------

The following are some general notes. For an example see the notebook ``Custom nodes`` under ``doc/examples``.

The class :class:`plottr.node.node.Node` forms the basis for all nodes in plottr. It is an extension of ``pyqtgraph``'s Node class with some additional tools, and defaults.


Basics:
^^^^^^^
The actual data processing the node is supposed to do is implemented in :meth:`plottr.node.node.Node.process`.


Defaults:
^^^^^^^^^

Per default, we use an input terminal (``dataIn``), and one output terminal (``dataOut``). Can be overwritten via the attribute :attr:`plottr.node.node.Node.terminals`.

User options:
^^^^^^^^^^^^^

We use ``property`` for user options. i.e., we implement a setter and getter function (e.g., with the ``@property`` decorator). The setter can be decorated with :meth:`plottr.node.node.updateOption` to automatically process the option change on assignment.

Synchronizing Node and UI:
^^^^^^^^^^^^^^^^^^^^^^^^^^

The UI widget is automatically instantiated when :attr:`plottr.node.node.Node.uiClass` is set to an appropriate node widget class, and :attr:`plottr.node.node.Node.useUi` is ``True``.

Messaging between Node and Node UI is implemented through Qt signals/slots. Any update to a node property is signalled automatically when the property setter is decorated with :meth:`plottr.node.node.updateOption`. A setter decorated with ``@updateOption('myOption')`` will, on assignment of the new value, call the function assigned to ``plottr.node.node.NodeWidget.optSetter['myOption']``.

Vice versa, there are tools to notify the node of changes made through the UI. Any trigger (such as a widget signal) can be connected to the UI by calling the functions :meth:`plottr.node.node.NodeWidget.signalOption` with the option name (say, ``myOption``) as argument, or :meth:`plottr.node.node.NodeWidget.signalAllOptions`. In the first case, the value of the option is taken by calling ``plottr.node.node.NodeWidget.optGetter['myOption']()``, and then the name of the option and that value are emitted through :meth:`plottr.node.node.updateGuiFromNode`; this is connected to :meth:`plottr.node.node.Node.setOption` by default. Similarly, :meth:`plottr.node.node.NodeWidget.signalAllOptions` results in a signal leading to :meth:`plottr.node.node.Node.setOptions`.

The implementation of the suitable triggers for emitting the option value and assigning functions to entries in ``optSetters`` and ``optGetters`` is up to the re-implementation.


Example implementation:
^^^^^^^^^^^^^^^^^^^^^^^

The implementation of a custom node with GUI can then looks something like this::

class MyNode(Node):

useUi = True
uiClass = MyNodeGui

...

@property
def myOption(self):
return self._myOption

# the name in the decorator should match the name of the
# property to make sure communication goes well.
@myOption.setter
@updateOption('myOption')
def myOption(self, value):
# this could include validation, etc.
self._myOption = value

...


That is essentially all that is needed for the Node; only the process function that does something depending on the value of ``myOption`` is missing here. The UI class might then look like this::

class MyNodeGui(NodeWidget):

def __init__(self, parent=None):
# this is a Qt requirement
super().__init__(parent)

somehowSetUpWidget()

self.optSetters = {
'myOption' : self.setMyOption,
}
self.optGetters = {
'myOption' : self.getMyOption,
}

# often the trigger will be a valueChanged function or so,
# that returns a value. Since the signalOption function
# doesn't require one, we can use a lambda to bypass, if necessary.
self.somethingChanged.connect(lambda x: self.signalOption('myOption'))

def setMyOption(self, value):
doSomething()

def getMyOption(self):
return getInfoNeeded()


This node can then already be used, with the UI if desired, in a flowchart.
113 changes: 0 additions & 113 deletions doc/concepts/nodes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,116 +2,3 @@
Nodes and Flowcharts
====================

Contents
--------

* `Setting up flowcharts`_
* `Create you own nodes`_



The basic concept of modular data analyis as we use it in plottr consists of `Nodes` that are connected directionally to form a `Flowchart`. This terminology is adopted from the great `pyqtgraph <http://www.pyqtgraph.org>`_ project; we currently use their `Node` and `Flowchart` API under the hood as well. Executing the flowchart means that data flows through the nodes via connections that have been made between them, and gets modified in some way by each node along the way. The end product is then the fully processed data. This whole process is typically on-demand: If a modification of the data flow occurs somewhere in the flowchart -- e.g., due to user input -- then only 'downstream' nodes need to re-process data in order to keep the flowchart output up to date.


.. _Setting up flowcharts:

Setting up flowcharts
---------------------

TBD.

.. _Create you own nodes:

Creating custom nodes
---------------------

The following are some general notes. For an example see the notebook ``Custom nodes`` under ``doc/examples``.

The class :class:`plottr.node.node.Node` forms the basis for all nodes in plottr. It is an extension of ``pyqtgraph``'s Node class with some additional tools, and defaults.


Basics:
^^^^^^^
The actual data processing the node is supposed to do is implemented in :meth:`plottr.node.node.Node.process`.


Defaults:
^^^^^^^^^

Per default, we use an input terminal (``dataIn``), and one output terminal (``dataOut``). Can be overwritten via the attribute :attr:`plottr.node.node.Node.terminals`.

User options:
^^^^^^^^^^^^^

We use ``property`` for user options. i.e., we implement a setter and getter function (e.g., with the ``@property`` decorator). The setter can be decorated with :meth:`plottr.node.node.updateOption` to automatically process the option change on assignment.

Synchronizing Node and UI:
^^^^^^^^^^^^^^^^^^^^^^^^^^

The UI widget is automatically instantiated when :attr:`plottr.node.node.Node.uiClass` is set to an appropriate node widget class, and :attr:`plottr.node.node.Node.useUi` is ``True``.

Messaging between Node and Node UI is implemented through Qt signals/slots. Any update to a node property is signalled automatically when the property setter is decorated with :meth:`plottr.node.node.updateOption`. A setter decorated with ``@updateOption('myOption')`` will, on assignment of the new value, call the function assigned to ``plottr.node.node.NodeWidget.optSetter['myOption']``.

Vice versa, there are tools to notify the node of changes made through the UI. Any trigger (such as a widget signal) can be connected to the UI by calling the functions :meth:`plottr.node.node.NodeWidget.signalOption` with the option name (say, ``myOption``) as argument, or :meth:`plottr.node.node.NodeWidget.signalAllOptions`. In the first case, the value of the option is taken by calling ``plottr.node.node.NodeWidget.optGetter['myOption']()``, and then the name of the option and that value are emitted through :meth:`plottr.node.node.updateGuiFromNode`; this is connected to :meth:`plottr.node.node.Node.setOption` by default. Similarly, :meth:`plottr.node.node.NodeWidget.signalAllOptions` results in a signal leading to :meth:`plottr.node.node.Node.setOptions`.

The implementation of the suitable triggers for emitting the option value and assigning functions to entries in ``optSetters`` and ``optGetters`` is up to the re-implementation.


Example implementation:
^^^^^^^^^^^^^^^^^^^^^^^

The implementation of a custom node with GUI can then looks something like this::

class MyNode(Node):

useUi = True
uiClass = MyNodeGui

...

@property
def myOption(self):
return self._myOption

# the name in the decorator should match the name of the
# property to make sure communication goes well.
@myOption.setter
@updateOption('myOption')
def myOption(self, value):
# this could include validation, etc.
self._myOption = value

...


That is essentially all that is needed for the Node; only the process function that does something depending on the value of ``myOption`` is missing here. The UI class might then look like this::

class MyNodeGui(NodeWidget):

def __init__(self, parent=None):
# this is a Qt requirement
super().__init__(parent)

somehowSetUpWidget()

self.optSetters = {
'myOption' : self.setMyOption,
}
self.optGetters = {
'myOption' : self.getMyOption,
}

# often the trigger will be a valueChanged function or so,
# that returns a value. Since the signalOption function
# doesn't require one, we can use a lambda to bypass, if necessary.
self.somethingChanged.connect(lambda x: self.signalOption('myOption'))

def setMyOption(self, value):
doSomething()

def getMyOption(self):
return getInfoNeeded()


This node can then already be used, with the UI if desired, in a flowchart.
18 changes: 18 additions & 0 deletions doc/examples.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
Customization examples
======================

Here we want to show some ideas on how plottr could be customized.
can include other files (scripts, etc) if necessary.
Maybe this file should be moved into a subdirectory.


Creating a custom node
----------------------

to be done.


Creating a custom app
---------------------

to be done.
14 changes: 10 additions & 4 deletions doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,20 @@
Welcome to plottr's documentation!
==================================

Todo: a quick description of what you can do with plottr, and a screenshot, or better a gif,
showing it in action.

.. toctree::
:maxdepth: 2
:caption: Contents:

intro
concepts/index
nodes/index
plotnode
api/index
examples

.. nodes/index
.. plotnode
.. api/index
Expand All @@ -22,4 +28,4 @@ Indices and tables

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
* :ref:`search`
7 changes: 7 additions & 0 deletions doc/intro.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Basic usage
===========

Content: a quick tour of how to look at different types of data (qcodes, ddh5,
datadict directly using jupyter).

TBD.
35 changes: 35 additions & 0 deletions doc/make.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
@ECHO OFF

pushd %~dp0

REM Command file for Sphinx documentation

if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set SOURCEDIR=.
set BUILDDIR=_build

if "%1" == "" goto help

%SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.https://www.sphinx-doc.org/
exit /b 1
)

%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
goto end

:help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%

:end
popd

0 comments on commit b7abe3c

Please sign in to comment.