├── .gitignore ├── MANIFEST.in ├── Makefile ├── README.md ├── calysto_processing ├── __init__.py ├── __main__.py ├── images │ ├── logo-32x32.png │ └── logo-64x64.png └── kernel.py ├── notebooks └── Extensions.ipynb └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | *.egg-info/ 23 | .installed.cfg 24 | *.egg 25 | 26 | # PyInstaller 27 | # Usually these files are written by a python script from a template 28 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 29 | *.manifest 30 | *.spec 31 | 32 | # Installer logs 33 | pip-log.txt 34 | pip-delete-this-directory.txt 35 | 36 | # Unit test / coverage reports 37 | htmlcov/ 38 | .tox/ 39 | .coverage 40 | .coverage.* 41 | .cache 42 | nosetests.xml 43 | coverage.xml 44 | *,cover 45 | 46 | # Translations 47 | *.mo 48 | *.pot 49 | 50 | # Django stuff: 51 | *.log 52 | 53 | # Sphinx documentation 54 | docs/_build/ 55 | 56 | # PyBuilder 57 | target/ 58 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include setup.py 2 | include calysto_processing/__init__.py 3 | include calysto_processing/__main__.py 4 | include calysto_processing/kernel.py 5 | include README.md 6 | include calysto_processing/images/*.png 7 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | python setup.py register 3 | python setup.py sdist --formats=gztar,zip upload 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Calysto Processing** is the merging of [ProcessingJS](http://processingjs.org/) with [Project Jupyter](http://jupyter.org/) (aka IPython). Processing Sketches are entered into Jupyter notebook cells, and even run in rendered notebooks. Sketches can be paused, and stepped one draw() at a time. 2 | 3 | Because Calysto Processing uses [MetaKernel](https://github.com/Calysto/metakernel/blob/master/README.rst), it has a fully-supported set of "magics"---meta-commands for additional functionality. A list of magics can be seen at [MetaKernel Magics](https://github.com/Calysto/metakernel/blob/master/metakernel/magics/README.md). 4 | 5 | Calysto Processing in use: 6 | 7 | * [CS110: Introduction to Computing](http://jupyter.cs.brynmawr.edu/hub/dblank/public/CS110%20Intro%20to%20Computing/2015/Syllabus.ipynb) 8 | * [Video](https://www.youtube.com/watch?v=V4TzARh-ClY) 9 | 10 | You can install Calysto Processing with: 11 | 12 | ``` 13 | pip3 install --upgrade calysto_processing --user 14 | python3 -m calysto_processing install --user 15 | ``` 16 | 17 | or in the system kernels with: 18 | 19 | ``` 20 | sudo pip3 install --upgrade calysto_processing 21 | python3 -m calysto_processing install --user 22 | ``` 23 | 24 | Next, install Processing 2 or 3 from https://processing.org/download/ 25 | 26 | You will need to make sure that you have installed and access to the `processing_java` command. Mac users will need to install it from Processing by selecting 'Install "processing_java"' under the Tools menu. 27 | 28 | Finally, you need to set an environment variable with the location of processing-java, if it is not in your path. For example: 29 | 30 | ``` 31 | export PROCESSING_JAVA=/opt/processing-3.3.3/processing-java 32 | ``` 33 | 34 | Then, you can use it in the notebook with: 35 | 36 | ``` 37 | jupyter notebook 38 | ``` 39 | 40 | and then select `Calysto Processing` for a new notebook kernel. 41 | 42 | Calysto Processing also has an enhancement: Tables, and some related functions: 43 | 44 | ```java 45 | /* @pjs includeTable="true"; */ 46 | 47 | Table table; 48 | 49 | void setup() { 50 | table = loadTable("test.csv", "header"); 51 | println(table.getRowCount() + " total rows in table"); 52 | } 53 | 54 | long findMax() { 55 | int retval = 0; 56 | for (TableRow row : table.rows()) { 57 | int pop = row.getInt("Population"); 58 | if (pop > retval) 59 | retval = pop; 60 | } 61 | return retval; 62 | } 63 | ``` 64 | 65 | Table-related classes and methods: 66 | 67 | * loadTable(CSV_FILNAME, "header"); 68 | * Table class 69 | * TableRow class 70 | * table.rows() - returns iterator for use with for(TableRow row : table.rows()) {...} 71 | * row.getInt(COLUMN_NAME) 72 | * row.getString(COLUMN_NAME) 73 | * row.getFloat(COLUMN_NAME) 74 | 75 | See source for more details. 76 | 77 | Example notebooks can be found in https://github.com/Calysto/calysto_processing/tree/master/notebooks 78 | 79 | Requires: 80 | 81 | * Jupyter 82 | * Python3 83 | * metakernel (installed with pip) 84 | * calysto (installed with pip) 85 | 86 | Calysto Processing supports: 87 | 88 | * MetaKernel Magics 89 | * All of ProcessingJS, plus pause/restart and stepper 90 | -------------------------------------------------------------------------------- /calysto_processing/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '2.0.3' 2 | -------------------------------------------------------------------------------- /calysto_processing/__main__.py: -------------------------------------------------------------------------------- 1 | from calysto_processing.kernel import ProcessingKernel 2 | 3 | if __name__ == "__main__": 4 | ProcessingKernel.run_as_main() 5 | -------------------------------------------------------------------------------- /calysto_processing/images/logo-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Calysto/calysto_processing/3594bf71872010ba1e011a64afd9536693960d20/calysto_processing/images/logo-32x32.png -------------------------------------------------------------------------------- /calysto_processing/images/logo-64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Calysto/calysto_processing/3594bf71872010ba1e011a64afd9536693960d20/calysto_processing/images/logo-64x64.png -------------------------------------------------------------------------------- /calysto_processing/kernel.py: -------------------------------------------------------------------------------- 1 | from metakernel import MetaKernel 2 | from IPython.display import HTML, Javascript 3 | 4 | import re 5 | import os 6 | import sys 7 | import subprocess 8 | import tempfile 9 | 10 | class ProcessingKernel(MetaKernel): 11 | implementation = 'Processing' 12 | implementation_version = '2.0' 13 | language = 'java' 14 | language_version = '2.2.1' 15 | language_info = { 16 | 'mimetype': 'text/x-java', 17 | 'name': 'java', 18 | 'codemirror_mode': { 19 | "version": 2, 20 | "name": "text/x-java" 21 | }, 22 | # 'pygments_lexer': 'language', 23 | # 'version' : "x.y.z", 24 | 'file_extension': '.java', 25 | } 26 | kernel_json = { 27 | "argv": [sys.executable, 28 | "-m", "calysto_processing", 29 | "-f", "{connection_file}"], 30 | "display_name": "Calysto Processing", 31 | "language": "java", 32 | "codemirror_mode": "java", 33 | "name": "calysto_processing", 34 | } 35 | banner = "Processing kernel - evaluates Processing programs" 36 | canvas_id = 0 37 | keywords = ["@pjs", "Array", "ArrayList", "HALF_PI", 38 | "HashMap", "Object", "PFont", "PGraphics", "PI", "PImage", 39 | "PShape", "PVector", "PrintWriter", "QUARTER_PI", "String", 40 | "TWO_PI", "XMLElement", "abs", "acos", "alpha", "ambient", 41 | "ambientLight", "append", "applyMatrix", "arc", "arrayCopy", 42 | "asin", "atan", "atan2", "background", "beginCamera", 43 | "beginRaw", "beginRecord", "beginShape", "bezier", 44 | "bezierDetail", "bezierPoint", "bezierTangent", 45 | "bezierVertex", "binary", "blend", "blendColor", "blue", 46 | "boolean", "boolean", "box", "break", "brightness", "byte", 47 | "byte", "camera", "case", "ceil", "char", "char", "class", 48 | "color", "color", "colorMode", "concat", "constrain", 49 | "continue", "copy", "cos", "createFont", "createGraphics", 50 | "createImage", "createInput", "createOutput", "createReader", 51 | "createWriter", "cursor", "curve", "curveDetail", 52 | "curvePoint", "curveTangent", "curveTightness", "curveVertex", 53 | "day", "default", "degrees", "directionalLight", "dist", 54 | "double", "draw", "ellipse", "ellipseMode", "else", 55 | "emissive", "endCamera", "endRaw", "endRecord", "endShape", 56 | "exit", "exp", "expand", "extends", "false", "fill", "filter", 57 | "final", "float", "float", "floor", "focused", "font", "for", 58 | "frameCount", "frameRate", "frameRate", "frustum", "get", 59 | "globalKeyEvents", "green", "height", "hex", "hint", "hour", 60 | "hue", "if", "image", "imageMode", "implements", "import", 61 | "int", "int", "join", "key", "keyCode", "keyPressed", 62 | "keyPressed", "keyReleased", "keyTyped", "lerp", "lerpColor", 63 | "lightFalloff", "lightSpecular", "lights", "line", "link", 64 | "loadBytes", "loadFont", "loadImage", "loadPixels", 65 | "loadShape", "loadStrings", "log", "long", "loop", "mag", 66 | "map", "match", "matchAll", "max", "millis", "min", "minute", 67 | "modelX", "modelY", "modelZ", "month", "mouseButton", 68 | "mouseClicked", "mouseDragged", "mouseMoved", "mouseOut", 69 | "mouseOver", "mousePressed", "mousePressed", "mouseReleased", 70 | "mouseX", "mouseY", "new", "nf", "nfc", "nfp", "nfs", 71 | "noCursor", "noFill", "noLights", "noLoop", "noSmooth", 72 | "noStroke", "noTint", "noise", "noiseDetail", "noiseSeed", 73 | "norm", "normal", "null", "online", "open", "ortho", "param", 74 | "pauseOnBlur", "perspective", "pixels[]", "pmouseX", 75 | "pmouseY", "point", "pointLight", "popMatrix", "popStyle", 76 | "pow", "preload", "print", "printCamera", "printMatrix", 77 | "printProjection", "println", "private", "public", 78 | "pushMatrix", "quad", "radians", "random", "randomSeed", 79 | "rect", "rectMode", "red", "requestImage", "resetMatrix", 80 | "return", "reverse", "rotate", "rotateX", "rotateY", 81 | "rotateZ", "round", "saturation", "save", "saveBytes", 82 | "saveFrame", "saveStream", "saveStrings", "scale", "screen", 83 | "screenX", "screenY", "screenZ", "second", "selectFolder", 84 | "selectInput", "selectOutput", "set", "setup", "shape", 85 | "shapeMode", "shininess", "shorten", "sin", "size", "smooth", 86 | "sort", "specular", "sphere", "sphereDetail", "splice", 87 | "split", "splitTokens", "spotLight", "sq", "sqrt", "static", 88 | "status", "str", "stroke", "strokeCap", "strokeJoin", 89 | "strokeWeight", "subset", "super", "switch", "tan", "text", 90 | "textAlign", "textAscent", "textDescent", "textFont", 91 | "textLeading", "textMode", "textSize", "textWidth", "texture", 92 | "textureMode", "this", "tint", "translate", "triangle", 93 | "trim", "true", "unbinary", "unhex", "updatePixels", "vertex", 94 | "void", "while", "width", "year"] 95 | 96 | processing_functions = ["draw", "exit", "loop", "noLoop", "popStyle", "redraw", "setup", "size", "cursor", "frameRate", "noCursor", "binary", "boolean", "byte", "char", "float", "hex", "int", "str", "unbinary", "unhex", "join", "match", "matchAll", "nf", "nfc", "nfp", "nfs", "split", "splitTokens", "trim", "append", "arrayCopy", "concat", "expand", "reverse", "shorten", "sort", "splice", "subset", "for", "while", "else", "if", "switch", "arc", "ellipse", "line", "point", "quad", "rect", "triangle", "bezier", "bezierDetail", "bezierPoint", "bezierTangent", "curve", "curveDetail", "curvePoint", "curveTangent", "curveTightness", "box", "sphere", "sphereDetail", "ellipseMode", "noSmooth", "rectMode", "smooth", "strokeCap", "strokeJoin", "strokeWeight", "beginShape", "bezierVertex", "curveVertex", "endShape", "texture", "textureMode", "vertex", "loadShape", "shape", "shapeMode", "mouseClicked", "mouseDragged", "mouseMoved", "mouseOut", "mouseOver", "mousePressed", "mouseReleased", "keyPressed", "keyReleased", "keyTyped", "createInput", "loadBytes", "loadStrings", "open", "selectFolder", "selectInput", "link", "param", "status", "day", "hour", "millis", "minute", "month", "second", "year", "print", "println", "save", "saveFrame", "beginRaw", "beginRecord", "createOutput", "createReader", "createWriter", "endRaw", "endRecord", "saveBytes", "saveStream", "saveStrings", "selectOutput", "applyMatrix", "popMatrix", "printMatrix", "pushMatrix", "resetMatrix", "rotate", "rotateX", "rotateY", "rotateZ", "scale", "translate", "ambientLight", "directionalLight", "lightFalloff", "lightSpecular", "lights", "noLights", "normal", "pointLight", "spotLight", "beginCamera", "camera", "endCamera", "frustum", "ortho", "perspective", "printCamera", "printProjection", "modelX", "modelY", "modelZ", "screenX", "screenY", "screenZ", "ambient", "emissive", "shininess", "specular", "background", "colorMode", "fill", "noFill", "noStroke", "stroke", "alpha", "blendColor", "blue", "brightness", "color", "green", "hue", "lerpColor", "red", "saturation", "createImage", "image", "imageMode", "loadImage", "noTint", "requestImage", "tint", "blend", "copy", "filter", "get", "loadPixels", "set", "updatePixels", "createGraphics", "hint", "createFont", "loadFont", "text", "textFont", "textAlign", "textLeading", "textMode", "textSize", "textWidth", "textAscent", "textDescent", "abs", "ceil", "constrain", "dist", "exp", "floor", "lerp", "log", "mag", "map", "max", "min", "norm", "pow", "round", "sq", "sqrt", "acos", "asin", "atan", "atan2", "cos", "degrees", "radians", "sin", "tan", "noise", "noiseDetail", "noiseSeed", "random", "randomSeed"] 97 | 98 | special_keywords = { 99 | "@pjs": "pjs%20directive", 100 | "array": "array%20access", 101 | "[]": "array%20access", 102 | "[": "array%20access", 103 | "]": "array%20access", 104 | "()": "parentheses", 105 | "(": "parentheses", 106 | ")": "parentheses", 107 | "=": "assign", 108 | ",": "comma", 109 | "/*": "multiline%20comment", 110 | "*/": "multiline%20comment", 111 | ".": "dot", 112 | ";": "semicolon", 113 | "+=": "add%20assign", 114 | "+": "addition", 115 | "--": "decrement", 116 | "/": "divide", 117 | "/=": "divide%20assign", 118 | "++": "increment", 119 | "-": "minus", 120 | "%": "modulo", 121 | "*": "multiply", 122 | "*=": "multiply%20assign", 123 | "-=": "subtract%20assign", 124 | "&": "bitwise%20AND", 125 | "|": "bitwise%20OR", 126 | "<<": "left%20shift", 127 | ">>": "right%20shift", 128 | "==": "equality", 129 | ">": "greater%20than", 130 | ">=": "greater%20than%20or%20equal%20to", 131 | "!=": "inequality", 132 | "<": "less%20than", 133 | "<=": "less%20than%20or%20equal%20to", 134 | "&&": "logical%20AND", 135 | "!": "logical%20NOT", 136 | "||": "logical%20OR", 137 | } 138 | 139 | def get_usage(self): 140 | return "This is the Processing kernel based on Processingjs.org." 141 | 142 | def do_execute_direct(self, code): 143 | """%%processing - run contents of cell as a Processing script""" 144 | if code.strip() == "": 145 | return 146 | 147 | # first, we make sure it compiles 148 | 149 | in_directory = tempfile.mkdtemp() 150 | out_directory = tempfile.mkdtemp() 151 | filename = os.path.basename(in_directory) + ".pde" 152 | 153 | with open(os.path.join(in_directory, filename), "w") as fp: 154 | fp.write(code) 155 | 156 | processing_java = os.environ.get("PROCESSING_JAVA", "processing-java") 157 | cmd = [processing_java, 158 | "--sketch=%s" % in_directory, 159 | "--build", "--force", 160 | "--output=%s" % out_directory] 161 | try: 162 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 163 | except: 164 | self.Error("Unable to run command:", cmd) 165 | return 166 | stdout, stderr = [str(bin, encoding="utf-8") for bin in p.communicate()] 167 | 168 | if stderr: 169 | # 'other messages here...\nSketch.pde:8:0:8:0: The field Component.y is not visible\n' 170 | # sketch name:line start: col start: line end: col end: message 171 | # empty if successful 172 | for line in stderr.split("\n"): 173 | if line.strip() == "": 174 | continue 175 | if line.startswith(filename): 176 | tempname, line_start, col_start, line_end, col_end, message = line.split(":", 5) 177 | message = message.strip() 178 | code_lines = code.split("\n") 179 | line_start = int(line_start) 180 | line_end = int(line_end) 181 | col_start = int(col_start) 182 | if line_end == line_start: 183 | line_end = line_start + 1 184 | display_start = max(0, line_start - 3) 185 | display_end = min(line_start + 3, len(code_lines)) 186 | if col_start: 187 | self.Error(" " + (" " * (col_start - 1)) + "|") 188 | self.Error(" " + (" " * (col_start - 1)) + "V") 189 | self.Error(" Line +" + ("-" * 75)) 190 | for line in range(display_start, display_end): 191 | self.Error("%5s: %s | %s" % (line + 1, "->" if (line + 1) == line_start else " ", code_lines[line])) 192 | self.Error(" +" + ("-" * 75)) 193 | self.Error("") 194 | self.Error("Compile error in line %d: %s" % (line_start, message)) 195 | #self.Print("Highlighted: %s %s %s %s" % (line_start - 2, 0, line_end - 2, 0)) 196 | self.Display(HTML(""" 197 | 200 | 201 | 213 | """ % (line_start - 2, 0, line_end - 2, 0))) 214 | else: 215 | self.Error(line) 216 | return 217 | # else: 218 | # stdout 219 | # 'Finished.\n', if successful; '' otherwise 220 | 221 | self.canvas_id += 1 222 | repr_code = repr(code) 223 | if repr_code.startswith('u'): 224 | repr_code = repr_code[1:] 225 | env = {"code": repr_code, 226 | "id": self.canvas_id} 227 | code = """ 228 |