pax_global_header00006660000000000000000000000064152651331110014510gustar00rootroot0000000000000052 comment=4d5415ac3d167d1e73892967615ff08bc1d25a68 pyx-project-pyx-21f71ce/000077500000000000000000000000001526513311100152245ustar00rootroot00000000000000pyx-project-pyx-21f71ce/.gitignore000066400000000000000000000001201526513311100172050ustar00rootroot00000000000000# Python byte code __pycache__/ *.py[cod] .python-version PyX.egg-info MANIFEST pyx-project-pyx-21f71ce/AUTHORS000066400000000000000000000002021526513311100162660ustar00rootroot00000000000000Jörg Lehmann Michael Schindler André Wobst pyx-project-pyx-21f71ce/CHANGES000066400000000000000000001475411526513311100162330ustar00rootroot000000000000000.18 (2026/10/18): - new pdffile module: - embed PDF pages in PDF output - font and text modules: - add OpenType font support (TrueType and CFF) including UnicodeEngine integration - deformer module: - Fix parallel deformer continuation at normsubpath endpoints (thanks to NicolasW1 for reporting this in issue #48) - rework the manual 0.17 (2025/11/02): - Move metadata from setup.py to pyproject.toml - graph modules: - enable log axis on negative values (either all values need to be positive or negative) - move the density parameter to the rater (with a deprecation warning in the axis) - limit subaxis range in bar and split axes to [0..1] except for epsilon=None - improve exception handling for invalid data in density style - add a new grid layer below filldata and paint axes grids there - support modification of x2, y2, etc. graph axes by keyword arguments - Cleanup of pdfwriter and pdfextras - Add support for fillattrs and trafos in UnicodeEngine - various improvements to the documentation 0.16 (2022/10/16): - graph module: - enable shortcut for passing arguments through graph components (axes, painters, etc.) by passing keyword arguments consisting of graph components separated by underscores. - graph.axis.style: - Allow invalid values (e.g. None) in color values of density style. - text module: - make alignment work with texlive 2020 (reported by Thomas Bending) - fix deprecation warning for isSet - dvi module: - ignore the l3backend header special for dvips - bitmap module: - fix bitmap palette data pdf output being bytes - canvas module: - add clear() method to canvas class (suggested by Camilo Talero) - t1 extension module: - adjust to int/Py_ssize_t change in python 3.10 (thanks to Michael J Gruber) - graph.axis.texter: - rename multiplication_tex -> multiplicationtex and multiplication_unicode -> multiplicationunicode in default texter - manual: - Remove deprecated code in colorname.py and gradientname.py (thanks to grozin for reporting this in bug #37) - the gallery has been moved away from sourceforge.net wiki to the PyX website. Contributions by pull requests are welcome. 0.15 (2019/07/14): - text module: - introduce UnicodeEngine - MultiEngineText to express combined text data for TeX based engines and the new UnicodeEngine - Text and StackedText classes for simple typesetting operations on UnicodeEngine text - rename TexRunner and LatexRunner to TexEngine and LatexEngine - rename cls argument of text.set to engine (with fallback and deprecation warning in place) - improve error handling when input cannot be encoded by texenc - add support for virtual fonts in virtual fonts - font maps: treat font files without extension as Type 1 (to prevent warnings occuring especially with Minion or Libertine fonts) - fix UnicodeDecodeError for invalid character responses by TeX/LaTeX (reported by Gert Ingold) - new examples: - non-ASCII TeX encoding - t1font: - use integers in auto-guessed font descriptors to prevent an issue in pdftex (reported by Michael Hartmann) - fix typo: ItalicAngles -> ItalicAngle (thanks to Ross Moore) - graph.axis.texter: - unify exponential and mixed texter to default texter - use MultiEngineText in all texters (decimal, default, factional) - pdfwriter, pswriter, svgwriter: - removed underscore in PS and PDF and SVG writer options strip_fonts, text_as_path, mesh_as_bitmap, mesh_as_bitmap_resolution (new: stripfonts, textaspath, meshasbitmap and meshasbitmapresolution) to prevent ambiquity with write_ prefixes. - Fix color output in SVG (reported by Michael Hartmann) - deformer: - Fix parallel deformer for empty normsubpaths (thanks to Michael J Gruber) - graph.style: - Use RGBA instead of ARGB in the bitmap fallback of graph.style.density Fix saving SVG as supported modes are limited (thanks to Michael J Gruber) - pattern: - inject default linewidth (reported by Michael J Gruber) - version control: - switched to git on 2018/07/16 with main repository on GitHub 0.14.1 (2015/11/02): - distribution: - upload to PyPI (including old releases) - remove old releases from sourceforge - text module: - fix load_def message parser (reported by Mico Filós) - normpath: - fix intersect with empty normsubpaths (bug #62, thanks to Florent Hivert) 0.14 (2015/04/30): - new svgwriter module: - complete SVG output - SVG font output disabled by default due to missing support by most browsers, fallback by rendering fonts as paths - new svgfile module: - SVG reader - unparsed mode: embedd svg in other svg - parsed mode: supports reading paths (including styles, tranformations, etc.) into a PyX canvas - bitmap module: - using bytes in image type conversions and channel extraction - color module: - fix grey class - fix rgb css binary issue and short code index error - epsfile module: - fix parsing of bounding box - text module: - no end of pages test when no dvi is created at all - add chroot config option needed to use a chrooted TeX installation - graph module: - add xy12axesat feature to graphxyz - canvas module: - fix clipping and transformation applied together - provide _repr_svg_ in canvas for use by IPython - new constructor argument ipython_bboxenlarge - deco module: - remove shortcut for ornaments only to not skip global styles 0.13 (2013/12/20): - Requires at least Python 3.2 - The gallery has been moved to https://sourceforge.net/p/pyx/gallery/, which is a wiki. Contributions are welcome. - filelocator module: - cygwin LaTeX with windows python patch (thanks to Sybren A. Stüvel) - graph styles: - fix numerical instability of line clippings - remove errorbar range checks, as they fail on a reverse axis, which is correct (reported by Néstor Espinoza) - path module: - fix internal name clash when generating a normpath from an empty path (reported by Brendon Higgins) - normpath module: - several stability and precision improvements and bugfixes - cusp removal at normpath construction (and getting rid of invalid results for curvature, rotation, tangent, and trafo methods) - remove curveradius methods as they are invalid for straigt paths - deco module: - apply text trafos to each character in curvedtext (reported by Hans L) - properly apply all textattrs in curvedtext (for example colors or scalings) - canvas module: - layer method takes layer names above or below (instead of an instance), also reorders layer accordingly when layer is already existing - remove the before and after arguments of insert - handle trafo and clip separately in constructor and write methods - allow for one clipping instance only - optimize graphics state stack usage - dvi/dvifile module: - change special handling for transformations and colors to use subcanvases - apply transformations to markers - trafos and styles are no longer canvasitems - style module: - fillrules are now fillstyles and handled within the PS/PDF context - text module: - new texenc setting - major code reorganization and documentation revision (now using autodoc) - font/afmfile module: - parse more AFM files, also some with common inconsistencies (thanks to Markus Schwienbacher for reporting these issues) - color module: - functiongradient has been split into functiongradient_rgb, etc. and the function parameters are now passed directly - lineargradient has been removed for factory functions lineargradient_rgb, etc. that provide linear gradients between colors of a particular color model - bitmap module: - fix jpegimage for progressive jpeg files (thanks to Michael Schindler) - pyxrc: - use APPDATA environment variable to locate the pyxrc on windows - tex, latex, kpsewhich, and locate executables are now customizable in the pyxrc - on the package level: - add pyxinfo to enable output of some useful information - manual: - PyX theme and various sphinx tweaks 0.12.1 (2012/10/26): - graph styles: - fix drawing and clipping of gradient style 0.12 (2012/10/17): - canvas module: - insert method now returns canvas wrapping item if attrs are given - insert method allows specification of position where item is inserted by before and after arguments - new layer method allows creation of separated drawing layers for grouping of drawing operations - writeXXXfile methods now use "page_" and "write_" prefixes for passing the keyword arguments to the page constructor and write method - pipeGS now returns a file handle instead of writing to a file or to stdout - the new method writeGSfile restores the previous pipeGS functionality - support rendering as png for use in IPython notebooks (as suggested by Nikolas Tezak) - document module: - writeXXXfile methods now support writing to stdout when filename is set to "-" - type 1 font modules: - allow font slanting for T1builtinfont instances - improve stripped font compatibility - remove UniqueID lookup from embedded fonts in PostScript output (fixes missing glyph issue with dvips and certain fonts) - allow Type1 font usage without TeX and without AFM font metric - add support for pfm font matrices - epsfile module: - fix race condition while generating bitmap for PDF inclusion - fix file opening for bbox reading when using filelocator (reported by Michael J Gruber) - filelocator module: - fix text mode line ending issue for MS Windows - text module: - fix subprocess call on MS Windows (closefds not functional not also not required at all) - fix pyxgraphics functionality because at least some versions of graphics and friends seem to expect the file extension .def for the driver files (thanks to Michael J Gruber) - deco module: - decorator to put text along a path; based on a patch by Michael J Gruber - dvifile module: - fix for MS Windows: open virtual font files in binary mode - graph modules: - graphs: - uses new canvas layers to stack graph components (fixing bug #1518414, reported by Dominic Ford) - add a flipped option to graphxy to exchange x and y coordinates - add a 1d graph "graphx" (use case: convert a value to a color) - add hiddenaxes layer to the 3d graph - add linkedaxes for the xy-plane in 3d like in 2d (works now properly due to the hiddenaxes feature) - graph styles: - add density style - add gradient style to convert a value to a color using a 1d graph - add a usenames dictionary to the pos style (like rangepos had it already) - graph data: - add a join data provide which adds concatenates several data sources - axis module: - divisor was not properly taken into account in tick handling (axis range extension and range rating) - added the metapost module: - create smooth paths from a series of points - bitmap module: - new fundamental constructor based on arbitrary affine transformations - add ASCIIHexDecode end marker - color module: - add rgbgradient and cmykgradient to force color space - mesh module: - add ASCIIHexDecode end marker - sourceforge.net: - upgrade PyX project page to the Allura platform 0.11.1 (2011/05/20): - canvas: - fix pipeGS (adding support for writing using pycompat.popen) - deco module: - arrow decorator: proper sign of constriction length for positioning reversed arrows - dvi/texfont: - fix exception type - increase designsize deviation to 4 (needs some further investigation) - contrib files: - fixes due to the dvi and font restructuring - setup.py: - fix build process for extension modules - fix download url to allow for easy_install (hopefully) - manual: - converted to sphinx 0.11 (2011/05/15): - font and dvi modules: - major reorganization - TeX mapping files are a property of the writer now By that the pdfwriter now uses pdftex.map instead of psfonts.map (It's also possible to pass a fontmap to a texrunners text method to use different mappings within a single output file) - support for font matrices (afm) for Type1 fonts (using fonts without a metrics is still supported, but properly issues a warning now) - interface for basic TeX-less text output - new PS and PDF writer options: strip_fonts, text_as_path, mesh_as_bitmap, mesh_as_bitmap_resolution - fix for commented out UniqueID - fix rounding of font sizes - fix scaling of VF position increments - new filelocator module - graph modules: - bar style on graphxyz (single datasets only) - graphxyz: - fix position of z4 axis - set correct errorname for z axis (thanks to Axel Freyn) - fix wrong y value usage instead of z value in pos methods - fix unused color range settings in surface style (thanks to Michael J Gruber) - fallbackrange for axes with vanishing range - dokeyitem method (to be called with a plotitem) to alter the key order - doplot() was renamed to doplotitem(), dodata() was renamed to doplot() to have similar naming conventions like for the graph key - axis module: do not divide by None for data.min and/or data.max being None (see patch #2833369) - axis painter: - properly rotate axis titles when ticks are not othorgonal to the axis (reported by Christian Delfosse) - correct namedirection in bar axis painter (reported by rhunger, bug #2028032) - graph.style.arrow: decorator is an parameter of the constructor now (thanks to Axel Freyn) - remove ticks with unset ticklevel and labellevel to prevent rating failures (thanks to Brendon Higgins) - canvas and document modules: - auto-guess output filename from the script filename - add ciecolor flag and input type to the pipeGS method of canvas - pyxrc: - new config options for psfontmaps and pdffontmaps - new config option for formatting of Python warnings - new config section for new filelocator module - text module: - fix two bugs in the read pipe of the texrunner (thanks to Laurence Tratt and Eric Faurot) - fix "<" token handling in mapping file parser (thanks to Matthew West) - fix start message parse error in MiKTeX (thanks to Wojciech Jaskowski) - fix rigid aux file checking (thanks to Clayton E. Myers) - use subprocess module if available - proper error messages when TeX is stopped due to unrecoverable error - style module: - implement style.fillrule - deco module: - added an explicit hatch pattern as an alternative for real postscript patterns - arrow decorator: take into account constriction length when arrow pos < 1 - bitmap module: - add support for transparent bitmaps (in postscript stencil masking only) - path and normpath modules: - remove incorrect zero length line in PDF output for each first moveto path element (thanks to Michael J Gruber) - raise correct normpath exception (thanks to Axel Freyn) - epsfile module: - an ugly way to import EPS in PDF using a bitmap (requires PIL) 0.10 (2007/10/03): - graph modules: - graph module: - graphxyz for 3d graphs with parallel and central projection - doplot method (to be called with a plotitem) to alter the plotitem order etc. - graph styles: - new surface style for 3d graphs (colored surfaces are functional (and useful!) for 2d graphs as well) - new grid style for 3d graphs - new impulses style - optional textdx/textdy columns to the text style added - arrowpos parameter to the arrow style added - bugfix: fromvalue axis range adjustment in histogram style - bugfix: axis range adjustment in range style - axis module: - painter: don't insert axis title twice (thanks to Tim Gray for reporting this problem) - parter: extend the logarithmic parter to calculate automatic partitions for huge ranges (TODO: documentation of the new autoexponent parameter) (suggested by Dominic Ford) - fix: range rating was not taken into account due in the 0.9 release - data module: - list class was renamed to points; deprecation warning added for instance creation, but inheritance from list failes - new values class - new mesh module: - internal helper module for efficient handling of triangular colored meshs - color module: - renamed: palette->gradient, functionpalette->functiongradient, linearpalette->lineargradient - new class palette representing a discrete ordered list of colors - support transparency for filling/stroking in pdf separately - transparency support for postscript as available by means of a proprietary ghostscript extension (for ps2pdf) - renamed method: tostring8bit -> to8bitstring (bug #2932888) - attr module: - add multichangeattr to perform a select on different changeable attributes depending on the selects total number - font modules: - t1font: - add missing glyph traversal in t1seacs updatepath - normpath module: - support zero-length normsubpaths - canvas module: - don't change order of attrs passed to canvas constructor in place - added __truediv__ methods according to PEP 238 0.9 (2006/05/24): - most important changes (to be included in the release notes): - mathtree removal (warning about integer division) - barpos style does not build tuples for nestedbar axes automatically - new deformers for path manipulation (for smoothing, shifting, ... paths) - font modules: - new framework for font handling - own implementation of type1 font stripping (old pdftex code fragments removed) - complete type1 font command representation and glyph path extraction from font programs - t1code extension module (C version of de-/encoding routines used in Type 1 font files) - AFM file parser - graph modules: - data module: - mathtree removal: more flexibility due to true python expressions - default style instantiation bug (reported by Gregory Novak) - style module: - automatic subaxis tuple creation removed in barpos (create tuples in expressions now; subnames argument removed since it became pointless; adujstaxis became independend from selectstyle for all styles now) - remove multiple painting of frompath in histogram and barpos styles - fix missing attribute select when using a bar style once only (reported by Alan Isaac) - fix histograms for negative y-coordinates (reported by Dominic Ford, bug #1492548) - fix histogram to stroke lines to the baseline for steps=0 when two subsequent values are equal - add key method for histogram style (reported by Hagemann, bug #1371554) - implement a changebar style - graph, axis and style module: - support for mutual linking of axes between graphs - new domethods dependency handling - separate axis range calculation from dolayout - axis.parter module: - linear and logarthmic partitioners always need lists now (as it was documented all the time; renamed tickdist/labeldist to tickdists/labeldists; renamed tickpos/labelpos to tickpreexps/labelpreexps) - axis module: - patch to tickpos and vtickpos (reported by Wojciech Smigaj, cf. patch #1286112) - anchoredpathaxis added (suggested by Wojciech Smigaj) - properly handle range rating on inversed axis (reported by Dominic Ford, cf. bug #1461513) - invalidate axis partitions with a single label only by the distance rater - fallback (with warning) to linear partitioner on a small logarithmics scale - painter module: - patch to allow for tickattrs=None (reported by Wojciech Smigaj, cf. patch #1286116) - color module: - transparency support (PDF only) - conversion between colorspaces - nonlinear palettes added - the former palette must now be initialized as linearpalette - remove min and max arguments of palettes - text module: - improve escapestring to handle all ascii characters - correct vshift when text size is modified by a text.size instance - recover from exceptions (reported by Alan Isaac) - handle missing italic angle information in tfm for pdf output (reported by Brett Calcott) - allow for .def and .fd files in texmessage.loaddef (new name for texmessage.loadfd, which was restricted to .fd files) - path module: - correct closepath (do not invalidate currentpoint but set it to the beginning of the current subpath); structural rework of pathitems - calculate real bboxes for Bezier curves - fix intersection due to non-linear parametrization of bezier curves - add rotate methods to path, normpath, normsubpath, and normsubpathitems - add flushskippedline to normsubpath - add arclentoparam to normsubpath and normsubpathitems - path is no longer a canvasitem - reduce number of parameters of outputPS/outputPDF methods (do not pass context and registry) - normpath module: - contains normpath, normsubpath and normpathparam which have originally been in the path module - return "invalid" for certain path operations when the curve "speed" is below a certain threshold - normpath is no longer a canvasitem - reduce number of parameters of outputPS/outputPDF methods (do not pass context and registry) - deformer module: - rewritten smoothed to make use of the subnormpath facilities - rewritten parallel for arbitrary paths - deco module: - add basic text decorator - allow arrows at arbitrary positions along the path - connector module: - boxdists parameter need to be a list/tuple of two items now - changed the orientation of the angle parameters - trafo module: - renamed _apply to apply_pt - introduce _epsilon for checking the singularity of a trafo - epsfile module: - use rectclip instead of clip to remove the clipping path from the PostScript stack, which otherwise might create strange effects for certain PostScript files (reported by Gert Ingold) - dvifile module: - silently ignore TrueType fonts in font mapping files (reported by Gabriel Vasseur) - type1font module: - accept [ and ] as separators in encoding files (reported by Mojca Miklavec, cf. bug #1429524) - canvas module: - remove registerPS/registerPDF in favour of registering resourcing during the outputPS/outputPDF run - move bbox handling to registry - rename outputPS/outputPDF -> processPS/processPDF - remove set method of canvas - add a pipeGS method to directly pass the PyX output to ghostscript - allow file instances as parameter of the writeXXXfile methods (feature request #1419658 by Jason Pratt) - document modules: - allow file instances as parameter of the writeXXXfile methods (feature request #1419658 by Jason Pratt) - style module: - make rellength the default for dash styles - random notes: - switched to subversion on 2006/03/09 0.8.1 (2005/08/13): - deco module: - fix bug in postscript deco code for stroking only attributes - path module: - fix multicurveto._normalized - fix path.paramtoarclen and path.paramtoarclen_pt - remove unused method-local function - fix linestyle rellength in PostScript - correction to the rounding problems in circles (reported by Uwe Fabricius) - epsfile module: - fix a typo - pattern module: - issue a warning when not using a stroke color for patterns - text module: - postpone PDFfontdescriptor information, since it raises an error on certain fonts even when PostScript output was requested (reported by Gert Ingold) - remove spurious spaces when checking for empty texmessages - kpathsea module: - caching in fallback to lower system call bottleneck - canvas module: - add missing writePSfile wrapper - add *args to writeEPSfile and writePDFfile wrappers - writer modules: - writebbox option to write bbox information (disabled by default) even when a paper format is specified (PS and PDF writers only) - use arclen in spring example - add knot example - use pdf graphic files for pdf version of the manual - use PyX to create tipa fallbacks for FAQ - correct description regarding the manual in the README file 0.8 (2005/07/13): - changed requirements to python 2.1 or newer: - nested scopes are needed without fallback solution by the path module (at other places fallback solutions for missing nested scopes are missing as well) - use warning module for warnings - path module: - path parameters and argument handling - the arct to arc/arcn conversion (needed for bbox calculation and for conversion into normpath) has been fixed - document module: new - container classes for document and pages - document.paperformat class (strings are deprecated) - canvas module: - writeEPSfile wraps a canvas in a single page document and performs the output - bbox module: - add _pt methods - pdfwriter module: - completely rewritten: support for fonts and patterns has been added - pswriter module: new - separate PS output from canvas - new signature of outputPS methods: writer and context are passed as additional arguments - color module: - allow selection on zero range palette (reported by Francisco Borges, cf. bug #1116257) - prolog module: removed due to code reorganisation - graph modules: - modifications on __init__.py in graph and axis subdirectories to make "from pyx.graph import *" working as expected - graph styles: - addontop added to stackedbarpos - column -> columnname renaming where appropriate - histogram style added - graph data: - function needs explicit variable definition (implicit variable definition is deprecated) - column names are inherited by data.data() except when copy=0; unused columns are silently ignored now - dynamic function data on a logarithmic axis uses isinstance check now (although it removes the only (mis)use of axis.inverse, it is a temporary solution only) - graph key: - extend graph keys to allow for several columns - axis data handling refactoring: - introcuded an axis positioner (module graph.axis.positioner) - introduced anchoredaxis to make axis data and positioning local to a graph - linkedaxis is a special version of anchoredaxis and is generic (it uses the new linkpainter provided by an axis) - unification of split and bar axes; removed some black magic in baraxis in favor of a nestedbar axis - x linked to x2 etc. is now possible - axis.inverse was removed (the only place it was (mis)used was by a function) - graphxy: - allow to transform axis after layout - [xy]axisat arguments in the constructor to easily move [xy]-axes to a position defined the orthogonal axis - remove axispos (use the axis dictionary now, since it now contains anchored axis instances and those have shortcuts for the axis positioner methods) - dvifile: - tfm->dvi conversion rounding bugfix - fix parsing of empty strings ("") in fontmap files (reported by John Owens, bug #1218983) - text module: - support for halign of boxes and content of boxes (see halign example) - take units xscale into account in parbox - messageparser for replaced fontsizes: Warning -> implemented by texmessage.fontwarning - messageparser for size differences at the end: Warning not Exception -> implemented by texmessage.fontwarning - messageparser for overfull/underfull vbox/hbox: Warning not Exception -> implemented by texmessage.boxwarning - dvicopy flag removed - allow argument of set to be None - rename nomathmode and nophantom to clearmathmode and clearphantom - texmessagepattern for easy creation of simple TeX message parsers - allow long file names in file checking TeX message parsers - no newline removal to not disturbe TeX messages when reporting errors - reworked documentation to use the python documentation standards - style module: - linewidth is no longer a unit.length subclass but expects a such as first argument - epsfile module: - correct EOL handling while reading DSC's (reported by Markus Meyer) - pattern module: new - moved canvas.pattern to its own module together with the new PDFpattern class - add some default patterns: hatched and crosshatched - deformer module: - improve the smoothing deformer - add a parallel deformer - tex module: - the very old tex module finally got removed completely - contrib directory: - a simple converter from dvi to EPS/PS/PDF files (dviconvert.py) has been added - a simple imagine to EPS/PS/PDF converter (imgconvert.py) has been added - a simple dvitype.py has been added - update address of FSF all over the place 0.7.1 (2004/12/15): - canvas module: - EPS header fixed (reported by Russell Lang, cf. bug #1065099) - Makefile fixes: - use CURDIR instead of PWD (reported by David M. Cooke, bug #1070285) - pykpathsea module: - support windows line endings (patch by Hans-Andreas Engel, cf. bug #1071160) - graph modules: - line attributes handling fixed (reported by Andrea Riciputi) - fix typos in predefined symbols (reported by Andrea Riciputi) - cut column name list at the max. number of columns (reported by Arnd Baecker) - examples: - add INDEX and README files to distribution - new errorbar and julia example - faq: - pdf snippets for tipa based phonetic transliterations 0.7 (2004/10/21): - bitmap module: - new module for inclusion of bitmap images - path module: - names of local and member variables now follow the naming convention of having a _pt suffix when containing lengths in points - bbox module: - names of local and member variables now follow the naming convention of having a _pt suffix when containing lengths in points - enlarge was misspelled as enlarged - renamed _bbox -> bbox_pt - new bbox method center, which returns the coordinates of the center of the bbox - enlarge and enlarged do no longer interprete unqualified lengths as being of type visual - unit module: - unit.cm, unit.t_cm, etc. are no longer sub classes but instances of length - never convert implicitly into visual/width, etc. lengths (this is more about usage of the unit module in various other modules) (TODO: update documentation) - support for string initialization removed - support for initialisation with other length removed - lengths can now be divided by other lengths (as suggested by Michael Gruber and Magnus Lie Hetland) - text module: - postpone reading of fontmap files until TeX/LaTeX is started - sign of font number in dvifile (reported by Michael Gruber) - phantom attribute - canvas module: - added new classes page and document for multipage PostScript output - apply deformers (instead of trafos) in draw method - style module: - decrease interval for dotted and dash-dotted lines for better visual appearance - setup.py and distribution: - create siteconfig on install to store positions of the shared data and the global pyxrc - graph modules: - graph style + data reorganization - modularization of the graph styles by separating data handling and drawing tasks - several graph styles can now be combined together - graph data can internally now combine different data sources (by that, some nasty side effects could have been removed) - enum -> num renaming - allow for horizontally and vertically centered graph key alignment and a key background - fix bug that graph was not finished automatically when a bbox was specified manually (reported by David Barton) - path module: - pathel -> pathitem, etc. renaming - methods accepting a parameter value / arc length now also allow the user to pass a tuple (subpath, param) / (subpath, arclen) - normpath constructor no longer accepts a path or normpath as argument but only a list of normsubpaths. Use the new normpath method of the path instead to construct a normpath from a path. - normsubpath can now deal with short (i.e. shorter than epsilon) segments correctly - the intersect and split methods of normpath and normsubpath have been completely rewritten and now take the accuracy epsilon correctly into account. Note that for a closed subpath the split function now returns the segment containing the closing point as first element in the result list (before, it was returned as last element). - normsubpathitems and normsubpath now implement much more methods also provided by path and normpath instances - normpath.append no longer accepts pathitems but only normsubpaths - deformer module: new - moved cycloid and smoothed from deco into deformer - bbox module: - handle "BoundingBox: (atend)" (cf. bug #945621 reported by Jim Boyle) - kpsearch option to search for file using the kpathsea library (contributed by Michael Gruber) - base module: - PSCmd and PSOp are now joined in a new class canvasitem - deco module: - decorated path no longer allows modification of its path - new method excluderange which allows to remove certain parameter ranges from the stroked path - additional canvas provided by decorated path is now called ornaments - constriction=None now indicates an arrowhead without constriction - trafo module: - trafos are now deformers - examples: - a bunch of bargraph examples have been added 0.6.x (????/??/??): - graph/axis module: - fix errorbar range adjustment - fix empty tick lists bug (reported by Marko Vendelin, cf. bug #977323) - graph/style module: - symbolline drawing order in graph key (cf. bug #990687) - graph/data module: - access to builtin list (reported by Marcus Mendenhall, cf. bug #1042458) 0.6.3 (2004/04/27): - graph module: - fix drawing with background - fix insertion of a zero length path when the whole line is outside the valid axis range (reported by Marko Vendelin) - distribution: - include source for faq and manual - distribute the pdf instead of postscript (manual, faq, examples) 0.6.2 (2004/04/07): - graph module: - fixed title=None + graph key issue reported by Gabriel Vasseur - graph.axis.painter.plain -> graph.axis.painter.regular (as it was in parts of the documentation already) - changeable-gridattrs-become-None-bug fixed - graph style cutting outside lines (double-)fixed 0.6.1 (2004/03/31): - fixes missing install of the graph and axis directories introduced in 0.6 - some minor updates to the faq 0.6 (2004/03/30): - graph module: - reorganisation of the graph structure finished (there might be some small pending issues, but the basic restructuring is done with this release): - graph split into several modules in pyx/graph and pyx/graph/axis - painters are using the new attribute scheme including changeable attributes - graph styles rewrite - graph data rewrite - axis zeropath feature has been removed - mergelabels removed; linpart doesn't have a label argument anymore - names and texts removed from baraxis - iteration on graph style, when it is used several times in the same graph - symbols + lines -> symbollines; symbols do not allow setting lineattrs, and lines not symbolattrs - manual line clipping (do not include unneeded line segments when the axis range is set manually etc.) - automatic file key titles - graph.data now also includes the old data module - data.list adds (by default) a line number like data.file (thus regular columns are counted from 1) - path: - added new pathels multilineto_pt and multicurveto which allows to specify a list of points and can thus be much more efficient - internal methods return coordinates in pts - arclentoparam returns only parameters not total length - added path.arclength_pt, path.at_pt, path.begin_pt, path.end_pt (and correspondingly for normpath) - complete refactoring of the normpath class: normpaths now consist of normsubpaths which themselves consist of normlines and normcurves This is much more convenient for any routines working with normpaths. - reversing of closed sub paths does not change the first point of the sub path - renamed: arclength -> arclen - renamed: lentopar -> arclentoparam - renamed: glue -> joined - normpath now supports join, the in-place version of joined - path and normpath method raise exception instead of returning None when parameter is out of range - the accuracy epsilon can now only be specified in normpath and normsubpath constructor and no longer in arguments of path and normpath methods - negative parameters are no longer supported in path and normpath methods - path and normpath methods which accept parameter value param now alternatively accept an arc length - deco module: - cycloid decorator - smoothed decorator - arrow heads are no longer stroked (as suggested by Magnus Lie Hetland) - canvas: - writeEPSfile deprecates writetofile - internally, write methods are renamed in outputPS - canvas constructor no longer accepts variable argument list but expects a list of attrs as first argument (defaulting to []) and a texrunner as second argument (defaulting to text.defaulttexrunner) - set, draw, stroke and fill no longer return self, i.e., the canvas, but None - bbox module: - added inplace add (__iadd__), enlarge and transform methods - callers use inplace add where possible now (yielding a considerable speedup) - "undefined" corners of bounding boxes are no longer supported which makes the bounding box operations much more efficient. - connnector module: - renamed _xxx -> xxx_pt - epsfile module: - removed showbbox argument of epsfile class - text module: - default handling of texmessages as in the new attribute scheme - multiple insert bug fixed - made left, right, width, height, depth information available (x length not taking into account box transformations) - ignore tex message "Please type a command or say `\\end'" - added textboxes that are sequentially filled (experimental) - examples: - mandel.py (contributed by Stephen Phillips) - unit module: - length comparision (David Beach) - x-scale for TeX - more unit tests - mathtree module: - switched to the new parser using pythons parser module - data module: - removed, it all lives in the graph.data module now, while before it was split into two separate modules - tex module: - not imported by default anymore - obsolete warning when importing this module 0.5.1 (2004/01/22): - distribution: - include missing c-files for optional extension modules - prolog module: - fix unpaired BeginProcSet/EndProcSet in font enconding 0.5 (2004/01/20): - setup.py and distribution: - allow customization of the extension modules built (via setup.cfg) - disable building pykpathsea module by default - more detailed description of install process in INSTALL - provide more information and pointers to other files in README - include example data files in distribution (suggested by Andrea Riciputi) - force dvips to write ps files instead of printing them (suggested by Otto Tronarp) - includ pyxfaq.pdf in distribution - text module: - improved is-readable test for lfs files and pyx.def file - explicitly quit (La)TeX in cleantmp (helps when quitting with C) - showwaitfortex implemented following a suggestion by Fernando Perez (waitfortex is increased to 60 seconds now) - support of TeX extension --ipc for reading dvi results while TeX keeps running - configurable font mapping files (via pyxrc or parameter of the texrunner constructor) - markers to get access to positions within TeX expressions - fix: allow for e-tex in texmessage.start (reported by Andrea Riciputi) - fix: print warning at syntax errors in font mapping file and continue (cf. bug #795271) - remove limitation on number of fonts in dvi file - added native virtual font support - dvicopy support not needed anymore (it is still available, but obsolete and removed from the documentation) - do not include too many glyphs in the eps file - _xxx -> xxx_pt renaming - dvifile module (NEW): - separated from the text module - dvifile class returns standard pyx canvas instances on readpage - graph module: - removed manualpart and partitioners mix keyword - results of the splitting at "=" in graph.function were not stripped - skip title=None in key (cf. bug #821284), properly align a single key entry - another (the last?!) axis redesign: axispos -> class of its own - some axispos name have changed slightly (zeroline -> zeropath etc.) - tick/data-vmin/vmax removed - pathaxis - linkaxis - minor enhancements in exponentionaltexter - axes alongs paths including a set of examples - mixing a partitioner and manual ticks by two distinct keyword arguments now - _xxx -> xxx_pt renaming - part -> parter renaming - canvas module: - stroke, fill, draw, set and insert do no longer accept variable length argument lists but an attribute list as last argument - stroke and fill now support trafos (TODO: documentation) - uppercase version of a4, a3, ... paperformats - config module: - new module for loading PyX configuration information - pyx module: - automatically import main modules into pyx namespace as suggested by Fernando Perez. - path module: - check for sorting of parameter list passed to path.split method - _xxx -> xxx_pt renaming - deco module (NEW): - contains decoratedpath and decorators from canvas module - all predefined decorators are instances now (deco.stroked is thus ok) and attributes have to be passed explicitely, e.g., deco.earrow.small(attrs=color.rgb.red) and deco.stroked([color.rgb.blue]) - style module (NEW): - contains all line- and fillstyles which formerly had been defined in the canvas module - dash now supports relative dash lengths (as suggested by Otto Tronarp) - mathtree module: - fixed incorrect handling of - (for instance -x**2 was not negative) - attrlist module: - contents have been moved to the (obsolete) tex module, which was the only user anyhow, and the module itself was removed - t1strip module: - new fallback solution in pure python - bugfix: pyxadapt.h needs to open files binary under Windows (reported by Gary Pajer) - box module: - _xxx -> xxx_pt renaming - trafo module: - _xxx -> xxx_pt renaming 0.4.1 (2003/09/17): - canvas module: - "in" to "inch" in paperformats - text module: - fix pyx.def hack occuring whenever \ProcessOptions* was used by a package - pykpathsea module: - implement different file formats for Python version of module - t1strip module: - python fallback solution should behave the same way as c extension module (closes SF bug #799182 reported by Marcus Mendenhall) - __init__.py: - added "connector" to __all__ 0.4 (2003/08/22): - graph module: - separate texter out of the axispainter - axis/partitioner/texter/painter/axispos redesign & interfaces - tick.text is renamed to tick.label - ticks and labels are renamed to tickpos/tickdist and labelpos/labeldist in partitioning - ticks can be used in the part to mix a partitioner with some manual ticks -> manualpart and the mix technique is not needed anymore (both things are still available and working, but they will be removed in the future) - _ensurefrac is implemented inside the frac constructor now; initialization is possible by: - a (enum, denom) tuple now (previously there were two arguments) - a string (as before via _ensurefrac) - exponential strings are allowed as well (e.g. "1e10" etc.) - a float (precision is determined by floatprecision -- the number of decimal places) - dense -> density - axis.maxworse - axis interface - text module: - reset() method for the texrunner - automatic restart of a TeX instance with the same preamble (preamble changes are not possible) - texmessage.loadfd for accepting font description loading - don't bail out on width_index == 0, but mark character invalid instead - dvicopy flag - support for specials; pyxgraphics flag - support psfonts.map: font names, font encodings - bugfix \def\ProcessPyXBox -> \long\def\ProcessPyXBox - improved lfs handling - data module: - full documentation via doc strings - connector module: - some preliminary version - box module: - multiple radii (up to two per point) and softnesses - ensurecenter added --- do we always force the creation of a center? - path module: - lentopar methods added including some tests - epsfile module: - new parameter bbox allows to override the bounding box of the eps file bugfixes: - text module: - derive TFMError and DVIError correctly from exceptions.Exception - close files and pipes, if they are no longer used (thanks to Marcus Mendenhall) - remove DeprecationWarning in Python 2.3 (thanks to Marcus Mendenhall) - box module: - correct rounding algorithm (Michael Schindler) - graph module: - refer to the graphs texrunner instead of the defaulttexrunner (cf. #728209) - rounding towards zero bugfix in autolinpart - log axis range rating bugfix - mathtree module: - addarg bugs (#738724) - epsfile module: - fix mixing up of height and width in scale calculation - and various other fixer here and there 0.3.1 (2003/04/04): - text module: - fix bug in dvi rule code where width was height - fix preamble attribute checking bug - fix texmessage.load pattern search instead of pattern match bug - renamed vbox to parbox (was done in 0.3 partially only) - data module: - allow for tuples in arguments of the data class - convenience: exchanged order of named parameters in data.data - graph module: - convenience: allow for part=None in _axis (base of linaxis and logaxis) - examples: - added a latex example (requested) - added a attributechange example (requested) - added back the integral example (requested; prior PyX 0.3 it was part of the user manual) - small change in vector example (allow for the access to the texrunner) - examples included in source distribution - canvas module: - correct arrow template calculation for very short paths 0.3 (2003/03/31): - examples - new easy to use example generation (will hopefully lead to nice examples) - unit box: - new module for handling of convex polygons (taken out of the graph module) - unit helper: - new module containing a collection of helper functions (taken out of the graph module) - moved the attrlist into helper -- as plain functions; attrlist becomes obsolete - text module: - new module: a new and preferable integration of TeX/LaTeX - t1strip module: - strip glyphs from pfa/pfb-fonts - there is a C implementation taken from pdftex - fallback solution via an external program (pfb2pfa) - pykpathsea module: - (partial) C binding to libkpathsea - fallback solution via an external program (kpsewhich) - graph module: - removed some code duplication (various axis painters) - use text module instead of the obsolete tex module - allow for tailing zeros of automatic generated labels - allow for missing data in bar graphs -> skipmissing parameter - remove the support for variables given as keyword arguments in data constructor - use context instead of extern for extern variables and functions - graph keys; titles in data/function/etc. - unit module: - new classes for visual and width lengths, aliases for user length (u_pt = pt) - all length classes have now by default a quantifier 1 (instead of 0), such that, for instance, 5*unit.t_cm() == unit.t_cm(5) - default_unit now has to be set via unit.set. For instance: unit.set(defaultunit="m"). - convert_to is now an internal function, which moreover does not longer accept tuples or lists - bbox module: - new class _bbox (the former bbox) which accepts points in the constructor. This is used for internal purposes. - the bbox constructor now accepts user lengths in the constructor. - new methods height, width, top, bottom, left, right - ll & ur ???, what about ul and lr -> ugly! - enlarge (was enhance) now allows selective enlargement to the left, bottom, right and top - output HiResBoundingBox - never reduce bbox upon output - epsfile module: - new constructor signature, more in line with rest of PyX: epsfile(x, y, filename, **additional_args) - data module: - removed additional column support in addcolumn; removed _addcolumn - line reduction for datafile like the every parameter in gnuplot - canvas module: - new way of PS prolog generation that writes only necessary parts - added support for patterns - canvas.insert() now supports arguments - bbox of canvas can be specified in writetofile command explicitely - writetofile does not return self anymore - arrow template now uses intersection with circle to get size right (as per a suggestion by Michael Schindler) - mathtree module: - added abs function - changed the handling of extern functions and all variables - color module: - gradient renamed to palette - numerous bugfixes: - problem with sizefile on windows (tex module) - allow for strings in graphxy's width and height; allow for width only (graph module) - disable rating for labelattrs equals None (graph module) - defaultstyle selection, when a list of data is provided to the plot function (graph module) - traverse when adding functions as arguments of operators (mathtree module) - allow for extern functions in addcolumn (data module) - just one common place for the version number - fix incorrect exception name MathError (path module) - prevent double return of intersections for closed sub paths - ... 0.2 (2003/01/17): - unit module: - allow division of length by numbers - trafo module: - new transformation: slant - renamed all trafo methods to use the participle (i.e translate->translated) - the name of all trafo subclasses are verbs (i.e. translation->translate) - graph module: - mark class renamed to symbol - (text-)box distance measurement - moved axis partitioning to axis and axis painter - automatic axis partitioning (now officially: general cleanup, distance measurement, documentation) - splitaxis - baraxis, baraxispainter, and bar style - data module: - previously named datafile module - class "_datafile" renamed to class "data" - class sectionfile added - testsuite - mathtree module: - extern variables and functions (support in graph.function, graph.paramfunction and data.data) - testsuite - text module: - deferred to Version 0.3 - running TeX "on the fly" is basically implemented - numerous bugfixes: - transformation bug (#624068, trafo module) - canvas transformations (canvas module???) - textbox alignment (graph module) - return linewidth upon calculation with linewidths (unit module) - allow column number variables with several digits - ... - british and american spellings (color module, graph module) - small logo modifications 0.1 (2002/10/07): - initial release pyx-project-pyx-21f71ce/INSTALL.md000066400000000000000000000052061526513311100166570ustar00rootroot00000000000000Installation ============ Prerequisites ------------- PyX requires Python 3.2 or newer and a TeX installation (including Type1 fonts). Try to start 'python', 'tex' and 'kpsewhich cmr10.pfb' (the latter should issue a full path of the requested Type1 font). Installation procedure ---------------------- PyX can be installed via pip straightforwardly. It can be run as an zipped egg. As PyX is hosted on PyPI, it can be directly downloaded and installed by pip: pip install pyx For debugging, you can call the pyxinfo() method immediately after the import to get some details written to stderr. Local usage without C extension modules --------------------------------------- PyX can be run without any installation. To test your environment copy the file hello.py from the examples directory to the main pyx directory (where the subdirectory pyx containing the modules is located) and type 'python hello.py'. Installation procedure ---------------------- The installation of PyX is pretty straightforward if you have installed the Python distutils package. First, you have to decide which C extension modules you want to build. This can be done by setting the respective flags in the setup.cfg config file. By default no C extension modules are built and appropriate fallbacks will be used instead. The build_t1code option enables building of an extension module, which enables faster coding/decoding of Type 1 fonts. The only requisites for building this module are the Python header files and a C compiler. Note that the C compiler has to suit the Python distribution you are using. The second extension module pykpathsea provides Python binding for the kpathsea library, which enables fast searching for files in the TeX/LaTeX directory hierarchy. You will need the header files of this library, which unfortunately are not included in many standard TeX distributions. Note that the fallback, which uses the kpsewhich program, works equally well, although it is not as efficient as using the library directly. If you want to build the C extension module, you may also have to specify the location of the kpathsea header files and of the library itself in the setup.cfg file. After you have adapted the setup.cfg file to your needs, you can either build the extension modules locally by running python setup.py build_ext -i or install PyX system wide by using python setup.py install or an appropriate variant thereof. Development version ------------------- For development checkout the PyX repo from github: git clone https://github.com/pyx-project/pyx To prepare the develpment environment create a virtual env and run pip install -e .[dev] pyx-project-pyx-21f71ce/LICENSE000066400000000000000000000354511526513311100162410ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS pyx-project-pyx-21f71ce/MANIFEST.in000066400000000000000000000006771526513311100167740ustar00rootroot00000000000000include AUTHORS CHANGES INSTALL.md LICENSE README.md pyxrc setup.cfg setup.py include manual/Makefile manual/pyx.sty manual/*.rst manual/*.py manual/*.dat recursive-include manual/theme * include faq/Makefile faq/conf.py faq/*.rst recursive-include pyx *.c *.py recursive-include pyx/data * recursive-include contrib *.py *.cfg *.tex recursive-include examples README *.py *.dat *.jpg *.txt recursive-include gallery README *.py *.dat *.jpg *.txt pyx-project-pyx-21f71ce/Makefile000066400000000000000000000004421526513311100166640ustar00rootroot00000000000000all: cd test;$(MAKE) cd examples;$(MAKE) cd gallery;$(MAKE) cd manual;$(MAKE) cd faq;$(MAKE) cd www/png;$(MAKE) cd www;$(MAKE) clean: cd examples;$(MAKE) clean cd gallery;$(MAKE) clean cd manual;$(MAKE) clean cd faq;$(MAKE) clean cd www/png;$(MAKE) clean cd www;$(MAKE) clean pyx-project-pyx-21f71ce/README.md000066400000000000000000000026161526513311100165100ustar00rootroot00000000000000PyX - Python graphics package ============================= PyX is a Python package for the creation of PostScript and PDF files. It combines an abstraction of the PostScript drawing model with a TeX/LaTeX interface. Complex tasks like 2d and 3d plots in publication-ready quality are built out of these primitives. Installation ------------ The installation of PyX is described in the file INSTALL. Documentation ------------- A prebuilt version of the manual can be found on the PyX webpage under https://pyx-project.org/manual.pdf. For answers to frequently asked questions, we refer to https://pyx-project.org/pyxfaq.pdf. We also recommend taking a look on the nice examples for the use of PyX, which can be found in the examples directory. License ------- PyX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. PyX is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PyX; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA pyx-project-pyx-21f71ce/TODO000066400000000000000000000075621526513311100157260ustar00rootroot00000000000000Code: - text module: - repair PDF generation with unincluded standard fonts (currently broken) - change DSC in PS fonts: Resource instead of Font (also in pswriter) - SlantFont & Co support - discuss reltransform: https://sourceforge.net/mailarchive/forum.php?thread_id=9137692&forum_id=23700 - add encoding; check whether encoding=ascii works well for the common existing cases - write graphics driver for pgf.sty from LaTeX - ignore "(Please type a command or say `\end')" in preamble method - properly handle file names with spaces in (like "C:\program files\texmf\tex\latex\base\article.cls" in texmessage.load - graph.graph module - common bboxes for different graphs - circular graphs - axis painter labelattrs=None + automatic axis partitioning leads to no valid partitioning - when all titles are None, a graph key currently raises an exception - translatecanvas should be the default in graph.style.symbol - automatic scaling of y-axis according to subset of data shown on x-axis - graph.axis.timeaxis.timetick must not override datetime.datetime __init__ method (since datetime.datetime instances are immutable like ints) - graph.style and graph.data modules - fix docu of gridattrs functionality of axis painters (how can one, e.g. draw a grid at the ticks and not at the subticks) - make graph.style.symbol.diamond a graph.style.symbol instance (to be discussed) - histogram style should be comptatible with numpy.histogram - graph.data module: - use csv module (new in 2.3) - Check for "inf" and "nan" in datafiles. (When plotted, the graph does not complain, but the output will be broken; this depends on the plattform and is not only an issue within the graph system) - graph.style module: - add styles using curves instead of lines - rework graph.style.arrow: size argument should be called length and arrowsize should be able to be controlled separately. one might also want to color-code the arrows - graph.texter module: - rename period argument of decimal texters to recurring_decimal or something similar (as pointed out by Tim Head) - canvas module: - stroking of patterns does not work in PDF - style and color module: - support modification of existing styles via __call__ - bitmap module: - ReusableStreamDecode? - proper ASCII85Decode/HexDecode switch - deformer module: - move helper path routines to some more generic place for paths? - pdffile module needed (similar to epsfile) - open discussion: - clearly distingish between readers and writers. dvifile, epsfile, etc. might be renamed to dvireader, epsreader ... - support gsave and grestore in some way to make context handling easier? - ps/pdfwriters: - support colorspace argument (like c.writeEPSfile("bla", colorspace="cmyk")) - move pyx.def, lfs-files etc. into a new share directory - write fakepattern.py which substitutes some of the pattern functionality using re-usable canvases - libkpathsea bindung: - create a ctypes based binding to replace the extension module implementation in the long Documentation: - path module: - describe + vs << vs join - more details in path constructor: allowed pathels, first pathel... - set method - pattern module: - check and update - graphics section: Changeable attributes should be explained at a central place. - box module: - linealign and circlealign - need to be redone anyway - graph module: styles: document what data name the styles accept (require). Try also to be more userfriendly and not to describe immediately the internals of the implementation: (see e.g. class.style.symbol) - document interface to access tick positions Examples: - add an epsfile example (suggested by Stathis Sideris) - add a small example line on y="f($1)" in one of the plot examples FAQ: - describe creation and modification (inplace and ``modify by new'') of graph data pyx-project-pyx-21f71ce/contrib/000077500000000000000000000000001526513311100166645ustar00rootroot00000000000000pyx-project-pyx-21f71ce/contrib/color.cfg000066400000000000000000000001221526513311100204560ustar00rootroot00000000000000\DeclareOption{pyx}{\def\Gin@driver{pyx.def} \def\c@lor@namefile{dvipsnam.def}} pyx-project-pyx-21f71ce/contrib/dviconvert.py000066400000000000000000000044771526513311100214350ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # # # Copyright (C) 2005-2011 André Wobst # # dviconvert is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # epstopng is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with epstopng; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from optparse import OptionParser from pyx import * from pyx import bbox, version from pyx.dvi import dvifile parser = OptionParser(usage="usage: %prog [-b] [-p paperformat] -o output-file dvi-file", version="%prog " + version.version) parser.add_option("-o", "--output", type="string", dest="output", help="output-file") parser.add_option("-p", "--paperformat", type="string", dest="paperformat", default=None, help="optional paper format string") parser.add_option("-b", "--writebbox", action="store_true", dest="writebbox", default=0, help="Add bouding box information on PS and PDF when a paperformat is defined") (options, args) = parser.parse_args() if len(args) != 1: parser.error("can process a single dvi-file only") if options.paperformat: options.paperformat = getattr(document.paperformat, options.paperformat) df = dvifile.DVIfile(args[0]) d = document.document() while 1: dvipage = df.readpage() if not dvipage: break if options.paperformat: aligntrafo = trafo.translate(unit.t_inch, -unit.t_inch + options.paperformat.height) aligneddvipage = canvas.canvas([aligntrafo]) aligneddvipage.insert(dvipage) p = document.page(aligneddvipage, paperformat=options.paperformat, centered=0) else: p = document.page(dvipage) d.append(p) if options.writebbox: d.writetofile(options.output) else: d.writetofile(options.output, writebbox=1) pyx-project-pyx-21f71ce/contrib/dvitype.py000066400000000000000000000022451526513311100207250ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # # # Copyright (C) 2005-2011 André Wobst # # dvitype is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # epstopng is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with epstopng; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from optparse import OptionParser from pyx import version from pyx.dvi import dvifile parser = OptionParser(usage="usage: %prog dvi-file", version="%prog " + version.version) (options, args) = parser.parse_args() if len(args) != 1: parser.error("can process a single dvi-file only") df = dvifile.DVIfile(args[0], debug=True) while df.readpage(): pass pyx-project-pyx-21f71ce/contrib/graphics.cfg000066400000000000000000000000561526513311100211460ustar00rootroot00000000000000\DeclareOption{pyx}{\def\Gin@driver{pyx.def}} pyx-project-pyx-21f71ce/contrib/imgconvert.py000066400000000000000000000035271526513311100214220ustar00rootroot00000000000000#!/usr/bin/env python # -*- encoding: utf-8 -*- # # # Copyright (C) 2005 André Wobst # # epstopng is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # epstopng is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with epstopng; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA from optparse import OptionParser from pyx import * from pyx import version parser = OptionParser(usage="usage: %prog -o output-file [-r resolution] image-file", version="%prog " + version.version) parser.add_option("-o", "--output", type="string", dest="output", help="output-file") parser.add_option("-r", "--resolution", type="string", dest="resolution", default=None, help="resolution of the image in dpi (optional when available in the image data)") (options, args) = parser.parse_args() if len(args) != 1: parser.error("can process a single image-file only") try: im = bitmap.jpegimage(args[0]) except ValueError: from PIL import Image im = Image.open(args[0]) compressmode = "Flate" else: compressmode = None if options.resolution is None: width = None else: width = im.size[0] / float(options.resolution) * unit.inch c = canvas.canvas() c.insert(bitmap.bitmap(0, 0, im, compressmode=compressmode, width=width)) c.writetofile(options.output) pyx-project-pyx-21f71ce/contrib/textboxes.tex000066400000000000000000000325341526513311100214420ustar00rootroot00000000000000% Modified \output-routine for the use with PyX % this file makes changes of \hsize and \vsizes possible after % every pagebreak % % Copyright (C) 2004 Michael Schindler % % This file is part of PyX (https://pyx-project.org/). % % PyX is free software; you can redistribute it and/or modify % it under the terms of the GNU General Public License as published by % the Free Software Foundation; either version 2 of the License, or % (at your option) any later version. % % PyX is distributed in the hope that it will be useful, % but WITHOUT ANY WARRANTY; without even the implied warranty of % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the % GNU General Public License for more details. % % You should have received a copy of the GNU General Public License % along with PyX; if not, write to the Free Software % Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA % % \newtoks\lovsizes \newtoks\lohsizes \newtoks\parnos \newtoks\parshapes % % Please note that all four tokenlists have to end with {\relax} % This is needed for correct shortening % %%%%%%%%%% TeX's part %%%%%%%%%% \newif\ifverbose \verbosefalse \newcount\tempcnt \newcount\parno \parno=1 \newcount\myprevgraf \myprevgraf=0 \newcount\showprevgraf \showprevgraf=0 \newcount\outputtype \outputtype=0 \newcount\razor \newcount\leastcost \leastcost=10000000 \newcount\futurecost % % Tools for splitting and merging tokenlists after their first element {{{ % did I learn too much lisp or what? \def\cdr#1{\expandafter\precdr\expandafter#1\the#1@} \def\numcdr#1{\expandafter\prenumcdr\expandafter#1\the#1@} \def\numconcat#1#2{\edef\foo{{\the#1}\the#2}\global#2=\expandafter{\foo}} % \def\precdr#1#2#3@{\ifx#2\relax\relax\global#1={\relax}\else#2\global#1={#3}\fi} \def\prenumcdr#1#2#3@{\ifx\relax#2 0\global#1={\relax}\else#2\global#1={#3}\fi} % }}} % % The output routine {{{ % Documentation {{{ % 1. Question: Who calls the pagebuilder and \output? % Answer: Only \par and $$ (as far as I have read the TeXbook) % % 2. Question: So, all together: What is to be done? % Answer: We have to simulate the work of the linebuilder that makes % paragraphs and math into lines in order to find out, what value \prevgraf % might have at a pagepreak. Then, we change the \hsize and \vsize at the % pagepreak and inform PyX about the value of \prevgraf. % % 3. Question: When is \prevgraf advanced? % Answer: At every line by 1 and at every display math by 3 % % 4. Question: How can we hook into the pagebuilding mechanism to find out % about lines and displays? % Answer: We get into the pagebuilder that splits vertical lists into pages % if we enforce a penalty of less than -10000. There are three built-in % hooks: \interlinepenalty % \predisplaypenalty % \postdisplaypenalty % These are set to values less than -10000 by wrapping \par and $$, the % ones who call the pagebuilder and, therefore, \output % % Unfortunately, we get only "breaks", but we are interested in lines. At % each list, we have one break less than lines. So, we have to add another % call of \output at the end of a paragraph. This is done by an explicit % \penalty % A display math succeeding some text also calls the pagebuilder. We have % to add another line in such situations. This is done in the output % routine while processing \predisplaypenalty. % % 5. Question: Why are there so many \ifnum s in the output routine? % Answer: As explained avove, we have to do different things at different % positions of our text. \interlinepenalty and the \penalty for paragraph % endings have to add a line. \postdisplaypenalty has to add the display % (advances \prevgraf by 3), while \predisplaypenalty may still reside on % the previous page, while the display math has moved to the next one. % Therefore, it does not contribute to the \prevgraf. Nevertheless, if % there was some text before the display math in the same paragraph, we % still have to add the last line of text! % % This is the reason for the whole \outputtype business: % We have to show a \prevgraf value different to \myprevgraf at a situation % where an \interlinepenalty is followed by a \predisplaypenalty which is % followed by a pagebreak. The display is on the next page. % The same can -- of course -- also occur with a \predisplaypenalty % following a \penalty caused by \par % % 6. Question: What the hell does \leastcost do? % Answer: This is a tricky point. We hooked into the pagebuilding mechanism % by changing penalties. In this case, TeX thinks, there is a very good % pagebreak and calls \output. But \output removes the strongly negative % penalty we added. Now, TeX has to reconsider the pagebreak and may come % to the result that some of the lines that have appeared as perfect % pagebreaks are not so perfect... % Therefore, before we re-inject the whole vertical list and remove the % negative penalty by saying % \unvbox255 \advance\outputpenalty by XXXXXX \penalty\outputpenalty % we have to know in advance, what the pagebuilder will think of the % pagebreak in the next run. See the TeXbook, p. 111 for the correct % formula. % % This is the reason for \showprevgraf. We have two counters: % - \myprevgraf counts real lines and displays. This keeps us up-to-date % with the paragraph all the time % - \showprevgraf only counts what will be visible on the current page. It % will be reset to \myprevgraf after the pagebreak. % % 7. Question: What do you do to \deadcycles? % Answer: \deadcycles is advanced every time an \output routine has % re-inserted \box255 into the recent contributions. We have to do this for % every line and display math. Therefore, we are restricted to % \maxdeadcycles lines or displays :-( % To avoid this, we cheat the counting of deadcycles and re-advance % \deadcycles by -1. Please, be careful with this hack! % }}} \def\setshowprevgraf#1{% % \futurecost will be the cost in the next step (TeXBook, p.111) \futurecost=#1 \advance\futurecost by\outputpenalty % redo Knuth's formula for pagebreaking: futurecost (is the penalty), badness and insertpenalties \ifnum\insertpenalties<10000 \ifnum\futurecost<-9999 \else\ifnum\futurecost<10000 \ifnum\badness<10000 \advance\futurecost by\badness \else\ifnum\badness=10000 \futurecost=100000 \else \futurecost=10000000 % infinity \fi\fi \else \futurecost=10000 % this case is not in Knuth's formula !?? \fi\fi \else \futurecost=10000000 % infinity \fi % track the leastcost up to now and % set showprevgraf to the current value of myprevgraf \ifnum\futurecost>\leastcost\else \global\leastcost=\futurecost \global\showprevgraf=\myprevgraf \fi % show some debugging info \inform } \def\inform{\ifverbose\immediate\write16{% \space myprevgraf=\the\myprevgraf \space showprevgraf=\the\showprevgraf \space futurecost=\the\futurecost \space leastcost=\the\leastcost}\fi } % at the end of all input we will need \showprevgraf to be \myprevgraf % \supereject is called by \bye % and explicitly by the textboxes() method \edef\savesupereject{\supereject} \def\supereject{\global\showprevgraf=\myprevgraf\savesupereject} % save whatever someone said to be the output routine % \plainoutput uses \makeheadline and \makefootline \newtoks\saveoutput \def\makeheadline{} \def\makefootline{} \saveoutput=\expandafter{\the\output} \def\linemarker{\PyXMarker{start@\the\parno@\the\myprevgraf}} \output={% \tempcnt=\deadcycles \advance\tempcnt by-1 \deadcycles=\tempcnt% \razor=-50000 \ifnum\outputpenalty>\razor %%%%%%%%%% End of the page %%%%%%%%%% \immediate\write16{PyXVariableBox:page=\the\pageno,par=\the\parno,prevgraf=\the\showprevgraf:}% % reset showprevgraf \global\showprevgraf=\myprevgraf \tempcnt=\deadcycles \advance\tempcnt by 1 \deadcycles=\tempcnt % set the outputtype % \global\outputtype=0 % this has no outputtype!! Otherwise, the outputtype of the last page is lost % e.g. makes % <\interlinepenalty (1)> <\predisplaypenalty (should be 5, not 2)> % after the page has been shipped out, we need a new leastcost \global\leastcost=10000000 % do whatever someone told to be the output routine \the\saveoutput % and change the \hsize and \vsize \cdr\lovsizes \cdr\lohsizes \else\advance\razor by -100000 \ifnum\outputpenalty>\razor %%%%%%%%%% InterLinePenalty: -100000 %%%%%%%%%% \ifverbose\immediate\write16{******** InterLinePenalty ********}\fi \global\advance\myprevgraf by 1 % this will be the cost in the next page break finding: \setshowprevgraf{100000} % set the outputtype \global\outputtype=1 % and re-inject the whole page with the original penalty \unvbox255 \linemarker % \setbox0=\lastbox% % \setbox0=\hbox to \the\wd0{\PyXMarker{start@\the\parno@\the\myprevgraf}% % \unhbox0% % \PyXMarker{end@\the\parno@\the\myprevgraf}}% % \nointerlineskip\box0% \advance\outputpenalty by 100000 \penalty\outputpenalty \else\advance\razor by -100000 \ifnum\outputpenalty>\razor %%%%%%%%%% PreDisplayPenalty: -200000 %%%%%%%%%% \ifverbose\immediate\write16{******** PreDisplayPenalty ********}\fi \ifnum\outputtype=1 \global\advance\myprevgraf by 1 % this is for the last preceding text line \global\outputtype=5 % this will be the cost in the next page break finding: \setshowprevgraf{200000} \else\ifnum\outputtype=4 \global\advance\myprevgraf by 1 % this is for the first line of the current par % which has no interlinepenalty \global\outputtype=2 % this will be the cost in the next page break finding: \setshowprevgraf{200000} \else \global\outputtype=2 \def\linemarker{} \fi\fi % and re-inject the whole page with the original penalty \unvbox255 \linemarker \advance\outputpenalty by 200000 \penalty\outputpenalty \else\advance\razor by -100000 \ifnum\outputpenalty>\razor %%%%%%%%%% PostDisplayPenalty: -300000 %%%%%%%%%% \ifverbose\immediate\write16{******** PostDisplayPenalty ********}\fi \global\advance\myprevgraf by 3 % all prevgraf for the display comes here, not in PreDisplayPenalty % this will be the cost in the next page break finding: \setshowprevgraf{300000} % set the outputtype \global\outputtype=3 % and re-inject the whole page with the original penalty \unvbox255 \linemarker \advance\outputpenalty by 300000 \penalty\outputpenalty \else\advance\razor by -100000 \ifnum\outputpenalty>\razor %%%%%%%%%% end of the paragraph: \penalty-400000 %%%%%%%%%% \ifverbose\immediate\write16{******** Penalty ********}\fi \global\advance\myprevgraf by 1 % this will be the cost in the next page break finding: \setshowprevgraf{400000} \global\outputtype=4 % and re-inject the whole page with the original penalty \unvbox255 \linemarker \advance\outputpenalty by 400000 \penalty\outputpenalty \else %%%%%%%%%% some stuff unknown to us %%%%%%%%%% \immediate\write16{******** VEEEEEEERY negative value of outputpenalty: ERROR? ********}% \unvbox255 \tempcnt=\deadcycles\advance\tempcnt by 1 \deadcycles=\tempcnt \fi\fi\fi\fi\fi} % }}} % % We have to reset certain things at the beginning of {{{ % every paragraph: Hook into it with \everypar \newtoks\saveeverypar \saveeverypar=\expandafter{\the\everypar} \everypar={% \global\advance\parno by 1 \global\myprevgraf=0 \global\showprevgraf=0 % \global\leastcost=10000000 % check if the following paragraph will need a \parshape % if yes, say the first token of \parshapes % if no, restore the parno number into \parnos. % This has to come in \everypar to avoid content after the last \par \tempcnt=\numcdr\parnos \ifnum\tempcnt=\parno \cdr\parshapes \else \numconcat\tempcnt\parnos \fi %PAR--\the\parno--% \the\saveeverypar} % }}} % % \par calls the pagebuilder and \output {{{ % We wrap the \par primitive % - set \interlinepenalty first and reset it afterwards % - call \output another time for the last line of the paragraph \let\savepar\par \def\par{% \ifvmode\savepar\else\ifinner\savepar\else % \global\leastcost=10000000 \advance\interlinepenalty by -100000 \vadjust{\penalty-400000}% \savepar \advance\interlinepenalty by 100000 \fi\fi} % }}} % % $$ also calls the pagebuilder and \output {{{ % We wrap these characters with newly defined commands % \display and \enddisplay % XXX Can $ be redefined to achieve the same result? % - $$ (begin) calls the pagebuilder for the previous text % we have to do similar things as in \par % - $$ (end) calls the pagebuilder for the display math % we have to adjust \predisplaypenalty and \postdisplaypenalty % XXX Has \interdisplaylinepenalty any effect on \prevgraf ? \def\display{% % \global\leastcost=10000000 \global\advance\interlinepenalty by -100000 $$% \global\advance\interlinepenalty by 100000\relax} \def\enddisplay{% % \global\leastcost=10000000 \global\advance\predisplaypenalty by -200000 \global\advance\postdisplaypenalty by -300000 $$% \global\advance\predisplaypenalty by 200000 \global\advance\postdisplaypenalty by 300000\relax} % }}} % % vim:fdm=marker pyx-project-pyx-21f71ce/design/000077500000000000000000000000001526513311100164755ustar00rootroot00000000000000pyx-project-pyx-21f71ce/design/attributes000066400000000000000000000125571526513311100206200ustar00rootroot00000000000000Attributes. Design summary. =========================== What are attributes? -------------------- Attributes define properties of a given object when it is being used. They are instances derived from the class attr.attr. Typically, there are different kind of attributes which are usually orthogonal to each other, while for one attribute kind, several choices are possible. Example: When stroking a path, the linewidth and the linestyle are different kind of attributes. The linewidth might be normal, thin, thick, or whatever else. The linestyle might be solid, dashed etc. Where are attributes used? -------------------------- Typically, attributes occur in lists passed as an optional keyword argument to a method or a function. The object the attributes are refering to is usually the first argument (not taking into account the self argument) of the method, like in canvas.stroke(path, [attr1, attr2, attr3]) Attribute categories -------------------- There are different categories of attributes. We give a (not yet?) complete list here: - stroke attributes, aka strokestyles (style module) inherited from style.strokestyle - fill attributes, aka fillstyles inherited from style.fillstyle - text attributes, aka textattrs (text module) inherited from style.textattr - decorators (deco module) inherited from deco.deco - transformations (trafo module) - clippings? (AW: might go away; boxes could do that) Operations usually allow for certain attibute categories only. For example when stroking a path, text attributes are not allowed, while stroke attributes and decoraters are. Some attributes might belong to several attribute categories like colors, which are both, stroke and fill attributes. This is described by multiple inheritance and the attribute categories can be queried using the builtin isinstance method. Attribute instances as member variables --------------------------------------- Usable attributes are always instances. For simple attributes, we have the following technology: class linewidth(strokestyle): def __init__(...): etc. linewidth.normal = linewidth("0.2 mm") linewidth.thick = linewidth("0.2828 mm") etc. Thus there are different possibilities to get a linewidth: by linewidth("0.25 mm") and by linewidth.normal (and the like). Note that attribute classes usually contain a set of special attribute values as member variables. This is done in order to group the attributes in a nice way. Specializing attribute instances -------------------------------- There might be more complicated attributes, where it is more questionable, how attribute instances should be used. An easy, yet not striking, example would be changes in some color parameters of a color attribute. Consider a CMYK color, where only the blackness should be changed. Thus we need to have a syntax for further specializing an already existing attribute instance. This could be done by __call__ (or some arbitrary other named method --- the latter would not really be helpfull in the authors eyes). The code would look like: some_cmyk_color = color.cmyk(0.1, 0.2, 0.3, 0.4) darker_version = some_cmyk_color(b=1) Both, some_cmyk_color and darker_version are instances of color.cmyk. Since usually some parameters are to be changed only, the parameters should be accessable by keyword arguments. Attribute lists in keyword arguments could gain from the attribute replacement and clearing functionality described below. Basically, the specialization (__call__ method) should take exactly the same arguments like the constructor (__init__ method). It might be consistent to provide the specialization possibility for all attribute instances. Merging attribute lists ----------------------- Attributes allow for exclusion, overwriting each other and ordering. This process is called merging of attributes and it is performed by the function merge from attr.py. The merging process might take into account some default attributes. They are passed in a special keyword argument. Example: use_attr_list = attr.mergeattrs(original_attr_list) There are special clearing attributes, which overwrite other attributes and do not add themself when merging an attribute list. By that it is possible to change certain or all default attributes. To construct an instance of a clearing attributes which removes all preceding attributes of a certain class c use attr.clearclass(c). The attr module also contains a predefined instance attr.clear which clears all preceding attributes. Changeable attributes --------------------- Changeable attributes are instances derived from attr.changeattr. They provide a select method with the following prototype: select(self, index, total) The index is an unsigned integer and the total is a positive integer. The select method might raise an ValueError, when the select method is called for parameters, it doesn't allow for. An example would be a color change from a starting color to an end color. Such a changeable attribute would not allow for a total equals to 1. The select function from attr.py returns a list of attributes out of a list of attributes and changeable attributes. The prototype uses the same index and total arguments, as described above: select(attr_list, index, total) When changeable attributes are used, the select process must be performed previous to the merging. pyx-project-pyx-21f71ce/design/beziers.tex000066400000000000000000000610311526513311100206630ustar00rootroot00000000000000\documentclass{article} \usepackage{amsmath} \usepackage{array} \usepackage{graphicx} \newcommand{\sign}{\operatorname{sign}} \begin{document} \section{B\'ezier curves with prescribed tangent directions and curvatures at the endpoints} % <<< Parameterization of the B\'ezier curve, for $x(t)$ and $y(t)$ equivalently, % \begin{align} x(t) &= x_0(1-t)^3 + 3x_1t(1-t)^2 + 3x_2t^2(1-t) + x_3 t^3\\ \dot x(t) &= 3(x_1-x_0)(1-t)^2 + 3(x_3-x_2)t^2 + 6(x_2-x_1)t(1-t) \\ \ddot x(t) &= 6(x_0 - 2x_1 + x_2)(1-t) + 6(x_1-2x_2+x_3) t \\ \dddot x(t) &= 6(x_3-x_0) + 18(x_1-x_2) \end{align} % The curvature is \begin{equation} \kappa(t) = \frac{\dot x\ddot y - \ddot x\dot y}{[\dot x^2 + \dot y^2]^{3/2}} \end{equation} % with the sign % \begin{equation} \begin{aligned} \sign\kappa &> 0 \quad\text{for left bendings}\\ \sign\kappa &< 0 \quad\text{for right bendings.} \end{aligned} \end{equation} % At the endpoints we can summarize: % \begin{align} \dot x(0) &= 3(x_1 - x_0) \\ \dot x(1) &= 3(x_3 - x_2) \\ \ddot x(0) &= 6(x_0 - 2x_1 + x_2) = -4\dot x(0) - 2\dot x(1) + 6(x_3 - x_0) \\ \ddot x(1) &= 6(x_1 - 2x_2 + x_3) = +4\dot x(1) + 2\dot x(0) - 6(x_3 - x_0) \end{align} % and the same for the $y$ coordinates. The equations for the $\ddot x$ contain a convenient parameterization for this problem, with given endpoints and tangent directions. We now introduce two parameters for the distances between the first and the last pair of control points: % \begingroup \arraycolsep=0pt \begin{align} \left(\begin{array}{cc} x_1-x_0 \\ y_1-y_0 \end{array}\right) &= \frac{1}{3} \left(\begin{array}{cc} \dot x(0) \\ \dot y(0) \end{array}\right) =: \alpha \left(\begin{array}{cc} t_x(0) \\ t_y(0) \end{array}\right) \\ \left(\begin{array}{cc} x_3-x_2 \\ y_3-y_2 \end{array}\right) &= \frac{1}{3} \left(\begin{array}{cc} \dot x(1) \\ \dot y(1) \end{array}\right) =: \beta \left(\begin{array}{cc} t_x(1) \\ t_y(1) \end{array}\right) \qquad \end{align} \endgroup % Here, the externally prescribed tangent vectors are expected to be parallel to the tangent vectors of the parameterization and normalized to 1. This implies $\alpha>0$ and $\beta>0$ are the distances between the endpoints and their corresponding control points. The problem to now to find proper parameters $\alpha>0$ and $\beta>0$ for a given set of endpoints $(x_0,y_0)$, $(x_3, y_3)$, normalized tangent vectors $\mathbf{t}(0)$, $\mathbf{t}(1)$ and of curvatures $\kappa(0), \kappa(1)$. The rest of the control points is then given by % \begin{equation} x_1 = x_0 + \alpha t_x(0) \quad\text{and}\quad x_2 = x_3 - \beta t_x(1). \end{equation} % For the curvatures at the endpoints we get a nonlinear equation, % \begin{align} \kappa(0) (\dot x^2(0) + \dot y^2(0))^{3/2} &= \dot x(0) \ddot y(0) - \ddot x(0) \dot y(0) \\ = 27 \kappa(0) |\alpha|^3 &= \begin{aligned}[t] &+\dot x(0) \bigl[- 4\dot y(0) - 2\dot y(1) + 6(y_3-y_0)\bigr] \\ &-\dot y(0) \bigl[- 4\dot x(0) - 2\dot x(1) + 6(x_3-x_0)\bigr] \end{aligned}\\ &= \begin{aligned}[t] &-2 \bigl[\dot x(0) \dot y(1) - \dot y(0)\dot x(1)\bigr] \\ &+6 \bigl[\dot x(0) (y_3-y_0) - \dot y(0) (x_3-x_0)\bigr] \end{aligned}\\ &= \begin{aligned}[t] &-18 \alpha\beta \bigl[t_x(0)t_y(1) - t_y(0)t_x(1)\bigr] \\ &+18 \alpha \bigl[t_x(0) (y_3-y_0) - t_y(0) (x_3-x_0)\bigr] \end{aligned} \end{align} % And short, % \begin{equation} 0 = \frac{3}{2}\kappa(0) \alpha^2 \sign(\alpha) + \beta \bigl[t_x(0)t_y(1) - t_y(0)t_x(1)\bigr] - \bigl[t_x(0) (y_3-y_0) - t_y(0) (x_3-x_0)\bigr] \end{equation} % A similar calculation can be done for the end curvature, % \begin{align} \kappa(1) (\dot x^2(1) + \dot y^2(1))^{3/2} &= \dot x(1) \ddot y(1) - \ddot x(1) \dot y(1) \\ = 27 \kappa(1) |\beta|^3 &= \begin{aligned}[t] &+\dot x(1) \bigl[ 4\dot y(1) + 2\dot y(0) - 6(y_3-y_0)\bigr] \\ &-\dot y(1) \bigl[ 4\dot x(1) + 2\dot x(0) - 6(x_3-x_0)\bigr] \end{aligned}\\ &= \begin{aligned}[t] &-2 \bigl[\dot x(0) \dot y(1) - \dot y(0)\dot x(1)\bigr] \\ &-6 \bigl[\dot x(1) (y_3-y_0) - \dot y(1) (x_3-x_0)\bigr] \end{aligned}\\ &= \begin{aligned}[t] &-18 \alpha\beta \bigl[t_x(0)t_y(1) - t_y(0)t_x(1)\bigr] \\ &-18 \beta \bigl[t_x(1) (y_3-y_0) - t_y(1) (x_3-x_0)\bigr] \end{aligned} \end{align} \begin{equation} 0 = \frac{3}{2}\kappa(1) \beta^2 \sign(\beta) + \alpha \bigl[t_x(0)t_y(1) - t_y(0)t_x(1)\bigr] + \bigl[t_x(1) (y_3-y_0) - t_y(1) (x_3-x_0)\bigr] \end{equation} % Alltogether, we find the system of equations that is to be solved. % \begin{gather} \begin{aligned} 0 &= \frac{3}{2} \kappa(0) \alpha^2 \sign(\alpha) + \beta T - D \\ 0 &= \frac{3}{2} \kappa(1) \beta^2 \sign(\beta) + \alpha T - E \end{aligned}\\[\medskipamount] \begin{aligned} T &:= t_x(0)t_y(1) - t_y(0)t_x(1) \\ D &:= \bigl[t_x(0) (y_3-y_0) - t_y(0) (x_3-x_0)\bigr]\\ E &:= \bigl[t_x(1) (y_0-y_3) - t_y(1) (x_0-x_3)\bigr] \end{aligned} \end{gather} % Decoupling the two equations causes problems with the absolute values, % \begin{align} \alpha = \frac{1}{T}\left(E - \frac{3}{2}\kappa(1)\beta |\beta |\right)\quad\text{and}\quad \beta = \frac{1}{T}\left(D - \frac{3}{2}\kappa(0)\alpha|\alpha|\right) \end{align} % Thus, for $\alpha>0$ and $\beta>0$ we need also % \begin{align} \frac{1}{T}\left(E - \frac{3}{2}\kappa(1)\beta |\beta |\right) > 0\quad\text{and}\quad \frac{1}{T}\left(D - \frac{3}{2}\kappa(0)\alpha|\alpha|\right) > 0 \end{align} % which is not always guaranteed. E.g. the combination % \begin{equation} T>0,\quad E<0\quad\text{and}\quad \kappa(1)>0 \end{equation} % is not compatible with a positive value of $\beta$. Under what circumstances do we get such geometrically invalid results? Tests show that even allowing arbitrary signs of the curvatures $\kappa(0)$~and $\kappa(1)$ does not help in all cases. The decoupled equations can be constructed by inserting $\alpha$~and $\beta$ into the equations for the curvatures. This reads \begin{align} 0 &= \frac{3}{2}\kappa(0)\sign(\alpha) \left(E - \frac{3}{2}\kappa(1)\beta |\beta |\right)^2 + \beta T^3 - D T^2 \\ &= \begin{aligned}[t] \frac{27}{8} \kappa(0) \kappa^2(1) \sign(\alpha) \beta^4 - \frac{9}{2} E \kappa(0) \kappa(1) \sign(\alpha)\sign(\beta) \beta^2 + \beta T^3 \\ {}+ \frac{3}{2} \kappa(0) \sign(\alpha) E^2 - D T^2 \end{aligned}\\ 0 &= \begin{aligned}[t] \frac{27}{8} \kappa^2(0) \kappa(1) \sign(\beta) \alpha^4 - \frac{9}{2} D \kappa(0) \kappa(1) \sign(\alpha)\sign(\beta) \alpha^2 + \alpha T^3 \\ {}+ \frac{3}{2} \kappa(1) \sign(\beta) D^2 - E T^2 \end{aligned} \end{align} % % >>> \section{Bounding boxes for B\'ezier curves} % <<< The bounding box is defined by the minimal and maximal values of a curve. Hence the problem decouples for the two coordintes $x$ and $y$. We can search for the minima and maxima within the valid range for the parameter $t$ together with taking into account the values at the boundaries at $t=0$ and $t=1$. For the $x$ coordinate we have: \begin{align} x(t) & = x_0(1-t)^3 + 3x_1t(1-t)^2 + 3x_2t^2(1-t) + x_3 t^3\\ & = (x_3-3x_2+3x_1-x_0)t^3 + (3x_0-6x_1+3x_2)t^2 + (3x_1-3x_0)t + x_0\\ & = a\,t^3 + \frac{3}{2}\,b\,t^2 + 3\,c\,t + x_0 \end{align} % The constants $a$, $b$, and $c$ are % \begin{align} a & = x_3-3x_2+3x_1-x_0 \\ b & = 2x_0-4x_1+2x_2 \\ c & = x_1-x_0 \end{align} % Now $\dot x(t)$ is % \begin{equation} \dot x(t) = 3\left[\,a\,t^2 + b\,t + c\,\right] \end{equation} % For a numerically stable calculation of the roots of the function, we first compute % \begin{equation} q = -\frac{1}{2}\left[\,b+\mathrm{sgn}(b)\sqrt{b^2-4ac}\right]\, . \end{equation} % In case the square root is negative, we only need to take into account the values at the boundaries. Otherwise we need to take into account the two solutions % \begin{equation} t_1 = \frac{q}{a} \quad\text{and}\quad t_2 = \frac{c}{q} \end{equation} % Again, for numerical failures (divisions by zero), we just need to skip the particular solution. The minima and maxima for $x(t)$ can now occur at $t=0$, $t=t_1$, $t=t_2$ and $t=1$. % >>> \section{Replacing B\'ezier curves by straight lines} % <<< \begin{figure} \centerline{\includegraphics{beziertoline}} \caption{Example for a replacement of a B\'ezier curve by a straight line.} \label{fig:beziertoline} \end{figure} To solve certain geometrical tasks like measuring the length of a path or finding intersection points between paths, B\'ezier curves are recusively reduced to smaller B\'ezier curves by splitting the curves at the parameter value 0.5 until the parts become almost straight. Using the notation shown in fig.~\ref{fig:beziertoline} the straightness is expressed by a length measurement summing up the distances $\overline{AB}=l_1$, $\overline{BC}=l_2$ and $\overline{CD}=l_3$ and comparing this to the direct connection $\overline{AD}$. When the difference becomes smaller than a threshold $\epsilon$, the curve is adequately expressed by a straight line either because the curve is almost straight or it is very short. However, although the geometric changes are limited to distances of $\epsilon$, the parametrization $t$ of the B\'ezier curve might be mistakenly represented by the straight line on a much larger scale. In the shown example, the point $X$ on the B\'ezier curve and $Y$ on the straight line are both taken at the parameter value $t=0.5$, but clearly are more separated from each other than one would expect from the geometric distance of the two paths. While the parametrization on a line is proportional to the arc length, a non-linear behaviour is found on a B\'ezier curve. This non-linearity is originated in considerably different lengths $l_1$, $l_2$ and $l_3$ and the mapping of the non-linear parameter to a linear parametrization (in terms of the arc length) can be reduced to a one-dimensional problem upon an error $\epsilon$: % \begin{equation} x_0(1-t')+x_3t' = x_0(1-t)^3 + 3x_1t(1-t)^2 + 3x_2t^2(1-t) + x_3 t^3\,. \end{equation} % In this one-dimensional approximation the parameter $t'$ performs a linear mapping as for any straight line while $t$ represents the usual B\'ezier curve parametrization. It now becomes a matter of expressing $t$ by $t'$. The polynomial in $t$ to be solved is: % \begin{equation} 0 = at^3+bt^2+ct+d \end{equation} % with % \begin{align} a & = x_3-3x_2+3x_1-x_0 = l_1-2l_2+l_3 \\ b & = 3x_0-6x_1+3x_2 = -3l_1+3l_2 \\ c & = 3x_1-3x_0 = 3l_1 \\ d & = t'(x_0-x_3) = -t'(l_1+l_2+l_3)\,. \end{align} % For $0\le t'\le1$ there will be at least one solution $0\le t\le1$. Several solutions are possible as well, although they should be close to each other since otherwise the straight line approximation would not be valid at all. % >>> \section{Relative coordinates} % <<< A B\'ezier curve is given by \begin{equation} \vec b(t) = (1-t)^3\vec p_0 + 3t(1-t)^2\vec p_1 + 3t^2(1-t)\vec p_2 + t^3\vec p_3 \end{equation} where $\vec p_0 = (x_0, y_0)$, $\vec p_1 = (x_1, y_1)$, $\vec p_2 = (x_2, y_2)$, and $\vec p_3 = (x_3, y_3)$ are the control points. When $\vec p_0$ differs from $\vec p_3$ we can express the B\'ezier curve in relative coordinates $r(t)$ and $s(t)$ by \begin{equation} \vec b(t) = \vec q + r(t)\vec r + s(t)\vec s \end{equation} with \begin{align} \vec q & = \vec p_0\\ \vec r & = \vec p_3 - \vec p_0 = \left(\begin{array}{c} x_3 - x_0 \\ y_3 - y_0 \end{array}\right)\\ \vec s & = \left(\begin{array}{c} y_3 - y_0 \\ x_0 - x_3 \end{array}\right) \end{align} Note that \begin{equation} \vec r\cdot\vec r = \vec s\cdot\vec s := l^2 \end{equation} where $l$ is the distance between $\vec p_0$ and $\vec p_3$. In addition $\vec r$ and $\vec s$ are perpendicular: \begin{equation} \vec r\cdot\vec s = 0 \end{equation} We can express the control points in the new coordinates: \begin{align} \vec p_0 & = \vec q\\ \vec p_1 & = \vec q + r_1\vec r + s_1\vec s\\ \vec p_2 & = \vec q + r_2\vec r + s_2\vec s\\ \vec p_3 & = \vec q + \vec r \end{align} The coefficients $r_1$, $r_2$, $s_1$, $s_2$ are given by scalar products due to the properties of $\vec r$ and $\vec s$ given above: \begin{align} r_1 l^2 & = (\vec p_1 - \vec p_0)\cdot\vec r\\ r_2 l^2 & = (\vec p_2 - \vec p_0)\cdot\vec r\\ s_1 l^2 & = (\vec p_1 - \vec p_0)\cdot\vec s\\ s_2 l^2 & = (\vec p_2 - \vec p_0)\cdot\vec s \end{align} The parametric functions $r(t)$ and $s(t)$ become \begin{align} r(t) & = 3t(1-t)^2 r_1 + 3t^2(1-t) r_2 + t^3\\ s(t) & = 3t(1-t)^2 s_1 + 3t^2(1-t) s_2 \end{align} \emph{Note:} Originally the idea was to use relative coordinates to remove unstabilities in B\'ezier curves (especially cusps) considering all points with $\dot r(t)$ being zero or extremal. This idea works very well in general, and could, for example, also remove self-intersections. (You can get rid of any backwards directed curve sections, i.e. where $\dot r(t)<0$.) However, the whole idea has been discarded as $\dot r(t)$ could be close to zero for $t=0$ and $t=1$. The pre-removal of such problems would introduce major defects to the B\'ezier curve (like changing the direction of the tangential vector at the beginning and the end point). % >>> \section{Invalid parametrisation} % <<< If the derivative of the parametrisation vanishes (both coordinates) at a parameter~$t\in[0,1]$, the parametrisation is considered to be invalid at this point. Under which circumstances can this occur? We search for solutions~$t$ for the quadratic equations % \begin{equation} \label{zeroderiv} \begin{aligned} 0 = x(t)/3 &= t^2\bigl[(x_3-x_0) - 3(x_2-x_1)\bigr] + 2t\bigl[(x_2-x_1)-(x_1-x_0)\bigr] + (x_1-x_0) \\ 0 = y(t)/3 &= t^2\bigl[(y_3-y_0) - 3(y_2-y_1)\bigr] + 2t\bigl[(y_2-y_1)-(y_1-y_0)\bigr] + (y_1-y_0) \end{aligned} \end{equation} % Using the usual formula for a quadratic equation $0=at^2 + bt + c$, we get the same parameter for $x$- and $y$-coordinates, and the two inequalities from $0\leq t\leq1$, % \begin{equation} \label{samet} t_{1,2} = \frac{1}{2a_x} \Bigl(-b_x \pm^1 \sqrt{b_x^2 - 4a_xc_x}\Bigr) = \frac{1}{2a_y} \Bigl(-b_y \pm^2 \sqrt{b_y^2 - 4a_yc_y}\Bigr) \end{equation} % The two sign choices are independent of each other. For the moment, we put aside the special cases $p_3=p_0$ and $p_1=p_0$. As affine transformations cannot change the degeneracy of the parametrisation, we can fix three points without loss of generality: % \begin{equation} \begin{aligned} (x_0, y_0) = (0, 0),\quad (x_1, y_1) = (0, 1),\quad (x_3, y_3) = (1, 0). \end{aligned} \end{equation} % Thus, the only remaining true parameters are $(x_2, y_2)$. We will use $\Delta x = x_2$ and $\Delta y = y_2 - 1$. Equation~\eqref{samet} now becomes % \begin{equation} % a_y \Bigl(-b_x/2 \pm^1 \sqrt{(b_x/2)^2 - a_xc_x}\Bigr) % = a_x \Bigl(-b_y/2 \pm^2 \sqrt{(b_y/2)^2 - a_yc_y}\Bigr) % % ( -3\Delta y) \Bigl(-(\Delta x ) \pm^1 \sqrt{(\Delta x )^2 }\Bigr) % = (1-3\Delta x) \Bigl(-(\Delta y-1) \pm^2 \sqrt{(\Delta y-1)^2 + 3\Delta y}\Bigr) % \label{samet2} ( -3\Delta y) \Bigl(-\Delta x \pm^1 \sqrt{(\Delta x )^2 }\Bigr) = (1-3\Delta x) \Bigl(1-\Delta y \pm^2 \sqrt{1 + \Delta y + \Delta y^2}\Bigr) \end{equation} % Special care has to be taken if $a_x=0$ or $a_y=0$. For the inequalities, we have to consider the signs of $a_x$ and $a_y$ explicitly: \arraycolsep=0pt % \begin{equation} \begin{aligned} 0 \leq -\Delta x \pm^1 \sqrt{\Delta x^2} \leq 1-3\Delta x &\quad\text{if $\Delta x < 1/3$ (or $a_x > 0$)} \\ 0 \leq \Delta x \mp^1 \sqrt{\Delta x^2} \leq 3\Delta x-1 &\quad\text{if $1/3 < \Delta x$ (or $a_x < 0$)} \end{aligned} \end{equation} % which can be reduced to % \begin{equation} \label{constr1} \begin{aligned} \text{no constraint} &\quad\text{if $\Delta x \leq 0$} \\ \text{only the upper sign of $\pm^1$ is allowed} &\quad\text{if $0 < \Delta x < 1$} \\ \text{no constraint} &\quad\text{if $\Delta x \geq 1$} \end{aligned} \end{equation} % Between $0$ and $1$ the upper sign makes the inequality to be trivially satisfied, because $-\Delta x + |\Delta x| = 0$. The inequality constraint can equivalently be formulated for $\Delta y$, % \begin{equation} \begin{aligned} 0 \leq 1-\Delta y \pm^2 \sqrt{1+\Delta y+\Delta y^2} \leq -3\Delta y &\quad\text{if $\Delta y < 0$ (or $a_y > 0$)} \\ 0 \leq \Delta y-1 \mp^2 \sqrt{1+\Delta y+\Delta y^2} \leq 3\Delta y &\quad\text{if $\Delta y > 0$ (or $a_y < 0$)} \end{aligned} \end{equation} % In the first line, the comparison with~$0$ is always true. In the right comparison, the lower sign is always possible and does not yield a constraint, whereas the upper sign is only possible for $\Delta y \leq -1$. In the second line, the upper sign is incompatible with the left comparison, and the lower sign is always possible. We can reduce the conditions to % \begin{equation} \label{constr2} \begin{aligned} \text{no constraint} &\quad\text{if $\Delta y \leq -1$} \\ \text{only the lower sign of $\pm^2$ is allowed} &\quad\text{if $\Delta y > -1$} \\ \end{aligned} \end{equation} % Equation~\eqref{samet2} with the two constraints \eqref{constr1} and \eqref{constr2} is the system of equations that gives us the values $\Delta x, \Delta y$ for which the parametrisation could be invalid. First, let us check that the classic case for a cusp is well described. It has $\Delta x=-1, \Delta y=0$. We have no constraint on $x$, and we have to take the lower sign on $y$. Indeed, the left-hand side of eq.~\eqref{samet2} vanishes due for the lower sign, and the right one vanishes also for the lower sign. This case is shown among the examples in figure~\ref{fig:invalid3}. % \begin{figure}[ht] \centering \includegraphics{invalid2}% \caption{Absolute value of the difference between left- and right-hand side of eq.~\eqref{samet2}. The dotted lines are given by eqs.~\eqref{leftcurve} and \eqref{rightcurve}.}% \label{fig:invalid2}% \end{figure}% % \begin{figure}[ht] \centering \includegraphics{invalid3}% \caption{Some examples of invalid parametrisations from the general (non-degenerate) case described by eqs.~\eqref{samet2}, \eqref{constr1}, \eqref{constr2}.}% \label{fig:invalid3}% \end{figure}% % Figure~\ref{fig:invalid2} shows the difference between left- and right-hand side of Eq.~\eqref{samet2} for all valid signs, respecting the constraints. The horizontal and vertical lines are those special cases where $a_x=0$ or $a_y=0$ and need further considerations. The zero-level curve at $\Delta x < 0$ (dotted curve in the figure) is well described by the equation % \begin{equation} \label{leftcurve} \Delta x = \frac{1}{3}\Bigl(-1-2\Delta y - \sqrt{(2\Delta y+1)^2 + 3}\Bigr) \end{equation} % which is obtained by taking the upper sign of $\pm^1$ in eq.~\eqref{samet2}: With negative values of $\Delta x$ the left-hand side becomes $6\Delta x\Delta y$. Isolating the square-root and then taking the square leads to a quadratic equation for $\Delta x$, of which eq.~\eqref{leftcurve} is the negative solution. A numerical check shows that this solution corresponds to the lower sign of $\pm^2$ and has thus no restriction in $\Delta y$. The second solution (dotted curve in the figure for $\Delta x>0$) of the mentioned quadratic equation, % \begin{equation} \label{rightcurve} \Delta x = \frac{1}{3}\Bigl(-1-2\Delta y + \sqrt{(2\Delta y+1)^2 + 3}\Bigr) \end{equation} % corresponds to the upper sign of $\pm^2$ and is thus subject to the constraint \hbox{$\Delta y \leq -1$}. Apart from the general cases on the two curves, we must treat some special cases separately: % \begin{itemize} \item $a_y=0$: This appears as a zero-level line in figure~\ref{fig:invalid2}, but this is an artefact coming from both sides of eq.~\eqref{samet2} being zero. We have to go back to the original set of equations~\eqref{zeroderiv}: We have in the lower line $\Delta y=0$, thus $t=1/2$. Going back to the upper line with this value, we obtain $\Delta x=-1$. This parameter point is already covered by the general treatment. \item $a_x=0$: This implies $\Delta x=1/3$, and the upper line gives $t=0$. This, however, contradicts the lower line. We do not get an invalid parametrisation point from $a_x=0$. \item $p_1=p_0$: This is either an even more degenerate case (see below), or it can be mapped to the reverse situation of $\Delta x=1, \Delta y=-1$ which was $p_2=p_3$. \item $p_1=p_0$ and $p_2=p_3$: This is a line. \item $p_3=p_0$: There are invalid parametrisation points if all four $p_0,p_1,p_2,p_3$ are collinear. Depending on the sign of $(p_1-p_0)\cdot(p_3-p_2)$ there are one or two invalid points. \item $p_1=p_0=p_2=p_3$: This is a point. \end{itemize} % % >>> \section{Self-intersections} % <<< In order to determine the control points which lead to self-intersections, we could analyse the set of equations % \begin{equation} x(t_1) = x(t_2)\quad\text{and}\quad y(t_1) = y(t_2) \quad\text{for}\quad t_1\neq t_2. \end{equation} % To solve the problem, we could express the solutions $t(\Delta x, \bar x)$ of the cubic equation $\bar x = x(t)$, test their number via Cardano's equation, and, if they are more than one, use a pair of them in the $y$-equation to see whether we get two times the same $y$-value. This would be a formidable task. We here take a different route. As for the invalid parametrisation above, we exclude some degenerate cases and use affine transformations, such that only the parameters $\Delta x=x_2$ and $\Delta y=y_2-1$ are left. It is geometrically evident that a little left and right of the two relevant curves in figure~\ref{fig:invalid2} we must have different situations as far as self-intersections are concerned. Either we find one a little left or a little right of the curves, and none on the respective other side. Further, a self-intersection can clear away when parameters change such that the curve passes through one of its endpoints. These two conditions boil down to the phase diagram in figure~\ref{fig:selfinter2}. In the gray shaded areas, self-intersections are possible. % \begin{figure}[t] \includegraphics{selfinter2}% \caption{Self-intersections are possible in the gray-shaded areas. The black, red, green, blue curves are from eqs.~\eqref{leftcurve}, \eqref{rightcurve}, \eqref{pass00}, \eqref{pass10}, respectively.}% \label{fig:selfinter2}% \end{figure} % We first calculate the parameters $0>> \section{Removing cusps} A cusp is a point on a B\'ezier curve $\vec b(t)$, where $\mathrm{d}\vec b(t)/\mathrm{d}t=\dot{\vec b}(t)$ vanishs. For stability we don't want it to be almost zero either. For comparison, a straight line $\vec l(t)=\vec p_0 + (\vec p_3-\vec p_0)t$ has the constant derivative $\mathrm{d}\vec l(t)/\mathrm{d}t = \dot{\vec l}(t) = \vec p_3-\vec p_0$. As lines shorter than $\epsilon$ are forbidden, we have $|\dot{\vec l}(t)| \ge \epsilon$. We want to enforce this limit to B\'ezier curves as well, \emph{i.e.} $|\dot{\vec b}(t)| \ge \epsilon$. First we have to take into account the beginning ($t=0$) and end point ($t=1$) of the B\'ezier curve. Here, the derivates are given by $\dot{\vec b}(0) = 3(\vec p_1-\vec p_0)$ and $\dot{\vec b}(1) = 3(\vec p_3-\vec p_2)$. In case the absolute value of the derivatives are smaller than $\epsilon$, we need to shift $\vec p_1$ and $\vec p_2$, respectively. For $\vec p_1$ a new value is choosen in the direction of $\vec p_2$ with respect to $\vec p_0$ if $\vec p_2$ is more distant than $\epsilon/3$, otherwise the direction of $\vec p_3$ is used. The distance of the new point is choosen such that the absolute value of the derivate becomes $\epsilon$. $\vec p_2$ is shifted similarly using the unshifted position for $\vec p_1$. Once the derivatives at the boundary fulfil the requirement, we need to search for minimal values of the absolute value (or the square) of the derivate within the valid parameter range. If the absolute value is smaller at an extrema, the curve is split at that point. \end{document} % vim:foldmethod=marker:foldmarker=<<<,>>> pyx-project-pyx-21f71ce/design/beziertoline.py000077500000000000000000000014761526513311100215550ustar00rootroot00000000000000import sys, math sys.path[:0] = [".."] from pyx import * from pyx.normpath import normpathparam def mark(c, t, phi, x, y): c.stroke(path.line(x-0.1, y, x+0.1, y)) c.stroke(path.line(x, y-0.1, x, y+0.1)) t = text.text(x, y, t, [text.halign.center, text.vshift.mathaxis]) t.circlealign(0.2, math.cos(phi*math.pi/180), math.sin(phi*math.pi/180)) c.insert(t) c = canvas.canvas() b = path.curve(0, 0, 0, 0.5, 0, 1, 4, 4).normpath() l = path.line(*(b.atbegin() + b.atend())) c.draw(l, [deco.shownormpath()]) c.draw(b, [deco.shownormpath()]) mark(c, "A", 180, 0, 0) mark(c, "B", 180, 0, 0.5) mark(c, "C", 180, 0, 1) mark(c, "D", 0, 4, 4) mark(c, "Y", -45, 2, 2) mark(c, "X", 90, *b.at(normpathparam(b, 0, 0.5))) mark(c, "X'", 135, *b.at(0.5*b.arclen())) c.writeEPSfile("beziertoline") c.writePDFfile("beziertoline") pyx-project-pyx-21f71ce/design/boxalign.py000077500000000000000000000072251526513311100206630ustar00rootroot00000000000000#!/usr/bin/env python import sys, math sys.path[:0] = [".."] import pyx from pyx import * c = canvas.canvas() c.stroke(path.line(0, 0, 4, 2), [deco.earrow.Large()]) t = text.text(2, 1, r"$\vec p$") t.linealign(0.1, -2/math.sqrt(20), 4/math.sqrt(20)) c.insert(t) c.stroke(path.line(0, 0, 1, 1), [deco.earrow.Large()]) t = text.text(0.5, 0.5, r"$\vec a$") t.linealign(0.1, -1/math.sqrt(2), 1/math.sqrt(2)) c.insert(t) c.stroke(path.line(-1, 3, 3, -1), [style.linestyle.dotted]) c.stroke(path.line(1, 1, 1-1/math.sqrt(2), 1+1/math.sqrt(2)), [deco.earrow.Large()]) t = text.text(1-1/math.sqrt(8), 1+1/math.sqrt(8), r"$\vec b$") t.linealign(0.1, 1/math.sqrt(2), 1/math.sqrt(2)) c.insert(t) c.writeEPSfile("boxalignpal") ############################################################################### c = canvas.canvas() c.stroke(path.line(0, 0, 4, 2), [deco.earrow.Large()]) t = text.text(2, 1, r"$\vec p$") t.linealign(0.1, -2/math.sqrt(20), 4/math.sqrt(20)) c.insert(t) c.stroke(path.line(0, 0, -1, 1), [deco.earrow.Large()]) t = text.text(-0.5, 0.5, r"$\vec a$") t.linealign(0.1, -1/math.sqrt(2), -1/math.sqrt(2)) c.insert(t) c.stroke(path.path(path.arc(0, 0, math.sqrt(2), 0, 360), path.closepath()), [style.linestyle.dotted]) c.writeEPSfile("boxalignpac") ############################################################################### c = canvas.canvas() c.stroke(path.line(0, 0, 4, 2), [deco.earrow.Large()]) t = text.text(2, 1, r"$\vec e$") t.linealign(0.1, -2/math.sqrt(20), 4/math.sqrt(20)) c.insert(t) c.stroke(path.line(0, 0, 6, 2), [deco.earrow.Large()]) t = text.text(3, 1, r"$\vec f$") t.linealign(0.1, 2/math.sqrt(60), -6/math.sqrt(60)) c.insert(t) c.stroke(path.line(6, 2, 4, 2), [deco.earrow.Large()]) t = text.text(5, 2, r"$\vec g$") t.linealign(0.1, 0, 1) c.insert(t) c.stroke(path.line(0, 0, -1, 1), [deco.earrow.Large()]) t = text.text(-0.5, 0.5, r"$\vec a$") t.linealign(0.1, -1/math.sqrt(2), -1/math.sqrt(2)) c.insert(t) c.stroke(path.path(path.arc(0, 0, math.sqrt(2), 0, 360), path.closepath()), [style.linestyle.dotted]) c.stroke(path.line(0, 0, 0, math.sqrt(2)), [deco.earrow.Large()]) t = text.text(0, 1/math.sqrt(2), r"$\vec b$") t.linealign(0.1, -1, 0) c.insert(t) c.writeEPSfile("boxalignlac") ############################################################################### def drawexample(canvas, corner, linealign): r = 1.5 canvas.stroke(path.path(path.arc(0, 0, r, 0, 360))) phi = 0 while phi < 2 * math.pi + 1e-10: if corner: b = box.polygon(center=(0, 0), corners=[(0, 0), (1, 0), (0.5, math.sqrt(3)/2)]) else: b = box.polygon(center=(0, 0), corners=[(-0.5, -math.sqrt(3)/6), (0.5, -math.sqrt(3)/6), (0, math.sqrt(3)/3)]) if linealign: b.linealign(r, math.cos(phi), math.sin(phi)) else: b.circlealign(r, math.cos(phi), math.sin(phi)) if round(phi / math.pi * 2 * 100) % 100: canvas.stroke(b.path()) else: canvas.stroke(b.path(), [color.rgb.red]) phi += math.pi / 50 d = 6 c = canvas.canvas() sc = c.insert(canvas.canvas([trafo.translate(0, d)])) drawexample(sc, 0, 0) sc = c.insert(canvas.canvas([trafo.translate(d, d)])) drawexample(sc, 0, 1) sc = c.insert(canvas.canvas([trafo.translate(0, 0)])) drawexample(sc, 1, 0) sc = c.insert(canvas.canvas([trafo.translate(d, 0)])) drawexample(sc, 1, 1) c.text(0, 1.5*d, "align at a circle", [text.halign.center]) c.text(d, 1.5*d, "align at tangents", [text.halign.center]) c.text(-0.5*d, d, "reference point at the triangle center", [text.halign.center, trafo.rotate(90)]) c.text(-0.5*d, 0, "reference point at a triangle corner", [text.halign.center, trafo.rotate(90)]) c.writeEPSfile("boxalignexample") pyx-project-pyx-21f71ce/design/boxalign.tex000066400000000000000000000111471526513311100210260ustar00rootroot00000000000000% $Header$ % \documentclass{article} \usepackage{pyx,graphicx} \begin{document} \noindent\textbf{\huge Relative box alignment}\medskip \section{Introduction} The relative alignment of boxes is an important part in many drawing tasks. At the moment the main focus is the flexible alignment of text, because it is an essential ingredience for the drawing of axes in the graph module. Therefore, the implementation is part of the graph module at the moment, but the alignment of any kind of boxes is expected be become of general interest in the future. Later on it will certainly become a module for itself. Alternatively the alignment techniques might become a feature of path elements, which sounds quite sophisticated but it might turn out to be inadequate. We consider boxes to be two dimensional convex polygons. We may introduce round corners and other goodies later on, but for the moment polygons are everything we are in need for. The relative alignment takes place respecting an alignment vector $\vec a$. The box has a reference point $\vec c$, which can be placed anywhere within the polygon. Otherwise some alignment requests might fail or result in unexpected alignments. An alignment request has to calculate a translation vector $\vec t$ so that the reference point is on the line defined by the alignment vector. \begin{equation} \label{eq:center} \alpha\vec a=\vec c+\vec t \end{equation} The alignment vector $\vec a$ is described by a normalized direction vector, which is provided as a tuple \verb|(dx, dy)| to the alignment routine. The absolute value of the alignment vector is given by \verb|a| and might be zero or even negative. The distance of the box is calculated out of the alignment vector so that an additional alignment condition is met. The task of box alignment is splitted into the task of aligning a line segment (a segment of the polygon). The polygon and thus the line segments are considered to be vectored in mathematically positive orientation. Thus the alignment request for a line segment predefines a half space. It might happen, that the alignment of a line segment is restrained by the finite length of the segment in that way, that the alignment should take place based on an end point of the line segment. When this happens for the end point of a line segment and a starting of the following line segment, this very point has to be considered for the alignment. \pagebreak \section{Alignment Primitives} \subsection{Align a point relative to a tangent} The point $\vec p$ should be aligned at the dotted line: \centerline{\includegraphics{boxalignpal}} We introduce the normalized tangential vector $\vec b$ to the alignment vector $\vec a$, $\vec b\perp\vec a$. The solution is defined by equation~(\ref{eq:center}) and \begin{equation} \vec a+\beta\vec b=\vec p+\vec t\,. \end{equation} \subsection{Align a line segment relative to a tangent} The line segment has to be perpendicular to the alignment vector. We can than continue as in section \ref{s:calignline}. However, if the line segment is not perpendicular to the alignment vector, the starting point or end point of the line segment (whichever is closer in terms of the aligment direction) should be considered for the alignment. \subsection{Align a point relative to a circle} The point $\vec p$ should be aligned at the dotted circle: \centerline{\includegraphics{boxalignpac}} The solution is defined by equation~(\ref{eq:center}) and \begin{equation} |\vec a|=|\vec p+\vec t|\,. \end{equation} \subsection{Align a line segment relative to a circle} \label{s:calignline} The line segment between the points $\vec e$ and $\vec f$ should have a single point of contact with the dotted circle: \centerline{\includegraphics{boxalignlac}} We introduce $\vec g=\vec e-\vec f$. Thus the line segment is described by $\vec e-\beta \vec g$ for $\beta=[0;1]$. We introduce the vector $\vec b$ and ask for $\vec b\perp\vec g$. Therefore $\vec b$ is the contract point and it can be calculated by \begin{equation} \vec b=|\vec a|\frac{\vec a-\frac{\vec a\vec g}{\vec g\vec g}\vec g} {\left|\vec a-\frac{\vec a\vec g}{\vec g\vec g}\vec g\right|}\,. \end{equation} We can neglect solutions where the z-component of $\vec b\times\vec g$ is negative in order to restrict the solution to a half space. The solution is defined by equation~(\ref{eq:center}) and \begin{equation} \vec b=\vec e-\beta\vec g+\vec t\,. \end{equation} The solution has to fullfill the condition $\beta=[0;1]$, otherwise the starting point ($\beta<0$) or end point ($\beta>1$) of the line segment should be considered for the alignment. \section{Examples} \includegraphics{boxalignexample} \end{document} pyx-project-pyx-21f71ce/design/classtree.txt000066400000000000000000000032661526513311100212320ustar00rootroot00000000000000# some thoughts: # totally out of date PSOp +--- PSCmd ----+--- canvas | +--- epsfile | +--- tex | +--- _path ---+--- line | | +--- rect | +--- _bpath --+--- bline | | +--- bcurve | | +--- barc | +--- graph --- graphxy | +--- pathstyle +--- linewidth | +--- linestyle | +--- linecap +--- _trafo +--- _bpathel +--- _pathel pathdeco-----+---arrow---+---barrow | +---earrow +---filled +---stroked bbox _texattr ---+--- fontsize +--- halign +--- valign ---+--- vtop | +--- vbox +--- direction +--- style graphattr ---+--- axis ---+--- linaxis | +--- logaxis +--- part ---+--- linpart --- autolinpart | +--- logpart --- autologpart +--- rate --- momrate +--- style ---+--- marker | +--- line | +--- bar +--- data ---+--- datafile | +--- function --- paramfunction +--- key (Exception) --- PyXExcept ---+--- TeXExcept ---+--- TeXCmdError ---+--- TexLeftParenthesisError | | +--- TexRightParenthesisError ? +--- TeXRunError psattr ----+ texattr ---+--- color ---+--- colorgrey +--- colorrgb +--- colorhsb mathtree pyx-project-pyx-21f71ce/design/dtk/000077500000000000000000000000001526513311100172575ustar00rootroot00000000000000pyx-project-pyx-21f71ce/design/dtk/Makefile000066400000000000000000000011741526513311100207220ustar00rootroot00000000000000default: pyx.pdf # pyx.dvi: pyx.tex unitcircle.py arrow.py springs.py text.py piaxis.py arrow.eps springs.eps text.eps valign.eps piaxis.eps latex pyx latex pyx pyx.ps: pyx.dvi dvips pyx pyx.pdf: pyx.ps ps2pdf -sPAPERSIZE=a4 pyx.ps arrow.eps: arrow.py PYTHONPATH=../.. python arrow.py springs.eps: springs.py PYTHONPATH=../.. python springs.py text.eps: text.py PYTHONPATH=../.. python text.py valign.eps: valign.py PYTHONPATH=../.. python valign.py piaxis.eps: piaxis.py PYTHONPATH=../.. python piaxis.py clean: rm pyx.dvi pyx.log pyx.aux pyx.out pyx.ps pyx.pdf arrow.eps springs.eps text.eps valign.eps piaxis.eps pyx-project-pyx-21f71ce/design/dtk/arrow.py000066400000000000000000000004251526513311100207640ustar00rootroot00000000000000from pyx import * c = canvas.canvas() p = path.curve(0, 0, 0.05, 0.3, 0.2, 0.5, 0.5, 0.5) d = [deco.filled([color.gray(0.7)]), deco.stroked([color.gray(0.3), style.linejoin.round])] a = deco.earrow.large(d) c.stroke(p, [style.linestyle.dashed, a]) c.writeEPSfile("arrow") pyx-project-pyx-21f71ce/design/dtk/piaxis.py000066400000000000000000000007571526513311100211370ustar00rootroot00000000000000from math import pi from pyx import * from pyx.graph.axis import linear from pyx.graph.axis.texter import rational g = graph.graphxy(width=8, key=graph.key.key(pos="bl"), x=linear(min=0, max=2*pi, title="$x$", divisor=pi, texter=rational(suffix=r"\pi")), y=linear(title="$y$")) g.plot(graph.data.function("y(x)=sin(x)", title=r"$\sin(x)$")) g.plot(graph.data.function("y(x)=cos(x)", title=r"$\cos(x)$")) g.writeEPSfile("piaxis") pyx-project-pyx-21f71ce/design/dtk/pyx.tex000066400000000000000000000721221526513311100206250ustar00rootroot00000000000000\documentclass{scrartcl} \usepackage[latin1]{inputenc} \usepackage{ngerman,graphicx,listings,hyperref} \lstloadlanguages{Python} \lstset{language=Python,numbers=left,numberstyle=\tiny,numbersep=5pt} \def\PyX{P\kern-.3em\lower.5ex\hbox{Y}\kern-.18em X} \begin{document} \title{Graphiken mit \PyX} \author{Jörg Lehmann, André Wobst} \maketitle \tolerance=1500 \section{Einleitung} Während sich \TeX/\LaTeX{} als De-facto-Standardlösung zum hochwertigen Textsatz herausgebildet haben, ist die Situation bei Programmen zum Erstellen von Abbildungen wesentlich unübersichtlicher. Verschiedenste, zumeist auf bestimmte Anwendungsfälle zugeschnittene, Lösungen konkurrieren miteinander. Ohne Anspruch auf Vollständigkeit seien hier nur \textsc{Metapost}, das vorallem Stärken bei der Erzeugung geometrischer Skizzen aufweist, \textsc{PSTricks}, das sich direkt in eine \LaTeX-Datei einbinden lässt, sowie \textsc{Gnuplot} zur Erstellung von Funktionsgraphen aufgeführt. Ein Hauptkriterium bei der Auswahl einer geeigneten Lösung ist sicherlich die Integration mit \TeX/\LaTeX. Schliesslich sollte die Schriftart in der Abbildung möglichst mit derjenigen im Haupttext übereinstimmen und natürlich sollte es möglich sein, von den \TeX s Möglichkeiten des mathematischen Formelsatzes auch in Beschriftungen wie gewohnt gebrauch zu machen. Die gerade genannten Programme erfüllen diese Anforderung mehr oder minder, entweder bereits qua Design (z.B. im Falle von \textsc{PSTricks}) oder durch ein integriertes (wie bei \textsc{Metapost}) bzw. bei \textsc{Gnuplot} durch ein nachträglich aufgestülpbares \TeX/\LaTeX-Interface. Ist damit also alles in Butter? Leider nein, und der Hauptgrund liegt an der mangelnden Universitaliät der eben beschriebenen Programme. Wer schon einmal versucht hat das Resultat einer numerischen Berechnung mittels \textsc{Metapost} oder \textsc{PSTricks} darzustellen, weiss wie schwierig sich ein solches Unterfangen gestalten kann. Umgekehrt ist es praktisch unmöglich, eine Schemazeichnung in \textsc{Gnuplot} zu erstellen. Und wer kompliziertere programmatische Konstrukte zur Generierung der Abbildung verwenden will, stösst bei allen drei Lösung mehr oder minder schnell an seine Grenzen. Neue Lösungen sind also gefragt und eine ebensolche, die Graphikbibliothek \PyX{}, soll der Gegenstand dieses Artikels sein. Implementiert in der mächtigen, aber gleichzeitig leicht erlernbaren, Skriptsprache \textsc{Python}, stellt \PyX{} alle notwendigen Konstrukte zur programmatischen Erzeugung von qualitativ hochwertigen Abbildungen zur Verfügung. Aufbauend auf ein einer Abstraktion des \textsc{PostScript}-Zeichenmodells und einer integrierten \TeX/\LaTeX-Schnittstelle werden ausgefeilte Techniken zur Realisierung typischer Graphikaufgaben von der schematischen Darstellung bis zum Funktionsgraphen angeboten. Darüber hinausgehend bietet die \TeX-Schnittstelle sogar Möglichkeiten im Textsatz die über das bisher mit \TeX{} mögliche hinausgehen. Während für das Arbeiten mit \PyX{} Grundkenntnisse in Python empfehlenswert sind, zeigt die Erfahrung, dass es, eine gewisse Programmiererfahrung vorausgesetzt, am Anfang ganz gut auch ohne solche geht. Insbesondere sollten die in diesem Artikel vorgestellten Programmbeispiele auch für Python-Neulinge verständlich sein. \section{Installation} \PyX{} setzt einen Python-Interpreter ab Version 2.1 voraus, der im Handumdrehen installiert ist\footnote{Bei vielen Linux-Distributionen sowie unter neueren Versionen von OS X gehört Python zur Grundausstattung. Für Windows stehen unter \url{http://www.python.org} fertige Installer zur Verfügung.}. \PyX{} kann nach dem Auspacken des Archivs im Quellverzeichnis direkt verwendet werden; eine systemweite Installation ist in der Grundkonfiguration mit einem einzigen Befehl \verb|python setup.py install| erledigt. Darüber hinaus wird für die Text-Ausgabe eine funktionsfähige \TeX-Installation vorausgesetzt, die bei den Lesern der technischen Komödie sicher sowieso vorhanden sein dürfte. XXX bis hierher ist eigentlich alles ganz gut, aber jetzt wird's zu theoretisch. Ich würde vorschlagen, an die Sache viel anwendungsbezogener ranzugehen, sprich mit einem Graphen anzufangen. Ob die Erklärung des PostScript-Pfadmodells dann überhaupt noch notwendig ist, denke ich nicht. \section{Grundlagen für Vektorgraphiken: Pfade} Wie bereits erwähnt, abstrahiert \PyX{} das PostScript-Pfadsystem. Dabei lassen sich Pfade aus einzelnen Pfadelementen zusammensetzen, wobei gerade Linienstücke, Bezierkurven und Kreissegmente zur Verfügung stehen. Zusätzlich lässt sich der aktuelle Punkt beim Pfadaufbau neu setzen, so dass Pfade möglich sind, die aus mehreren, nicht zusammenhängenden Pfadteilen bestehen. Natürlich können (Teil-)Pfade auch geschlossen werden. %Dabei werden Pfade als mathematische Objekte aufgefasst, also %keine Linienbreite o.ä. besitzen. \PyX{} ergänzt diese Grundfunktionalität zur Beschreibung von Pfaden durch eine Vielzahl an geometrischen Operationen, die auf Pfaden angewendet werden können. Beispielsweise lassen sich Pfade in Teilstücke zerschneiden und neue Pfade aus bestehenden zusammensetzen. Die Parametrisierung eines Pfades ist sowohl aufgrund der Bogenlänge möglich wie auch mittels einer internen Parametrisierung auf der Basis der im Pfad enthaltenen Pfadelemente. Weiterhin möglich ist die Bestimmung von Schnittpunkten zwischen Pfaden und von geometrische Eigenschaften entlang des Pfades, wie Tangenten und Krümmungsradien. Für viele dieser Funktionen ist es notwendig, Pfade in sogenannte Normpfade zu überführen, die nur noch aus Linien und Bezierkurven bestehen und eine definierte, einstellbare Rechengenauigkeit besitzen. Diese Konvertierung geschieht automatisch, sobald es für die angeforderten Operationen notwendig ist, kann aber auch auch explizit durchgeführt werden. XXX warum nicht was zum Anfang malen, ist doch die Hauptaufgabe von \PyX{}, oder? In einem ersten Beispiel soll die Bogenlänge eines Einheitskreises bestimmt werden. Dies erledigt folgendes kleine Python-Script: \begin{quote} \lstinputlisting{unitcircle.py} \end{quote} Abgespeichert als Datei \verb|unitcircle.py| kann es mit dem Befehl \verb|python unitcircle.py| ausgeführt werden. XXX im folgenden sind wir schon ganz schön tief drinnen, obwohl wir noch gar nichts gezeigt haben. Der weniger geneigte Leser sagt hier eventuell ade. Ist also vielleicht ein schlechtes Beispiel, oder? In der ersten Zeile dieses Beispiels werden die \PyX{}-Module geladen. Die zweite Zeile legt einen Einheitskreis an der Koordinatenposition \verb|(0, 0)| mit dem Radius \verb|1| an. Das Koordinatensystem, das \PyX{} verwendet, ist eine x-y-Ebene, in der die x-Achse horizontal nach rechts verläuft und die y-Achse vertikal nach oben. Als Einheit wird standardmäßig \verb|1 cm| verwendet. In der dritten Zeile des Beispiels wird die Bogenlänge des Kreises ausgegeben. Als Ausgabe erscheint: \begin{quote} \begin{verbatim} (0.062832 t + 0.000000 u + 0.000000 v + 0.000000 w + 0.000000 x) m \end{verbatim} \end{quote} Dieses etwas längliche Ergebnis mag zunächst etwas überraschen. Andererseits zeigt es aber bereits eine Grundfunktionalität des Einheitensystems von \PyX. Es gibt mehrere Längenskalen, die unabhängig voneinander eingestellt werden können. Die Komponenten \verb|t| bis \verb|x| stehen für \glqq{}true\grqq{} (unskalierbar), \glqq{}user\grqq{} (Standardskala), \glqq{}visual\grqq{} (für Abstände), \glqq{}width\grqq{} (für Linienbreiten) und \glqq{}\TeX\grqq{} (für Textgrößen). Nachdem ursprünglich gar keine Einheiten angegeben wurden, wurde in der \glqq{}user\grqq-Längenskala im cm-Maßstab gearbeitet. Bei der Berechnung der Bogenlänge mussten die Einheiten aufgelöst werden. Folglich wird ein Ergebnis in der \glqq{}true\grqq-Längenskala in Metern zurückgeliefert. Die anderen Komponenten werden zwar mit ausgegeben, sind aber alle Null. Die recht komplizierte Darstellung einer Länge als Zeichenkette braucht nicht weiter zu beunruhigen, denn man kann mit diesen Einheiten ganz normal rechnen. Als Vorteil bleibt, dass man beispielsweise die Größe einer fertigen Abbildung und die verwendeten Liniendicken unabhängig voneinander variieren kann. \section{Ausgabe von Pfaden: Dekoratoren} Um Pfade auszugeben, müssen diese zunächst mit Zeichenattributen versehen werden. Diese Aufgabe wird von sogenannten Dekoratoren ausgeführt, die dekorierte Pfade erzeugen, die neben dem Pfad selbst auch Attribute für das Zeichnen und Füllen des Pfades enthalten. Zusätzlich können dekorierte Pfade Teile des ursprünglichen Pfades vom Zeichnen ausschließen und Verziehrungen wie beispielsweise Pfeilspitzen anbringen. Es ist möglich, mehrere Dekoratoren zusammen oder sogar ineinander wirken zu lassen. Um das am Beispiel eines Pfeiles zu demonstrieren, benötigt man noch eine Zeichenfläche, die man nach Einfügen des dekorierten Pfades in eine PostScript oder PDF Datei ausgeben kann. Der entsprechende Quelltext lautet: XXX der Pfeil sieht ehrlicherweise nicht so toll aus (wegen der gestrichelten Linie -> als erstes Beispiel nicht optimal (TeX-Fritzen sind doch visuell empfindliche Zeitgenossen) Notfalls lassen wir einfach die gestrichelte Linie weg. \begin{quote} \lstinputlisting{arrow.py} \end{quote} \begin{figure}[tp] \centerline{\includegraphics[width=4cm]{arrow}} \caption{Pfeil-Beispiel. Die Abbildung ist stark vergrößert, da das Original sehr klein ist und auf die Weise die Details bequem sichtbar werden.} \label{fig:arrow} \end{figure} Die Ausgabe, die durch dieses Python-Script erzeugt wird, ist in Abbildung~\ref{fig:arrow} zu sehen. Zunächst werden in Zeile 2 und 3 eine Zeichenfläche \verb|c| und ein Pfad \verb|p| angelegt. In Zeile 4 und 5 wird eine Liste aus zwei Dekoratoren angelegt, die zum Zeichen und Füllen des Pfeils verwendet werden sollen. Der entsprechende Pfeildekorator wird in Zeile 6 aus dem bestehenden Pfeildekorator \verb|deco.earrow.large| erzeugt, also eine abgewandelte Version des schon existierenden Dekorators gebildet. In Zeile 7 kann nun die eigentliche Ausgabe stattfinden. Die ausführliche Schreibweise wäre, für den Pfad selbst nochmal einen \verb|stroked|-Dekorator anzuwenden und das Ganze mittels der \verb|canvas|-Methode \verb|show| auszugeben. Das würde dann so lauten: \verb|c.show(p, [deco.stoked([style.linestyle.dashed]), a])|. Nachdem man Pfade aber sehr oft einfach nur Zeichen oder Füllen möchte, gibt es die zwei \verb|canvas|-Methoden \verb|stroke| und \verb|fill|, die jeweils den unmodifizierten Dekorator \verb|deco.stroked| und \verb|deco.filled| zur Zeichenattributliste hinzufügen. In Wirklichkeit ist Zeile 7 in Beispiel also identisch zu \verb|c.show(p, [deco.stoked, style.linestyle.dashed, a])|. Hier werden also Dekoratoren und Zeichenattribute auf der selben Hierarchieebene gemischt, was bedeutet, dass die Zeichenattribute dann für alle Dekoratoren zu verwenden sind. Soweit so gut, doch der aufmerksame Leser mag einwenden, dass das gar nicht dem entspricht, was in der Abbildung gezeigt ist. Dort ist nämlich die Umrandung des Pfeils nicht gestrichelt. In der Tat würde diese Linie gestrichelt dargestellt, hätte nicht bereits der Pfeildekorator \verb|deco.earrow.large| die Eigenschaft, den Linienstil für seinen Wirkungsbereich auf durchgezogen zu schalten. Aber man kann dieses Verhalten durch das zusätzliche Attribut \verb|deco.linestyle.clear| auf der richtigen Hierarchieebene beim Modifizieren eines Dekorators sogar wieder entfernen! Wenn man \verb|deco.linestyle.clear| in die Liste \verb|d| einfügt, erhält man eine gestrichelte Pfeilumrandung. Das Beispiel eben hat gezeigt, dass die Verknüpfung von Zeichenattributen im Detail recht komplex werden kann. Gleichzeitig ermöglicht \PyX{} es, solche komplexen Strukturen durch geeignete Dekoratoren überhaupt darzustellen und einmal vorgefertigt immer einsatzbereit zur Verfügung zu haben. Der Pfeildekorator, der automatisch auf durchgezogene Linien schaltet, ist so ein Beispiel, das zunächst unnötig komplex anmutet, aber im praktischen Anwendungsfall beinahe immer automatisch das gewünschte Ergebnis liefert. \section{Modifikation von Pfaden: Deformatoren} Deformatoren werden dazu verwendet, einen gegebenen beliebigen Pfad in einen anderen Pfad umzuwandeln. Ein ganz einfaches Beispiel sind affine Transformationen wie die Translation oder die Rotation eines Pfads. Mehrere solche Umformungen sind normalerweise nicht kommutativ. XXX hier kommt die komplizierte Methode vor der einfachen. Ebenso wird gleich auf ein Problem (Hierarchieebenen) hingewiesen, das für viele Benutzer gar keines sein dürfte. Man kann Pfade explizit umformen, indem man die \verb|deform|-Methode eines Deformators verwendet, aber es ist auch möglich, Deformatoren bei der Ausgabe eines Pfades direkt anzuwenden. Allerdings müssen die Deformatoren direkt auf der ersten Hierarchieebene angegeben sein, können also nicht als Argumente von Dekoratoren auftreten. Deformatoren werden dann stets in der Reihenfolge ihres Auftretens noch vor dem Dekorieren auf den gegebenen Pfad angewendet. Durch diese Einschränkungen bleibt das Ganze durchschaubar und vor allem auch wohldefiniert. Trotzdem lassen sich damit sehr elegante Ergebnisse erreichen, wie das folgende Beispiel zeigt, das drei, kreisförmig angeordnete, durch Federn verbundene Massen darstellt. \begin{quote} \lstinputlisting{springs.py} \end{quote} \begin{figure}[tp] \centerline{\includegraphics{springs}} \caption{Feder-Beispiel} \label{fig:springs} \end{figure} Das Ergebnis ist in Abbildung~\ref{fig:springs} zu sehen. In den ersten zehn Zeilen dieses Beispiels wird wie vorher gezeigt das \PyX-Paket geladen, ein paar Parameter definiert und eine Zeichenfläche erzeugt. Interessant wird es ab Zeile 11, wo ein kreisförmiger Pfad generiert wird, der später in die drei Federn umgeformt werden soll. Dazu wird in Zeile 12 und 13 zunächst eine Liste von Bogenlängen erzeugt, auf denen die Massen platziert werden. Die Variable \verb|i| läuft mittels Python's \verb|range|-Funktion über die Werte \verb|0|, \verb|1|, und \verb|2|. Mit der Schleife beginnend auf Zeile 14 wird der ursprüngliche \verb|springcircle| in drei Einzelteile zerlegt, die der Variable \verb|springsegment| zugewiesen sind. Mit einem geeigneten Zykliod-Deformator kann dieses Pfadstück in den Zeilen 15--17 direkt ausgegeben werden. Interessant ist auch der zweite Deformator, der auf Zeile 17 steht. Dieser glättet den gegeben Pfad, was in diesem Beispiel zu den etwas abgerundet angedeuteten Übergängen zwischen den geraden Federendstücken und dem gedrillten Federmittelstück führt. In Zeile 18 und 19 werden die drei Massen gezeichnet und die Zeilen 20 und 21 fügen die beiden Kreise hinzu, die das skizzierte Massesystem einschließen. % Die Bestimmung der Schwingungsmoden dieses System soll hier nicht % weiter verfolgt werden, gehört das doch eher in eine einführende % Mechanik-Vorlesung denn in die Technische Komödie. \section{Erzeugung von Text: die \TeX/\LaTeX-Integration} Für die Textausgabe in \PyX{} wird \TeX{} oder alternativ \LaTeX{} verwendet. Die Herausforderung besteht dabei darin, diese Programme möglichst perfekt in das Graphiksystem zu integrieren. Zu diesem Zweck ist im \verb|text|-Modul ein \verb|texrunner| implementiert, dessen Instanzen jeweils ein laufendes \TeX{} oder \LaTeX{} steuern. Normalerweise wird nur ein einziger solcher \verb|texrunner| benötigt und dieser wird von dem System als \verb|defaulttexrunner| auch schon zu Beginn initialisiert. Die wesentlichen Schritte bei der Erzeugung von Text sind dann: \begin{itemize} \item \TeX{} oder \LaTeX{} wird als normaler Prozess gestartet und überwacht. \PyX{} kann dann Dinge auf den Eingabestrom des Prozesses schreiben und analysiert gleichzeitig, wie \TeX{} oder \LaTeX{} darauf reagiert. \item Sobald Text gesetzt werden muss, wird dieser von \PyX{} mit entsprechenden Befehlen versehen, die den Text in eine Box setzen und diese Box in der \verb|dvi|-Datei als einzelne Seite ausgeben. Die Größe der Box wird direkt auf dem Ausgabestrom zurückgegeben und steht instantan zur Verfügung steht. Auch merkt das System an dieser Stelle zuverlässig, ob Probleme beim Setzen des Textes aufgetreten sind. \item Sobald der gesetzte Text selbst benötigt wird, wird die \verb|dvi|-Datei analysiert. Das ist in der Regel erst bei der Erzeugung der Ausgabedateien nötig. Normalerweise muss \TeX{} bzw. \LaTeX{} dazu beendet werden. Die \verb|texrunner|-Instanz macht dies automatisch, wie auch das erneute Starten eines \TeX- bzw. \LaTeX-Prozesses, falls das notwendig wird. Es besteht auch die Möglichkeit, die \verb|ipc|-Option von \TeX/\LaTeX{} auszunutzen, so sie in der vorhandenen \TeX-Installation zur Verfügung steht und damit die \verb|dvi|-Datei zu analysieren, ohne \TeX{} bzw. \LaTeX{} beenden zu müssen. \item \PyX{} baut aus den Daten, die in der \verb|dvi|-Datei stehen, entsprechenden PostScript- bzw. PDF-Code. Dabei werden momentan ausschließlich Type1-Fonts verwendet, wie sie bei aktuellen \TeX-Installation auch von dvips oder pdf\TeX{} benutzt werden. \PyX{} arbeitet ähnlich zu diesen Programmen und verwendet die vorhandene \TeX{}-Installation, löst also virtuelle Fonts auf, schlägt in der vorliegenden \verb|map|-Datei nach und baut die Type1-Fonts heruntergerechnet auf die benötigten Gylphen ein. Im Grunde ist ein kleiner Teil von \PyX{} also ein \verb|dvips| und ein \verb|dvipdf|.\footnote{In der Tat steht ein kleines Kommandozeilenprogramm zur Verfügung, welches aus einer gegebenen \texttt{dvi}-Datei eine PostScript oder eine PDF-Datei erzeugt. Eine solche Funktionalität ist auf der Basis von \PyX{} mit einer handvoll Zeilen implementiert.} \item Der \verb|dvi|-Interpreter von \PyX{} unterstützt einen wohldefinierten Satz an \verb|\special|-Anweisungen. Eine Anpassung an die \verb|graphic[s/x]|- und \verb|color|-Pakete wird mitgeliefert. Darüber hinaus ist es möglich, im gesetzten Text sogenannte Marker einzubauen und deren Position in der Ausgabe wiederzufinden. \end{itemize} Die Integration von \TeX/\LaTeX{} in \PyX{} bedeutet, dass man im normalen Anwendungfall überhaupt nichts vom verwendeten \TeX/\LaTeX{} merkt, außer, dass man für die Textausgabe einen echten \TeX-Interpreter zur Hand hat und in programmiertechnischer Hinsicht keinerlei Einschränkungen auferlegt sind. Wie das am Ende aussieht, soll auch wieder an einem Beispiel demonstriert werden. Dazu folgendes kleines Programm: \begin{quote} \lstinputlisting{text.py} \end{quote} Die entstehende Ausgabe lohnt nicht des Abdrucks als extra Abbildung -- in der Ausgabedatei erscheint schlicht und einfach der angegebene Text. Neu an diesem Beispiel ist nur die dritte Zeile, in der die \verb|canvas|-Methode \verb|text| aufgerufen wird. Diese fügt einen Text an der Position, die mit den ersten beiden Parametern beschrieben wird, ein. Das \verb|r| vor der Zeichenkette führt dabei dazu, dass das Zeichen \verb|\| innerhalb der Zeichenkette nicht als \glqq{}escape\grqq-Zeichen interpretiert wird. Diese nützlichen sogenannten \glqq{}raw-strings\grqq{} in Python sind natürlich insbesondere für Zeichenketten, die \TeX{}-Syntax enthalten, sehr praktisch. Ausführlicher geschrieben ist die dritte Zeile identisch zu dem Befehl \verb|c.insert(text.text(0, 0, r"Das ist eine Textausgabe mit \TeX."))|, wobei die Funktion \verb|text.text| wiederum eine Abkürzung für den Aufruf der Methode \verb|text| in der Instanz \verb|text.defaulttexrunner| ist. Der Rückgabewert dieser \verb|text|-Methode ist dabei eine spezielle Zeichenfläche, die den Inhalt der jeweiligen \verb|dvi|-Seite enthält. Da man Zeichenflächen per \verb|insert|-Methode ineinander einfügen kann, erscheint der Inhalt der Seite in der Ausgabezeichenfläche, die in der Variablen \verb|c| gespeichert ist. Statt die Ausgabe der \verb|text|-Methode in die Ausgabe einzubinden, könnte man stattdessen natürlich auch deren Größe abfragen oder ähnliches. \begin{figure}[tp] \centerline{\includegraphics{valign}} \caption{Beispiel der vertikalen Ausrichtung von Text mittels Textattributen} \label{fig:valign} \end{figure} Abbildung~\ref{fig:valign} zeigt beispielhaft anhand verschiedener vertikaler Ausrichtungsmethoden, was im Rahmen der \TeX-Integration in \PyX{} möglich ist. Die Textausrichtung, wie auch viele andere Eigenschaften, lassen sich dabei ganz einfach anhand von Attributen setzen. Beispiele mit zugehörigem Quellcode finden sich auf der \PyX-Beispielseite unter \url{https://pyx-project.org/examples/}. \section{Komplexe Graphikaufgaben: Graphen} Aufgrund der Praxisrelevanz für die Autoren wurde bereits zu einem frühen Zeitpunkt in der \PyX-Entwicklung damit begonnen, Komponenten für die Erstellung von Daten- und Funktionsgraphen zu implementieren. Eine Designrichtlinie war dabei von Beginn an die Zerlegung eines solchen Systems in Einzelteile, die möglichst unabhängig voneinander sind und die mit einfachen Schnittstellen miteinander kommunizieren. Die grobe Struktur des Systems lautet: \begin{description} \item[Graph:] Der eigentliche Graph wird durch eine Graph-Instanz repräsentiert. Dieser legt die Graphengeometrie fest und dient als Container für alle graph-spezifischen Daten. \item[Achsen:] Die Achsen sind dafür zuständig, die Eingabedaten auf das graphinterne Koordinatensystem umzurechnen. Dabei ist es möglich, als Eingabedaten auch anderes als kontinuierliche Zahlen zu verwenden. beispielsweise sind diskrete Achsen möglich, wie sie für die saubere Implementation von Balkengraphen unverzichtbar sind. Auch Achsenteilungen % XXX was meinst Du hier mit Achsenteilungen? Splitaxis? sind möglich, indem man kontinuierliche Achsen in diskret geteilte Achsen schachtelt. Außerdem müssen Achsen eine graphische Repräsentation ihrer selbst entlang eines beliebigen Pfades erzeugen können, was wiederum durch eine Reihe von Einzelkomponenten erledigt wird: \begin{description} \item[Achsenteilung:] Bestimmung von Achsenteilungen, wobei manuell gesetzte Achsenstriche mit automatisch erzeugten Achsenstrichen gemischt werden können. Die Achsenteilung für normale Zahlenachsen basiert auf rationalen Zahlen und ist frei von jeglichen Rundungsproblemen. \item[Beschriftung von Achsenstrichen:] Die Erzeugung von Text passend zu den Achsenstrichen ist als getrennte Komponente ausgeführt und somit leicht änderbar. \item[Bewertung von Achsenteilungen:] Bei automatischer Achsenteilung sind normalerweise verschiedene Teilungen möglich, die bewertet werden müssen, um die beste Teilung zu finden. Dabei werden auch Abstände zwischen den Texte der Achsenstriche hinzugezogen. \item[Zeichner:] Der Zeichner ist eine Komponente, die die Ausgabe der Achse ausführt. Auch dieser Teil lässt sich anpassen oder auch komplett ersetzen. \end{description} \item[Daten:] Verschiedene Datenkomponenten bereiten Eingabedaten gegeben durch Zahlenspalten einer Datei, durch eine Funktion oder anderen Quellen für die Benutzung im Graphsystem vor. Insbesondere werden die Daten dabei mit Spaltennamen versehen, was die spätere Zuordnung zu Achsen oder Stileigenschaften ermöglicht. \item[Stile:] Graphstile erzeugen aus den eingehenden Daten eine graphische Repräsentation. Es gibt also beispielsweise Stile zum Zeichnen von Symbolen, Linien und Fehlerbalken und vieles andere mehr. Interessant ist die Eigenschaft, dass sich verschiedene Stile gleichzeitig auf Daten anwenden lassen. Außerdem lassen sich durch Implementation eigener Stile Dinge realisieren, die zunächst überhaupt nicht nach einem Graph aussehen sondern eher beispielsweise wie eine Tabelle. Dabei lässt sich dann aber gleichzeitig die Komponentenstruktur eines Graphen ausnutzen. \item[Legende:] Eine Legende schließlich erzeugt eine graphische Darstellung, die Stile mit Titeln der gezeigten Daten verknüpft. \end{description} Die Flexibilität des Graphsystems führt zu einer entsprechend großen Anzahl unterschiedlicher Anwendungsbeispiele. An dieser Stelle soll nur ein einfaches Beispiel gezeigt werden, um die prinzipielle Funktionsweise vorzustellen. Darüber hinaus ist ein Besuch auf der \PyX-Beispielseite unter \url{https://pyx-project.org/examples/} sehr zu empfehlen. \begin{figure}[tp] \centerline{\includegraphics{piaxis}} \caption{Graph-Beispiel} \label{fig:piaxis} \end{figure} Die Abbildung~\ref{fig:piaxis} wird durch folgendes Programm erzeugt: \begin{quote} \lstinputlisting{piaxis.py} \end{quote} In Zeile 1 wird die Variable \verb|pi| aus dem \verb|math| Modul von Python geladen. Dann folgt wieder der übliche Import der \PyX-Module. In Zeile 3 und 4 werden zwei Klassen direkt importiert. Durch Zeile 3 wird beispielsweise erreicht, dass eine lineare Achse statt unter ihrem langen Namen \verb|pxy.graph.axis.linear| direkt unter dem Namen \verb|linear| zur Verfügung steht. In den Zeilen 6 bis 9 wird eine Graph-Instanz \verb|g| angelegt. Als Grapheigenschaften werden dabei unter anderem \verb|x| und \verb|y|-Achsen mit speziellen Einstellungen explizit gesetzt. In Zeile 11 und 12 werden zwei Funktionen zum Graph hinzugefügt und schon ist alles fertig und kann in Zeile 14 in einer Datei gesichert werden. \section{Entwicklung von \PyX} XXX wie gesagt -> löschen (bis auf den letzten Absatz) Aber: wir brauchen noch was zu den ausgefalleneren TeX-Sachen und einen Ausblick in die Zukunft. Das \PyX-Projekt ist, wie wohl die Mehrzahl der OpenSource-Projekte, zunächst aus Eigenbedarf der beiden Projektgründer und Hauptentwickler, Jörg Lehmann und André Wobst, Mitte 2000 gestartet wurden. Diesem Start eines sich schon seinerzeit abzeichnenden langwierigen Entwicklungsprozesses gingen zahlreiche Diskussionen und Tests existierender anderer Lösungen voraus. Ursprünglich waren die Entwickler Benutzer von GLE (\url{http://glx.sourceforge.net/}), was sich wie \PyX{} auch vor allem dadurch auszeichnete, dass sich damit Zeichnungen wie auch Daten- und Funktionsgraphen erstellen lassen. Die fehlende \TeX-Anbindung wurde durch gletex (\url{http://www.physik.uni-augsburg.de/~wobsta/gletex/}) im Rahmen der bescheidenen Möglichkeiten hinzugefügt, aber das eigentliche Problem der völlig fehldesignten GLE-eigenen Sprache konnte auf die Weise nicht angegangen werden. Zunächst trennten sich die Wege der Entwickler (auch räumlich) und während Jörg Lehmann versuchte, eine GLE-Ersatzlösung auf der Basis von Perl und einem GLE-Übersetzer zu starten und André Wobst einlud, daran mitzuwirken, beschäftigte sich dieser lieber mit Graphen-Lösungen auf der Basis von {\font\logo=logo10\logo{}METAPOST}, allerdings am Ende frustriert ob der Probleme aufgrund der für dieses Problem ungeeigneten, zu sehr auf Zeichnen spezialisierten und ansonsten unhandlich unvollständigen Sprache. Als schließlich die Entwickler wieder zusammentrafen, starteten sie das \PyX-Projekt auf der Basis der Programmiersprache Python und verwarfen die Idee, eine vollständige sprachliche GLE-Kompatibilität zu schaffen. Gleichwohl besaßen frühe Versionen eine Endbenutzer-Sprachschicht, die allein mit Funktionsaufrufen und nicht mit Objektinstanzen arbeitete. Allerdings liessen sich in Python keine Strukturen schaffen, die einem GLE-typischen Abschnitt zur Beschreibung eines Graphen entsprachen, weshalb hier relativ bald auf Objektmethoden ausgewichen wurde. Schließlich setzte sich die Benutzung von Objektinstanzen auch für Zeichenflächen, Pfade und dergleichen durch. In den ersten frühen Versionen wurde übrigens \verb|dvips| verwendet, um \TeX{} anzubinden. Erst deutlich später wurden die Einschränkungen, die diese Lösung mit sich brachte, Grund genug ein eigenen \verb|dvi|-Parser zu schreiben. Bereits 2001 wurden die Grundlagen soweit fertig, dass Ende 2001 für das Erzeugen einer komplexen Tabelle das erste Mal \PyX{} den Vorzug gegenüber einer \TeX{} bzw. \LaTeX{} Lösung bekam. Im Frühjahr 2002 wurde das erste Mal ein A0-Poster mit \PyX{} erstellt, wobei die Graphen noch mit GLE erzeugt wurden. Zu diesem Zeitpunkt wurde der Quellcode einschließlich seiner Geschichte bis zurück ins Jahr 2000 bei SourceForge veröffentlicht. Im Herbst 2002 wurde \PyX{} 0.1 freigegeben und seit Version 0.3.1 vom April 2003, die auf freshmeat bekanntgegeben wurde, erfreut sich das Projekt zunehmender Nutzung auch durch nicht den Entwicklern nahestehenden Personen. Zudem wurden mit Michael Schindler und Gert-Ludwig Ingold zwei Mitstreiter gewonnen, die das Projekt zusätzlich voranbringen. Die Entwicklung von \PyX{} ist aber keineswegs ein geradliniger Prozess. Insbesondere hat die Erarbeitung von effizienten Strukturen für den Endanwender viele Entwicklungsschritte und deshalb auch inkompatible Veränderungen zwischen den Versionen notwendig gemacht. Mittlerweile sind viele der Strukturen aber schon sehr ausgereift und stabil, wie man auch an den immer wieder neu freigegebenen Versionen beobachten kann. Die aktuelle Version \PyX{} 0.8.1 vom August 2005 wird von den Entwicklern jedoch nach wie vor als Alpha-Release bezeichnet, was vor allem ausdrücken soll, dass in bestimmten Bereichen noch Aktualisierungen geplant sind, die zumindest teilweise auch vom Anwenderstandpunkt aus sichtbar sein werden. Nachdem aber bereits sehr viele \PyX-Programme existieren, sind größere, nicht einfach handhabbare Umstellungen in zukünftigen Versionen zunehmend sehr unwahrscheinlich. An dieser Stelle möchten wir uns ganz herzlich bei DANTE e.V. und dessen Vorstand bedanken, der im Sommer 2004 auf eine Anfrage hin ganz unbürokratisch zugestimmt hat, die relativ regelmäßig drei bis vielmal im Jahr stattfindenden Entwicklertreffen finanziell durch die Übernahme von anfallenden Fahrtkosten zu unterstützen. Durch die mittlerweile wieder vorhandene räumliche Trennung der Hauptentwickler ist diese Förderung enorm wichtig für die erfolgreiche Fortführung des Projekts. \end{document} pyx-project-pyx-21f71ce/design/dtk/springs.py000066400000000000000000000013341526513311100213170ustar00rootroot00000000000000from pyx import * n = 3 # number of masses r = 3.0 # system radius rcyc = 0.3 # radius of cycloid nl = 13 # number of cycloid half-loops rc = 0.5 # radius of masses eps = 0.03 # extra spacing for surrounding circles c = canvas.canvas() springcircle = path.circle(0, 0, r) masspositions = [i*springcircle.arclen()/n for i in range(n)] for springsegment in springcircle.split(masspositions): c.stroke(springsegment, [deformer.cycloid(rcyc, nl), deformer.smoothed(radius=0.1)]) for x, y in springcircle.at(masspositions): c.fill(path.circle(x, y, rc)) c.stroke(path.circle(0, 0, r - rc - eps)) c.stroke(path.circle(0, 0, r + rc + eps)) c.writeEPSfile("springs") pyx-project-pyx-21f71ce/design/dtk/text.py000066400000000000000000000001611526513311100206130ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.text(0, 0, r"Das ist eine Textausgabe mit \TeX.") c.writeEPSfile("text") pyx-project-pyx-21f71ce/design/dtk/unitcircle.py000066400000000000000000000000751526513311100217740ustar00rootroot00000000000000from pyx import * p = path.circle(0, 0, 1) print(p.arclen()) pyx-project-pyx-21f71ce/design/dtk/valign.py000066400000000000000000000034451526513311100211170ustar00rootroot00000000000000from pyx import * text.set(mode="latex") text.preamble(r"\usepackage{exscale}") spameggswidth = 2.7 arrowdist = 0.1 arrowlen = 0.2 textdist = 0.1 c = canvas.canvas() def label(x, y, width, t): # x == -1 -> left; x == 1 -> right c.stroke(path.line(width*(0.5*x+0.5) + x*arrowdist, y, width*(0.5*x+0.5) + x*(arrowdist + arrowlen), y), [deco.barrow.Small]) c.text(width*(0.5*x+0.5) + x*(arrowdist + arrowlen + textdist), y, t, [text.vshift.mathaxis, text.boxhalign(0.5-0.5*x)]) t = c.text(0, 0, r"\noindent spam \& eggs", [text.parbox(2.7), text.size.Huge]) t2 = text.text(0, 0, "eggs", [text.size.Huge]) c.stroke(t.bbox().path(), [style.linewidth.THin]) c.stroke(path.line(0, 0, 2.7, 0) + path.line(0, t2.depth-t.depth, 2.7, t2.depth-t.depth), [style.linestyle.dashed, style.linewidth.THin]) label(-1, t.height, spameggswidth, "valign.top") label(-1, 0.5*(t.height-t.depth), spameggswidth, "valign.middle") label(-1, -t.depth, spameggswidth, "valign.bottom") label(1, 0, spameggswidth, "parbox.top") label(1, 0.5*(t2.depth-t.depth), spameggswidth, "parbox.middle") label(1, t2.depth-t.depth, spameggswidth, "parbox.bottom") mathypos = -2.5 mathstr = r"\sum_{i=0}^{\infty}\frac{1}{i^2}=\frac{1}{6}\pi^2" t = c.text(0, mathypos, mathstr, [text.mathmode, text.vshift.mathaxis, text.size.LARGE]) t2 = text.text(0, mathypos, mathstr, [text.mathmode, text.size.LARGE]) c.stroke(t.bbox().path(), [style.linewidth.THin]) c.stroke(path.line(0, mathypos, t.width, mathypos)+ path.line(0, mathypos+t.height-t2.height, t.width, mathypos+t.height-t2.height), [style.linestyle.dashed, style.linewidth.THin]) label(-1, mathypos, t.width, "vshift.mathaxis") label(1, mathypos+t.height-t2.height, t.width, "baseline") c.writeEPSfile("valign") pyx-project-pyx-21f71ce/design/invalid1.py000066400000000000000000000033541526513311100205630ustar00rootroot00000000000000#!/usr/bin/env python import sys;sys.path.insert(0, "..") from math import * from pyx import * # File for invalid parametrisations of Bezier curves # visualise the constraints def fx(x, sign1): if x < 1/3.0: # a_x > 0 if sign1 == "upper": return -x + abs(x) else: return -x - abs(x) else: if sign1 == "upper": return x - abs(x) else: return x + abs(x) def boundx(x): if x < 1/3.0: return 1-3*x else: return 3*x-1 def fy(y, sign2): if y < 0: # a_y > 0 if sign2 == "upper": return 1-y + sqrt(1+y+y*y) else: return 1-y - sqrt(1+y+y*y) else: if sign2 == "upper": return y-1 - sqrt(1+y+y*y) else: return y-1 + sqrt(1+y+y*y) def boundy(y): if y < 0: return -3*y else: return 3*y def doplot(xtitle, con): g = graph.graphxy(width=10, x=graph.axis.lin(title=xtitle, min=-5, max=5), y=graph.axis.lin(), key=graph.key.key(pos="tc"), ) g.plot(graph.data.function("y(x)=0", points=2, title=None), [graph.style.line()]) g.plot(graph.data.function("y(x)=bound(x)", title=None, context=con, points=101), [graph.style.line()]) g.plot(graph.data.function("y(x)=f(x, 'upper')", title="upper sign", context=con, points=101), [graph.style.line([color.rgb.red])]) g.plot(graph.data.function("y(x)=f(x, 'lower')", title="lower sign", context=con, points=101), [graph.style.line([color.rgb.green])]) return g c1 = doplot(r"$\Delta x$", {"f":fx, "bound":boundx}) c2 = doplot(r"$\Delta y$", {"f":fy, "bound":boundy}) c1.insert(c2, [trafo.translate(0, c1.bbox().bottom() - c2.bbox().top() - 0.5)]) c1.writePDFfile() pyx-project-pyx-21f71ce/design/invalid2.py000066400000000000000000000030611526513311100205570ustar00rootroot00000000000000#!/usr/bin/env python3 import sys;sys.path.insert(0, "..") from math import * from pyx import * # File for invalid parametrisations of Bezier curves # Draws a sketch of the areas where invalid params are to be expected def lhs(x, y, sign1): if sign1 > 0: return -3*y*(-x + abs(x)) else: return -3*y*(-x - abs(x)) def rhs(x, y, sign2): if sign2 > 0: return (1-3*x) * (1-y + sqrt(1+y+y*y)) else: return (1-3*x) * (1-y - sqrt(1+y+y*y)) def f(x, y): xsigns = [-1, 1] ysigns = [-1, 1] if 0 < x < 1: xsigns = [1] if y > -1: ysigns = [-1] val = float("inf") for sign1 in xsigns: for sign2 in ysigns: val = min(val, abs(lhs(x,y,sign1) - rhs(x,y,sign2))) return val xmin, xmax, xn = -2, 3, 250 xvalues = [xmin + (xmax-xmin)*i/(xn-1) for i in range(xn)] ymin, ymax, yn = -3, 2, 250 yvalues = [ymin + (ymax-ymin)*i/(yn-1) for i in range(yn)] d = [] for x in xvalues: for y in yvalues: d.append((x, y, log(f(x, y)))) g = graph.graphxy(width=10, x=graph.axis.lin(title=r"$\Delta x$", min=xmin, max=xmax), y=graph.axis.lin(title=r"$\Delta y$", min=ymin, max=ymax), ) g.plot(graph.data.points(d, x=1, y=2, color=3, title=None), [graph.style.density(gradient=color.rgbgradient.Rainbow)]) g.dolayout() g.plot(graph.data.function("x(y)=(-1-2*y-sqrt((1+2*y)**2+3))/3.0"), [graph.style.line([style.linestyle.dotted])]) g.plot(graph.data.function("x(y)=(-1-2*y+sqrt((1+2*y)**2+3))/3.0", max=-1), [graph.style.line([style.linestyle.dotted])]) g.writePDFfile() pyx-project-pyx-21f71ce/design/invalid3.py000066400000000000000000000017411526513311100205630ustar00rootroot00000000000000#!/usr/bin/env python import sys;sys.path.insert(0, "..") from math import * from pyx import * # File for invalid parametrisations of Bezier curves # Some examples def Dx_m(Dy): return (-1-2*Dy-sqrt((1+2*Dy)**2+3))/3.0 def Dx_p(Dy): return (-1-2*Dy+sqrt((1+2*Dy)**2+3))/3.0 def acurve(Dx_fct, Dy, Dx=None): if Dx is None: Dx = Dx_fct(Dy) p = path.curve(0,0, 0,1, Dx,1+Dy, 1,0) c = canvas.canvas() c.stroke(p, [deco.shownormpath()]) c.text(-0.2, -10*unit.x_pt, r"\noindent$\Delta x=%g $\par\noindent$\Delta y=%g$"%(Dx,Dy), [text.parbox(4), text.size.footnotesize]) return c dx = 3 dy = -3 cc = acurve(Dx_m, 0) c = acurve(Dx_m, 1); cc.insert(c, [trafo.translate(dx, 0)]) c = acurve(Dx_m, -1); cc.insert(c, [trafo.translate(2*dx, 0)]) c = acurve(Dx_m, -2); cc.insert(c, [trafo.translate(0, dy)]) c = acurve(Dx_p, -1); cc.insert(c, [trafo.translate(dx, dy)]) c = acurve(Dx_p, -3); cc.insert(c, [trafo.translate(2*dx, dy)]) cc.writePDFfile() pyx-project-pyx-21f71ce/design/invalid4.py000066400000000000000000000026041526513311100205630ustar00rootroot00000000000000#!/usr/bin/env python import sys;sys.path.insert(0, "..") from math import * from pyx import * # File for invalid parametrisations of Bezier curves # Check a-posteriori the sign of Delta y for the square-root solution of Delta x def Dx_m(y): return (-1-2*y-sqrt((1+2*y)**2+3))/3.0 def Dx_p(y): return (-1-2*y+sqrt((1+2*y)**2+3))/3.0 con = {"Dx_m":Dx_m, "Dx_p":Dx_p} g = graph.graphxy(width=10, x=graph.axis.lin(), y=graph.axis.lin(min=-2, max=2), key=graph.key.key(pos="bl"), ) g.plot(graph.data.function("x(y)=6*y*Dx_m(y)", title="minus-sol, lhs", context=con), [graph.style.line([color.rgb.red])]) g.plot(graph.data.function("x(y)=(1-3*Dx_m(y))*(1-y-sqrt(1+y+y*y))", title="minus-sol, minus-rhs", context=con), [graph.style.line([color.rgb.blue, style.linestyle.dashed])]) g.plot(graph.data.function("x(y)=6*y*Dx_p(y)", title="plus-sol, lhs", context=con), [graph.style.line([color.rgb.green])]) g.plot(graph.data.function("x(y)=(1-3*Dx_p(y))*(1-y+sqrt(1+y+y*y))", title="plus-sol, plus-rhs", context=con), [graph.style.line([style.linestyle.dashed])]) g.plot(graph.data.function("x(y)=(1-3*Dx_p(y))*(1-y-sqrt(1+y+y*y))", title="plus-sol, minus-rhs", context=con), [graph.style.line([style.linestyle.dotted])]) g.plot(graph.data.function("x(y)=(1-3*Dx_m(y))*(1-y+sqrt(1+y+y*y))", title="minus-sol, plus-rhs", context=con), [graph.style.line([style.linestyle.dotted])]) g.writePDFfile() pyx-project-pyx-21f71ce/design/palettetest.py000077500000000000000000000025521526513311100214140ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: ISO-8859-15 -*- import sys sys.path.insert(0, "..") import math from math import * from pyx import * from pyx.graph import axis, data # define some functions for the color values: def red(x): return 2*x*(1-x)**5 + 3.5*x**2*(1-x)**3 + 2.1*x*x*(1-x)**2 + 3.0*x**3*(1-x)**2 + x**0.5*(1-(1-x)**2) def green(x): return 1.5*x**2*(1-x)**3 - 0.8*x**3*(1-x)**2 + 2.0*x**4*(1-x) + x**4 def blue(x): return 5*x*(1-x)**5 - 0.5*x**2*(1-x)**3 + 0.3*x*x*(1-x)**2 + 5*x**3*(1-x)**2 + 0.5*x**6 # use the implemented converter for the grey value: def grey(x): return color.rgb(red(x), green(x), blue(x)).grey().color["gray"] # plot the color values g = graph.graphxy(width=10, ratio=1) g.plot(data.function("y(x)=red(x)", min=0, max=1, context=locals()), [graph.style.line([color.rgb.red])]) g.plot(data.function("y(x)=green(x)", min=0, max=1, context=locals()), [graph.style.line([color.rgb.green])]) g.plot(data.function("y(x)=blue(x)", min=0, max=1, context=locals()), [graph.style.line([color.rgb.blue])]) g.plot(data.function("y(x)=grey(x)", min=0, max=1, context=locals())) # plot the colors n = 200 x = 0 for i in range(n): t = i * 1.0 / (n-1) g.fill(path.rect(x, -2, 10.5/(n-1), 1), [color.rgb(red(t), green(t), blue(t))]) x += 10.0 / n g.writeEPSfile("palettetest", paperformat=document.paperformat.A4) g.writePDFfile("palettetest") pyx-project-pyx-21f71ce/design/protokoll-entwicklertreffen-april-2004.txt000066400000000000000000000052221526513311100264730ustar00rootroot00000000000000Pfade (epsilon): ---------------- Als Argumente von findsubpath werden auch tupel zugelassen, die ein integer + den Parameter (die Länge) für den entsprechenden subnormpath enthalten.[DONE] Normpfad hat kein epsilon mehr, die findsubpath methode macht keine Annahmen über ein epsilon mehr (Achtung: nicht vor den ersten und nach den letzten laufen). [DONE] Auch der Subnormpfad schleift zunächst ungültige Parameter und Längenwerte durch. [DONE] Was die Normpfadelemente machen, wenn sie ausserhalb ihres Parameterbereichs aufgerufen werden, ist strittig: es gibt zwei Möglichkeiten: m-schindler) cut der Parameter auf den gültigen Bereich, ohne sonstige Fehlermeldungen etc. wobsta) ignorieren, d.h. es kommen Positionen raus, die ausserhalb des Parameterbereichs liegen Wir haben vor, das auf pyx-devel zur Diskussion zu stellen. Wer schreibt eine erste Version des Postings? wobsta rules [DONE] Es gibt keine leeren Subpfade. [Nein. Bessere Lösung gefunden, DONE] Append kann nur einen Subnormpfad anfügen, man könnte auch ein Extent haben. [beides DONE] Append und Extend sollte es auch innerhalb des subnormpfads geben. Diese Methoden sollten blöd sein. Es sollte eine close-methode geben, die auch die schliessende Linie sicherstellt. [Methoden sind jetzt nicht blöd, aber ansonsten DONE] module deform: -------------- enthält smooth, cycloid, ..., basisklasse deformer class deformer: def deform(self, path): return xxx(path) deformer ändern einen Pfad, sind auch als Parameter innerhalb einer attr-Liste (in draw etc.) möglich, werden dann zu Beginn ausgeführt. module deco: ------------ Path wird zum füllen verwendet, Segemente dieses Pfades werden zum stroken verwendet. Es gibt fillstyles und strokestyles (können jeweils None sein). Der Pfad (zum Stroken) kann verkürzt oder Lücken haben. Dazu muss eine "lasse aus" methode skipstroke geben, die eine Liste von tupeln kriegt, die die Intervalle angibt, die auszulassen sind. Es gibt zusätzlich eine subcanvas "ornaments", der ganz am Ende eingefügt wird. (für Pfeile, Beschriftungen, etc.) [DONE] Umbenennungen: -------------- pathel -> pathitem [DONE] PSCmd, PSOp -> canvasitem [DONE] module deform: -------------- bekommt eine Funktion bezierfromendpoints, die das bisherige onebezierfrompathels ersetzt. Hier keine Vorzeichenbehandlung. Vorzeichen der Krümmung ist durch Skalarprodukt von Krümmungsradius und Verbindungsvektor beeinflusst. Casp: Gleichungssystem für (x,y)(t) der Punkte mit Abstand r von der bisherigen Bezier. Dann kleinester Krümmungsradius t_krit und (x,y)(t1)=(x,y)(t2) mit t1 kriegen einen Vektor fuer die Richtung in 3D * 4 feste Achsen pro Dimension (x ist immer an derselben stelle) * trafo3D: modul fuer 3D->2D projektoren * Geometrie: Es wird eine minimale Geschw. delta im normpath eingefuehrt. delta != epsilon 1 Randfaelle: v am Rand < delta: Bestimme den Parameter, an dem v == delta (Gl. 4.Grades) --> Tangente bekannt Setze den ersten Kontrollpunkt in Richtung der Tangente so, dass v = delta wird. 2. Suche Parameter minimaler Geschw. (Gl. 3.Grades) Wenn v < delta: teile an dieser Stelle. Append wird kompliziert: Stelle sicher, dass die endgueltig eingefuegte Kurve kein v < delta hat. --> zuerst Skippedline anwenden --> dann delta-Test machen Wert von delta: Eine Linie der Laenge 10m hat Geschw. v = 3.5e-5 1/pt also delta = 1e-5 sinnvoll. pyx-project-pyx-21f71ce/design/pyx.sty000066400000000000000000000000651526513311100200570ustar00rootroot00000000000000\def\PyX{P\kern-.3em\lower.5ex\hbox{Y}\kern-.18em X} pyx-project-pyx-21f71ce/design/selfinter1.py000066400000000000000000000032151526513311100211240ustar00rootroot00000000000000#!/usr/bin/env python import sys;sys.path.insert(0, "..") from math import * #sys.path.insert(0, os.path.expanduser("~/python/pyx-trunk")) from pyx import * # File for invalid parametrisations of Bezier curves # Some examples def Dx_m(Dy): return (-1-2*Dy-sqrt((1+2*Dy)**2+3))/3.0 def Dx_p(Dy): return (-1-2*Dy+sqrt((1+2*Dy)**2+3))/3.0 def pass00(Dy): return 1.0/(3.0*(Dy+1)) def pass10(Dy): return (1.0+Dy**3)/(3.0*(Dy+1)) def acurve(Dx, Dy, trafo_reverse=False): p = path.curve(0,0, 0,1, Dx,1+Dy, 1,0) if trafo_reverse: # calculate the trafo to put p2=(1,-1): # (for the right branch only) x2, y2 = Dx, Dy+1 tr1 = trafo.scale(1, -1.0/y2) pp = tr1.apply_pt(x2, y2) tr2 = trafo.trafo(matrix=((1, (pp[0]-1)), (0, 1))) p = p.transformed(tr2*tr1) c = canvas.canvas() c.stroke(p, [deco.shownormpath()]) #c.text(-0.2, -10*unit.x_pt, r"\noindent$\Delta x=%g $\par\noindent$\Delta y=%g$"%(Dx,Dy), # [text.parbox(4), text.size.footnotesize]) return c dx = 3 dy = -3 Dy = -2.5 e = 0.1 # test the left branch: cc = acurve(pass00(Dy), Dy) # passes through startpoint #cc = acurve(Dx_m(Dy)-e, Dy) c = acurve(Dx_m(Dy) , Dy); cc.insert(c, [trafo.translate(1*dx, 0)]) c = acurve(Dx_m(Dy)+e, Dy); cc.insert(c, [trafo.translate(2*dx, 0)]) # test the right branch: #cc = acurve(Dx_p(Dy)-e, Dy, True) #c = acurve(Dx_p(Dy) , Dy, True); cc.insert(c, [trafo.translate(1*dx, 0)]) ##c = acurve(Dx_p(Dy)+e, Dy, True); cc.insert(c, [trafo.translate(2*dx, 0)]) #c = acurve(pass10(Dy), Dy, True); cc.insert(c, [trafo.translate(2*dx, 0)]) # passes through endpoint cc.writePDFfile() pyx-project-pyx-21f71ce/design/selfinter2.py000066400000000000000000000024651526513311100211330ustar00rootroot00000000000000#!/usr/bin/env python3 import sys;sys.path.insert(0, "..") from math import * from pyx import * # File for invalid parametrisations of Bezier curves # Draws a sketch of the areas where invalid params are to be expected xmin, xmax = -2, 5 ymin, ymax = -xmax, 2 g = graph.graphxy(width=10, x=graph.axis.lin(title=r"$\Delta x$", min=xmin, max=xmax), y=graph.axis.lin(title=r"$\Delta y$", min=ymin, max=ymax), key=graph.key.key(pos="tr"), ) g.plot(graph.data.function("y(x)=-1", title=None), [graph.style.line([style.linestyle.dotted])]) d1 = g.plot(graph.data.function("x(y)=(-1-2*y-sqrt((1+2*y)**2+3))/3.0", title=r"cusp ($-$)"), [graph.style.line()]) d2 = g.plot(graph.data.function("x(y)=(-1-2*y+sqrt((1+2*y)**2+3))/3.0", title=r"cusp ($+$)", max=-1), [graph.style.line([color.rgb.red])]) d3 = g.plot(graph.data.function("x(y)=1.0/(3.0*(y+1))", title=r"passes through $(0,0)$", max=-1), [graph.style.line([color.rgb.green])]) d4 = g.plot(graph.data.function("x(y)=(1+y**3)/(3.0*(1+y))", title=r"passes through $(1,0)$", max=-1), [graph.style.line([color.rgb.blue])]) g.doplot() p = d1.path << d3.path.reversed() p.append(path.closepath()) g.layers["filldata"].fill(p, [color.gray(0.8)]) p = d2.path << d4.path.reversed() p.append(path.closepath()) g.layers["filldata"].fill(p, [color.gray(0.8)]) g.writePDFfile() pyx-project-pyx-21f71ce/design/sourceforge000066400000000000000000000056111526513311100207460ustar00rootroot00000000000000> 1. Project Full Name PyX > 2. Project Purpose and Summarization > > Please provide detailed, accurate description of your project and what > SourceForge resources and in which way you plan to use. This description will > be the basis for the approval or rejection of your project's hosting on > SourceForge, and later, to ensure that you are using the services in the > intended way. This description will not be used as a public description of your > project. It must be written in English. PyX is a python package to create encapsulated PostScript figures. It provides classes and methods to access basic PostScript functionality at an abstract level. At the same time the emerging structures are very convenient to produce all kinds of drawings in a non-interactive way. In combination with the python language itself the user can just code any complexity of the figure wanted. Additionally an TeX/LaTeX interface enables one to use the famous high quality typesetting within the figures. A major part of PyX on top of the already described basis is the provision of high level functionality for complex tasks like 2d plots in publication-ready quality. The project started in the middle of last year and is developed by Jörg Lehmann and André Wobst. While we plan to use PyX ourself (and already do) we want to take the opportunity to share our project with others under the GPL. Thus, we would greatly appreciate sourceforge for the hosting of this project. > 3. License GPL > 4. Project Public Description > > This is the description of your project which will be shown on the Project > Summary page, in search results, etc. It should not be as comprehensive and > formal as Project Purpose description (step 2), so feel free to use concise and > catchy wording. Maximum length is 255 chars. PyX is a python package for the creation of encapsulated PostScript figures. It provides both an abstraction of PostScript and a TeX/LaTeX interface. Complex tasks like 2d plots in publication-ready quality are built out of these primitives. > 5. Project Unix Name > > In addition to full project name, you will need to choose short, "Unix" name for your project. > > The "Unix Name" has several restrictions because it is used in so many places around the site. They are: > > * Cannot match the Unix name of any other project > * Must be between 3 and 15 characters in length > * Must be in lower case > * Can only contain characters, numbers, and dashes > * Must be a valid Unix username > * Cannot match one of our reserved domains > * Unix name will never change for this project > > Your nix name is important, however, because it will be used for many things, including: > > * A web site at unixname.sourceforge.net > * A CVS Repository root of /cvsroot/unixname at cvs.unixname.sourceforge.net > * Shell access to unixname.sourceforge.net > * Search engines throughout the site pyx pyx-project-pyx-21f71ce/examples/000077500000000000000000000000001526513311100170425ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/.gitignore000066400000000000000000000000401526513311100210240ustar00rootroot00000000000000*.png *.eps *.pdf *.svg *.ipynb pyx-project-pyx-21f71ce/examples/3dgraphs/000077500000000000000000000000001526513311100205555ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/3dgraphs/INDEX000066400000000000000000000000271526513311100213460ustar00rootroot00000000000000surface color grid bar pyx-project-pyx-21f71ce/examples/3dgraphs/README000066400000000000000000000004731526513311100214410ustar00rootroot000000000000003d graphs 3d graphs are created by graphxyz instances. They behave quite similar to regular graphs. Various styles can be used on 3d graphs without further adjustment like the symbol, line, and errorbar styles. Beside that the surface and grid styles are available to handle 3d data defined on a rectangular grid. pyx-project-pyx-21f71ce/examples/3dgraphs/bar.py000077500000000000000000000006731526513311100217040ustar00rootroot00000000000000#!/usr/bin/env python from pyx import * g = graph.graphxyz(0, 0, size=5, x=graph.axis.bar(), y=graph.axis.bar(), z=None, z2=graph.axis.lin()) g.plot(graph.data.data(graph.data.points([[1, 1, 1.4], [1, 2, 1.8], [2, 1, -0.5], [2, 2, 0.9]]), xname=1, yname=2, z2=3), [graph.style.barpos(fromvalue=0, frompathattrs=None), graph.style.bar(barattrs=[style.linejoin.bevel])]) g.writeEPSfile("bar") g.writePDFfile("bar") g.writeSVGfile("bar") pyx-project-pyx-21f71ce/examples/3dgraphs/bar.txt000066400000000000000000000000771526513311100220660ustar00rootroot00000000000000Bar graphs in 3d The bar style can also be used in 3d graphs. pyx-project-pyx-21f71ce/examples/3dgraphs/color.dat000066400000000000000000000651611526513311100223760ustar00rootroot000000000000000 0 +2.744434246094877e-06 0 1 +2.518061584101027e-06 0 2 +1.759486087349929e-06 0 3 +9.970876191013776e-07 0 4 +3.824133190986796e-06 0 5 +2.975115378597332e-05 0 6 +1.699285851675448e-04 0 7 +6.720788024534639e-04 0 8 +1.792832060948163e-03 0 9 +3.200655253796644e-03 0 10 +3.816618683189747e-03 0 11 +3.032150111960852e-03 0 12 +1.590229109988915e-03 0 13 +5.326214926640671e-04 0 14 +9.904354320939544e-05 0 15 +9.357929797648389e-06 0 16 +9.904354320939544e-05 0 17 +5.326214926640671e-04 0 18 +1.590229109988915e-03 0 19 +3.032150111960852e-03 0 20 +3.816618683189747e-03 0 21 +3.200655253796644e-03 0 22 +1.792832060948163e-03 0 23 +6.720788024534639e-04 0 24 +1.699285851675448e-04 0 25 +2.975115378597332e-05 0 26 +3.824133190986796e-06 0 27 +9.970876191013776e-07 0 28 +1.759486087349929e-06 0 29 +2.518061584101027e-06 0 30 +2.744434246094877e-06 1 0 +1.653567652207974e-06 1 1 +2.080019415431434e-06 1 2 +2.256392327443844e-06 1 3 +2.353042222660531e-06 1 4 +4.658691276947686e-06 1 5 +2.435782462200616e-05 1 6 +1.490972431055931e-04 1 7 +6.377284017517769e-04 1 8 +1.771582235157512e-03 1 9 +3.225933640796166e-03 1 10 +3.906803557194595e-03 1 11 +3.197308254883010e-03 1 12 +1.817291725241250e-03 1 13 +7.630389801230493e-04 1 14 +2.807603469492349e-04 1 15 +1.608446672699473e-04 1 16 +2.807603469492349e-04 1 17 +7.630389801230493e-04 1 18 +1.817291725241250e-03 1 19 +3.197308254883010e-03 1 20 +3.906803557194595e-03 1 21 +3.225933640796166e-03 1 22 +1.771582235157512e-03 1 23 +6.377284017517769e-04 1 24 +1.490972431055931e-04 1 25 +2.435782462200616e-05 1 26 +4.658691276947686e-06 1 27 +2.353042222660531e-06 1 28 +2.256392327443844e-06 1 29 +2.080019415431434e-06 1 30 +1.653567652207974e-06 2 0 +4.903222446513287e-07 2 1 +1.470523991761591e-06 2 2 +2.270477656555739e-06 2 3 +1.893286577894258e-06 2 4 +8.875040369628528e-07 2 5 +1.382699095923903e-05 2 6 +1.323259508158545e-04 2 7 +6.252257214541712e-04 2 8 +1.780184015590029e-03 2 9 +3.259559977840245e-03 2 10 +3.952100806252818e-03 2 11 +3.252471803511440e-03 2 12 +1.899491987795393e-03 2 13 +8.762282695816127e-04 2 14 +4.087748017613867e-04 2 15 +2.912636182938809e-04 2 16 +4.087748017613867e-04 2 17 +8.762282695816127e-04 2 18 +1.899491987795393e-03 2 19 +3.252471803511440e-03 2 20 +3.952100806252818e-03 2 21 +3.259559977840245e-03 2 22 +1.780184015590029e-03 2 23 +6.252257214541712e-04 2 24 +1.323259508158545e-04 2 25 +1.382699095923903e-05 2 26 +8.875040369628528e-07 2 27 +1.893286577894258e-06 2 28 +2.270477656555739e-06 2 29 +1.470523991761591e-06 2 30 +4.903222446513287e-07 3 0 +2.525077324128639e-07 3 1 +1.411976960236152e-06 3 2 +2.585027402357342e-06 3 3 +2.455329005085701e-06 3 4 +1.524299827202244e-06 3 5 +1.730855351620528e-05 3 6 +1.485538901683144e-04 3 7 +6.672169413806638e-04 3 8 +1.845851704536038e-03 3 9 +3.314019707590146e-03 3 10 +3.938097395997995e-03 3 11 +3.137337133297499e-03 3 12 +1.714725940474006e-03 3 13 +6.894032775764756e-04 3 14 +2.562722332523367e-04 3 15 +1.572414788470460e-04 3 16 +2.562722332523367e-04 3 17 +6.894032775764756e-04 3 18 +1.714725940474006e-03 3 19 +3.137337133297499e-03 3 20 +3.938097395997995e-03 3 21 +3.314019707590146e-03 3 22 +1.845851704536038e-03 3 23 +6.672169413806638e-04 3 24 +1.485538901683144e-04 3 25 +1.730855351620528e-05 3 26 +1.524299827202244e-06 3 27 +2.455329005085701e-06 3 28 +2.585027402357342e-06 3 29 +1.411976960236152e-06 3 30 +2.525077324128639e-07 4 0 +1.226989384095427e-06 4 1 +2.143934503008343e-06 4 2 +3.419052137664231e-06 4 3 +5.044497070280032e-06 4 4 +1.019883325351201e-05 4 5 +4.134677767967157e-05 4 6 +2.024165951452637e-04 4 7 +7.595561633249549e-04 4 8 +1.957907998196094e-03 4 9 +3.390836776047649e-03 4 10 +3.907691866900613e-03 4 11 +2.958824680334640e-03 4 12 +1.433416637054468e-03 4 13 +4.183160198044826e-04 4 14 +6.825032672642671e-05 4 15 +1.565122491813854e-05 4 16 +6.825032672642671e-05 4 17 +4.183160198044826e-04 4 18 +1.433416637054468e-03 4 19 +2.958824680334640e-03 4 20 +3.907691866900613e-03 4 21 +3.390836776047649e-03 4 22 +1.957907998196094e-03 4 23 +7.595561633249549e-04 4 24 +2.024165951452637e-04 4 25 +4.134677767967157e-05 4 26 +1.019883325351201e-05 4 27 +5.044497070280032e-06 4 28 +3.419052137664231e-06 4 29 +2.143934503008343e-06 4 30 +1.226989384095427e-06 5 0 +2.307317576927403e-06 5 1 +2.716699175289595e-06 5 2 +3.392503181823541e-06 5 3 +5.499844452398325e-06 5 4 +1.535221942328690e-05 5 5 +6.146497948927013e-05 5 6 +2.527173255797678e-04 5 7 +8.466746072201876e-04 5 8 +2.063200871238251e-03 5 9 +3.474385548526664e-03 5 10 +3.926889486415615e-03 5 11 +2.892497988275950e-03 5 12 +1.312540781600459e-03 5 13 +3.136255923160151e-04 5 14 +2.172446734687579e-05 5 15 +7.019738683128956e-09 5 16 +2.172446734687579e-05 5 17 +3.136255923160151e-04 5 18 +1.312540781600459e-03 5 19 +2.892497988275950e-03 5 20 +3.926889486415615e-03 5 21 +3.474385548526664e-03 5 22 +2.063200871238251e-03 5 23 +8.466746072201876e-04 5 24 +2.527173255797678e-04 5 25 +6.146497948927013e-05 5 26 +1.535221942328690e-05 5 27 +5.499844452398325e-06 5 28 +3.392503181823541e-06 5 29 +2.716699175289595e-06 5 30 +2.307317576927403e-06 6 0 +2.373332825254899e-06 6 1 +2.321653560233388e-06 6 2 +1.822958685202512e-06 6 3 +1.998034295855592e-06 6 4 +1.070244688479249e-05 6 5 +6.062668963464542e-05 6 6 +2.637758074029551e-04 6 7 +8.732926224204041e-04 6 8 +2.104254493353289e-03 6 9 +3.536589556516121e-03 6 10 +4.022793689595565e-03 6 11 +3.021560454986797e-03 6 12 +1.452268740872702e-03 6 13 +4.229684890191378e-04 6 14 +7.183483566560646e-05 6 15 +1.825194993036989e-05 6 16 +7.183483566560646e-05 6 17 +4.229684890191378e-04 6 18 +1.452268740872702e-03 6 19 +3.021560454986797e-03 6 20 +4.022793689595565e-03 6 21 +3.536589556516121e-03 6 22 +2.104254493353289e-03 6 23 +8.732926224204041e-04 6 24 +2.637758074029551e-04 6 25 +6.062668963464542e-05 6 26 +1.070244688479249e-05 6 27 +1.998034295855592e-06 6 28 +1.822958685202512e-06 6 29 +2.321653560233388e-06 6 30 +2.373332825254899e-06 7 0 +1.587195130150310e-06 7 1 +1.713658780206171e-06 7 2 +9.411594223291881e-07 7 3 +6.776789721331578e-08 7 4 +6.860825504386979e-06 7 5 +5.146201467104523e-05 7 6 +2.396166831456199e-04 7 7 +8.264643309087650e-04 7 8 +2.056438818405584e-03 7 9 +3.549963363240440e-03 7 10 +4.156944303260867e-03 7 11 +3.275907813144717e-03 7 12 +1.756915148324869e-03 7 13 +6.844759133332523e-04 7 14 +2.464153674380294e-04 7 15 +1.495346760772398e-04 7 16 +2.464153674380294e-04 7 17 +6.844759133332523e-04 7 18 +1.756915148324869e-03 7 19 +3.275907813144717e-03 7 20 +4.156944303260867e-03 7 21 +3.549963363240440e-03 7 22 +2.056438818405584e-03 7 23 +8.264643309087650e-04 7 24 +2.396166831456199e-04 7 25 +5.146201467104523e-05 7 26 +6.860825504386979e-06 7 27 +6.776789721331578e-08 7 28 +9.411594223291881e-07 7 29 +1.713658780206171e-06 7 30 +1.587195130150310e-06 8 0 +5.842895768532483e-07 8 1 +1.514582924947651e-06 8 2 +1.918239459944766e-06 8 3 +2.478661441644039e-06 8 4 +8.932418369414274e-06 8 5 +4.159804448997610e-05 8 6 +1.917917504088143e-04 8 7 +7.237846411730068e-04 8 8 +1.937637574805104e-03 8 9 +3.510202961653063e-03 8 10 +4.266350475238421e-03 8 11 +3.503586015126449e-03 8 12 +1.998570138710667e-03 8 13 +8.585196678491770e-04 8 14 +3.479814933876024e-04 8 15 +2.236338486521513e-04 8 16 +3.479814933876024e-04 8 17 +8.585196678491770e-04 8 18 +1.998570138710667e-03 8 19 +3.503586015126449e-03 8 20 +4.266350475238421e-03 8 21 +3.510202961653063e-03 8 22 +1.937637574805104e-03 8 23 +7.237846411730068e-04 8 24 +1.917917504088143e-04 8 25 +4.159804448997610e-05 8 26 +8.932418369414274e-06 8 27 +2.478661441644039e-06 8 28 +1.918239459944766e-06 8 29 +1.514582924947651e-06 8 30 +5.842895768532483e-07 9 0 +3.642883870758245e-07 9 1 +2.053202999470949e-06 9 2 +3.837166158545995e-06 9 3 +5.348894469071784e-06 9 4 +7.858828200887174e-06 9 5 +2.145531964264211e-05 9 6 +1.278998893281748e-04 9 7 +6.057443575635683e-04 9 8 +1.807819709990386e-03 9 9 +3.456094204549144e-03 9 10 +4.332932758161096e-03 9 11 +3.623389816823501e-03 9 12 +2.054991941718712e-03 9 13 +8.036014751161785e-04 9 14 +2.166177170601839e-04 9 15 +6.915211547501020e-05 9 16 +2.166177170601839e-04 9 17 +8.036014751161785e-04 9 18 +2.054991941718712e-03 9 19 +3.623389816823501e-03 9 20 +4.332932758161096e-03 9 21 +3.456094204549144e-03 9 22 +1.807819709990386e-03 9 23 +6.057443575635683e-04 9 24 +1.278998893281748e-04 9 25 +2.145531964264211e-05 9 26 +7.858828200887174e-06 9 27 +5.348894469071784e-06 9 28 +3.837166158545995e-06 9 29 +2.053202999470949e-06 9 30 +3.642883870758245e-07 10 0 +2.512490246878957e-06 10 1 +4.396610854841844e-06 10 2 +6.575545000503195e-06 10 3 +7.083439501810090e-06 10 4 +3.470894493160968e-06 10 5 +2.622883261358829e-06 10 6 +8.709326319537562e-05 10 7 +5.447133938049011e-04 10 8 +1.752837291237968e-03 10 9 +3.455315221404786e-03 10 10 +4.398958252080046e-03 10 11 +3.686186997488258e-03 10 12 +2.037578409116048e-03 10 13 +7.234336912109821e-04 10 14 +1.396226098258371e-04 10 15 +7.543732908067557e-06 10 16 +1.396226098258371e-04 10 17 +7.234336912109821e-04 10 18 +2.037578409116048e-03 10 19 +3.686186997488258e-03 10 20 +4.398958252080046e-03 10 21 +3.455315221404786e-03 10 22 +1.752837291237968e-03 10 23 +5.447133938049011e-04 10 24 +8.709326319537562e-05 10 25 +2.622883261358829e-06 10 26 +3.470894493160968e-06 10 27 +7.083439501810090e-06 10 28 +6.575545000503195e-06 10 29 +4.396610854841844e-06 10 30 +2.512490246878957e-06 11 0 +6.815671315359540e-06 11 1 +8.264538431099037e-06 11 2 +1.005401247062773e-05 11 3 +1.059684653758765e-05 11 4 +8.755895107819839e-06 11 5 +1.555038478500510e-05 11 6 +1.170561839376850e-04 11 7 +5.962253896499082e-04 11 8 +1.824100571423304e-03 11 9 +3.550529315318575e-03 11 10 +4.513631727635005e-03 11 11 +3.777400017948165e-03 11 12 +2.069898556039909e-03 11 13 +7.321944395611375e-04 11 14 +1.800591890588128e-04 11 15 +7.252664246864497e-05 11 16 +1.800591890588128e-04 11 17 +7.321944395611375e-04 11 18 +2.069898556039909e-03 11 19 +3.777400017948165e-03 11 20 +4.513631727635005e-03 11 21 +3.550529315318575e-03 11 22 +1.824100571423304e-03 11 23 +5.962253896499082e-04 11 24 +1.170561839376850e-04 11 25 +1.555038478500510e-05 11 26 +8.755895107819839e-06 11 27 +1.059684653758765e-05 11 28 +1.005401247062773e-05 11 29 +8.264538431099037e-06 11 30 +6.815671315359540e-06 12 0 +9.749610156771229e-06 12 1 +1.055180001296198e-05 12 2 +1.180987001645569e-05 12 3 +1.395571025914737e-05 12 4 +2.057271886339045e-05 12 5 +5.026620068793996e-05 12 6 +1.931212798890028e-04 12 7 +7.199830460496915e-04 12 8 +1.978312822663844e-03 12 9 +3.714503821754403e-03 12 10 +4.680865749503483e-03 12 11 +3.932112021941086e-03 12 12 +2.178726369038801e-03 12 13 +7.706810332112831e-04 12 14 +1.501137773096962e-04 12 15 +1.261640298775073e-05 12 16 +1.501137773096962e-04 12 17 +7.706810332112831e-04 12 18 +2.178726369038801e-03 12 19 +3.932112021941086e-03 12 20 +4.680865749503483e-03 12 21 +3.714503821754403e-03 12 22 +1.978312822663844e-03 12 23 +7.199830460496915e-04 12 24 +1.931212798890028e-04 12 25 +5.026620068793996e-05 12 26 +2.057271886339045e-05 12 27 +1.395571025914737e-05 12 28 +1.180987001645569e-05 12 29 +1.055180001296198e-05 12 30 +9.749610156771229e-06 13 0 +8.490623059819040e-06 13 1 +8.799846154170221e-06 13 2 +8.994677966752248e-06 13 3 +1.010871017786102e-05 13 4 +1.870330300271311e-05 13 5 +6.084068161357250e-05 13 6 +2.356274475978317e-04 13 7 +8.098356562680192e-04 13 8 +2.107865874310841e-03 13 9 +3.865318650390775e-03 13 10 +4.852291507897281e-03 13 11 +4.126295330348602e-03 13 12 +2.369155320117100e-03 13 13 +9.147697022767272e-04 13 14 +2.308142003576141e-04 13 15 +6.328836926190641e-05 13 16 +2.308142003576141e-04 13 17 +9.147697022767272e-04 13 18 +2.369155320117100e-03 13 19 +4.126295330348602e-03 13 20 +4.852291507897281e-03 13 21 +3.865318650390775e-03 13 22 +2.107865874310841e-03 13 23 +8.098356562680192e-04 13 24 +2.356274475978317e-04 13 25 +6.084068161357250e-05 13 26 +1.870330300271311e-05 13 27 +1.010871017786102e-05 13 28 +8.994677966752248e-06 13 29 +8.799846154170221e-06 13 30 +8.490623059819040e-06 14 0 +4.687403389656196e-06 14 1 +5.079153114463964e-06 14 2 +4.497918246229313e-06 14 3 +2.774071303358379e-06 14 4 +5.904632068328592e-06 14 5 +4.270413859622926e-05 14 6 +2.207746257698169e-04 14 7 +8.135918874377782e-04 14 8 +2.139508173337537e-03 14 9 +3.927780870116436e-03 14 10 +4.956023042244558e-03 14 11 +4.277097097416137e-03 14 12 +2.546496865618815e-03 14 13 +1.093698356447127e-03 14 14 +4.092148715898557e-04 14 15 +2.440103587145870e-04 14 16 +4.092148715898557e-04 14 17 +1.093698356447127e-03 14 18 +2.546496865618815e-03 14 19 +4.277097097416137e-03 14 20 +4.956023042244558e-03 14 21 +3.927780870116436e-03 14 22 +2.139508173337537e-03 14 23 +8.135918874377782e-04 14 24 +2.207746257698169e-04 14 25 +4.270413859622926e-05 14 26 +5.904632068328592e-06 14 27 +2.774071303358379e-06 14 28 +4.497918246229313e-06 14 29 +5.079153114463964e-06 14 30 +4.687403389656196e-06 15 0 +1.501257749887276e-06 15 1 +2.435756825174617e-06 15 2 +2.411966242960009e-06 15 3 +7.157054724050202e-07 15 4 +1.716069852294603e-06 15 5 +3.013705168409485e-05 15 6 +1.904842036316344e-04 15 7 +7.619892865676402e-04 15 8 +2.077488033630016e-03 15 9 +3.878674705777598e-03 15 10 +4.943717078853101e-03 15 11 +4.303065526353173e-03 15 12 +2.573644579802008e-03 15 13 +1.075135802949144e-03 15 14 +3.350972364282421e-04 15 15 +1.464398667425757e-04 15 16 +3.350972364282421e-04 15 17 +1.075135802949144e-03 15 18 +2.573644579802008e-03 15 19 +4.303065526353173e-03 15 20 +4.943717078853101e-03 15 21 +3.878674705777598e-03 15 22 +2.077488033630016e-03 15 23 +7.619892865676402e-04 15 24 +1.904842036316344e-04 15 25 +3.013705168409485e-05 15 26 +1.716069852294603e-06 15 27 +7.157054724050202e-07 15 28 +2.411966242960009e-06 15 29 +2.435756825174617e-06 15 30 +1.501257749887276e-06 16 0 +2.323571591220434e-07 16 1 +1.393475802039957e-06 16 2 +2.091541786468290e-06 16 3 +2.126752993258124e-06 16 4 +4.835644738161436e-06 16 5 +2.852474621669622e-05 16 6 +1.659548141126014e-04 16 7 +6.933826714206772e-04 16 8 +1.963201825373199e-03 16 9 +3.743280998425761e-03 16 10 +4.819314315173870e-03 16 11 +4.206415709376830e-03 16 12 +2.492191540160578e-03 16 13 +9.778007064550418e-04 16 14 +2.051669934845689e-04 16 15 +7.791777078841276e-08 16 16 +2.051669934845689e-04 16 17 +9.778007064550418e-04 16 18 +2.492191540160578e-03 16 19 +4.206415709376830e-03 16 20 +4.819314315173870e-03 16 21 +3.743280998425761e-03 16 22 +1.963201825373199e-03 16 23 +6.933826714206772e-04 16 24 +1.659548141126014e-04 16 25 +2.852474621669622e-05 16 26 +4.835644738161436e-06 16 27 +2.126752993258124e-06 16 28 +2.091541786468290e-06 16 29 +1.393475802039957e-06 16 30 +2.323571591220434e-07 17 0 +6.534106903077690e-07 17 1 +1.487306123431552e-06 17 2 +1.979172297174789e-06 17 3 +1.976234205687681e-06 17 4 +3.531951296812328e-06 17 5 +2.095624840708503e-05 17 6 +1.382476024308607e-04 17 7 +6.241889811214583e-04 17 8 +1.838277343110348e-03 17 9 +3.567829091690213e-03 17 10 +4.619649049288467e-03 17 11 +4.029180994811406e-03 17 12 +2.389692813180007e-03 17 13 +9.801953064551853e-04 17 14 +3.010360683959697e-04 17 15 +1.339147984653232e-04 17 16 +3.010360683959697e-04 17 17 +9.801953064551853e-04 17 18 +2.389692813180007e-03 17 19 +4.029180994811406e-03 17 20 +4.619649049288467e-03 17 21 +3.567829091690213e-03 17 22 +1.838277343110348e-03 17 23 +6.241889811214583e-04 17 24 +1.382476024308607e-04 17 25 +2.095624840708503e-05 17 26 +3.531951296812328e-06 17 27 +1.976234205687681e-06 17 28 +1.979172297174789e-06 17 29 +1.487306123431552e-06 17 30 +6.534106903077690e-07 18 0 +1.876059361241538e-06 18 1 +2.057784840208347e-06 18 2 +1.777613271338336e-06 18 3 +8.699234969159874e-07 18 4 +1.968652577303025e-07 18 5 +1.208171122223021e-05 18 6 +1.171139379151092e-04 18 7 +5.767959563594669e-04 18 8 +1.740740070141123e-03 18 9 +3.396802527464631e-03 18 10 +4.382735284334756e-03 18 11 +3.786662133385478e-03 18 12 +2.219758764675431e-03 18 13 +9.142867897053784e-04 18 14 +3.110029558942641e-04 18 15 +1.692446500089834e-04 18 16 +3.110029558942641e-04 18 17 +9.142867897053784e-04 18 18 +2.219758764675431e-03 18 19 +3.786662133385478e-03 18 20 +4.382735284334756e-03 18 21 +3.396802527464631e-03 18 22 +1.740740070141123e-03 18 23 +5.767959563594669e-04 18 24 +1.171139379151092e-04 18 25 +1.208171122223021e-05 18 26 +1.968652577303025e-07 18 27 +8.699234969159874e-07 18 28 +1.777613271338336e-06 18 29 +2.057784840208347e-06 18 30 +1.876059361241538e-06 19 0 +3.062840789809967e-06 19 1 +2.527808076843036e-06 19 2 +1.633271973488836e-06 19 3 +9.736235185669393e-07 19 4 +1.380503967706013e-06 19 5 +1.469419689216322e-05 19 6 +1.207048147882760e-04 19 7 +5.719123589096748e-04 19 8 +1.692871022540258e-03 19 9 +3.256428719310688e-03 19 10 +4.139632891211538e-03 19 11 +3.504909208546127e-03 19 12 +1.982724381278589e-03 19 13 +7.402920491410022e-04 19 14 +1.617462685140096e-04 19 15 +2.053330572468854e-05 19 16 +1.617462685140096e-04 19 17 +7.402920491410022e-04 19 18 +1.982724381278589e-03 19 19 +3.504909208546127e-03 19 20 +4.139632891211538e-03 19 21 +3.256428719310688e-03 19 22 +1.692871022540258e-03 19 23 +5.719123589096748e-04 19 24 +1.207048147882760e-04 19 25 +1.469419689216322e-05 19 26 +1.380503967706013e-06 19 27 +9.736235185669393e-07 19 28 +1.633271973488836e-06 19 29 +2.527808076843036e-06 19 30 +3.062840789809967e-06 20 0 +3.965288889790357e-06 20 1 +2.752129060676672e-06 20 2 +1.161841016756794e-06 20 3 +5.701545853936663e-07 20 4 +3.098355792788597e-06 20 5 +2.353023458085338e-05 20 6 +1.431860973840122e-04 20 7 +6.003781224686864e-04 20 8 +1.683390907031591e-03 20 9 +3.145644377756497e-03 20 10 +3.912068929840578e-03 20 11 +3.233033884460954e-03 20 12 +1.771385768497788e-03 20 13 +6.375462234056684e-04 20 14 +1.434980619272460e-04 20 15 +3.195125662258565e-05 20 16 +1.434980619272460e-04 20 17 +6.375462234056684e-04 20 18 +1.771385768497788e-03 20 19 +3.233033884460954e-03 20 20 +3.912068929840578e-03 20 21 +3.145644377756497e-03 20 22 +1.683390907031591e-03 20 23 +6.003781224686864e-04 20 24 +1.431860973840122e-04 20 25 +2.353023458085338e-05 20 26 +3.098355792788597e-06 20 27 +5.701545853936663e-07 20 28 +1.161841016756794e-06 20 29 +2.752129060676672e-06 20 30 +3.965288889790357e-06 21 0 +4.809474577021396e-06 21 1 +3.265902127647575e-06 21 2 +1.153290298311127e-06 21 3 +1.734187798996243e-07 21 4 +4.307226170255345e-06 21 5 +3.268845994111086e-05 21 6 +1.673952798494322e-04 21 7 +6.297509875229867e-04 21 8 +1.674683627968040e-03 21 9 +3.043996694190472e-03 21 10 +3.709176492544443e-03 21 11 +2.997312013828311e-03 21 12 +1.599019952667030e-03 21 13 +5.728662937094130e-04 21 14 +1.609992934304200e-04 21 15 +7.737655471200314e-05 21 16 +1.609992934304200e-04 21 17 +5.728662937094130e-04 21 18 +1.599019952667030e-03 21 19 +2.997312013828311e-03 21 20 +3.709176492544443e-03 21 21 +3.043996694190472e-03 21 22 +1.674683627968040e-03 21 23 +6.297509875229867e-04 21 24 +1.673952798494322e-04 21 25 +3.268845994111086e-05 21 26 +4.307226170255345e-06 21 27 +1.734187798996243e-07 21 28 +1.153290298311127e-06 21 29 +3.265902127647575e-06 21 30 +4.809474577021396e-06 22 0 +5.555042869803733e-06 22 1 +4.420635368354199e-06 22 2 +3.028730507567648e-06 22 3 +3.100707295620601e-06 22 4 +9.243914480592160e-06 22 5 +4.087587045427118e-05 22 6 +1.760607022307088e-04 22 7 +6.247370338825327e-04 22 8 +1.629230426377810e-03 22 9 +2.933474132420932e-03 22 10 +3.538408480595143e-03 22 11 +2.811983434809747e-03 22 12 +1.451910099681378e-03 22 13 +4.768548007400953e-04 22 14 +9.099433778678653e-05 22 15 +1.171746709542609e-05 22 16 +9.099433778678653e-05 22 17 +4.768548007400953e-04 22 18 +1.451910099681378e-03 22 19 +2.811983434809747e-03 22 20 +3.538408480595143e-03 22 21 +2.933474132420932e-03 22 22 +1.629230426377810e-03 22 23 +6.247370338825327e-04 22 24 +1.760607022307088e-04 22 25 +4.087587045427118e-05 22 26 +9.243914480592160e-06 22 27 +3.100707295620601e-06 22 28 +3.028730507567648e-06 22 29 +4.420635368354199e-06 22 30 +5.555042869803733e-06 23 0 +5.404189672356805e-06 23 1 +4.892870830299098e-06 23 2 +4.557607934560358e-06 23 3 +5.537092541242136e-06 23 4 +1.083855203679700e-05 23 5 +3.547085934154473e-05 23 6 +1.510775020427121e-04 23 7 +5.676546615136151e-04 23 8 +1.538572432507774e-03 23 9 +2.819067621052516e-03 23 10 +3.417150766148686e-03 23 11 +2.705429500718680e-03 23 12 +1.374749562040417e-03 23 13 +4.333463453912217e-04 23 14 +7.941771000134053e-05 23 15 +1.479566369747944e-05 23 16 +7.941771000134053e-05 23 17 +4.333463453912217e-04 23 18 +1.374749562040417e-03 23 19 +2.705429500718680e-03 23 20 +3.417150766148686e-03 23 21 +2.819067621052516e-03 23 22 +1.538572432507774e-03 23 23 +5.676546615136151e-04 23 24 +1.510775020427121e-04 23 25 +3.547085934154473e-05 23 26 +1.083855203679700e-05 23 27 +5.537092541242136e-06 23 28 +4.557607934560358e-06 23 29 +4.892870830299098e-06 23 30 +5.404189672356805e-06 24 0 +3.955165536724783e-06 24 1 +3.584741991399201e-06 24 2 +3.508885372422360e-06 24 3 +3.939399145842972e-06 24 4 +4.822757117855054e-06 24 5 +1.528945559383431e-05 24 6 +1.028440676156929e-04 24 7 +4.865196638755525e-04 24 8 +1.440956718322974e-03 24 9 +2.733108955173010e-03 24 10 +3.366008382925306e-03 24 11 +2.697020398631471e-03 24 12 +1.391340841413025e-03 24 13 +4.489266759395228e-04 24 14 +8.931113109195366e-05 24 15 +2.423720573557286e-05 24 16 +8.931113109195366e-05 24 17 +4.489266759395228e-04 24 18 +1.391340841413025e-03 24 19 +2.697020398631471e-03 24 20 +3.366008382925306e-03 24 21 +2.733108955173010e-03 24 22 +1.440956718322974e-03 24 23 +4.865196638755525e-04 24 24 +1.028440676156929e-04 24 25 +1.528945559383431e-05 24 26 +4.822757117855054e-06 24 27 +3.939399145842972e-06 24 28 +3.508885372422360e-06 24 29 +3.584741991399201e-06 24 30 +3.955165536724783e-06 25 0 +2.214633245267957e-06 25 1 +1.585525169790331e-06 25 2 +1.483434350126737e-06 25 3 +1.972238971450125e-06 25 4 +8.239998404110594e-07 25 5 +3.274470653067594e-06 25 6 +7.580088249132948e-05 25 7 +4.457366278418717e-04 25 8 +1.401383271659800e-03 25 9 +2.715854393917418e-03 25 10 +3.391604051034845e-03 25 11 +2.775387360033505e-03 25 12 +1.495302570719864e-03 25 13 +5.208990796590071e-04 25 14 +9.956297062102457e-05 25 15 +4.074204269152465e-06 25 16 +9.956297062102457e-05 25 17 +5.208990796590071e-04 25 18 +1.495302570719864e-03 25 19 +2.775387360033505e-03 25 20 +3.391604051034845e-03 25 21 +2.715854393917418e-03 25 22 +1.401383271659800e-03 25 23 +4.457366278418717e-04 25 24 +7.580088249132948e-05 25 25 +3.274470653067594e-06 25 26 +8.239998404110594e-07 25 27 +1.972238971450125e-06 25 28 +1.483434350126737e-06 25 29 +1.585525169790331e-06 25 30 +2.214633245267957e-06 26 0 +1.270433760442372e-06 26 1 +3.916387056204372e-07 26 2 +2.231233391960010e-07 26 3 +1.503250077270970e-06 26 4 +3.125235105917701e-06 26 5 +1.232580616064923e-05 26 6 +9.755857943602422e-05 26 7 +4.851055857767528e-04 26 8 +1.457115907850736e-03 26 9 +2.782087863624691e-03 26 10 +3.471885190847275e-03 26 11 +2.885556868129979e-03 26 12 +1.636626067410123e-03 26 13 +6.667717289764138e-04 26 14 +2.263997570460314e-04 26 15 +1.189280941020137e-04 26 16 +2.263997570460314e-04 26 17 +6.667717289764138e-04 26 18 +1.636626067410123e-03 26 19 +2.885556868129979e-03 26 20 +3.471885190847275e-03 26 21 +2.782087863624691e-03 26 22 +1.457115907850736e-03 26 23 +4.851055857767528e-04 26 24 +9.755857943602422e-05 26 25 +1.232580616064923e-05 26 26 +3.125235105917701e-06 26 27 +1.503250077270970e-06 26 28 +2.231233391960010e-07 26 29 +3.916387056204372e-07 26 30 +1.270433760442372e-06 27 0 +1.299354594308245e-06 27 1 +5.522911269684502e-07 27 2 +4.619462725569895e-07 27 3 +2.265200690627976e-06 27 4 +8.097778286089136e-06 27 5 +3.240334951419666e-05 27 6 +1.498979407853844e-04 27 7 +5.803392722650569e-04 27 8 +1.582282591448272e-03 27 9 +2.903121917018245e-03 27 10 +3.560888391768400e-03 27 11 +2.942173666034896e-03 27 12 +1.681218578604672e-03 27 13 +7.183020985079531e-04 27 14 +2.890668649459803e-04 27 15 +1.861637286406668e-04 27 16 +2.890668649459803e-04 27 17 +7.183020985079531e-04 27 18 +1.681218578604672e-03 27 19 +2.942173666034896e-03 27 20 +3.560888391768400e-03 27 21 +2.903121917018245e-03 27 22 +1.582282591448272e-03 27 23 +5.803392722650569e-04 27 24 +1.498979407853844e-04 27 25 +3.240334951419666e-05 27 26 +8.097778286089136e-06 27 27 +2.265200690627976e-06 27 28 +4.619462725569895e-07 27 29 +5.522911269684502e-07 27 30 +1.299354594308245e-06 28 0 +2.040365887620211e-06 28 1 +1.650917666586412e-06 28 2 +1.774875725028040e-06 28 3 +3.556606295780957e-06 28 4 +1.121238171560661e-05 28 5 +4.596797846319543e-05 28 6 +1.924256950599667e-04 28 7 +6.695452279961972e-04 28 8 +1.710357891797661e-03 28 9 +3.026685345607163e-03 28 10 +3.623902514336288e-03 28 11 +2.912274546185048e-03 28 12 +1.573517463148064e-03 28 13 +5.814421846018108e-04 28 14 +1.585057189477723e-04 28 15 +6.269150114528087e-05 28 16 +1.585057189477723e-04 28 17 +5.814421846018108e-04 28 18 +1.573517463148064e-03 28 19 +2.912274546185048e-03 28 20 +3.623902514336288e-03 28 21 +3.026685345607163e-03 28 22 +1.710357891797661e-03 28 23 +6.695452279961972e-04 28 24 +1.924256950599667e-04 28 25 +4.596797846319543e-05 28 26 +1.121238171560661e-05 28 27 +3.556606295780957e-06 28 28 +1.774875725028040e-06 28 29 +1.650917666586412e-06 28 30 +2.040365887620211e-06 29 0 +2.889936412548378e-06 29 1 +2.523107656067143e-06 29 2 +2.137256869716177e-06 29 3 +2.408742209727751e-06 29 4 +7.837863399645522e-06 29 5 +4.293412664154757e-05 29 6 +2.012737823483604e-04 29 7 +7.094420933272181e-04 29 8 +1.788723143733490e-03 29 9 +3.116507360268357e-03 29 10 +3.668485365947303e-03 29 11 +2.864609577951840e-03 29 12 +1.444029026933867e-03 29 13 +4.403845160530417e-04 29 14 +6.521201643211877e-05 29 15 +2.389980714464935e-07 29 16 +6.521201643211877e-05 29 17 +4.403845160530417e-04 29 18 +1.444029026933867e-03 29 19 +2.864609577951840e-03 29 20 +3.668485365947303e-03 29 21 +3.116507360268357e-03 29 22 +1.788723143733490e-03 29 23 +7.094420933272181e-04 29 24 +2.012737823483604e-04 29 25 +4.293412664154757e-05 29 26 +7.837863399645522e-06 29 27 +2.408742209727751e-06 29 28 +2.137256869716177e-06 29 29 +2.523107656067143e-06 29 30 +2.889936412548378e-06 30 0 +3.189540008095353e-06 30 1 +2.665276215102024e-06 30 2 +1.538390887473923e-06 30 3 +2.126393704049059e-07 30 4 +2.872410902877456e-06 30 5 +3.332700529158972e-05 30 6 +1.874186897482456e-04 30 7 +7.023315789295831e-04 30 8 +1.808842702438711e-03 30 9 +3.169450767598823e-03 30 10 +3.727981450772813e-03 30 11 +2.895425157778220e-03 30 12 +1.436817970496205e-03 30 13 +4.198892675035715e-04 30 14 +6.131415667355502e-05 30 15 +9.736971670136333e-06 30 16 +6.131415667355502e-05 30 17 +4.198892675035715e-04 30 18 +1.436817970496205e-03 30 19 +2.895425157778220e-03 30 20 +3.727981450772813e-03 30 21 +3.169450767598823e-03 30 22 +1.808842702438711e-03 30 23 +7.023315789295831e-04 30 24 +1.874186897482456e-04 30 25 +3.332700529158972e-05 30 26 +2.872410902877456e-06 30 27 +2.126393704049059e-07 30 28 +1.538390887473923e-06 30 29 +2.665276215102024e-06 30 30 +3.189540008095353e-06 pyx-project-pyx-21f71ce/examples/3dgraphs/color.py000077500000000000000000000006431526513311100222530ustar00rootroot00000000000000#!/usr/bin/env python from pyx import * g = graph.graphxyz(size=4, projector=graph.graphxyz.parallel(170, 45)) g.plot(graph.data.file("color.dat", x=1, y=2, z=3, color=3), [graph.style.surface(gradient=color.gradient.RedGreen, gridcolor=color.rgb.black, backcolor=color.rgb.black)]) g.writeEPSfile("color") g.writePDFfile("color") g.writeSVGfile("color") pyx-project-pyx-21f71ce/examples/3dgraphs/color.txt000066400000000000000000000017761526513311100224470ustar00rootroot00000000000000A colored surface To add colors to the surface you need to pass color data to the plot command. As in this example, you can just reuse the z value. Alternatively you could pass some independend color data. ... To bring colors instead of black/white to the surface, you need to change the gradient. Be sure to use the same color space for the gridcolor and the backcolor too. ! In this example we also modified the projector. By that you can change the view angle, and you can also (as in this example) use a parallel projection instead of the default central projection. While the later looks more natural, a parallel projection keeps lines parallel independend from their depths. An very simple justification of the parallel projection is the vertical z axis, which stays vertical in the projection. Also the linear axes have equal distances between the ticks, which is not true for central projections. ! Skipping the value for the z component will allow you to plot this surface on a two-dimensional graph as well. pyx-project-pyx-21f71ce/examples/3dgraphs/grid.dat000066400000000000000000000651611526513311100222050ustar00rootroot000000000000000 0 +2.744434246094877e-06 0 1 +2.518061584101027e-06 0 2 +1.759486087349929e-06 0 3 +9.970876191013776e-07 0 4 +3.824133190986796e-06 0 5 +2.975115378597332e-05 0 6 +1.699285851675448e-04 0 7 +6.720788024534639e-04 0 8 +1.792832060948163e-03 0 9 +3.200655253796644e-03 0 10 +3.816618683189747e-03 0 11 +3.032150111960852e-03 0 12 +1.590229109988915e-03 0 13 +5.326214926640671e-04 0 14 +9.904354320939544e-05 0 15 +9.357929797648389e-06 0 16 +9.904354320939544e-05 0 17 +5.326214926640671e-04 0 18 +1.590229109988915e-03 0 19 +3.032150111960852e-03 0 20 +3.816618683189747e-03 0 21 +3.200655253796644e-03 0 22 +1.792832060948163e-03 0 23 +6.720788024534639e-04 0 24 +1.699285851675448e-04 0 25 +2.975115378597332e-05 0 26 +3.824133190986796e-06 0 27 +9.970876191013776e-07 0 28 +1.759486087349929e-06 0 29 +2.518061584101027e-06 0 30 +2.744434246094877e-06 1 0 +1.653567652207974e-06 1 1 +2.080019415431434e-06 1 2 +2.256392327443844e-06 1 3 +2.353042222660531e-06 1 4 +4.658691276947686e-06 1 5 +2.435782462200616e-05 1 6 +1.490972431055931e-04 1 7 +6.377284017517769e-04 1 8 +1.771582235157512e-03 1 9 +3.225933640796166e-03 1 10 +3.906803557194595e-03 1 11 +3.197308254883010e-03 1 12 +1.817291725241250e-03 1 13 +7.630389801230493e-04 1 14 +2.807603469492349e-04 1 15 +1.608446672699473e-04 1 16 +2.807603469492349e-04 1 17 +7.630389801230493e-04 1 18 +1.817291725241250e-03 1 19 +3.197308254883010e-03 1 20 +3.906803557194595e-03 1 21 +3.225933640796166e-03 1 22 +1.771582235157512e-03 1 23 +6.377284017517769e-04 1 24 +1.490972431055931e-04 1 25 +2.435782462200616e-05 1 26 +4.658691276947686e-06 1 27 +2.353042222660531e-06 1 28 +2.256392327443844e-06 1 29 +2.080019415431434e-06 1 30 +1.653567652207974e-06 2 0 +4.903222446513287e-07 2 1 +1.470523991761591e-06 2 2 +2.270477656555739e-06 2 3 +1.893286577894258e-06 2 4 +8.875040369628528e-07 2 5 +1.382699095923903e-05 2 6 +1.323259508158545e-04 2 7 +6.252257214541712e-04 2 8 +1.780184015590029e-03 2 9 +3.259559977840245e-03 2 10 +3.952100806252818e-03 2 11 +3.252471803511440e-03 2 12 +1.899491987795393e-03 2 13 +8.762282695816127e-04 2 14 +4.087748017613867e-04 2 15 +2.912636182938809e-04 2 16 +4.087748017613867e-04 2 17 +8.762282695816127e-04 2 18 +1.899491987795393e-03 2 19 +3.252471803511440e-03 2 20 +3.952100806252818e-03 2 21 +3.259559977840245e-03 2 22 +1.780184015590029e-03 2 23 +6.252257214541712e-04 2 24 +1.323259508158545e-04 2 25 +1.382699095923903e-05 2 26 +8.875040369628528e-07 2 27 +1.893286577894258e-06 2 28 +2.270477656555739e-06 2 29 +1.470523991761591e-06 2 30 +4.903222446513287e-07 3 0 +2.525077324128639e-07 3 1 +1.411976960236152e-06 3 2 +2.585027402357342e-06 3 3 +2.455329005085701e-06 3 4 +1.524299827202244e-06 3 5 +1.730855351620528e-05 3 6 +1.485538901683144e-04 3 7 +6.672169413806638e-04 3 8 +1.845851704536038e-03 3 9 +3.314019707590146e-03 3 10 +3.938097395997995e-03 3 11 +3.137337133297499e-03 3 12 +1.714725940474006e-03 3 13 +6.894032775764756e-04 3 14 +2.562722332523367e-04 3 15 +1.572414788470460e-04 3 16 +2.562722332523367e-04 3 17 +6.894032775764756e-04 3 18 +1.714725940474006e-03 3 19 +3.137337133297499e-03 3 20 +3.938097395997995e-03 3 21 +3.314019707590146e-03 3 22 +1.845851704536038e-03 3 23 +6.672169413806638e-04 3 24 +1.485538901683144e-04 3 25 +1.730855351620528e-05 3 26 +1.524299827202244e-06 3 27 +2.455329005085701e-06 3 28 +2.585027402357342e-06 3 29 +1.411976960236152e-06 3 30 +2.525077324128639e-07 4 0 +1.226989384095427e-06 4 1 +2.143934503008343e-06 4 2 +3.419052137664231e-06 4 3 +5.044497070280032e-06 4 4 +1.019883325351201e-05 4 5 +4.134677767967157e-05 4 6 +2.024165951452637e-04 4 7 +7.595561633249549e-04 4 8 +1.957907998196094e-03 4 9 +3.390836776047649e-03 4 10 +3.907691866900613e-03 4 11 +2.958824680334640e-03 4 12 +1.433416637054468e-03 4 13 +4.183160198044826e-04 4 14 +6.825032672642671e-05 4 15 +1.565122491813854e-05 4 16 +6.825032672642671e-05 4 17 +4.183160198044826e-04 4 18 +1.433416637054468e-03 4 19 +2.958824680334640e-03 4 20 +3.907691866900613e-03 4 21 +3.390836776047649e-03 4 22 +1.957907998196094e-03 4 23 +7.595561633249549e-04 4 24 +2.024165951452637e-04 4 25 +4.134677767967157e-05 4 26 +1.019883325351201e-05 4 27 +5.044497070280032e-06 4 28 +3.419052137664231e-06 4 29 +2.143934503008343e-06 4 30 +1.226989384095427e-06 5 0 +2.307317576927403e-06 5 1 +2.716699175289595e-06 5 2 +3.392503181823541e-06 5 3 +5.499844452398325e-06 5 4 +1.535221942328690e-05 5 5 +6.146497948927013e-05 5 6 +2.527173255797678e-04 5 7 +8.466746072201876e-04 5 8 +2.063200871238251e-03 5 9 +3.474385548526664e-03 5 10 +3.926889486415615e-03 5 11 +2.892497988275950e-03 5 12 +1.312540781600459e-03 5 13 +3.136255923160151e-04 5 14 +2.172446734687579e-05 5 15 +7.019738683128956e-09 5 16 +2.172446734687579e-05 5 17 +3.136255923160151e-04 5 18 +1.312540781600459e-03 5 19 +2.892497988275950e-03 5 20 +3.926889486415615e-03 5 21 +3.474385548526664e-03 5 22 +2.063200871238251e-03 5 23 +8.466746072201876e-04 5 24 +2.527173255797678e-04 5 25 +6.146497948927013e-05 5 26 +1.535221942328690e-05 5 27 +5.499844452398325e-06 5 28 +3.392503181823541e-06 5 29 +2.716699175289595e-06 5 30 +2.307317576927403e-06 6 0 +2.373332825254899e-06 6 1 +2.321653560233388e-06 6 2 +1.822958685202512e-06 6 3 +1.998034295855592e-06 6 4 +1.070244688479249e-05 6 5 +6.062668963464542e-05 6 6 +2.637758074029551e-04 6 7 +8.732926224204041e-04 6 8 +2.104254493353289e-03 6 9 +3.536589556516121e-03 6 10 +4.022793689595565e-03 6 11 +3.021560454986797e-03 6 12 +1.452268740872702e-03 6 13 +4.229684890191378e-04 6 14 +7.183483566560646e-05 6 15 +1.825194993036989e-05 6 16 +7.183483566560646e-05 6 17 +4.229684890191378e-04 6 18 +1.452268740872702e-03 6 19 +3.021560454986797e-03 6 20 +4.022793689595565e-03 6 21 +3.536589556516121e-03 6 22 +2.104254493353289e-03 6 23 +8.732926224204041e-04 6 24 +2.637758074029551e-04 6 25 +6.062668963464542e-05 6 26 +1.070244688479249e-05 6 27 +1.998034295855592e-06 6 28 +1.822958685202512e-06 6 29 +2.321653560233388e-06 6 30 +2.373332825254899e-06 7 0 +1.587195130150310e-06 7 1 +1.713658780206171e-06 7 2 +9.411594223291881e-07 7 3 +6.776789721331578e-08 7 4 +6.860825504386979e-06 7 5 +5.146201467104523e-05 7 6 +2.396166831456199e-04 7 7 +8.264643309087650e-04 7 8 +2.056438818405584e-03 7 9 +3.549963363240440e-03 7 10 +4.156944303260867e-03 7 11 +3.275907813144717e-03 7 12 +1.756915148324869e-03 7 13 +6.844759133332523e-04 7 14 +2.464153674380294e-04 7 15 +1.495346760772398e-04 7 16 +2.464153674380294e-04 7 17 +6.844759133332523e-04 7 18 +1.756915148324869e-03 7 19 +3.275907813144717e-03 7 20 +4.156944303260867e-03 7 21 +3.549963363240440e-03 7 22 +2.056438818405584e-03 7 23 +8.264643309087650e-04 7 24 +2.396166831456199e-04 7 25 +5.146201467104523e-05 7 26 +6.860825504386979e-06 7 27 +6.776789721331578e-08 7 28 +9.411594223291881e-07 7 29 +1.713658780206171e-06 7 30 +1.587195130150310e-06 8 0 +5.842895768532483e-07 8 1 +1.514582924947651e-06 8 2 +1.918239459944766e-06 8 3 +2.478661441644039e-06 8 4 +8.932418369414274e-06 8 5 +4.159804448997610e-05 8 6 +1.917917504088143e-04 8 7 +7.237846411730068e-04 8 8 +1.937637574805104e-03 8 9 +3.510202961653063e-03 8 10 +4.266350475238421e-03 8 11 +3.503586015126449e-03 8 12 +1.998570138710667e-03 8 13 +8.585196678491770e-04 8 14 +3.479814933876024e-04 8 15 +2.236338486521513e-04 8 16 +3.479814933876024e-04 8 17 +8.585196678491770e-04 8 18 +1.998570138710667e-03 8 19 +3.503586015126449e-03 8 20 +4.266350475238421e-03 8 21 +3.510202961653063e-03 8 22 +1.937637574805104e-03 8 23 +7.237846411730068e-04 8 24 +1.917917504088143e-04 8 25 +4.159804448997610e-05 8 26 +8.932418369414274e-06 8 27 +2.478661441644039e-06 8 28 +1.918239459944766e-06 8 29 +1.514582924947651e-06 8 30 +5.842895768532483e-07 9 0 +3.642883870758245e-07 9 1 +2.053202999470949e-06 9 2 +3.837166158545995e-06 9 3 +5.348894469071784e-06 9 4 +7.858828200887174e-06 9 5 +2.145531964264211e-05 9 6 +1.278998893281748e-04 9 7 +6.057443575635683e-04 9 8 +1.807819709990386e-03 9 9 +3.456094204549144e-03 9 10 +4.332932758161096e-03 9 11 +3.623389816823501e-03 9 12 +2.054991941718712e-03 9 13 +8.036014751161785e-04 9 14 +2.166177170601839e-04 9 15 +6.915211547501020e-05 9 16 +2.166177170601839e-04 9 17 +8.036014751161785e-04 9 18 +2.054991941718712e-03 9 19 +3.623389816823501e-03 9 20 +4.332932758161096e-03 9 21 +3.456094204549144e-03 9 22 +1.807819709990386e-03 9 23 +6.057443575635683e-04 9 24 +1.278998893281748e-04 9 25 +2.145531964264211e-05 9 26 +7.858828200887174e-06 9 27 +5.348894469071784e-06 9 28 +3.837166158545995e-06 9 29 +2.053202999470949e-06 9 30 +3.642883870758245e-07 10 0 +2.512490246878957e-06 10 1 +4.396610854841844e-06 10 2 +6.575545000503195e-06 10 3 +7.083439501810090e-06 10 4 +3.470894493160968e-06 10 5 +2.622883261358829e-06 10 6 +8.709326319537562e-05 10 7 +5.447133938049011e-04 10 8 +1.752837291237968e-03 10 9 +3.455315221404786e-03 10 10 +4.398958252080046e-03 10 11 +3.686186997488258e-03 10 12 +2.037578409116048e-03 10 13 +7.234336912109821e-04 10 14 +1.396226098258371e-04 10 15 +7.543732908067557e-06 10 16 +1.396226098258371e-04 10 17 +7.234336912109821e-04 10 18 +2.037578409116048e-03 10 19 +3.686186997488258e-03 10 20 +4.398958252080046e-03 10 21 +3.455315221404786e-03 10 22 +1.752837291237968e-03 10 23 +5.447133938049011e-04 10 24 +8.709326319537562e-05 10 25 +2.622883261358829e-06 10 26 +3.470894493160968e-06 10 27 +7.083439501810090e-06 10 28 +6.575545000503195e-06 10 29 +4.396610854841844e-06 10 30 +2.512490246878957e-06 11 0 +6.815671315359540e-06 11 1 +8.264538431099037e-06 11 2 +1.005401247062773e-05 11 3 +1.059684653758765e-05 11 4 +8.755895107819839e-06 11 5 +1.555038478500510e-05 11 6 +1.170561839376850e-04 11 7 +5.962253896499082e-04 11 8 +1.824100571423304e-03 11 9 +3.550529315318575e-03 11 10 +4.513631727635005e-03 11 11 +3.777400017948165e-03 11 12 +2.069898556039909e-03 11 13 +7.321944395611375e-04 11 14 +1.800591890588128e-04 11 15 +7.252664246864497e-05 11 16 +1.800591890588128e-04 11 17 +7.321944395611375e-04 11 18 +2.069898556039909e-03 11 19 +3.777400017948165e-03 11 20 +4.513631727635005e-03 11 21 +3.550529315318575e-03 11 22 +1.824100571423304e-03 11 23 +5.962253896499082e-04 11 24 +1.170561839376850e-04 11 25 +1.555038478500510e-05 11 26 +8.755895107819839e-06 11 27 +1.059684653758765e-05 11 28 +1.005401247062773e-05 11 29 +8.264538431099037e-06 11 30 +6.815671315359540e-06 12 0 +9.749610156771229e-06 12 1 +1.055180001296198e-05 12 2 +1.180987001645569e-05 12 3 +1.395571025914737e-05 12 4 +2.057271886339045e-05 12 5 +5.026620068793996e-05 12 6 +1.931212798890028e-04 12 7 +7.199830460496915e-04 12 8 +1.978312822663844e-03 12 9 +3.714503821754403e-03 12 10 +4.680865749503483e-03 12 11 +3.932112021941086e-03 12 12 +2.178726369038801e-03 12 13 +7.706810332112831e-04 12 14 +1.501137773096962e-04 12 15 +1.261640298775073e-05 12 16 +1.501137773096962e-04 12 17 +7.706810332112831e-04 12 18 +2.178726369038801e-03 12 19 +3.932112021941086e-03 12 20 +4.680865749503483e-03 12 21 +3.714503821754403e-03 12 22 +1.978312822663844e-03 12 23 +7.199830460496915e-04 12 24 +1.931212798890028e-04 12 25 +5.026620068793996e-05 12 26 +2.057271886339045e-05 12 27 +1.395571025914737e-05 12 28 +1.180987001645569e-05 12 29 +1.055180001296198e-05 12 30 +9.749610156771229e-06 13 0 +8.490623059819040e-06 13 1 +8.799846154170221e-06 13 2 +8.994677966752248e-06 13 3 +1.010871017786102e-05 13 4 +1.870330300271311e-05 13 5 +6.084068161357250e-05 13 6 +2.356274475978317e-04 13 7 +8.098356562680192e-04 13 8 +2.107865874310841e-03 13 9 +3.865318650390775e-03 13 10 +4.852291507897281e-03 13 11 +4.126295330348602e-03 13 12 +2.369155320117100e-03 13 13 +9.147697022767272e-04 13 14 +2.308142003576141e-04 13 15 +6.328836926190641e-05 13 16 +2.308142003576141e-04 13 17 +9.147697022767272e-04 13 18 +2.369155320117100e-03 13 19 +4.126295330348602e-03 13 20 +4.852291507897281e-03 13 21 +3.865318650390775e-03 13 22 +2.107865874310841e-03 13 23 +8.098356562680192e-04 13 24 +2.356274475978317e-04 13 25 +6.084068161357250e-05 13 26 +1.870330300271311e-05 13 27 +1.010871017786102e-05 13 28 +8.994677966752248e-06 13 29 +8.799846154170221e-06 13 30 +8.490623059819040e-06 14 0 +4.687403389656196e-06 14 1 +5.079153114463964e-06 14 2 +4.497918246229313e-06 14 3 +2.774071303358379e-06 14 4 +5.904632068328592e-06 14 5 +4.270413859622926e-05 14 6 +2.207746257698169e-04 14 7 +8.135918874377782e-04 14 8 +2.139508173337537e-03 14 9 +3.927780870116436e-03 14 10 +4.956023042244558e-03 14 11 +4.277097097416137e-03 14 12 +2.546496865618815e-03 14 13 +1.093698356447127e-03 14 14 +4.092148715898557e-04 14 15 +2.440103587145870e-04 14 16 +4.092148715898557e-04 14 17 +1.093698356447127e-03 14 18 +2.546496865618815e-03 14 19 +4.277097097416137e-03 14 20 +4.956023042244558e-03 14 21 +3.927780870116436e-03 14 22 +2.139508173337537e-03 14 23 +8.135918874377782e-04 14 24 +2.207746257698169e-04 14 25 +4.270413859622926e-05 14 26 +5.904632068328592e-06 14 27 +2.774071303358379e-06 14 28 +4.497918246229313e-06 14 29 +5.079153114463964e-06 14 30 +4.687403389656196e-06 15 0 +1.501257749887276e-06 15 1 +2.435756825174617e-06 15 2 +2.411966242960009e-06 15 3 +7.157054724050202e-07 15 4 +1.716069852294603e-06 15 5 +3.013705168409485e-05 15 6 +1.904842036316344e-04 15 7 +7.619892865676402e-04 15 8 +2.077488033630016e-03 15 9 +3.878674705777598e-03 15 10 +4.943717078853101e-03 15 11 +4.303065526353173e-03 15 12 +2.573644579802008e-03 15 13 +1.075135802949144e-03 15 14 +3.350972364282421e-04 15 15 +1.464398667425757e-04 15 16 +3.350972364282421e-04 15 17 +1.075135802949144e-03 15 18 +2.573644579802008e-03 15 19 +4.303065526353173e-03 15 20 +4.943717078853101e-03 15 21 +3.878674705777598e-03 15 22 +2.077488033630016e-03 15 23 +7.619892865676402e-04 15 24 +1.904842036316344e-04 15 25 +3.013705168409485e-05 15 26 +1.716069852294603e-06 15 27 +7.157054724050202e-07 15 28 +2.411966242960009e-06 15 29 +2.435756825174617e-06 15 30 +1.501257749887276e-06 16 0 +2.323571591220434e-07 16 1 +1.393475802039957e-06 16 2 +2.091541786468290e-06 16 3 +2.126752993258124e-06 16 4 +4.835644738161436e-06 16 5 +2.852474621669622e-05 16 6 +1.659548141126014e-04 16 7 +6.933826714206772e-04 16 8 +1.963201825373199e-03 16 9 +3.743280998425761e-03 16 10 +4.819314315173870e-03 16 11 +4.206415709376830e-03 16 12 +2.492191540160578e-03 16 13 +9.778007064550418e-04 16 14 +2.051669934845689e-04 16 15 +7.791777078841276e-08 16 16 +2.051669934845689e-04 16 17 +9.778007064550418e-04 16 18 +2.492191540160578e-03 16 19 +4.206415709376830e-03 16 20 +4.819314315173870e-03 16 21 +3.743280998425761e-03 16 22 +1.963201825373199e-03 16 23 +6.933826714206772e-04 16 24 +1.659548141126014e-04 16 25 +2.852474621669622e-05 16 26 +4.835644738161436e-06 16 27 +2.126752993258124e-06 16 28 +2.091541786468290e-06 16 29 +1.393475802039957e-06 16 30 +2.323571591220434e-07 17 0 +6.534106903077690e-07 17 1 +1.487306123431552e-06 17 2 +1.979172297174789e-06 17 3 +1.976234205687681e-06 17 4 +3.531951296812328e-06 17 5 +2.095624840708503e-05 17 6 +1.382476024308607e-04 17 7 +6.241889811214583e-04 17 8 +1.838277343110348e-03 17 9 +3.567829091690213e-03 17 10 +4.619649049288467e-03 17 11 +4.029180994811406e-03 17 12 +2.389692813180007e-03 17 13 +9.801953064551853e-04 17 14 +3.010360683959697e-04 17 15 +1.339147984653232e-04 17 16 +3.010360683959697e-04 17 17 +9.801953064551853e-04 17 18 +2.389692813180007e-03 17 19 +4.029180994811406e-03 17 20 +4.619649049288467e-03 17 21 +3.567829091690213e-03 17 22 +1.838277343110348e-03 17 23 +6.241889811214583e-04 17 24 +1.382476024308607e-04 17 25 +2.095624840708503e-05 17 26 +3.531951296812328e-06 17 27 +1.976234205687681e-06 17 28 +1.979172297174789e-06 17 29 +1.487306123431552e-06 17 30 +6.534106903077690e-07 18 0 +1.876059361241538e-06 18 1 +2.057784840208347e-06 18 2 +1.777613271338336e-06 18 3 +8.699234969159874e-07 18 4 +1.968652577303025e-07 18 5 +1.208171122223021e-05 18 6 +1.171139379151092e-04 18 7 +5.767959563594669e-04 18 8 +1.740740070141123e-03 18 9 +3.396802527464631e-03 18 10 +4.382735284334756e-03 18 11 +3.786662133385478e-03 18 12 +2.219758764675431e-03 18 13 +9.142867897053784e-04 18 14 +3.110029558942641e-04 18 15 +1.692446500089834e-04 18 16 +3.110029558942641e-04 18 17 +9.142867897053784e-04 18 18 +2.219758764675431e-03 18 19 +3.786662133385478e-03 18 20 +4.382735284334756e-03 18 21 +3.396802527464631e-03 18 22 +1.740740070141123e-03 18 23 +5.767959563594669e-04 18 24 +1.171139379151092e-04 18 25 +1.208171122223021e-05 18 26 +1.968652577303025e-07 18 27 +8.699234969159874e-07 18 28 +1.777613271338336e-06 18 29 +2.057784840208347e-06 18 30 +1.876059361241538e-06 19 0 +3.062840789809967e-06 19 1 +2.527808076843036e-06 19 2 +1.633271973488836e-06 19 3 +9.736235185669393e-07 19 4 +1.380503967706013e-06 19 5 +1.469419689216322e-05 19 6 +1.207048147882760e-04 19 7 +5.719123589096748e-04 19 8 +1.692871022540258e-03 19 9 +3.256428719310688e-03 19 10 +4.139632891211538e-03 19 11 +3.504909208546127e-03 19 12 +1.982724381278589e-03 19 13 +7.402920491410022e-04 19 14 +1.617462685140096e-04 19 15 +2.053330572468854e-05 19 16 +1.617462685140096e-04 19 17 +7.402920491410022e-04 19 18 +1.982724381278589e-03 19 19 +3.504909208546127e-03 19 20 +4.139632891211538e-03 19 21 +3.256428719310688e-03 19 22 +1.692871022540258e-03 19 23 +5.719123589096748e-04 19 24 +1.207048147882760e-04 19 25 +1.469419689216322e-05 19 26 +1.380503967706013e-06 19 27 +9.736235185669393e-07 19 28 +1.633271973488836e-06 19 29 +2.527808076843036e-06 19 30 +3.062840789809967e-06 20 0 +3.965288889790357e-06 20 1 +2.752129060676672e-06 20 2 +1.161841016756794e-06 20 3 +5.701545853936663e-07 20 4 +3.098355792788597e-06 20 5 +2.353023458085338e-05 20 6 +1.431860973840122e-04 20 7 +6.003781224686864e-04 20 8 +1.683390907031591e-03 20 9 +3.145644377756497e-03 20 10 +3.912068929840578e-03 20 11 +3.233033884460954e-03 20 12 +1.771385768497788e-03 20 13 +6.375462234056684e-04 20 14 +1.434980619272460e-04 20 15 +3.195125662258565e-05 20 16 +1.434980619272460e-04 20 17 +6.375462234056684e-04 20 18 +1.771385768497788e-03 20 19 +3.233033884460954e-03 20 20 +3.912068929840578e-03 20 21 +3.145644377756497e-03 20 22 +1.683390907031591e-03 20 23 +6.003781224686864e-04 20 24 +1.431860973840122e-04 20 25 +2.353023458085338e-05 20 26 +3.098355792788597e-06 20 27 +5.701545853936663e-07 20 28 +1.161841016756794e-06 20 29 +2.752129060676672e-06 20 30 +3.965288889790357e-06 21 0 +4.809474577021396e-06 21 1 +3.265902127647575e-06 21 2 +1.153290298311127e-06 21 3 +1.734187798996243e-07 21 4 +4.307226170255345e-06 21 5 +3.268845994111086e-05 21 6 +1.673952798494322e-04 21 7 +6.297509875229867e-04 21 8 +1.674683627968040e-03 21 9 +3.043996694190472e-03 21 10 +3.709176492544443e-03 21 11 +2.997312013828311e-03 21 12 +1.599019952667030e-03 21 13 +5.728662937094130e-04 21 14 +1.609992934304200e-04 21 15 +7.737655471200314e-05 21 16 +1.609992934304200e-04 21 17 +5.728662937094130e-04 21 18 +1.599019952667030e-03 21 19 +2.997312013828311e-03 21 20 +3.709176492544443e-03 21 21 +3.043996694190472e-03 21 22 +1.674683627968040e-03 21 23 +6.297509875229867e-04 21 24 +1.673952798494322e-04 21 25 +3.268845994111086e-05 21 26 +4.307226170255345e-06 21 27 +1.734187798996243e-07 21 28 +1.153290298311127e-06 21 29 +3.265902127647575e-06 21 30 +4.809474577021396e-06 22 0 +5.555042869803733e-06 22 1 +4.420635368354199e-06 22 2 +3.028730507567648e-06 22 3 +3.100707295620601e-06 22 4 +9.243914480592160e-06 22 5 +4.087587045427118e-05 22 6 +1.760607022307088e-04 22 7 +6.247370338825327e-04 22 8 +1.629230426377810e-03 22 9 +2.933474132420932e-03 22 10 +3.538408480595143e-03 22 11 +2.811983434809747e-03 22 12 +1.451910099681378e-03 22 13 +4.768548007400953e-04 22 14 +9.099433778678653e-05 22 15 +1.171746709542609e-05 22 16 +9.099433778678653e-05 22 17 +4.768548007400953e-04 22 18 +1.451910099681378e-03 22 19 +2.811983434809747e-03 22 20 +3.538408480595143e-03 22 21 +2.933474132420932e-03 22 22 +1.629230426377810e-03 22 23 +6.247370338825327e-04 22 24 +1.760607022307088e-04 22 25 +4.087587045427118e-05 22 26 +9.243914480592160e-06 22 27 +3.100707295620601e-06 22 28 +3.028730507567648e-06 22 29 +4.420635368354199e-06 22 30 +5.555042869803733e-06 23 0 +5.404189672356805e-06 23 1 +4.892870830299098e-06 23 2 +4.557607934560358e-06 23 3 +5.537092541242136e-06 23 4 +1.083855203679700e-05 23 5 +3.547085934154473e-05 23 6 +1.510775020427121e-04 23 7 +5.676546615136151e-04 23 8 +1.538572432507774e-03 23 9 +2.819067621052516e-03 23 10 +3.417150766148686e-03 23 11 +2.705429500718680e-03 23 12 +1.374749562040417e-03 23 13 +4.333463453912217e-04 23 14 +7.941771000134053e-05 23 15 +1.479566369747944e-05 23 16 +7.941771000134053e-05 23 17 +4.333463453912217e-04 23 18 +1.374749562040417e-03 23 19 +2.705429500718680e-03 23 20 +3.417150766148686e-03 23 21 +2.819067621052516e-03 23 22 +1.538572432507774e-03 23 23 +5.676546615136151e-04 23 24 +1.510775020427121e-04 23 25 +3.547085934154473e-05 23 26 +1.083855203679700e-05 23 27 +5.537092541242136e-06 23 28 +4.557607934560358e-06 23 29 +4.892870830299098e-06 23 30 +5.404189672356805e-06 24 0 +3.955165536724783e-06 24 1 +3.584741991399201e-06 24 2 +3.508885372422360e-06 24 3 +3.939399145842972e-06 24 4 +4.822757117855054e-06 24 5 +1.528945559383431e-05 24 6 +1.028440676156929e-04 24 7 +4.865196638755525e-04 24 8 +1.440956718322974e-03 24 9 +2.733108955173010e-03 24 10 +3.366008382925306e-03 24 11 +2.697020398631471e-03 24 12 +1.391340841413025e-03 24 13 +4.489266759395228e-04 24 14 +8.931113109195366e-05 24 15 +2.423720573557286e-05 24 16 +8.931113109195366e-05 24 17 +4.489266759395228e-04 24 18 +1.391340841413025e-03 24 19 +2.697020398631471e-03 24 20 +3.366008382925306e-03 24 21 +2.733108955173010e-03 24 22 +1.440956718322974e-03 24 23 +4.865196638755525e-04 24 24 +1.028440676156929e-04 24 25 +1.528945559383431e-05 24 26 +4.822757117855054e-06 24 27 +3.939399145842972e-06 24 28 +3.508885372422360e-06 24 29 +3.584741991399201e-06 24 30 +3.955165536724783e-06 25 0 +2.214633245267957e-06 25 1 +1.585525169790331e-06 25 2 +1.483434350126737e-06 25 3 +1.972238971450125e-06 25 4 +8.239998404110594e-07 25 5 +3.274470653067594e-06 25 6 +7.580088249132948e-05 25 7 +4.457366278418717e-04 25 8 +1.401383271659800e-03 25 9 +2.715854393917418e-03 25 10 +3.391604051034845e-03 25 11 +2.775387360033505e-03 25 12 +1.495302570719864e-03 25 13 +5.208990796590071e-04 25 14 +9.956297062102457e-05 25 15 +4.074204269152465e-06 25 16 +9.956297062102457e-05 25 17 +5.208990796590071e-04 25 18 +1.495302570719864e-03 25 19 +2.775387360033505e-03 25 20 +3.391604051034845e-03 25 21 +2.715854393917418e-03 25 22 +1.401383271659800e-03 25 23 +4.457366278418717e-04 25 24 +7.580088249132948e-05 25 25 +3.274470653067594e-06 25 26 +8.239998404110594e-07 25 27 +1.972238971450125e-06 25 28 +1.483434350126737e-06 25 29 +1.585525169790331e-06 25 30 +2.214633245267957e-06 26 0 +1.270433760442372e-06 26 1 +3.916387056204372e-07 26 2 +2.231233391960010e-07 26 3 +1.503250077270970e-06 26 4 +3.125235105917701e-06 26 5 +1.232580616064923e-05 26 6 +9.755857943602422e-05 26 7 +4.851055857767528e-04 26 8 +1.457115907850736e-03 26 9 +2.782087863624691e-03 26 10 +3.471885190847275e-03 26 11 +2.885556868129979e-03 26 12 +1.636626067410123e-03 26 13 +6.667717289764138e-04 26 14 +2.263997570460314e-04 26 15 +1.189280941020137e-04 26 16 +2.263997570460314e-04 26 17 +6.667717289764138e-04 26 18 +1.636626067410123e-03 26 19 +2.885556868129979e-03 26 20 +3.471885190847275e-03 26 21 +2.782087863624691e-03 26 22 +1.457115907850736e-03 26 23 +4.851055857767528e-04 26 24 +9.755857943602422e-05 26 25 +1.232580616064923e-05 26 26 +3.125235105917701e-06 26 27 +1.503250077270970e-06 26 28 +2.231233391960010e-07 26 29 +3.916387056204372e-07 26 30 +1.270433760442372e-06 27 0 +1.299354594308245e-06 27 1 +5.522911269684502e-07 27 2 +4.619462725569895e-07 27 3 +2.265200690627976e-06 27 4 +8.097778286089136e-06 27 5 +3.240334951419666e-05 27 6 +1.498979407853844e-04 27 7 +5.803392722650569e-04 27 8 +1.582282591448272e-03 27 9 +2.903121917018245e-03 27 10 +3.560888391768400e-03 27 11 +2.942173666034896e-03 27 12 +1.681218578604672e-03 27 13 +7.183020985079531e-04 27 14 +2.890668649459803e-04 27 15 +1.861637286406668e-04 27 16 +2.890668649459803e-04 27 17 +7.183020985079531e-04 27 18 +1.681218578604672e-03 27 19 +2.942173666034896e-03 27 20 +3.560888391768400e-03 27 21 +2.903121917018245e-03 27 22 +1.582282591448272e-03 27 23 +5.803392722650569e-04 27 24 +1.498979407853844e-04 27 25 +3.240334951419666e-05 27 26 +8.097778286089136e-06 27 27 +2.265200690627976e-06 27 28 +4.619462725569895e-07 27 29 +5.522911269684502e-07 27 30 +1.299354594308245e-06 28 0 +2.040365887620211e-06 28 1 +1.650917666586412e-06 28 2 +1.774875725028040e-06 28 3 +3.556606295780957e-06 28 4 +1.121238171560661e-05 28 5 +4.596797846319543e-05 28 6 +1.924256950599667e-04 28 7 +6.695452279961972e-04 28 8 +1.710357891797661e-03 28 9 +3.026685345607163e-03 28 10 +3.623902514336288e-03 28 11 +2.912274546185048e-03 28 12 +1.573517463148064e-03 28 13 +5.814421846018108e-04 28 14 +1.585057189477723e-04 28 15 +6.269150114528087e-05 28 16 +1.585057189477723e-04 28 17 +5.814421846018108e-04 28 18 +1.573517463148064e-03 28 19 +2.912274546185048e-03 28 20 +3.623902514336288e-03 28 21 +3.026685345607163e-03 28 22 +1.710357891797661e-03 28 23 +6.695452279961972e-04 28 24 +1.924256950599667e-04 28 25 +4.596797846319543e-05 28 26 +1.121238171560661e-05 28 27 +3.556606295780957e-06 28 28 +1.774875725028040e-06 28 29 +1.650917666586412e-06 28 30 +2.040365887620211e-06 29 0 +2.889936412548378e-06 29 1 +2.523107656067143e-06 29 2 +2.137256869716177e-06 29 3 +2.408742209727751e-06 29 4 +7.837863399645522e-06 29 5 +4.293412664154757e-05 29 6 +2.012737823483604e-04 29 7 +7.094420933272181e-04 29 8 +1.788723143733490e-03 29 9 +3.116507360268357e-03 29 10 +3.668485365947303e-03 29 11 +2.864609577951840e-03 29 12 +1.444029026933867e-03 29 13 +4.403845160530417e-04 29 14 +6.521201643211877e-05 29 15 +2.389980714464935e-07 29 16 +6.521201643211877e-05 29 17 +4.403845160530417e-04 29 18 +1.444029026933867e-03 29 19 +2.864609577951840e-03 29 20 +3.668485365947303e-03 29 21 +3.116507360268357e-03 29 22 +1.788723143733490e-03 29 23 +7.094420933272181e-04 29 24 +2.012737823483604e-04 29 25 +4.293412664154757e-05 29 26 +7.837863399645522e-06 29 27 +2.408742209727751e-06 29 28 +2.137256869716177e-06 29 29 +2.523107656067143e-06 29 30 +2.889936412548378e-06 30 0 +3.189540008095353e-06 30 1 +2.665276215102024e-06 30 2 +1.538390887473923e-06 30 3 +2.126393704049059e-07 30 4 +2.872410902877456e-06 30 5 +3.332700529158972e-05 30 6 +1.874186897482456e-04 30 7 +7.023315789295831e-04 30 8 +1.808842702438711e-03 30 9 +3.169450767598823e-03 30 10 +3.727981450772813e-03 30 11 +2.895425157778220e-03 30 12 +1.436817970496205e-03 30 13 +4.198892675035715e-04 30 14 +6.131415667355502e-05 30 15 +9.736971670136333e-06 30 16 +6.131415667355502e-05 30 17 +4.198892675035715e-04 30 18 +1.436817970496205e-03 30 19 +2.895425157778220e-03 30 20 +3.727981450772813e-03 30 21 +3.169450767598823e-03 30 22 +1.808842702438711e-03 30 23 +7.023315789295831e-04 30 24 +1.874186897482456e-04 30 25 +3.332700529158972e-05 30 26 +2.872410902877456e-06 30 27 +2.126393704049059e-07 30 28 +1.538390887473923e-06 30 29 +2.665276215102024e-06 30 30 +3.189540008095353e-06 pyx-project-pyx-21f71ce/examples/3dgraphs/grid.py000077500000000000000000000003571526513311100220640ustar00rootroot00000000000000#!/usr/bin/env python from pyx import * g = graph.graphxyz(size=4, z=graph.axis.lin(min=0.001)) g.plot(graph.data.file("grid.dat", x=1, y=2, z=3), [graph.style.grid()]) g.writeEPSfile("grid") g.writePDFfile("grid") g.writeSVGfile("grid") pyx-project-pyx-21f71ce/examples/3dgraphs/grid.txt000066400000000000000000000006121526513311100222420ustar00rootroot00000000000000Stroking the grid The grid as its created by PyX internally can also be stroked by means of the grid style. In this example the minimal value of the z axis was changed too. As lines are cut at graph boundaries properly, this results in a cutted grid. ... ! The surface style does not support cuts at the graph boundary. It'll always skip rectangles partially (or fully) outside of the graph. pyx-project-pyx-21f71ce/examples/3dgraphs/surface.dat000066400000000000000000000651611526513311100227100ustar00rootroot000000000000000 0 +2.744434246094877e-06 0 1 +2.518061584101027e-06 0 2 +1.759486087349929e-06 0 3 +9.970876191013776e-07 0 4 +3.824133190986796e-06 0 5 +2.975115378597332e-05 0 6 +1.699285851675448e-04 0 7 +6.720788024534639e-04 0 8 +1.792832060948163e-03 0 9 +3.200655253796644e-03 0 10 +3.816618683189747e-03 0 11 +3.032150111960852e-03 0 12 +1.590229109988915e-03 0 13 +5.326214926640671e-04 0 14 +9.904354320939544e-05 0 15 +9.357929797648389e-06 0 16 +9.904354320939544e-05 0 17 +5.326214926640671e-04 0 18 +1.590229109988915e-03 0 19 +3.032150111960852e-03 0 20 +3.816618683189747e-03 0 21 +3.200655253796644e-03 0 22 +1.792832060948163e-03 0 23 +6.720788024534639e-04 0 24 +1.699285851675448e-04 0 25 +2.975115378597332e-05 0 26 +3.824133190986796e-06 0 27 +9.970876191013776e-07 0 28 +1.759486087349929e-06 0 29 +2.518061584101027e-06 0 30 +2.744434246094877e-06 1 0 +1.653567652207974e-06 1 1 +2.080019415431434e-06 1 2 +2.256392327443844e-06 1 3 +2.353042222660531e-06 1 4 +4.658691276947686e-06 1 5 +2.435782462200616e-05 1 6 +1.490972431055931e-04 1 7 +6.377284017517769e-04 1 8 +1.771582235157512e-03 1 9 +3.225933640796166e-03 1 10 +3.906803557194595e-03 1 11 +3.197308254883010e-03 1 12 +1.817291725241250e-03 1 13 +7.630389801230493e-04 1 14 +2.807603469492349e-04 1 15 +1.608446672699473e-04 1 16 +2.807603469492349e-04 1 17 +7.630389801230493e-04 1 18 +1.817291725241250e-03 1 19 +3.197308254883010e-03 1 20 +3.906803557194595e-03 1 21 +3.225933640796166e-03 1 22 +1.771582235157512e-03 1 23 +6.377284017517769e-04 1 24 +1.490972431055931e-04 1 25 +2.435782462200616e-05 1 26 +4.658691276947686e-06 1 27 +2.353042222660531e-06 1 28 +2.256392327443844e-06 1 29 +2.080019415431434e-06 1 30 +1.653567652207974e-06 2 0 +4.903222446513287e-07 2 1 +1.470523991761591e-06 2 2 +2.270477656555739e-06 2 3 +1.893286577894258e-06 2 4 +8.875040369628528e-07 2 5 +1.382699095923903e-05 2 6 +1.323259508158545e-04 2 7 +6.252257214541712e-04 2 8 +1.780184015590029e-03 2 9 +3.259559977840245e-03 2 10 +3.952100806252818e-03 2 11 +3.252471803511440e-03 2 12 +1.899491987795393e-03 2 13 +8.762282695816127e-04 2 14 +4.087748017613867e-04 2 15 +2.912636182938809e-04 2 16 +4.087748017613867e-04 2 17 +8.762282695816127e-04 2 18 +1.899491987795393e-03 2 19 +3.252471803511440e-03 2 20 +3.952100806252818e-03 2 21 +3.259559977840245e-03 2 22 +1.780184015590029e-03 2 23 +6.252257214541712e-04 2 24 +1.323259508158545e-04 2 25 +1.382699095923903e-05 2 26 +8.875040369628528e-07 2 27 +1.893286577894258e-06 2 28 +2.270477656555739e-06 2 29 +1.470523991761591e-06 2 30 +4.903222446513287e-07 3 0 +2.525077324128639e-07 3 1 +1.411976960236152e-06 3 2 +2.585027402357342e-06 3 3 +2.455329005085701e-06 3 4 +1.524299827202244e-06 3 5 +1.730855351620528e-05 3 6 +1.485538901683144e-04 3 7 +6.672169413806638e-04 3 8 +1.845851704536038e-03 3 9 +3.314019707590146e-03 3 10 +3.938097395997995e-03 3 11 +3.137337133297499e-03 3 12 +1.714725940474006e-03 3 13 +6.894032775764756e-04 3 14 +2.562722332523367e-04 3 15 +1.572414788470460e-04 3 16 +2.562722332523367e-04 3 17 +6.894032775764756e-04 3 18 +1.714725940474006e-03 3 19 +3.137337133297499e-03 3 20 +3.938097395997995e-03 3 21 +3.314019707590146e-03 3 22 +1.845851704536038e-03 3 23 +6.672169413806638e-04 3 24 +1.485538901683144e-04 3 25 +1.730855351620528e-05 3 26 +1.524299827202244e-06 3 27 +2.455329005085701e-06 3 28 +2.585027402357342e-06 3 29 +1.411976960236152e-06 3 30 +2.525077324128639e-07 4 0 +1.226989384095427e-06 4 1 +2.143934503008343e-06 4 2 +3.419052137664231e-06 4 3 +5.044497070280032e-06 4 4 +1.019883325351201e-05 4 5 +4.134677767967157e-05 4 6 +2.024165951452637e-04 4 7 +7.595561633249549e-04 4 8 +1.957907998196094e-03 4 9 +3.390836776047649e-03 4 10 +3.907691866900613e-03 4 11 +2.958824680334640e-03 4 12 +1.433416637054468e-03 4 13 +4.183160198044826e-04 4 14 +6.825032672642671e-05 4 15 +1.565122491813854e-05 4 16 +6.825032672642671e-05 4 17 +4.183160198044826e-04 4 18 +1.433416637054468e-03 4 19 +2.958824680334640e-03 4 20 +3.907691866900613e-03 4 21 +3.390836776047649e-03 4 22 +1.957907998196094e-03 4 23 +7.595561633249549e-04 4 24 +2.024165951452637e-04 4 25 +4.134677767967157e-05 4 26 +1.019883325351201e-05 4 27 +5.044497070280032e-06 4 28 +3.419052137664231e-06 4 29 +2.143934503008343e-06 4 30 +1.226989384095427e-06 5 0 +2.307317576927403e-06 5 1 +2.716699175289595e-06 5 2 +3.392503181823541e-06 5 3 +5.499844452398325e-06 5 4 +1.535221942328690e-05 5 5 +6.146497948927013e-05 5 6 +2.527173255797678e-04 5 7 +8.466746072201876e-04 5 8 +2.063200871238251e-03 5 9 +3.474385548526664e-03 5 10 +3.926889486415615e-03 5 11 +2.892497988275950e-03 5 12 +1.312540781600459e-03 5 13 +3.136255923160151e-04 5 14 +2.172446734687579e-05 5 15 +7.019738683128956e-09 5 16 +2.172446734687579e-05 5 17 +3.136255923160151e-04 5 18 +1.312540781600459e-03 5 19 +2.892497988275950e-03 5 20 +3.926889486415615e-03 5 21 +3.474385548526664e-03 5 22 +2.063200871238251e-03 5 23 +8.466746072201876e-04 5 24 +2.527173255797678e-04 5 25 +6.146497948927013e-05 5 26 +1.535221942328690e-05 5 27 +5.499844452398325e-06 5 28 +3.392503181823541e-06 5 29 +2.716699175289595e-06 5 30 +2.307317576927403e-06 6 0 +2.373332825254899e-06 6 1 +2.321653560233388e-06 6 2 +1.822958685202512e-06 6 3 +1.998034295855592e-06 6 4 +1.070244688479249e-05 6 5 +6.062668963464542e-05 6 6 +2.637758074029551e-04 6 7 +8.732926224204041e-04 6 8 +2.104254493353289e-03 6 9 +3.536589556516121e-03 6 10 +4.022793689595565e-03 6 11 +3.021560454986797e-03 6 12 +1.452268740872702e-03 6 13 +4.229684890191378e-04 6 14 +7.183483566560646e-05 6 15 +1.825194993036989e-05 6 16 +7.183483566560646e-05 6 17 +4.229684890191378e-04 6 18 +1.452268740872702e-03 6 19 +3.021560454986797e-03 6 20 +4.022793689595565e-03 6 21 +3.536589556516121e-03 6 22 +2.104254493353289e-03 6 23 +8.732926224204041e-04 6 24 +2.637758074029551e-04 6 25 +6.062668963464542e-05 6 26 +1.070244688479249e-05 6 27 +1.998034295855592e-06 6 28 +1.822958685202512e-06 6 29 +2.321653560233388e-06 6 30 +2.373332825254899e-06 7 0 +1.587195130150310e-06 7 1 +1.713658780206171e-06 7 2 +9.411594223291881e-07 7 3 +6.776789721331578e-08 7 4 +6.860825504386979e-06 7 5 +5.146201467104523e-05 7 6 +2.396166831456199e-04 7 7 +8.264643309087650e-04 7 8 +2.056438818405584e-03 7 9 +3.549963363240440e-03 7 10 +4.156944303260867e-03 7 11 +3.275907813144717e-03 7 12 +1.756915148324869e-03 7 13 +6.844759133332523e-04 7 14 +2.464153674380294e-04 7 15 +1.495346760772398e-04 7 16 +2.464153674380294e-04 7 17 +6.844759133332523e-04 7 18 +1.756915148324869e-03 7 19 +3.275907813144717e-03 7 20 +4.156944303260867e-03 7 21 +3.549963363240440e-03 7 22 +2.056438818405584e-03 7 23 +8.264643309087650e-04 7 24 +2.396166831456199e-04 7 25 +5.146201467104523e-05 7 26 +6.860825504386979e-06 7 27 +6.776789721331578e-08 7 28 +9.411594223291881e-07 7 29 +1.713658780206171e-06 7 30 +1.587195130150310e-06 8 0 +5.842895768532483e-07 8 1 +1.514582924947651e-06 8 2 +1.918239459944766e-06 8 3 +2.478661441644039e-06 8 4 +8.932418369414274e-06 8 5 +4.159804448997610e-05 8 6 +1.917917504088143e-04 8 7 +7.237846411730068e-04 8 8 +1.937637574805104e-03 8 9 +3.510202961653063e-03 8 10 +4.266350475238421e-03 8 11 +3.503586015126449e-03 8 12 +1.998570138710667e-03 8 13 +8.585196678491770e-04 8 14 +3.479814933876024e-04 8 15 +2.236338486521513e-04 8 16 +3.479814933876024e-04 8 17 +8.585196678491770e-04 8 18 +1.998570138710667e-03 8 19 +3.503586015126449e-03 8 20 +4.266350475238421e-03 8 21 +3.510202961653063e-03 8 22 +1.937637574805104e-03 8 23 +7.237846411730068e-04 8 24 +1.917917504088143e-04 8 25 +4.159804448997610e-05 8 26 +8.932418369414274e-06 8 27 +2.478661441644039e-06 8 28 +1.918239459944766e-06 8 29 +1.514582924947651e-06 8 30 +5.842895768532483e-07 9 0 +3.642883870758245e-07 9 1 +2.053202999470949e-06 9 2 +3.837166158545995e-06 9 3 +5.348894469071784e-06 9 4 +7.858828200887174e-06 9 5 +2.145531964264211e-05 9 6 +1.278998893281748e-04 9 7 +6.057443575635683e-04 9 8 +1.807819709990386e-03 9 9 +3.456094204549144e-03 9 10 +4.332932758161096e-03 9 11 +3.623389816823501e-03 9 12 +2.054991941718712e-03 9 13 +8.036014751161785e-04 9 14 +2.166177170601839e-04 9 15 +6.915211547501020e-05 9 16 +2.166177170601839e-04 9 17 +8.036014751161785e-04 9 18 +2.054991941718712e-03 9 19 +3.623389816823501e-03 9 20 +4.332932758161096e-03 9 21 +3.456094204549144e-03 9 22 +1.807819709990386e-03 9 23 +6.057443575635683e-04 9 24 +1.278998893281748e-04 9 25 +2.145531964264211e-05 9 26 +7.858828200887174e-06 9 27 +5.348894469071784e-06 9 28 +3.837166158545995e-06 9 29 +2.053202999470949e-06 9 30 +3.642883870758245e-07 10 0 +2.512490246878957e-06 10 1 +4.396610854841844e-06 10 2 +6.575545000503195e-06 10 3 +7.083439501810090e-06 10 4 +3.470894493160968e-06 10 5 +2.622883261358829e-06 10 6 +8.709326319537562e-05 10 7 +5.447133938049011e-04 10 8 +1.752837291237968e-03 10 9 +3.455315221404786e-03 10 10 +4.398958252080046e-03 10 11 +3.686186997488258e-03 10 12 +2.037578409116048e-03 10 13 +7.234336912109821e-04 10 14 +1.396226098258371e-04 10 15 +7.543732908067557e-06 10 16 +1.396226098258371e-04 10 17 +7.234336912109821e-04 10 18 +2.037578409116048e-03 10 19 +3.686186997488258e-03 10 20 +4.398958252080046e-03 10 21 +3.455315221404786e-03 10 22 +1.752837291237968e-03 10 23 +5.447133938049011e-04 10 24 +8.709326319537562e-05 10 25 +2.622883261358829e-06 10 26 +3.470894493160968e-06 10 27 +7.083439501810090e-06 10 28 +6.575545000503195e-06 10 29 +4.396610854841844e-06 10 30 +2.512490246878957e-06 11 0 +6.815671315359540e-06 11 1 +8.264538431099037e-06 11 2 +1.005401247062773e-05 11 3 +1.059684653758765e-05 11 4 +8.755895107819839e-06 11 5 +1.555038478500510e-05 11 6 +1.170561839376850e-04 11 7 +5.962253896499082e-04 11 8 +1.824100571423304e-03 11 9 +3.550529315318575e-03 11 10 +4.513631727635005e-03 11 11 +3.777400017948165e-03 11 12 +2.069898556039909e-03 11 13 +7.321944395611375e-04 11 14 +1.800591890588128e-04 11 15 +7.252664246864497e-05 11 16 +1.800591890588128e-04 11 17 +7.321944395611375e-04 11 18 +2.069898556039909e-03 11 19 +3.777400017948165e-03 11 20 +4.513631727635005e-03 11 21 +3.550529315318575e-03 11 22 +1.824100571423304e-03 11 23 +5.962253896499082e-04 11 24 +1.170561839376850e-04 11 25 +1.555038478500510e-05 11 26 +8.755895107819839e-06 11 27 +1.059684653758765e-05 11 28 +1.005401247062773e-05 11 29 +8.264538431099037e-06 11 30 +6.815671315359540e-06 12 0 +9.749610156771229e-06 12 1 +1.055180001296198e-05 12 2 +1.180987001645569e-05 12 3 +1.395571025914737e-05 12 4 +2.057271886339045e-05 12 5 +5.026620068793996e-05 12 6 +1.931212798890028e-04 12 7 +7.199830460496915e-04 12 8 +1.978312822663844e-03 12 9 +3.714503821754403e-03 12 10 +4.680865749503483e-03 12 11 +3.932112021941086e-03 12 12 +2.178726369038801e-03 12 13 +7.706810332112831e-04 12 14 +1.501137773096962e-04 12 15 +1.261640298775073e-05 12 16 +1.501137773096962e-04 12 17 +7.706810332112831e-04 12 18 +2.178726369038801e-03 12 19 +3.932112021941086e-03 12 20 +4.680865749503483e-03 12 21 +3.714503821754403e-03 12 22 +1.978312822663844e-03 12 23 +7.199830460496915e-04 12 24 +1.931212798890028e-04 12 25 +5.026620068793996e-05 12 26 +2.057271886339045e-05 12 27 +1.395571025914737e-05 12 28 +1.180987001645569e-05 12 29 +1.055180001296198e-05 12 30 +9.749610156771229e-06 13 0 +8.490623059819040e-06 13 1 +8.799846154170221e-06 13 2 +8.994677966752248e-06 13 3 +1.010871017786102e-05 13 4 +1.870330300271311e-05 13 5 +6.084068161357250e-05 13 6 +2.356274475978317e-04 13 7 +8.098356562680192e-04 13 8 +2.107865874310841e-03 13 9 +3.865318650390775e-03 13 10 +4.852291507897281e-03 13 11 +4.126295330348602e-03 13 12 +2.369155320117100e-03 13 13 +9.147697022767272e-04 13 14 +2.308142003576141e-04 13 15 +6.328836926190641e-05 13 16 +2.308142003576141e-04 13 17 +9.147697022767272e-04 13 18 +2.369155320117100e-03 13 19 +4.126295330348602e-03 13 20 +4.852291507897281e-03 13 21 +3.865318650390775e-03 13 22 +2.107865874310841e-03 13 23 +8.098356562680192e-04 13 24 +2.356274475978317e-04 13 25 +6.084068161357250e-05 13 26 +1.870330300271311e-05 13 27 +1.010871017786102e-05 13 28 +8.994677966752248e-06 13 29 +8.799846154170221e-06 13 30 +8.490623059819040e-06 14 0 +4.687403389656196e-06 14 1 +5.079153114463964e-06 14 2 +4.497918246229313e-06 14 3 +2.774071303358379e-06 14 4 +5.904632068328592e-06 14 5 +4.270413859622926e-05 14 6 +2.207746257698169e-04 14 7 +8.135918874377782e-04 14 8 +2.139508173337537e-03 14 9 +3.927780870116436e-03 14 10 +4.956023042244558e-03 14 11 +4.277097097416137e-03 14 12 +2.546496865618815e-03 14 13 +1.093698356447127e-03 14 14 +4.092148715898557e-04 14 15 +2.440103587145870e-04 14 16 +4.092148715898557e-04 14 17 +1.093698356447127e-03 14 18 +2.546496865618815e-03 14 19 +4.277097097416137e-03 14 20 +4.956023042244558e-03 14 21 +3.927780870116436e-03 14 22 +2.139508173337537e-03 14 23 +8.135918874377782e-04 14 24 +2.207746257698169e-04 14 25 +4.270413859622926e-05 14 26 +5.904632068328592e-06 14 27 +2.774071303358379e-06 14 28 +4.497918246229313e-06 14 29 +5.079153114463964e-06 14 30 +4.687403389656196e-06 15 0 +1.501257749887276e-06 15 1 +2.435756825174617e-06 15 2 +2.411966242960009e-06 15 3 +7.157054724050202e-07 15 4 +1.716069852294603e-06 15 5 +3.013705168409485e-05 15 6 +1.904842036316344e-04 15 7 +7.619892865676402e-04 15 8 +2.077488033630016e-03 15 9 +3.878674705777598e-03 15 10 +4.943717078853101e-03 15 11 +4.303065526353173e-03 15 12 +2.573644579802008e-03 15 13 +1.075135802949144e-03 15 14 +3.350972364282421e-04 15 15 +1.464398667425757e-04 15 16 +3.350972364282421e-04 15 17 +1.075135802949144e-03 15 18 +2.573644579802008e-03 15 19 +4.303065526353173e-03 15 20 +4.943717078853101e-03 15 21 +3.878674705777598e-03 15 22 +2.077488033630016e-03 15 23 +7.619892865676402e-04 15 24 +1.904842036316344e-04 15 25 +3.013705168409485e-05 15 26 +1.716069852294603e-06 15 27 +7.157054724050202e-07 15 28 +2.411966242960009e-06 15 29 +2.435756825174617e-06 15 30 +1.501257749887276e-06 16 0 +2.323571591220434e-07 16 1 +1.393475802039957e-06 16 2 +2.091541786468290e-06 16 3 +2.126752993258124e-06 16 4 +4.835644738161436e-06 16 5 +2.852474621669622e-05 16 6 +1.659548141126014e-04 16 7 +6.933826714206772e-04 16 8 +1.963201825373199e-03 16 9 +3.743280998425761e-03 16 10 +4.819314315173870e-03 16 11 +4.206415709376830e-03 16 12 +2.492191540160578e-03 16 13 +9.778007064550418e-04 16 14 +2.051669934845689e-04 16 15 +7.791777078841276e-08 16 16 +2.051669934845689e-04 16 17 +9.778007064550418e-04 16 18 +2.492191540160578e-03 16 19 +4.206415709376830e-03 16 20 +4.819314315173870e-03 16 21 +3.743280998425761e-03 16 22 +1.963201825373199e-03 16 23 +6.933826714206772e-04 16 24 +1.659548141126014e-04 16 25 +2.852474621669622e-05 16 26 +4.835644738161436e-06 16 27 +2.126752993258124e-06 16 28 +2.091541786468290e-06 16 29 +1.393475802039957e-06 16 30 +2.323571591220434e-07 17 0 +6.534106903077690e-07 17 1 +1.487306123431552e-06 17 2 +1.979172297174789e-06 17 3 +1.976234205687681e-06 17 4 +3.531951296812328e-06 17 5 +2.095624840708503e-05 17 6 +1.382476024308607e-04 17 7 +6.241889811214583e-04 17 8 +1.838277343110348e-03 17 9 +3.567829091690213e-03 17 10 +4.619649049288467e-03 17 11 +4.029180994811406e-03 17 12 +2.389692813180007e-03 17 13 +9.801953064551853e-04 17 14 +3.010360683959697e-04 17 15 +1.339147984653232e-04 17 16 +3.010360683959697e-04 17 17 +9.801953064551853e-04 17 18 +2.389692813180007e-03 17 19 +4.029180994811406e-03 17 20 +4.619649049288467e-03 17 21 +3.567829091690213e-03 17 22 +1.838277343110348e-03 17 23 +6.241889811214583e-04 17 24 +1.382476024308607e-04 17 25 +2.095624840708503e-05 17 26 +3.531951296812328e-06 17 27 +1.976234205687681e-06 17 28 +1.979172297174789e-06 17 29 +1.487306123431552e-06 17 30 +6.534106903077690e-07 18 0 +1.876059361241538e-06 18 1 +2.057784840208347e-06 18 2 +1.777613271338336e-06 18 3 +8.699234969159874e-07 18 4 +1.968652577303025e-07 18 5 +1.208171122223021e-05 18 6 +1.171139379151092e-04 18 7 +5.767959563594669e-04 18 8 +1.740740070141123e-03 18 9 +3.396802527464631e-03 18 10 +4.382735284334756e-03 18 11 +3.786662133385478e-03 18 12 +2.219758764675431e-03 18 13 +9.142867897053784e-04 18 14 +3.110029558942641e-04 18 15 +1.692446500089834e-04 18 16 +3.110029558942641e-04 18 17 +9.142867897053784e-04 18 18 +2.219758764675431e-03 18 19 +3.786662133385478e-03 18 20 +4.382735284334756e-03 18 21 +3.396802527464631e-03 18 22 +1.740740070141123e-03 18 23 +5.767959563594669e-04 18 24 +1.171139379151092e-04 18 25 +1.208171122223021e-05 18 26 +1.968652577303025e-07 18 27 +8.699234969159874e-07 18 28 +1.777613271338336e-06 18 29 +2.057784840208347e-06 18 30 +1.876059361241538e-06 19 0 +3.062840789809967e-06 19 1 +2.527808076843036e-06 19 2 +1.633271973488836e-06 19 3 +9.736235185669393e-07 19 4 +1.380503967706013e-06 19 5 +1.469419689216322e-05 19 6 +1.207048147882760e-04 19 7 +5.719123589096748e-04 19 8 +1.692871022540258e-03 19 9 +3.256428719310688e-03 19 10 +4.139632891211538e-03 19 11 +3.504909208546127e-03 19 12 +1.982724381278589e-03 19 13 +7.402920491410022e-04 19 14 +1.617462685140096e-04 19 15 +2.053330572468854e-05 19 16 +1.617462685140096e-04 19 17 +7.402920491410022e-04 19 18 +1.982724381278589e-03 19 19 +3.504909208546127e-03 19 20 +4.139632891211538e-03 19 21 +3.256428719310688e-03 19 22 +1.692871022540258e-03 19 23 +5.719123589096748e-04 19 24 +1.207048147882760e-04 19 25 +1.469419689216322e-05 19 26 +1.380503967706013e-06 19 27 +9.736235185669393e-07 19 28 +1.633271973488836e-06 19 29 +2.527808076843036e-06 19 30 +3.062840789809967e-06 20 0 +3.965288889790357e-06 20 1 +2.752129060676672e-06 20 2 +1.161841016756794e-06 20 3 +5.701545853936663e-07 20 4 +3.098355792788597e-06 20 5 +2.353023458085338e-05 20 6 +1.431860973840122e-04 20 7 +6.003781224686864e-04 20 8 +1.683390907031591e-03 20 9 +3.145644377756497e-03 20 10 +3.912068929840578e-03 20 11 +3.233033884460954e-03 20 12 +1.771385768497788e-03 20 13 +6.375462234056684e-04 20 14 +1.434980619272460e-04 20 15 +3.195125662258565e-05 20 16 +1.434980619272460e-04 20 17 +6.375462234056684e-04 20 18 +1.771385768497788e-03 20 19 +3.233033884460954e-03 20 20 +3.912068929840578e-03 20 21 +3.145644377756497e-03 20 22 +1.683390907031591e-03 20 23 +6.003781224686864e-04 20 24 +1.431860973840122e-04 20 25 +2.353023458085338e-05 20 26 +3.098355792788597e-06 20 27 +5.701545853936663e-07 20 28 +1.161841016756794e-06 20 29 +2.752129060676672e-06 20 30 +3.965288889790357e-06 21 0 +4.809474577021396e-06 21 1 +3.265902127647575e-06 21 2 +1.153290298311127e-06 21 3 +1.734187798996243e-07 21 4 +4.307226170255345e-06 21 5 +3.268845994111086e-05 21 6 +1.673952798494322e-04 21 7 +6.297509875229867e-04 21 8 +1.674683627968040e-03 21 9 +3.043996694190472e-03 21 10 +3.709176492544443e-03 21 11 +2.997312013828311e-03 21 12 +1.599019952667030e-03 21 13 +5.728662937094130e-04 21 14 +1.609992934304200e-04 21 15 +7.737655471200314e-05 21 16 +1.609992934304200e-04 21 17 +5.728662937094130e-04 21 18 +1.599019952667030e-03 21 19 +2.997312013828311e-03 21 20 +3.709176492544443e-03 21 21 +3.043996694190472e-03 21 22 +1.674683627968040e-03 21 23 +6.297509875229867e-04 21 24 +1.673952798494322e-04 21 25 +3.268845994111086e-05 21 26 +4.307226170255345e-06 21 27 +1.734187798996243e-07 21 28 +1.153290298311127e-06 21 29 +3.265902127647575e-06 21 30 +4.809474577021396e-06 22 0 +5.555042869803733e-06 22 1 +4.420635368354199e-06 22 2 +3.028730507567648e-06 22 3 +3.100707295620601e-06 22 4 +9.243914480592160e-06 22 5 +4.087587045427118e-05 22 6 +1.760607022307088e-04 22 7 +6.247370338825327e-04 22 8 +1.629230426377810e-03 22 9 +2.933474132420932e-03 22 10 +3.538408480595143e-03 22 11 +2.811983434809747e-03 22 12 +1.451910099681378e-03 22 13 +4.768548007400953e-04 22 14 +9.099433778678653e-05 22 15 +1.171746709542609e-05 22 16 +9.099433778678653e-05 22 17 +4.768548007400953e-04 22 18 +1.451910099681378e-03 22 19 +2.811983434809747e-03 22 20 +3.538408480595143e-03 22 21 +2.933474132420932e-03 22 22 +1.629230426377810e-03 22 23 +6.247370338825327e-04 22 24 +1.760607022307088e-04 22 25 +4.087587045427118e-05 22 26 +9.243914480592160e-06 22 27 +3.100707295620601e-06 22 28 +3.028730507567648e-06 22 29 +4.420635368354199e-06 22 30 +5.555042869803733e-06 23 0 +5.404189672356805e-06 23 1 +4.892870830299098e-06 23 2 +4.557607934560358e-06 23 3 +5.537092541242136e-06 23 4 +1.083855203679700e-05 23 5 +3.547085934154473e-05 23 6 +1.510775020427121e-04 23 7 +5.676546615136151e-04 23 8 +1.538572432507774e-03 23 9 +2.819067621052516e-03 23 10 +3.417150766148686e-03 23 11 +2.705429500718680e-03 23 12 +1.374749562040417e-03 23 13 +4.333463453912217e-04 23 14 +7.941771000134053e-05 23 15 +1.479566369747944e-05 23 16 +7.941771000134053e-05 23 17 +4.333463453912217e-04 23 18 +1.374749562040417e-03 23 19 +2.705429500718680e-03 23 20 +3.417150766148686e-03 23 21 +2.819067621052516e-03 23 22 +1.538572432507774e-03 23 23 +5.676546615136151e-04 23 24 +1.510775020427121e-04 23 25 +3.547085934154473e-05 23 26 +1.083855203679700e-05 23 27 +5.537092541242136e-06 23 28 +4.557607934560358e-06 23 29 +4.892870830299098e-06 23 30 +5.404189672356805e-06 24 0 +3.955165536724783e-06 24 1 +3.584741991399201e-06 24 2 +3.508885372422360e-06 24 3 +3.939399145842972e-06 24 4 +4.822757117855054e-06 24 5 +1.528945559383431e-05 24 6 +1.028440676156929e-04 24 7 +4.865196638755525e-04 24 8 +1.440956718322974e-03 24 9 +2.733108955173010e-03 24 10 +3.366008382925306e-03 24 11 +2.697020398631471e-03 24 12 +1.391340841413025e-03 24 13 +4.489266759395228e-04 24 14 +8.931113109195366e-05 24 15 +2.423720573557286e-05 24 16 +8.931113109195366e-05 24 17 +4.489266759395228e-04 24 18 +1.391340841413025e-03 24 19 +2.697020398631471e-03 24 20 +3.366008382925306e-03 24 21 +2.733108955173010e-03 24 22 +1.440956718322974e-03 24 23 +4.865196638755525e-04 24 24 +1.028440676156929e-04 24 25 +1.528945559383431e-05 24 26 +4.822757117855054e-06 24 27 +3.939399145842972e-06 24 28 +3.508885372422360e-06 24 29 +3.584741991399201e-06 24 30 +3.955165536724783e-06 25 0 +2.214633245267957e-06 25 1 +1.585525169790331e-06 25 2 +1.483434350126737e-06 25 3 +1.972238971450125e-06 25 4 +8.239998404110594e-07 25 5 +3.274470653067594e-06 25 6 +7.580088249132948e-05 25 7 +4.457366278418717e-04 25 8 +1.401383271659800e-03 25 9 +2.715854393917418e-03 25 10 +3.391604051034845e-03 25 11 +2.775387360033505e-03 25 12 +1.495302570719864e-03 25 13 +5.208990796590071e-04 25 14 +9.956297062102457e-05 25 15 +4.074204269152465e-06 25 16 +9.956297062102457e-05 25 17 +5.208990796590071e-04 25 18 +1.495302570719864e-03 25 19 +2.775387360033505e-03 25 20 +3.391604051034845e-03 25 21 +2.715854393917418e-03 25 22 +1.401383271659800e-03 25 23 +4.457366278418717e-04 25 24 +7.580088249132948e-05 25 25 +3.274470653067594e-06 25 26 +8.239998404110594e-07 25 27 +1.972238971450125e-06 25 28 +1.483434350126737e-06 25 29 +1.585525169790331e-06 25 30 +2.214633245267957e-06 26 0 +1.270433760442372e-06 26 1 +3.916387056204372e-07 26 2 +2.231233391960010e-07 26 3 +1.503250077270970e-06 26 4 +3.125235105917701e-06 26 5 +1.232580616064923e-05 26 6 +9.755857943602422e-05 26 7 +4.851055857767528e-04 26 8 +1.457115907850736e-03 26 9 +2.782087863624691e-03 26 10 +3.471885190847275e-03 26 11 +2.885556868129979e-03 26 12 +1.636626067410123e-03 26 13 +6.667717289764138e-04 26 14 +2.263997570460314e-04 26 15 +1.189280941020137e-04 26 16 +2.263997570460314e-04 26 17 +6.667717289764138e-04 26 18 +1.636626067410123e-03 26 19 +2.885556868129979e-03 26 20 +3.471885190847275e-03 26 21 +2.782087863624691e-03 26 22 +1.457115907850736e-03 26 23 +4.851055857767528e-04 26 24 +9.755857943602422e-05 26 25 +1.232580616064923e-05 26 26 +3.125235105917701e-06 26 27 +1.503250077270970e-06 26 28 +2.231233391960010e-07 26 29 +3.916387056204372e-07 26 30 +1.270433760442372e-06 27 0 +1.299354594308245e-06 27 1 +5.522911269684502e-07 27 2 +4.619462725569895e-07 27 3 +2.265200690627976e-06 27 4 +8.097778286089136e-06 27 5 +3.240334951419666e-05 27 6 +1.498979407853844e-04 27 7 +5.803392722650569e-04 27 8 +1.582282591448272e-03 27 9 +2.903121917018245e-03 27 10 +3.560888391768400e-03 27 11 +2.942173666034896e-03 27 12 +1.681218578604672e-03 27 13 +7.183020985079531e-04 27 14 +2.890668649459803e-04 27 15 +1.861637286406668e-04 27 16 +2.890668649459803e-04 27 17 +7.183020985079531e-04 27 18 +1.681218578604672e-03 27 19 +2.942173666034896e-03 27 20 +3.560888391768400e-03 27 21 +2.903121917018245e-03 27 22 +1.582282591448272e-03 27 23 +5.803392722650569e-04 27 24 +1.498979407853844e-04 27 25 +3.240334951419666e-05 27 26 +8.097778286089136e-06 27 27 +2.265200690627976e-06 27 28 +4.619462725569895e-07 27 29 +5.522911269684502e-07 27 30 +1.299354594308245e-06 28 0 +2.040365887620211e-06 28 1 +1.650917666586412e-06 28 2 +1.774875725028040e-06 28 3 +3.556606295780957e-06 28 4 +1.121238171560661e-05 28 5 +4.596797846319543e-05 28 6 +1.924256950599667e-04 28 7 +6.695452279961972e-04 28 8 +1.710357891797661e-03 28 9 +3.026685345607163e-03 28 10 +3.623902514336288e-03 28 11 +2.912274546185048e-03 28 12 +1.573517463148064e-03 28 13 +5.814421846018108e-04 28 14 +1.585057189477723e-04 28 15 +6.269150114528087e-05 28 16 +1.585057189477723e-04 28 17 +5.814421846018108e-04 28 18 +1.573517463148064e-03 28 19 +2.912274546185048e-03 28 20 +3.623902514336288e-03 28 21 +3.026685345607163e-03 28 22 +1.710357891797661e-03 28 23 +6.695452279961972e-04 28 24 +1.924256950599667e-04 28 25 +4.596797846319543e-05 28 26 +1.121238171560661e-05 28 27 +3.556606295780957e-06 28 28 +1.774875725028040e-06 28 29 +1.650917666586412e-06 28 30 +2.040365887620211e-06 29 0 +2.889936412548378e-06 29 1 +2.523107656067143e-06 29 2 +2.137256869716177e-06 29 3 +2.408742209727751e-06 29 4 +7.837863399645522e-06 29 5 +4.293412664154757e-05 29 6 +2.012737823483604e-04 29 7 +7.094420933272181e-04 29 8 +1.788723143733490e-03 29 9 +3.116507360268357e-03 29 10 +3.668485365947303e-03 29 11 +2.864609577951840e-03 29 12 +1.444029026933867e-03 29 13 +4.403845160530417e-04 29 14 +6.521201643211877e-05 29 15 +2.389980714464935e-07 29 16 +6.521201643211877e-05 29 17 +4.403845160530417e-04 29 18 +1.444029026933867e-03 29 19 +2.864609577951840e-03 29 20 +3.668485365947303e-03 29 21 +3.116507360268357e-03 29 22 +1.788723143733490e-03 29 23 +7.094420933272181e-04 29 24 +2.012737823483604e-04 29 25 +4.293412664154757e-05 29 26 +7.837863399645522e-06 29 27 +2.408742209727751e-06 29 28 +2.137256869716177e-06 29 29 +2.523107656067143e-06 29 30 +2.889936412548378e-06 30 0 +3.189540008095353e-06 30 1 +2.665276215102024e-06 30 2 +1.538390887473923e-06 30 3 +2.126393704049059e-07 30 4 +2.872410902877456e-06 30 5 +3.332700529158972e-05 30 6 +1.874186897482456e-04 30 7 +7.023315789295831e-04 30 8 +1.808842702438711e-03 30 9 +3.169450767598823e-03 30 10 +3.727981450772813e-03 30 11 +2.895425157778220e-03 30 12 +1.436817970496205e-03 30 13 +4.198892675035715e-04 30 14 +6.131415667355502e-05 30 15 +9.736971670136333e-06 30 16 +6.131415667355502e-05 30 17 +4.198892675035715e-04 30 18 +1.436817970496205e-03 30 19 +2.895425157778220e-03 30 20 +3.727981450772813e-03 30 21 +3.169450767598823e-03 30 22 +1.808842702438711e-03 30 23 +7.023315789295831e-04 30 24 +1.874186897482456e-04 30 25 +3.332700529158972e-05 30 26 +2.872410902877456e-06 30 27 +2.126393704049059e-07 30 28 +1.538390887473923e-06 30 29 +2.665276215102024e-06 30 30 +3.189540008095353e-06 pyx-project-pyx-21f71ce/examples/3dgraphs/surface.py000077500000000000000000000003631526513311100225640ustar00rootroot00000000000000#!/usr/bin/env python from pyx import * g = graph.graphxyz(size=4, x2=None, y2=None) g.plot(graph.data.file("surface.dat", x=1, y=2, z=3), [graph.style.surface()]) g.writeEPSfile("surface") g.writePDFfile("surface") g.writeSVGfile("surface") pyx-project-pyx-21f71ce/examples/3dgraphs/surface.txt000066400000000000000000000017361526513311100227550ustar00rootroot00000000000000Simple 3d surface This first simple example provides data for the x, y and z coordinates. PyX creates a rectangular grid from the data from the first two coordinates without relying on a special ordering of the data. ... A missing point will create a hole in the surface. ! The surface is plotted using a mesh. In case of a huge number of data points, you may want to replace the mesh by a bitmap rasterized on a different (i.e. lower) resolution. This can reduce the file size and may also resolve various printing problems (unfortunately those are quite common with mesh data). To enable the mesh by bitmap replacement feature use the option `meshasbitmap` (together with its `meshasbitmapresolution` option):: g.writeEPSfile(write_meshasbitmap=True) g.writePDFfile(write_meshasbitmap=True) !! The underlying rectangular grid is created by the gridpos style. By changing its parameters you can also create the base rectangular grid from others than the first two coordinates. pyx-project-pyx-21f71ce/examples/INDEX000066400000000000000000000001521526513311100176320ustar00rootroot00000000000000hello drawing/ path/ drawing2/ text/ graphs/ axis/ graphstyles/ bargraphs/ splitgraphs/ 3dgraphs/ bitmap/ pyx-project-pyx-21f71ce/examples/Makefile000066400000000000000000000020331526513311100205000ustar00rootroot00000000000000PYTHON ?= python3 GS ?= gs files = $(foreach item, $(shell grep -v / INDEX), $(item)) $(foreach item, $(shell grep / INDEX), $(addprefix $(item), $(shell cat $(item)INDEX))) pyfiles = $(addsuffix .py, $(files)) epsfiles = $(addsuffix .eps, $(files)) pdffiles = $(addsuffix .pdf, $(files)) pngfiles = $(addsuffix .png, $(files)) svgfiles = $(addsuffix .svg, $(files)) ipynbfiles = $(addsuffix .ipynb, $(files)) thumbpngfiles = $(addsuffix _thumb.png, $(files)) .PRECIOUS: $(epsfiles) $(pngfiles) all: $(MAKE) $(ipynbfiles) $(MAKE) $(thumbpngfiles) clean: rm -f $(epsfiles) $(pdffiles) $(pngfiles) $(svgfiles) $(ipynbfiles) $(thumbpngfiles) %.eps: %.py cd $(dir $^); $(PYTHON) -W default $(notdir $^) %.ipynb: %.png $(PYTHON) $(CURDIR)/../www/mkipynb.py $@ %.png: %.eps $(GS) -r100 -dEPSCrop -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pngalpha -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sOutputFile=$@ $^ %_thumb.png: %.eps $(GS) -r50 -dEPSCrop -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pngalpha -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sOutputFile=$@ $^ pyx-project-pyx-21f71ce/examples/README000066400000000000000000000017221526513311100177240ustar00rootroot00000000000000PyX examples The following examples are part of the PyX release __version__. For each PyX example the source code and the corresponding output are shown. You can take a guided tour through all examples by the ''prev'' and ''next'' links on the upper right. All the examples and their descriptions are included in the source distribution of PyX in the examples subdirectory. ! Some paragraphs (like the one you're just reading) are marked with a ''dangerous bend sign''. Some people will recognize this classification from the TeXbook by D.E. Knuth and we use it at the PyX example pages for the same purpose. The bend marks parts of the description, which require some experiences with PyX. On the other hand, those parts can savely be ignored by PyX beginners. !! There are even some paragraphs marked as ''doubly dangerous''. The explanations given in those paragraphs provide some deeper insights of what's really going on, but are not important for the average PyX user. pyx-project-pyx-21f71ce/examples/axis/000077500000000000000000000000001526513311100200065ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/axis/INDEX000066400000000000000000000000721526513311100205770ustar00rootroot00000000000000log link minimal painter texter manualticks rating parter pyx-project-pyx-21f71ce/examples/axis/README000066400000000000000000000016771526513311100207010ustar00rootroot00000000000000Graph axes This section demonstrates the axis subsystem of the graph module. The axes delegate a lot of tasks to different components like ''painters'' (which control how the baseline of the axis, the ticks and the axis title are drawn), ''texters'' (which create the label strings written on the ticks), ''parters'' (short for partionioners, which take care of determining appropriate tick positions along the axis, and ''raters'' (which adjust the number of ticks to match the available size). In the present section, we will explain various basic aspects of these components. Most of the time, the examples will not show a complete graph but just a single axis. In that case, we will take an axis created along an arbitrary path, partially in order to demonstrate the flexibility of PyX's axis system but also too increase the coolness factor. Of course, in a real-world example, you will use the shown features mostly for simple, boring, straight axes. pyx-project-pyx-21f71ce/examples/axis/link.py000066400000000000000000000006411526513311100213160ustar00rootroot00000000000000import math from pyx import * c = canvas.canvas() g1 = c.insert(graph.graphxy(width=8)) g1.plot(graph.data.function("y(x)=2*exp(-30*x)-exp(-3*x)", min=0, max=1)) g2 = c.insert(graph.graphxy(width=8, ypos=g1.height+0.5, x=graph.axis.linkedaxis(g1.axes["x"]))) g2.plot(graph.data.function("y(x)=cos(20*x)*exp(-2*x)")) c.writeEPSfile("link") c.writePDFfile("link") c.writeSVGfile("link") pyx-project-pyx-21f71ce/examples/axis/link.txt000066400000000000000000000015701526513311100215070ustar00rootroot00000000000000Linking one axis to another one When plotting two or more related graphs, you sometimes want to have identical axes. This example demonstrates how to achieve this goal in PyX using a `linkedaxis`. ... In order to arrange the two graphs, we first create a canvas `c`, in which we insert the first graph `g1` (the lower panel in the output), which contains the graph of a function. In the next graph `g2` (the upper panel in the output), we now refer to the x-axis of `g1`. We do this by creating a `graph.axis.linkedaxis` instance passing the x-axis of `g1` as the only argument. The latter is obtained from the axis dictionary `axes` of the graph. Note that for a linked axis, PyX automatically turns off the drawing of the axis labels, as you can see in the upper panel. If you do not like this behaviour, you have to pass a different axis painter to the `linkedaxis` constructor. pyx-project-pyx-21f71ce/examples/axis/log.py000066400000000000000000000011501526513311100211360ustar00rootroot00000000000000import fractions, math from pyx import * from pyx.graph import axis # we here use parters and texters which are explained in the examples below log2parter = axis.parter.log([axis.parter.preexp([axis.tick.rational(1)], 4), axis.parter.preexp([axis.tick.rational(1)], 2)]) log2texter = axis.texter.default(base=fractions.Fraction(2)) g = graph.graphxy(width=10, x=axis.log(min=1, max=1024), y=axis.log(min=1, max=1024, parter=log2parter), y2=axis.log(min=1, max=1024, parter=log2parter, texter=log2texter)) g.writeEPSfile("log") g.writePDFfile("log") g.writeSVGfile("log") pyx-project-pyx-21f71ce/examples/axis/log.txt000066400000000000000000000016121526513311100213300ustar00rootroot00000000000000Logarithmic axes Logarithmic axes are quite similar to linear axes and differ only in a very few properties, namely a non-linear mapping of values to axis positions. They also have different default partitioners and raters (see below). ... While the partitioner really is quite different - it implements a logarithmic positioning of the ticks - the rater just alters some defaults in favour of using more subticks to improve the visualization of the logarithmic nature of the axis. ! Besides presenting a standard logarithmic axis, we also show you how to alter the base used by the logarithmic axis. Since the functionality of a logarithmic axis is independent of the base, all we need to adjust are the components for creating ticks (see `log2parter`) and the texts for the labels (see `log2texter`). More details about the parters and texters components are given below in the corresponding examples. pyx-project-pyx-21f71ce/examples/axis/manualticks.py000066400000000000000000000010521526513311100226710ustar00rootroot00000000000000import math from pyx import * p1 = path.curve(0, 0, 3, 0, 1, 4, 4, 4) p2 = p1.transformed(trafo.translate(4, 0)) myticks = [graph.axis.tick.tick(math.pi, label=r"\pi", labelattrs=[text.mathmode]), graph.axis.tick.tick(2*math.pi, label=r"2\pi", labelattrs=[text.mathmode])] c = canvas.canvas() c.insert(graph.axis.pathaxis(p1, graph.axis.linear(min=0, max=10))) c.insert(graph.axis.pathaxis(p2, graph.axis.linear(min=0, max=10, manualticks=myticks))) c.writeEPSfile("manualticks") c.writePDFfile("manualticks") c.writeSVGfile("manualticks") pyx-project-pyx-21f71ce/examples/axis/manualticks.txt000066400000000000000000000012141526513311100230600ustar00rootroot00000000000000Manually place ticks at certain positions Ticks can be set manually by passing tick instances to the `manualticks` argument of the axis instance as shown at the right axis in this example. ... As you can see, the manual ticks are combined with the automatically created ticks. You could disable any automatic tick creation by setting the `parter` argument to None. But what's much more interesting is, that the manually and automatically created ticks are not just merged, but their combination is used for rating the resulting partition. Therefore, the additional manual ticks lead to a different set of automatically created ticks in this example. pyx-project-pyx-21f71ce/examples/axis/minimal.py000066400000000000000000000003271526513311100220100ustar00rootroot00000000000000from pyx import * c = graph.axis.pathaxis(path.curve(0, 0, 3, 0, 1, 4, 4, 4), graph.axis.linear(min=0, max=10)) c.writeEPSfile("minimal") c.writePDFfile("minimal") c.writeSVGfile("minimal") pyx-project-pyx-21f71ce/examples/axis/minimal.txt000066400000000000000000000011401526513311100221710ustar00rootroot00000000000000Minimal example for drawing an isolated axis This is the basic example of how to draw an axis alone -- without the whole graph. It serves to simplify the following examples. ... The function `pathaxis` from the `graph.axis` module takes a path and returns a canvas which contains the drawn axis. In contrast to the typical usecase of graphs containing data, we here have to provide the range explicitly (using the `min` and `max` arguments). For real graphs the range of an axis, of course, is adjusted automatically, although you can still set minimal and/or maximal values to force a certain axis range. pyx-project-pyx-21f71ce/examples/axis/painter.py000066400000000000000000000006751526513311100220320ustar00rootroot00000000000000from pyx import * mypainter = graph.axis.painter.regular(outerticklength=graph.axis.painter.ticklength.normal, basepathattrs=[style.linewidth.THick, deco.earrow.large]) c = graph.axis.pathaxis(path.curve(0, 0, 3, 0, 1, 4, 4, 4), graph.axis.linear(min=0, max=11, title="axis title", painter=mypainter)) c.writeEPSfile("painter") c.writePDFfile("painter") c.writeSVGfile("painter") pyx-project-pyx-21f71ce/examples/axis/painter.txt000066400000000000000000000024051526513311100222120ustar00rootroot00000000000000Painter: Controlling the visual features of an axis The visual features of an axis (such as ticklengths, linewidths, distances of the labels, their orientation, text attributes, etc.) are controlled by its painter. You can modify these attributes by creating a painter explicitly. ... While the axis painter has quite some parameters to adjust the output, here we only change its width, add an arrow and alter the ticks: By default, ticks are stroked only towards the inside of the graph (in the path examples there is no graph but don't mind). The labels and the axis title are plotted outside of the graph. Futhermore, the axis title (when present as in this example) is rotated along the axis (without writing it upside down), while the tick labels are not rotated at all. In this example we set an `outerticklength`. Together with the `innerticklength`, which by default is set to the same value, the ticks are stroked across the axis. As it is common to sub-components of the axis, you need to pass the adapted instances (stored in the variable `mypainter` here) to the axis in its constructor. ! In this example there is no tick at the end due to the axis range. You can suppress individual ticks by the `manualticks` axis parameter with ticklevel and labellevel being zero. pyx-project-pyx-21f71ce/examples/axis/parter.py000066400000000000000000000010031526513311100216470ustar00rootroot00000000000000import math from pyx import * p = path.curve(0, 0, 3, 0, 1, 4, 4, 4) myparter = graph.axis.parter.linear(["1/3", "1/6"]) c = canvas.canvas() c.insert(graph.axis.pathaxis(p, graph.axis.linear(min=0, max=1, parter=myparter))) c.insert(graph.axis.pathaxis(p.transformed(trafo.translate(4, 0)), graph.axis.linear(min=0, max=1, parter=myparter, texter=graph.axis.texter.rational()))) c.writeEPSfile("parter") c.writePDFfile("parter") c.writeSVGfile("parter") pyx-project-pyx-21f71ce/examples/axis/parter.txt000066400000000000000000000025731526513311100220530ustar00rootroot00000000000000Parter: Control over the partitioning of the axis In the above example, the (default) automatic choice of a good partitioning has been selected. Here, we show how to gain more control over the ticks, in order to fix their intervals. ... Partitioners (in the code the short form `parter` is used) take care of calculating appropriate tick positions for a given axis range. Automatic partitioners create several tick lists, which are than rated by an axis rater instance, as explained in the above example. In contrast, manual partitioners create a single tick list only, which thus doesn't need to be rated at all. In this example we create a manual partitioner, which places ticks with a distance of 1/3 and subticks with a distance of 1/6. We then use this partitioner at two axis, which are identical except for a texter instance (to show you another feature of the axes in PyX, namely the rational number arithmetics used to place ticks). The rational numbers are preserved throughout the whole process of merging ticks, until the texter finally needs to output the rational numbers. And at the very end the decimal texter steps into the problem to create a proper representation for the fractions. The solution is shown at the left part of the example: the texter marks a period to express the fraction. Alternatively you can use the rational texter to display the values by fractions directly. pyx-project-pyx-21f71ce/examples/axis/rating.py000066400000000000000000000006651526513311100216530ustar00rootroot00000000000000from pyx import * p2 = path.curve(0, 0, 3, 0, 1, 4, 4, 4) p1 = p2.transformed(trafo.translate(-4, 0).scaled(0.75)) p3 = p2.transformed(trafo.scale(1.25).translated(4, 0)) myaxis = graph.axis.linear(min=0, max=10) c = canvas.canvas() c.insert(graph.axis.pathaxis(p1, myaxis)) c.insert(graph.axis.pathaxis(p2, myaxis)) c.insert(graph.axis.pathaxis(p3, myaxis)) c.writeEPSfile("rating") c.writePDFfile("rating") c.writeSVGfile("rating") pyx-project-pyx-21f71ce/examples/axis/rating.txt000066400000000000000000000036311526513311100220360ustar00rootroot00000000000000Rater: How a nicely looking axis partition is chosen We here demonstrate how an axis actually chooses its partition. ... There are good-looking partitions of an axis and bad-looking ones. The element which chooses one or the other, is the `rater` of an axis. It asks yet another element, the `parter` to suggest several partitions and then chooses the best, according to criteria such as tick distance, number of ticks, subticks, etc. (The partitioning process itself is explained in a later example). In this example we show the influence of the tick distances: Several axes with the same parameters are plotted on a path which is scaled. Note that the axes choose the ticks appropriately to the available space. The rating mechanism takes into account the number of ticks and subticks, but also the distances between the labels. Thus, the example in the middle has less ticks than the right version, because there is more space available at the larger path. More interestingly more labels are also shown on the very left path, although it is smaller than the middle one. This is due to the fact, that there is not enough room for labels with a decimal place on the smaller axis! ! The rating mechanism is configurable and exchangeable by passing rater instances to the `rater` keyword of the axis constructor. But instead of reconfiguring the whole rating mechanism, simple adjustments to favour more or less ticks are easily possible by the axis keyword argument `density`. !! In this example, the same axis instance is used several times. This works since the axis does not store any data within its own instance. Instead, an `anchoredaxis` instance is created by the `pathaxis` which embeds the axis in a proper environment. This way, a place for storing information for this specific use of the axis instance is provided. When using axes in a graph, the graph instance takes care of the proper setup of the anchored axes instances. pyx-project-pyx-21f71ce/examples/axis/texter.py000066400000000000000000000016511526513311100216760ustar00rootroot00000000000000import math from pyx import * from pyx.graph import axis texter1 = axis.texter.decimal(plus="+", minus="-", equalprecision=1) texter2 = axis.texter.rational() class piaxis(axis.linear): def __init__(self, divisor=math.pi, texter=axis.texter.rational(suffix=r"\pi"), **kwargs): axis.linear.__init__(self, divisor=divisor, texter=texter, **kwargs) p1 = path.path(path.moveto(0, 0), path.curveto(3, 0, 1, 4, 4, 4)) p2 = p1.transformed(trafo.translate(4, 0)) p3 = p2.transformed(trafo.translate(4, 0)) p4 = p3.transformed(trafo.translate(4, 0)) c = canvas.canvas() c.insert(axis.pathaxis(p1, axis.linear(min=0, max=1e2))) c.insert(axis.pathaxis(p2, axis.linear(min=-0.7, max=0.4, texter=texter1))) c.insert(axis.pathaxis(p3, axis.linear(min=-0.7, max=0.4, texter=texter2))) c.insert(axis.pathaxis(p4, piaxis(min=0, max=2*math.pi))) c.writeEPSfile("texter") c.writePDFfile("texter") c.writeSVGfile("texter") pyx-project-pyx-21f71ce/examples/axis/texter.txt000066400000000000000000000021401526513311100220570ustar00rootroot00000000000000Texter: Controlling the formatting of tick labels Texters do the formatting of the tick labels: They create the strings which are then passed to the painter. You can choose between fractions and decimal numbers with/without an exponential part. ... The `texter` should not be mixed up with the `painter`: The `painter` is afterwards doing the TeXing and finally creates the labels -- the `texter` prepares the string that is to be processed by TeX. The first example shows the default behavior, which chooses either decimal and exponential formatting. The second example is for special purpose only (because it is ugly), in case that it is strictly necessary to have the same width of all labels. The third example shows how to create fractions instead of decimal numbers. ! At the rightmost axis we also show how to create a special piaxis. Here, some axis parameters are altered to fit an pi-scaled axis nicely. Futhermore, instead of just creating a special axis instance by setting the divisor and texter parameters, a `piaxis` class is created which just alters the defaults of the linear axis it is based at. pyx-project-pyx-21f71ce/examples/bargraphs/000077500000000000000000000000001526513311100210135ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/bargraphs/INDEX000066400000000000000000000000711526513311100216030ustar00rootroot00000000000000minimal month changebar compare fromvalue stacked errors pyx-project-pyx-21f71ce/examples/bargraphs/README000066400000000000000000000010031526513311100216650ustar00rootroot00000000000000Bar graphs In this section we show you the basic features of bar graphs in PyX. All examples shown here use the same data from `minimal.dat` available for download at the first [minimal bar-graph example minimal.html]. Note that bar graphs differ from other xy-graphs in that they use ''discrete axes'' for one graph dimension. However, the only affected components of this fundamental change are one of the axes, which needs to be come a discrete one, i.e. a bar axis, and the usage of appropriate graph styles. pyx-project-pyx-21f71ce/examples/bargraphs/changebar.py000066400000000000000000000003461526513311100233020ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.bar()) g.plot(graph.data.file("minimal.dat", xname=0, y=2), [graph.style.changebar()]) g.writeEPSfile("changebar") g.writePDFfile("changebar") g.writeSVGfile("changebar") pyx-project-pyx-21f71ce/examples/bargraphs/changebar.txt000066400000000000000000000010431526513311100234640ustar00rootroot00000000000000Changing the attributes of the bars This example is equal to the [minimal bar-graph example minimal.html] except for the used style to draw the bars. ... ! It is not possible to use the changebar style to change itself on a list of data as it is shown for the bar style in the [comparing bars example compare.html]. ! We are sorry that a graph key implementation for the changebar style is currently missing. The implementation of such a graph key needs a major rework on the whole graph key system. This rework is planned for the near future. pyx-project-pyx-21f71ce/examples/bargraphs/compare.py000066400000000000000000000004531526513311100230150ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.nestedbar()) g.plot([graph.data.file("minimal.dat", xname="$0, 0", y=2), graph.data.file("minimal.dat", xname="$0, 1", y=3)], [graph.style.bar()]) g.writeEPSfile("compare") g.writePDFfile("compare") g.writeSVGfile("compare") pyx-project-pyx-21f71ce/examples/bargraphs/compare.txt000066400000000000000000000053701526513311100232070ustar00rootroot00000000000000Comparing bars To draw bars side by side to show differences for the same value you basically need to replace the bar axis by a nestedbar axis and adjust the data to that nesting. ... The latter is done by providing a tuple of two values to the nested bar axis instead of a single value. The first element of the tuple is used to select a subaxis (in the present case: one out of twelve) of the nestedbar axis. The second element of the tuple then selects a sub-axis of that particular bar axis (here: one out of two). ! You can replace `0` and `1` in the values provided to the xname parameter of the data by other unique hashable objects. Note, however, that this does not affect the order of the bars of the subaxis. Instead, the order is defined by the order that data is added to the bar axis. Consequently, when you swap `0` and `1` in the xname parameter nothing will change in the output. However, this value becomes relevant if you turn on naming of the sub-axis by using graph.axis.bar(defaultsubaxis=graph.axis.bar(dist=0)) instead of the `graph.axis.nestedbar` instance in the graph constructor. !! You can also use the same values (i.e. objects with the same hash value) for the subselection of the nested bar axis. Then the bars will overpaint each other and by proper ordering of the data you can fake stacked bars by that. For an description of how to do this properly, we refer to the [stacked.html Stack bars on top of each other]. !! Let's suppose you change the values provided to the xname parameter of the data from `"$1, 0"` and `"$1, 1"` to `"0, $1"` and `"1, $1"`, respectively. The answer is, that all red bars will be shown on one subaxis and all blue bars will be shown on another subaxis. !! A nested bar axis is totally equivalent to a regular bar axis except for its default value for the `defaultsubaxis` parameter in the constructor. While this `defaultsubaxis` parameter is a special instance of a linear axis for the bar axis, for a nestedbar axis its a special instance of another bar axis. The nesting of bar axes is not limited to a single level: You can nest bar axes into each other to any level you want. Providing explicit subaxes for certain values, the nesting levels can even vary for the differen subaxes. (This is totally crazy.) ! In PyX versions prior to PyX 0.9 the creation of nested data for the bar axes was hidden inside the graph styles (with the limitation as we use it here in this example: adding precisely a single nesting level when passing multiple data to a single set of styles). In previous versions we didn't had the possibility to simply generate tuples for data columns. The automatism was removed completely, which makes ''all'' the bended sections above possible. This is a quite incompatible but absolutely necessary change. pyx-project-pyx-21f71ce/examples/bargraphs/errors.py000066400000000000000000000010311526513311100226740ustar00rootroot00000000000000from random import random from pyx import * g = graph.graphxy(width=8, x=graph.axis.bar()) g.plot(graph.data.file("minimal.dat", xname=0, y=2, stack=3, dy="1+random()", dstack="1+random()", context={"random": random}), [graph.style.errorbar(), graph.style.stackedbarpos("stack"), graph.style.bar([color.rgb.green]), graph.style.range({"y": "stack"}), graph.style.errorbar()]) g.writeEPSfile("errors") g.writePDFfile("errors") g.writeSVGfile("errors") pyx-project-pyx-21f71ce/examples/bargraphs/errors.txt000066400000000000000000000006511526513311100230720ustar00rootroot00000000000000Skipping the first bar in a stacked bargraph This example shows a bar graph, which starts with a stacked bar skipping to plot the original bar. ... This is done by using stackedbarpos before plotting a bar with the bar style. However you can still add errorbars, even to the lower bound of the bar. !! This example also shows how to handle several errorbars in one plot command by the usenames argument of the range style. pyx-project-pyx-21f71ce/examples/bargraphs/fromvalue.py000066400000000000000000000004101526513311100233600ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.bar()) g.plot(graph.data.file("minimal.dat", xname=0, y=2), [graph.style.barpos(fromvalue=0), graph.style.bar()]) g.writeEPSfile("fromvalue") g.writePDFfile("fromvalue") g.writeSVGfile("fromvalue") pyx-project-pyx-21f71ce/examples/bargraphs/fromvalue.txt000066400000000000000000000012641526513311100235570ustar00rootroot00000000000000Changing the starting values of the bars To adjust the value the bars are starting at you need to set a `fromvalue` at the `barpos` style. ... By default the bars start at the baseline not taking into account its value at all. !! When setting a `barpos` style explicitely, no other positioning style instance is needed by the bar style and thus you can set other default values for the `barpos` style. Note, that as soon as you explicitely set a barpos style, you can also use other styles requesting a point position at the graph (since the bar style also initializes a point position). Hence you could for example replace the bar style in this example by a `graph.style.symbol` instance. pyx-project-pyx-21f71ce/examples/bargraphs/minimal.dat000066400000000000000000000003301526513311100231270ustar00rootroot00000000000000January -5 1 Feburary -4 3 March 0 8 April 3 13 May 7 18 June 10 21 July 12 23 August 12 23 September 8 19 October 4 13 November 0 6 December -4 2 pyx-project-pyx-21f71ce/examples/bargraphs/minimal.py000066400000000000000000000002771526513311100230210ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.bar()) g.plot(graph.data.file("minimal.dat", xname=0, y=2), [graph.style.bar()]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/examples/bargraphs/minimal.txt000066400000000000000000000033061526513311100232040ustar00rootroot00000000000000Minimal bar-graph example For a minimal bar plot you have set an bar axis in the graph constructor and provide Xname column data (X stands for the bar axis to be used). ... Here, we just use column 0 which is automatically filled by `graph.data.file` with the line number of the corresponding entry. Furthermore, you need to specify the graph style, since the default graph styles `symbol` and `function` (depending on the data type) are not appropriate for bar graphs. Note that bar graphs differ from other xy-graphs in that they use ''discrete axes'' for one graph dimension. However, the only affected components of this fundamental change are one of the axes, which needs to be come a discrete one, i.e. a bar axis, and the usage of appropriate graph styles. ! A bar graph is fundamentally different from a graph with a histogram style in its usage of a ''discrete axis'' in one graph dimension. A histogram instead is created using ''continuous axes'' in all graph dimensions and just drawing the data in a specific bar-graph-like presentation. In particular, the discreteness of the bar axis is reflected in the naming of its column name: instead of the continuous "X" it expects an "Xname" (where X stands for the bar axis used) as mentioned above. ! As all axes and graph dimensions in the PyX graph system are treated equally all you need to modify to get bar graph with horizontal bars is to assign the bar axis to the y-axis in the graph constructor and change the names of the data columns to `yname` and `x`. !! By using the bar style you implicitly also select a different positioning style, namepy `barpos`. This positioning style handles a single-nested axes with sub-axis values of the range going from 0 to 1. pyx-project-pyx-21f71ce/examples/bargraphs/month.py000066400000000000000000000006601526513311100225140ustar00rootroot00000000000000from pyx import * mypainter = graph.axis.painter.bar(nameattrs=[trafo.rotate(45), text.halign.right], innerticklength=0.1) myaxis = graph.axis.bar(painter=mypainter) g = graph.graphxy(width=8, x=myaxis) g.plot(graph.data.file("minimal.dat", xname=1, y=2), [graph.style.bar()]) g.writeEPSfile("month") g.writePDFfile("month") g.writeSVGfile("month") pyx-project-pyx-21f71ce/examples/bargraphs/month.txt000066400000000000000000000012311526513311100226760ustar00rootroot00000000000000Naming bars To name the bars you just need to use a proper data column (instead of column 0, which is the line number in `data.file` instances). ... Beside that we show in this example how to adjust the bar axis painter to properly show the names. ! The internals of a bar axis are quite different from a continuous axis (like a linear or logarithmic) axis. A bar axis just handles a set of subaxes - one for each discrete value. The painting of a bar axis can only draw the names for the subaxes and some ticks between the subaxes. Other axes features known from continous axes like ticks and labels, partitioners, texters, raters are non-existent for bar axes. pyx-project-pyx-21f71ce/examples/bargraphs/stacked.py000066400000000000000000000006171526513311100230070ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=14, height=6, x=graph.axis.bar()) g.plot(graph.data.file("minimal.dat", xname=0, y=2, stack=3), [graph.style.bar(), graph.style.text("y"), graph.style.stackedbarpos("stack"), graph.style.bar([color.rgb.green]), graph.style.text("stack")]) g.writeEPSfile("stacked") g.writePDFfile("stacked") g.writeSVGfile("stacked") pyx-project-pyx-21f71ce/examples/bargraphs/stacked.txt000066400000000000000000000005721526513311100231760ustar00rootroot00000000000000Stack bars on top of each other To stack bars on top of each other, you can add stackedbarpos styles and further bars to the list of styles. ... The stackbarpos need to get different column names each time to access the new stack data. This example also adds text styles to the bars, which just repeat the value column data here, but they could refer to other columns as well. pyx-project-pyx-21f71ce/examples/bitmap/000077500000000000000000000000001526513311100203165ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/bitmap/INDEX000066400000000000000000000000211526513311100211010ustar00rootroot00000000000000minimal pil jpeg pyx-project-pyx-21f71ce/examples/bitmap/README000066400000000000000000000002031526513311100211710ustar00rootroot00000000000000Bitmaps Although PyX creates scaleable vector graphics, you can embed bitmap data into your output by means of the bitmap module. pyx-project-pyx-21f71ce/examples/bitmap/jpeg.jpg000066400000000000000000001140041526513311100217450ustar00rootroot00000000000000ÿØÿàJFIF,,ÿá€ExifII*  ’œ8¤¬(TF1 ´2¾K.¥ÄÐÒi‡¢PanasonicDMC-LZ1HHVer.1.0 2005:04:07 16:32:56PrintIM0250d ¬ Ä€ ' '—'°''^'‹'Ë'å'"š‚@�‚H"ˆO8'ˆ@88�0220�P�d‘‘x’ €’ˆ’en’9- ’9- ’�|’\˜ 0100 85   À¢O-£n_U£IA¤U¤.I¤SO¤ô¤%15¤15¤-8¤88 ¤85 ¤IS ü €  2005:04:07 16:32:562005:04:07 16:32:56d = Panasonic !úê"#$%ä&0100'() *+,-./012DVEPð?DB0ð?AFŽ`G €bGdGfGNGPrGtGzG‘ÿ|G~G@G@BG[ LG8\GóvGèxGRG�VG+TGHlG·pG-nG]XGýžG‘œGÈŒGŽGŠG[ �G’G”G–G˜GjšGð?STF¤F¦F¨FªF¬F®F°F¶F¸FºFôGöG²F´F°D²Dð?AEÂEEDE"J1ÀYÁYèF‚ÌFÔF ÎF!ÐFEÖFAPXÚFÅYïFÔYÖYŸPØYM`ÚYÏ<ð?WBDMD^\DDçDÈEDc^D._DDçDÈDCDèÌDÜÎDíÐD=ÒD#ÜD‰ÞD´D¶D0D`8D‹2Dp:Dy4DèÿD`LDäND«ÀDÝÂD·êD€E‚ErƒEU„E†E‡EˆEŠE‹EŒEŽEk�Ed�E’E“ERD‘TD“VD“XD“ÔDÄÖD¼ØD‘ÚD“Ô]XšX�X8X%6X›8X›:X9GÎEð?CM üEðð?IS”F–FC˜FÔšFå`FbFAEBMPRSTFCCV[ [ A èÌÎ×èÍßÖA êY @q @À‰ ªÊ¡ ]Á¹æŽWBCZ       # 0HØGT DHT€¯@ƒT À0@P À@pÈeTpäeTpfT0#>Y #>YF020502140166sr R980100 hp(HHÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀA"ÿÄÿÄ>!1A"Qa2q#�‘¡BR±Ñ3Ábá$CcÂðr‚’ÿÄÿÄ(!1AQ"2a¡#RqÿÚ ?ñ–¹�“\™&^dB�È&oRad»x€¤èË|;‘¹P¼Ím©Qt&Ž€^„E2îÐ p"‹qט;ì,<Í\´FÅ2,î:ˆ°æ5d ^f –�ÖݰêwPÊÚ†‰‘a qZJMƒ¢,uÜžd5.¨`Àæ1V;9àIãã›q:NŸÒû€ùfsÈ¢Kg?ù6Ä•ó;‡é_'é”=KÖ DrÛ (šM�Fb‰µŒ�ŠdVlˆ¬fÙ Ëó"ÄÁ÷F�ƒ«ýaP‚b€“â6%¤!ÀÀ2JüÅA>ðŠÒ[Æ×)«#ÞYãuÐçFQÜØnÞeÂtK�áÓœä#õÄîËî<%Bß¿xAlÓ™*?¥½9þNŒ+ܣĦ¡ÏÄÑ1ÂQ��‰‹KlJëÓjOÒ8þbÙ2YUBÙ“QĆÎüB.ÌÌ´l)3aHñ¢KZ’0D´ŽÉ…d'Ú �шƒªÐ±šòu¢�j4¬,ÒÜI G…\H½‡²µÎ »ŒbÚÎÈÔÂ&* !Üaêrx?„DÐ%&†8 Úð`Ѷ7"-s± YÐÔÌÙ™ L}4@ª—B!�d±F&¸Èa«ýQœtÝêO´Z­ïq´¹Cƒï:"Ìä]Ñh@=£g+åúÊ�z²�›™‡#^ Û‘(k*ý¡ÐœwS´›ܹÍÎ „ws9ËK^äûLrH¥±fîó2êÑ™1Ùb�ŠÛâà0ö— Hƒ5)3ŸÚJÔßI?„L±5¨öšøcR–T4Vº@ëÞX>8h 1HçRÖD 4XDÙ}Žfš²°g{�‘&›˜Æ6ÙGU¡3X´›ïTÉž±é/NÖõ®Ðn }‹mÒ<Ã#¡æS_wÂ$}¥[C¢?yôŽg¦)lb>ñôžOêŸKš,w©5ûEĪhá Í(î›zÚ·*Ñ H£ÒC6(bÐë„ÇÚ\W†%…8@�ÄÏ'—]Èåß§6·¨¥¸L‡ÄîŽ#ĬÌÀ©8üÛt+95¯°ó c*žÃ^g¯Ž\•ŽÉkr:Ñ„AˆÜR5ï4lj¢Ú$“! Åb :·cÄÚ“í4±PÒÙ¦Üurö4ej|˜Â�mA0 n@×Ò'e¥Ì9¤¼Å`xä˦Åin&~YÇ´Ø^ß2\YI† Ä"W¾LŠˆÅzÔ(l‰«ˆª:Gh»0¡»\~òÊšÀþqKWí�o[Ú8‰¿¥…uï\Cná2‚Ôlíó4•o�Þæ-f!Sât4 ``rhÄt„Žu©àÅn¯RæÊ´H‰_V”Ìd‹©µÁŒ"Ms"“S$Ð{âk¿Ú*&©Ø1Úr»t ¯c¹ Ä©QL‰QÐ&JèI�¯™Q]Ä®·®ÿc5¶HáÊu÷ƒn ÀùŠÛt\w;GÉ’Òm­iÙ0•¯+kÆã5Ûâ‡@]w¼ÈKÍ2ˆœ¢<Èþm~²NâÖP}§'­0phwó*}ä–õ&T2X§ÞbØÊaë´_%€Íئ¼¦_x_ΓæC„¬®A.Fó÷�'fZÑ'Aé¼#~J¶·ÌöïLãüTöÏ7ô."بÄyžÍÓqt ´P⾇¹Á¨ìN?¬tåÉWÚÎÒê~C)o§d‚#zCúx©ú+a嵊šRyœýU7sÛýEÐW2–ùw8Š}7ð. ¯ƒï0Ë•A›tQâVÊ ²êZVË­ cOJ©”ù@ n.„�"èõ] Dö“ï0’re�rêVç*dŽObw�y—ƒœŠ‰KœWfVp o1»ØèÄ ¶õ>�\cE �`ÌvÌÏ„ÞòB¦²Œ L˜®ID:¤”1c\�¯¶>*šze®„¥ØŽUNνä)¤ïRã �ÆÄ¨FØ›£XÝ<0™`:Z"ð¤™}ÓznõòËÄé¯é�q†Œ›8 ºqíØIU•‚Ëιž�IùOË9Î¥ÓHV$BP)Hâ;{ajmy„ȨÕiÜ]ž'3[64T ƒ"µ¿€dÅ\üÑ’+edŸö�Z[gb]׊¥#̃㪟GÄV)ŽYÙ�£mw5ïÄ-@§ �´Æê~Ãô“µÃE˜�ï Öà"º*ͽ*Ow¼Vú;†µ3Nƒ¶!ös¶ãN¢¬¥_ßH•5iަRE&< ç˜4c(>Y(³^f¯ÚK¶l'К#Üׯ ñ6ɹ‹Vô"lT€lå¹êPˆ:j ^€Žc/Ì&‹¢( ¤â`©—IeF7pÞ¤ìÃZ‰,£µ‰‘û¨ùæCˆ[9”¹L.•¥c’� ^IærÑÓv6ô®¢–ÓÏd†Ââ¢ää-SP�WŒîxRi3‹bùSý'¯zwÒdP¤ ;u-3ý X¬•¨IRD«<7°¯‘ÜNÿ«z.ÊËÔ�å9,ŽOðÉ5 ¤tþ…êéM¢–<ƒ=Ã¥õí¥@a>[ÄlŒ•°+)zï¤:ëd¹–í =ÑëÀ‹UfÓØÛ�ô÷ø”‚~“y´÷!‡h¾Ž~Ä[DN{©a­@ØéZ²¤‰[ÔñËÐÀý'4¡ËLÑN•£Íú¶_jv�$èDq°þ'ÌG&;ÕðìlÄE[—=7§j°Ì¾Ó—6ÔHŒ”ÛäVâáµn8—ظ¥ô5\ Xq-pq”8؇øj¶ ZFbô W}°Öt•*~YuPD®Ca‰·Å´‘Äu>—Ú¬BN7%~Œ>ó׳±”7Dó®·Ó NYDàòð;䉔~œÕ–³$§¼nÊ�;•™±ßŸ‹tÉhŸæøó¾Öx»VÔ*)?yíaì &¢y3>ÖõÌ}1û¼ÂüN®#²¹q s©3ŒxܶZGfµõkÚDU~|CWV�1¦E׈2BÌÜFE«q!Ù³$ÖIVÃb4†ØJªƒ©Ñtš†Ä¡­†„èº;‚Tnk²$v�3Ç¥£ x”>Àª'I‰`+:‘¹x`! NWªbéXkÌí²NÔÎs>°{·3˺®[OñÄÐñÌì:¦wÞ¸‰U€xœî4R)j§ŽW™· ý'D˜ €¿�â‘[I#qâN‰}� ðÒÖI†#z’ †2TW¿ÍGu·d8¼Ñä�äWÚ "Qäòæ_å8a(²µ³3œ‘HO[‡¨{%â�ïÚef�>ÖäJèó«°56h'�KŒ€MÍööÃü2¼H‘ÌlTûŒÒÚqí+ŽÔÂ×kïrÔˆhì°ŠüIçSv�IúJŒ<³ðÔïîªt)hÉ´‚ó&˜ ù!c´py+Îâ�Äa‘àÊ÷ÎV�Q%¼s+òù)gÐÊñ¼EÑWgо…ë˜÷ãÖ �êz1Tº¯|Ç讫f/QZÞÒgÑ7óªw¾% ~ÍéuÙ½¨ær�O Rwò èV(a(ú†9$èF�›<Û#Ó>ÿ†?¤_¥·LÈ X*7;ïË�yX¾VØ„…æDÝ G‘eéî§ñ+TcÌé›N“�éÀãäqÇ3²ÇÉ P;‘þ”è ´ÆWu ‡Â"[Ûb‘¹W”~#jI #—= ]�¬µ,UPKL\pÏâ=f?pÐTöi»ÑÚ4ÝA�Ë»p¹ñ0wí7¤û%ZøÌA24Þc–bv�¯% 7 “qèÒåØý™«ðH>g!ÖmF ½G²n g/ÕrÊ0šy!£<ŸÎŠÓZ91k±T‰±nŒ™¹Jòg…,sÇ#²—#’@æBš9äKKH0aW¶{¾Û�2ÍWX ㉾Á¿뉦}O@D¾Qïɰ(úÀä_£ÁŠ›Í„%° ·>ð/ݾ( áD'cöò$PÖ ÆGió ”Œ6u+_{“- l´¯(o{—}/¨"Z>mÈ “0 ‚aМYì=M{F˜ýçGƒÕ@]ÅzW²­ó:l.¸n?yÓ©™S]žŸoP ¾eEù=äó¹D�TØŸ+ñ%^Aß™|ÐÐ\Åï ¼Z0™Þ,ÆquÜ +¢v‛³(v‚5¹~ÿ2Jl´Ù;�¢ŽCª�e3–·)ûÏ&u½kJ¬DâìæÃ9rhVã³oÓòu¥¤©¡hõzO$ÚØÚ²èÚ¿i‹¶•âßmÍ ŠŸ0”„ÑlúÄ*Ì d^¤L%1£/#R£!{‰–V¸`uµw2sÙHH ÝC`j.ÉÌs l…•vU�cbï“âX %ìñ ‹V�F€ó¹ÑÒ&ì¦ÈÆíÞ„¯±{}§Cz%6b-¢‘Ye„ ûˆGÌf#3 ,ñoø´±\…#Ì£¬óRN¥)Q.%‹\»à̉©:™.ÙNjÛ;ŒU¼Â¹€ihdÍÈîkqcÒ²Î6uo½s>‚ô_Tè;¶u>nVÑzo }@*d­ßDqÌh/gÐh;“q[éÈ€éÝN«èRxŽ=ªßHÓEUÔ¨"n �K;Æ÷©\䩿)$ÁJŠû)í~凧,Ô½¤Ì´ìD/mL2>;,α2+zØüAnQ ç‰ ~¦úyù2˳XµGy‡XíÉ(eIÎWQ³/Z� μRD2OާÚ.ô…öŽ¥¨ÞðW€DëB+-Q£¹ÏõB¨¤‰{™jÖ„“8/Põ�_pÞ€Ž“Ó“в»¨föwhÎo"Ãc–3v朗$ ·:a‘žäíŠÛoiˆ¶avî5–B¡ñ)*?'åäna›dMl½«ºÁ¼ÈáTB�ÇÙn¥b :*mB›‰Ûw�<ËL•*†åCak'@Åî°»kp¸‰·wFqX+ƒ2ú?…ÅÛ �#�'ŠÀ ?hÖ†¦ÉO“ˆ½‡åœÞU=ŽF§_–Gisyëó~ó<€‘PFŒÖý¡ÍdÁšÈ˜J­î?EŒŒÌA>S§G˜ìTt�?#`h˺ÉÐ$Îc»5/©¸shÈŠ-«”s ^Gió+ÒÞ4LÓ^ù–¦]þt•ó+òò ˜™ÊíƒÉÌ:2ùŠ„:­�ÊwÉœ­©ó“/r­6¹Sr�ñ9òH¨¢5q¨ÈäE“Ž ‘r¼L¬°ýý°6_¨&´ê.ÎIó%Ž×ió¸Ú]¹R�®# gÞsÊ#¢Ð?d ÙŠ­¼B-›‘ÄDØs Ž{\s[bm˜Ö‹øtø¶î±õÔ;7¼çèÌj†‰â7þ"¤pg\&¨Š¢Â×¾e6c†$B¶M–ª ‰ÝUÍÉR?”©Kð¨±'0gÌ+©Á� I™2ØZš9_Í¡¦®CW²³&ˆ‹8^à^¢%š×u` ȲìVU2êj2éVt)Y@ÈŒáæ[‡p²¶ ˆM¨ì;=7 zõªUKGï;ÞŸë*¯n?¬ùÔ1SÁŽcu\œcòXaA´}0½v‹a„Zî«[O Çõn`Ò‚wûΫ£ggf€[z0Øùý�Hs£³4?Äëùиö7MmlÎ|Ðr@¬FþæS¯&W ­ªÁ­’LèìÅ ÁUa£0,'œã.™µ&†z(´V 'rðÛb�“!ÓqW´´|=§‰¾ Oàž…±ú€Aókzš”àÊÌÊ~ô%pcÜw:ùIiH—Vê'á¶§™uü“wwqÐÑ2(ø ñ8ÏPô;-­ÙA´…¹]”ÜTz8ÚsðN¡›¨ Ò›-lÄ´£‚‰>Og£èæ¡Þ¥Ô‹‚óÓ[ø€“+]ͯ³Á=¬—+aGeŠÛ¬GÓ•”˜Y!@–c)ùæh™6K)W°™Ìçè9Ñ–ùy{R¢È%‰&L˜ûß0´¸æ$ï¢a±¶Ì&w±³¤Ã°•1àX�Õ*qw¡®%‚¹j¥¢HdžÕ=ÆQ_óØe®S%[ïºg7e  �{ö�"Vee šù’F*a˜ ˆÑŠÀ²Å·�¹k�~¼™ÎÕgiÔ°¦ñõ��¨¼9\­ù„š(rB¯�Ä2/Ùó1Ñaþ#¯-fz¿ù¥CÛ³æDËSaı²õaÇ1GäîD<Ùi›v4ˆ�dŽäØñFâ v H‡+ R1@¬’š”„]ÎäØî ĆÄГvßXî×¼ØmÈ0âAw¸˜1�Í�ĈnLJÈ‘ æA¥& dMñ4LÖã`ºÂD††pÕ� X©Ô͡ծ íý6Īq8ΛŽùWêzo§úY­åÔ¼iÙ/oGiÒl*Š%÷ÆÒîRáÓØ¢Xw|º3r‘;-GŠÙŒ¶ƒ±¸–U­Kl!0óÖÎ ™9S¦©ÓÿCwh—XXÂ�ÚZšò$-ÌJ½Äµ%C¥v[y™9÷ëu)×x™4+GÉÄÈ3M±�"“[šÜÑ™ÌÜÞä[€\zz¯�Õ*_¼¤_úM€ë5ïÞ8­“.� ý7‚½¥ÓR]ÈöƒôøS„Ÿ´²)óñ)ÅêÁÞ£é@Ä-KÄ?n–!¢·(†s�»�>oé"rRÏ„IÞ¤MhiìÝV*¸[ÖÁ«àÏ=Éë«V@^ðçKÒ:½w ù·9±IÝ2äÓè±{ž‹<@dg‡R ‡Ì)e{™A{äN´dôJÇîrd©b® X1Ü=<°–AyV­§™Ëú‹¤&Mmµ�.9íQꬿ™›5]7—Òÿ/qR¼H®8‰uêëFßR×–¤y™½2ÒL¨ÀÀ÷•ö�½ŠÐ ™\‰p±ŽàÝ´±úñ¾!ñý-ˆØ\�(2…ÛfJ¶ÔnîšèߤÍÓÓlb81sŠTF»ÊÃ~hê1þÚñ³ ÄmaÍÕ²âÐ c”³ÜMK>†Ð Ì—t ó~$ׇ&�°@&¨È¨Ž$Ž3•ØÐ!1Äœ!ư{MŸé19"ˆÐ�gÔ+Öúñt}ø1ÄM› ³º0*�¿U‡±–“?GPey€Â)âa:�˜L‡%Ý"Ì ‰2aig³GQ2dÔ 0ÍjndŒ·ôõ¿ ªÔOÖTÃâZhÉKðw>¡ô®WÅĬoÚuh �™åþ„êõÛ�Yï‰èÇ6±WpaþYc[u Çå”5u/ú†£ëšŒºî Ë#FyÿªòE»oS´ê9K]Dîxÿ®:Ðøv nOb`Î3©½Ùö7qÖô'CÐúëcüNœ÷¾d«½ÁáŒç–;vŠø{E~¦G@;Çõ’^¢—6ö'‘Ó�uzÓŸë.0ºóV@c©¬%Zd4þž�[«ëFXPƒƒ8 OP¦ÆÜY�ê û?Xþ³K£«ø¢µäÊN±ÔkošUfú‰Î?¬ãºÇ¨¾.Õ[fK•�?ãe•SÀ”ëySæFÖk¹ò`[‰-˜úf?�æQ$nS‡Ô2[£u]:ÕvΫ»*Ùyæa­ÁÜì:gVSX¦rF�{ÌÀ¬lèEiª°yÔg/5Z³Ì¡·)ë$ƒ9ä›'"Ù{ðê5²šÉð%õvv �ë'ë'„Œ.›¿ �4V>’”õƒõ�=\ïÌ|$M—-EcØEnT�JÆêÌ}à,ê Þòã cû^íKzÕ—™ÌŒ‡'{–ýI�reI:4‹ÑÐZÊòįè%wøÏf‡X_¬ËŒ‰rC̓Yö-Ók'À�a¼˜êµŸx%$+$:R}&˜ºñ$½R¿¨“ÿ­½ã¹$,zh ,é²ÇóµŸó £“Y÷–I!Ú)lÀ*`¬»{ûÅÜ¡š,�öŠsK}& ˜{KNÅúM­Kô”ä.EWiÓ4~’ßò�½ ß �ccäW žy‡4í W¶&ô;5©%Ð`Lv¦l‘2»%»;ÏMg*ž��œ3Âp3ìÄ´sÆçwÒ:ú²®ÛûΘ=]hôÏŒ¬»ÜVü•Pyœòõ¥ìýcúIJú³°=»2Û,?WÏXwN#;0=§GÞ5Ô²²nÞ”Ê��lÛ9sî&9%z-i·cQ�¦ˆÑS€<Ǫyž.Fâ̆R¡Û2IK2s9±Ò<�{™© fç×�O$Éq¡$w7¸ÆnIGÖDC¢À ïOz‚þ“h�gûOAÇõز  ŸÞy2¬�f ŒTz÷ýdŠ›ø 9fu·%áì±ÈUE,O°fó=×ð—ÑTàtdëù”ƒ›” Çîö«ñ±÷?_¦¥$*(úáå•%Y~¤¼—?0¬øÿù7þõ—Ù‡Ý ­t¬šq0ªÅÊ#tZ¤í[Û|ò%çXbs\{/K¥d5VnY?OœzŽOKê9ušï¡Ê:Ÿb?ñc>ˆõÿ£±=SÓlÍ¢žÎ¯UdÖè?ï?C±Ÿ<Ù[Wc#©WS¦R4AúI(¦ôD�Y½DÆ™ŠåO˜î>kÔFŒH¬ŽÈ’ÑJGMGP�1Œ¶ ËWqSæYcç•ÖÏ ä5“ƒÞ ¦ì[j> þœ¤·Ün©KÀ“t'ÎLìHeæ_MO2¢Ú^¢v8šE¦fâÐ Lš�ÁîML¦‰ «'£ ­6^E Ó {Á±2LÛ�ÞãH i°Íõ™© *&¬ßXU-õ0j!–KC¤A­udFM»òa]AI^ÚCi%AEöæ`¾Íë“:�Oz7/¬2·aJ�¾§¥ô¯Ã¾›‚ªn¬;û“4Œm•ôyMé]K¨ºŠqß´ÿ˜Ž'yÒÿ ²,U|«÷ OMÄ阘ŠTªëívTKPH|?Nc§z#¦b¨ Xfú™bþ‘éVl~]yûK-‘ȇ©öÜÊÑI%ðòÏVþþ^¦ÉÀSÇ%DòÜ”²‹,R¬ˆ3ê\¼ŠElÑxž_ë�Òÿ/va �¢fs‚{�ôy³˜Uq¨½‹¦=¾7 ,*fJñhq˜IÓŸf1ùOI^n2ËIÎÇ¥õ;2l“ûN×^£¸ny�Fk+¸ODé}IkAÝÄ´Td¾—§¢Té¾ÑO¡ð²Ç¬PÊpަeN6“$¨¶“9{: ¤p²ºüNÂx�–M•²žD¢ÊDgöž~|IôK‚*éÄv]èÌ�-uЇdæ^$HP>|ÔÍB £=ã@mdß™ JB557©�±ˆÚùŒ×Ì]V5Hç˜eS0®„2�4àj1‰¿ê›YŽ9&i|Èc  Óc‘" Ç™ŠyƒcÌÚ˜èSPžÑd~!;ø‘@\z_¤»ê~ŸÓ�—ÜÈòÉþÀϬ…)Ž”ÑR®µ Š<€Ÿ6þÔ—~"à—ö-Œ»>ý¦}+�`Àxš.€çz×MF\ ‡‘õ”˜ºL�¾ÓµÉU%¿Cg1Õ:m¸wµÈ¤ÖN÷©Be…YÕ)k{4j?F×·Þ*„îš&@�Mo˜¨d÷$ˆ fn4ÇjÈ+ï,ñú‰ v%mB%¤Iq-Hê’ôµx"FìTµ|J*rYH ËLlðtG.ÓÉ錄”†èÚa©ÜôÞ—Y·áâ×Þ}ÏÒz§zv;‡ê­îÕaÀ–­™É%Ñá![·}§_]IÑ�~]¢¬zl¶Ãá+RÇú ôÖo@ôí86b >q¢G�éî›ÐqY0qÂ÷�µ‡–oÜÊHƒÇ° =Oœ�ÎP��`Sý90ùß…>¦ÂVjè§)Toø6sý§¾cžá¸Ñ׈R䜬<Œ,‡ÇʦÊnC¦K‚?”éYz'ÕNý‚¾ ˆE7Ž6}•¾£ý§ÏÖâdÛ�z¶§(ê|‚ˆ’Õ ¡¤ Á%�ÞçKé/LÝÖsÑÙ¡O'^e§z5½g¨¥*§³1žýÑz=#+­` ¡{dIrÐÏNéôôìdªµBëw$Zù¶É5²ü0G˜­ŽKòx™ÝÚº)—v—Ï0۲몱Ï2¾Þ¬W„•–ZîÚÜЯCm­°ç)œ›no”sÌóO[uïÎd~V¦þþ­N“ÕipðZºÛLF‡ï<¶×k»’vfSe$×qwMÛx‹ÙÉ’†ÅÊÆz}ì�¦.G1Œ;MÿC(—Ñßô®ˆ®Š{gFž�-^Ôj'éÌúl­6G3¹Æº’ƒDJ I4qoÒ/Ççgˆ»æ¾/�´Îøl‡DN ®PÚ2$ƒ‚]þ¡ A§U>û§�”õÜ{[ÞZtE·'LÛÔçœb·ÑÞQÔÀO3"cƒ{™3´WHƒ±ƒ)ž øúõTAïˆôaÿ3Ú›+@ÿ§r�0ö:¾3!ò¼ÅêÎW.ý¶}įÊê–ÿi¬ªòŸ²À;½£†êl?u%ǰ mÇÚ\Õšˆ dé‡>ò`…µ�9€¨¦§&ÌwùŽþÆYÑ‘GQ¦Ì{Ñ]\dq°GÜHõ±íÄ{B€ê?œçëËjÛòµ’?¤NªÆ¿"õ÷á¶OIêWåôj�ø Û4×ËÓö׺ý眺5nUÔ«#‘=ï 3%¿ù–fb­²O¼å¿=:Θޤť›U’h«ÿ•�ïãù ç`óã›/­#«/Ž±Ã•žY2kQÞ—‰ùÞ£MÃ7Íû{ÎæÒVÎx«tC§æe Ñ‹u£zÚ!06#Óc%ŠÊêtU†ˆžÙÐÀÇ©~ „®­i@âR~%útõRôÛ0jQnm°®Aóýç69rúÒ:²øÊä™åÊÆ_ú¡çõÌ¥¯¦ìßÍf¸YÛa~`Ô+9Ùc�6»ãsÐz/JÆé�5颵©Wè'uªL«è/Ó´öQ·°�;s.Ó6Á¢ÇD�ñ5¨ñÉߘJ«î&4ˆl9Ck÷xÙ–5H̦€¹�h g�dþÑ lÐ;�.ü˜˜Ðum�}ç™~'ú!óTõΙ@7"“–‹åÔr=ç¦ šn"ò;a1qß'!)¬m˜èN·ñ+ /Dõ…éB*Ñ”õ"Ž|ýA–¾ƒôßι¹+¯p’£±6v^‰ôí]',u†É3«ºï`bÁÕj ¼ Q��£,]Ö½çq†kæ öy€êY€Ôòbµù¶:1;Y­^âx’Lk.næeÕ3ÄŒBËæ¨åŒLFr}¡T5mÚÙÇzשµXÿ E¸ƒt¬Äõ¾«f~{±bPFØæ¹2u™‹vZ܈^aüÁ¸’†ÅˆÑ›Y&J%’]tžªøN'´NËÕ+ðÇÏýçœ,'Ä+à˜¹õÑßæz´:yËuP[•°Ìê}7“Z¯c ä¶w NKRÝÊÚ"DÕ¢âÏU[«í‰“Îׯd(×q™0ã#Oj9­M� Û6z$ɨ’Ö¦�@êopeµ5Ý 1­&åˆ*™"ÜAƒ©¦°AŒ ›ö€øœÍüMÈeÜž$KÁ»ÉH»AîmŒæˆƒ& ´Ùc éß‚bŸ]5%ô21l@>¤ßø3Ù,Í®¼»”ì|Äq>pôR=/×=#$�/æÿéo”ÿc=목N§~�=äÆ uîªÞâÃìOÒ-�yÄÍàìn ¶²Ÿßë ¬ÿcp»Õç�Õñ«:: .(ÚÐÙFå¦ì6ªÎt½»÷—}'»òŠ oC[€ÊŽ­Âî@Yñ)h=ŃrÔ²ëL@Vá†Ä©î*8”–‰ofú_K¯í CÔÍÀúF=KÓ?ÓC kîã8Têk¯æ>Í�g¹rÁ?‰ŽŽ*Fç><0Æßk,’šÛ>H#˜×NË8Bœ�6¹Qï Ö1_ ­gbØ¥^›Ý>Úb"3F­SmlöŒ.«…�éë$¹ÇkUKÊó¯¼C¥úˆúŸÖU]B2ââÓðë-äóÉûHu a…ø%B‘¦´£ÿ6}ÿ´_ðÓ-×(Ý„ëI†/%Ê+hÓ&iIS=ï¼ó¸Ë3¸ý‡´ CCCϹ–¨ #[¤ÀKZ0µ�øŒÛMlç·�´‡åȰhÓCJ~P}ȘÎ>ò`^Ï §Ä‰n7ïÂWó0]Ëß|}%m ©žL}˜ÐÐ!†‡˜Z�±Îáë:’3Ë¿°—©zëX|´ã ýþf2Ó.5+UcZ^¼Œ}u’]¶“~÷_î aè±û,S §˜¤Ü`ä•°I9SKˆNLg »˜’b wÌ•NÈÜM#n6Ém'Hµ·#³å˜µ*-»¹Œ ÇdÉÔ�ÝÁóAv1WPUÎ8¿ µþ­q\â“õ–˜8•×�Þè }HˆÞÅn,©Ì9]MÀ;TâzO¬:òb㺩ùµ >óÈ2,7;;rXìÌòKàÒcÌÚ°šqÌ€:‚èc¦œÁ©Ü‘æ*îjo¶f£€êlÈêaƒˆš"Ò:Ü‘ñ6²ZÑ ì�e"6Ôƒ¨™òÙ,WFd!^fK²Eä„�’t–JD‰#âD�Æޤ{¦7“!¸Uh@Ñ`fûÌ`2^ ›rÛ›ÔÒ7Ý$CS$ŒŸ|4É&ja›P͉’@MÁb™´2ïbÅ#_¼ú7Ô9·'©Ý*ãU®Õ‡“©óÿ¦h«+Ôý.‹Îª³*µsö,'Ñ^¢¥,êôæÔr€q9¼¸Êxš‡f¸$£4ä/^BgR…ÙròuïOaîß2Êʫɠ݊;]GΣÜJà6$xPÉu7bÏ(¹ZEÏLÉ.Ž»ùˆ÷šõ¨2z-& (oùƒh}DªÇ±è´7´±Êį®a {-ˆ{ª¡ú~Ó£*›ƒPìœRŠ’åЖ7W~¨Ãã�Ø}ÈÔaÓ@ñÈ<Ètœ°ÚÊòq†ë:a­ßs¼åÿÇK<”½¦žRÆšà7Ò-ezÞÆãô¯b2ï€u©[ÓnXû�K�fA_¯3¹ö`º<7ñ‡¥~SÕ‰œ¿öóiVñ­2ü§ý�þsÏ‘{œ(“=Ëñ§þsÓue ÛáÜý{ƒýûg›ú#Ò×õî­UÎ¥p©°ýDsÚ?ýâ!¦z_ªºFo¢º_EÄ 0²¥vo ª‡dÿhçD蘽 §&&(:»·—o©�P †¾± º•«&LˆIaŠt ûÄ‚ìEòó2q�„'|ž$gȱAÍ•Ž.râ‹ ½Ï÷›Èþ\y0?-²“µé"Ð7ÁšÊ´¿I��äÃÈ�ÄÓ.'�°{Ðß¹šS¿2>@ç‰ £{™Ô` -öÔmlGÖ)XmëëEÐæK¥É×Ò2>Q½î)Xù|�CZÿÁ+½4 ‚Ïë}|ßø�˜Ðõ+ŠP�´sý÷= 1ݰk*9#sÍ3:Âõíhë±ûÄö jøéŒu°¾ ˜š(�eNˆÔÚ§2ï©ôî×øˆ8•AHmM¯FmS1S¹¥†-×"�ïMZÆ\tœrl.G.ÙEƒ�T Ëz�9:~3�€uõ7Z³¤º=j ˜ý'�ú«Õ¿â™�Z?ðÇ�{ÌÞEÉÇ鲃ãȤë}BÞ£–ÌwØS21:’}§AÓºmÝMÇÂCÛþ©Ðÿ„ôî�WÄÈ*öý&|[vÅ_‡#Òý>ù¯üpÕ©nTõL1ƒÔ-Ç ÜðgO�Õo¶Òh´59Ìš.¾ÖµÎÙ�$Ì⦲7z5ipªØŠ˜QÌ‹QbžD",Ù™ìÜÑ]C4V$€뙲7$W™ž%„�ˆb7ÉW’-Ä3[�à*$DÉÌ‹‰ÄhŸê%Æ[¢G bdkÕÇ�}Dw;T ªy©¹`=¥v¶%�LÉ â‹¹©ø;ö—%[%oB$¡ðm5\ �™ý=ð®'–¥¹FŠr ó=¹q£*¬MXãcÏ´c¥åÿA>x?¼ž~?¼°+s§@ö…ñ‡Ã½Þ=š§ã#Žl®¦{iž‡S(Ÿûè ê?–êÞ�“§øõ•jϺêsŸ‡«Óíéûùð²ì­¸ÖùØ2ÿ©á%v·U6v +.ã^B�Î;ð—"Ρ×úîc«iW+½è’Óž2Ëì’’þ~8Âq{úz6qð¿éEÊ�qæ!ƒå?ú‘íÓN¨é>Èöêkm#úÌì$è{Ãh)TI3wüŽ:ØŸG[)]j�ç€ñ `Ú†gäÌI1|ÏÁüÖ[úÁEý—üJ�D"2ª~'ggá�UØT;p~±Šÿ è+úŽÿxž2ÖC‰Õoô›ü²0ð'ggáË'ý«9]—è¾¥Š ¬—ê$Ò IúI•Bš™SFd¡P“VD )[=0 �¿hÔÈ¡:Ç1Ä^$%OˆeBRh�H�jÏF³�D¶;4Þf‚ͳ%Ý5Y°»1šªûA…‹ö¤Ø¬ÇÅkô�tш;8�+a`�Ä*¬‚ ]Éh"ü,NÎLbÓc³*('Xæ^ô<ÆéýG%Y€G»O•÷ÒQ!Ñ�c¿"g;NÆ�z¨¥Øéjåe ¬=Äo¥µo�õØT�8s¾ŒêËÕ:(¨�/Ç·Qì§ûKʱVì¥*ý�½óqÏ6±½•‚Q„ÿ®Ž� YþS iôpg=Ÿ…fAªÁÇ•of¹W_SWU¤÷!ý_YqMøýg§þW(…½Cý é¦Kð屬Ì¢½-[>_—Ž'YÏÓê;ä4Øá/¶�pÃb%—Uï‰[ÖI“ܳŽ\°FSŽþš¹s¥Ð¿_©—ÒýMˆãò¶sÿõ3“üÂt>¡–GÍeý›û*ïÿÈΧ«^ÒS|ëÁÿÓ+ýCbúoi±À>çdâ/È–hs’ qQÒ-Ê’KkŸ0Š„žD¥¨u›ÙÚU7À&t”©d^áók™¦*Y%N "²`P�©["¨{Œ$–c �Û!G�!ÙÀ�Qýg;ü$™5¨¿-â ¨^ppÚà½ÞÚ•˜=c#"åBªCq8¼¯>‹útañå‘Ytþ;WÀ†Ç¹j æÁÚ£C[�¬í„êÆÔ¢š2’q•2ý,WQ̯ÍAvO*�˜ûZ–×¼rÁA;?x×`Êã˜âÒší¯Â‰·£�ã�cY8*ëÞ¼’äšÏÃcÀƒtM~›º”³"²Ãħë½>¼›ÕˆKKój°yU]“ù»€SÀœ2üE>‹OOßn9£'´è©TzûËLåZå®�‡Q&Ï´c&õe[ såó}4ªÍ!ŠÑÙ`YU$³j'ÖýC]U:Ôÿ6¼Å,»Up}§ÖÇQÉ·áaQ½ž]½§ts9GD´“ØžSëþ¡d±üª¶ÕG¿ï==pñU@í£ÓXmÓºz †í×&Xfeº×lv£O²ZVÚ~µeLGl ýlšY™HŠ]gqá` 5œ0âiR IxÊ&ÅÞ£¹•Ô¨4ª’ðwn¶¾ )æ2+GeWY’)BçÀ“Ãê ”»MÉ–H©(ý-EÕ†ÉèXYk§¥NþÓ–ê߇ô:—Åùí;z­Ü>à B< «t¡ÒÜ›+gA ?œú?¦Ñ™S%ˆþÓȽcèkqKåa/J�yœñòZ“£“†~�iRùÒåa�ÑDå¹òÓ[F\™l€8À "QU•£²e•=@ÑiM4�c‘%°7⸰èLŒœºØï¸L‹“4$9“�xŠ%ÃëKA‰¦…h/åÁö‘l^8ŒTÛÔk´vÌ\Úe$PßQQ+\i§G“WSäS¢x�XgdI ƒ ­Ù£«5t ™aR ]_ÊcõX53“( .áÆ¢ùÄ• bÎ`w1Ü“!-Q% ¦N0"ë¸~—ÓSêã Üy'Ú ø–/ªW’™˜—¹‚µ�çº|J‡K—Gsgá=Ó Ø¹Ìo ¾Ö<êÌ[°òl¢Ô+emÚÀûî^ŠÎÎÉÝ9¸­K�Àr>oÚsŸˆŽê7uÖÎÂé®h±f]h´óüiùÇ ±:3G\¢uœ®‹ž™Të‡CáÇÐÏ]ÂêøÝK¬¼VÚ?‘î­îÞyçHô†FvA«-lÅúC̱êÞ•ë~“¡³z~Q³�ØPxýÁÿy×þL1Ï×'³Lœy#Ôñ²ñzž8ÇÈÒZ?K}b–Ñn £g�ü¬<å½?×nš\êNÇÿR¯ø3¸é>»é9ˆ1òrëín³åþ»›©¥Ñ•2þû?=Rï_ë«/òoñ»BrIö’Ì „Ÿ™®Àqü–'…R~‘<«qúŽ=V++�1C¹•-ogIWUÄê5¦F5Ëa¯†×ÐÃÚåò³¢èJþúœwCÇÇéÉñ w§ãB\cuaØC‘Á*gÎøÿ}šMG—óЇTWÿ¦:¢ª³3ÐT*�“¾?ó#�˜z¥zE 6½U2�ÏÌ ?Þ;eâ¬+›|?ÜM^Ôå&7r« œ0ß± ÃÅÊ¡�DRì¸ ßãÆ¡HøUýâ½6Ö¹¸ðäõÑæ<ÏFRª#¡_…³³$@Q³ NÌ&ÎØÿ)£�ô æb®}&«6ý%v/D§ñbXçG|Ë—aíϱ©œ°cÈîh¥–QÔY ž ëoœ�}oÿÓêG¦ãül»‚)áG» ŸoS·P-]Kð©<}Ø}äçòqáUÿD9nÙž©õuý=Êâi¯Ëóø”8ŸŠ×Õ¥³s:í##×ê'ŸÓ†Í˜j>ÆFÎQm—Éž¥ÿÄ[³øt‘¹ºÎEösçÚrXƦ‰ÐcãÛbm�}çÉ–NÝ膟*ê=Jå$R 3}!º]Bä︊“êbUdщa{ÛæÆVõ?Pß’{)b•û0R�lÑ&uø¹g ®ø¶«�ò�ÂUÕ^ûÔ#3ÍÅ÷?Ìlcû™qÑó-KÇ$ÎL‘§hÝä¥ÖÏ[Å»¾‘±Î£˜úgÞ—Rƒ¦^o mK Šà#;ÚXï= zü2«Ù}ùŠÑyÔC#&¶<˜¶ÆBw£ð`.Àòw=$ÿh“^ƒÂÍ-¬Þ)@»mJÕ|®ˆ�’º,]•È‘¶ù–B°G‰!PúF˜¨¯øjWµ—bnª¯Ð ~ÒÄP5âhV¢ €R@ŒTÍï&¨†Ö5Ä`k»pY8‰•CVê"á�$Ð@gÎÿˆž?ª›+]+ž@œ[c°žßø�Ó‹T/€w<™ëS3›¦5Êc[,ÖÜKCJŸiŠ´”ÁÁ¿„ÈéÅñ2UÀ¬[H1š¯ûÅ s66“XùŽcépËø õ;VªÇšêm±þ~÷ž»ÔlLP+¨û©DîKyš(¡6Sáú{¥töW£ ¯‡˜ÿÐyæhÌ÷–A°Ì§¹Nˆúk�ê<Ú‘k±…ÕŽ4þ¬©ð~Ò'\è-XÓ£­O æÑÛ‘I¢ípá|ÜA”N©Ó¯Âø£N¥;ÀßóÔåIr7÷ŽôÜæÆÈO˜ö{Ï;ÎñÔ’ÉÿÉÕƒ#ÿOӔꄽN¾æÁÌÇÉÈÛFÿ�ï8Χéþ«Ñ¬í϶ŸýDm¨â}‡~.jÛÙÔ與VÆÈjˆG¯.­rŒqÿÄ×Xd�Ä™ÅÅÓ<»ÑÝs¨ac&>oñpl¬³l¨÷þ_iÑâœú›âㆭ.^àWôô€ÊÀƺ©[c^ý¶þƒþ *ž�`:üÅnNýõ9¼—)F¢é“ŽIJä´3�{Uˆ¶�®Ó­ý¥=}^ƼԄ³?€<˜^±ŸWNèõãüïfHøœóÇÚs¾˜Ê¬kD¹C¦ß‰Ã'6œŸÃ_\\’‹;Ρœk騭Ám ­ÿ¾¿„i�xØ|Húˆ…Àư9$¾™IûDðÕÎ1²¶sç‘9š©#E‰Æv·G¡?PJ˜Ö€¡í4LJþ«Ô¨Ó]U0¨�6|4G:âÝR¦^E•)þ~?ñ:|:–ºë6h¿¶ýŒîÃÏqRª1SJ\š ‘“V+ää1TEÛ ×ò™}SѲÛUuu,Kz~mØ·kâTÝ­¯ÑYJŒ'*=¾þ¿Ò±Ðµ½Ouõ¹wþó�ë‰XuƒWJ©²-Þ¾-ƒIü‡“ý§•ØI’ ÀhîhòJŒœõ¤tu,Χ‘ñ³/{_Û¸ð>À{K¾“]·:­jI”ý7¥åe2„©€>äOCè},à*’6æqÿ‹,ÒßFQNNÁ‹uõö¿DôŸNŸäe33§ÌíÑGnÙI?@"YUSñ–ö«øPy�9°úñ5‹³·JK—EKzs+âbÖÕ\¼ùò$jLl"Ž·�Bé“ë,ë¸á‹-ºÕ;{ÊFÍÍTõ4àñÜòâk":sñ„¹@¨êCó \;A<!Ò:]ËÜ2{œêz·Gǵ҂ ¿nç<}?WÆjvTûKàâú0O{_GÂ%‘r;´8æoSy×  f¿OdÐwY,>Ñì\++`?´çõMÍ·Ðç4ÒI4dÙEaÕI]àu*3jí±yÆS%ßtÕ÷äF±2ðK€?†ÇØÏGÇŠ]�ÓEøöé·ö‚²¶ÿ%°6»F؉Ûm•¶»´ge¤…MŽ\—½% }Ä/L†ìOï*Tj[�çÞ§Å«õ0ßïŒo“)I¥GiK� Áñ<üzë Ÿ.?¬~Ÿ^à­jíb€~¦,SI‚‹i´v¿öÅm¨ƒ¹™×ðº�`Õj�ýå›V®6&¤•è½ÜBtý¡Z’§blr9…*Û»ƒ ÕèlA(æ0§cFr^³Á�"ÕÖΧ�]QªçF©Ôúg¬Ò­�nüj|ëÖÔ'WÈUñÝ#"Ð�9ñbmG0ê¼LÓ(TÕÌÈÉø™*Ê¢�'§5~E«eò'v Ø8Ræt�BÎle©ÑÊ$Ñôc8oSž8‹…*yÐMIZ!Œ:ó3p@ÉwqgâC¾ ›sBU 'Ìä*‚Iðì½;è–Ëí¿©—¦£È¬pÇ÷úG=éñm Õm¬>˜­{í#É�·*Ú2Ô~’ßÂûÓ”tî—JcãbU]~ä˜ýÉ÷�‰DjUëäyžyˆåm]1ó:œN¤øà+r‡ÚW`™bW¿æ×Í6Šº$qír©âÔ ÓTü§�É( ë8Œ,,4G´ç¬_Ÿïï;Lê]êby‰Ídã…f:çï-ÊÖšî×pÞ=¼H·o‚ 1Ï™¢5í$ÅwâE›ßÛï "y˜ê@ØAà€³Ó!ìkGW…U‹�VV(.¥tè%-ù9¸yOj­µ‚Äé‡8=K+§Ôÿ)ò§‘»ÔÖ\@²„:úNHà†99Evlò9*bÏ×ð²êu<`>–(ð~¿Q9¾®+À»¾‹þ.;�÷Ìè²³ºUõ³dâ“ÛÿŸê©Ó21Êá1C¯Òw¯ï9s¦H‡«(UÑ‚0®ÀÚã�Ì&Aé½'²r,uµMÀèïè"9?¨údafÉǰ »|ŸÛúÆúÂæazO7¿ó&ÞçåFŽ„Ï"æ´ôtcšŠv¶=Û/ÓÝ?)‰r•޼ÿû¨ÁZú_AÆÌªµwÉ­ÝáuÇ>—råzo'ˆï©¾"¿þ wã/Tô“aÓódQgz¨ûùÜÎiÂ2tÿ’OA}+Ô5Ôrj¤Ú’guŠ[*ÂäÑúyñ<§£áçb樶¦¬·~8ž“�oì(·Ÿ¨Ž ·Åtg5³£É­rz[ã1í°ò�ô3„õ7¦ú_V±/%jË]nÚÓ’>†v4e*®˜w©ˆu—‰�aµ�‡>âw¸K�ñØ £×G9Ñýé|¬õþnïõd|Ãÿóât¯Ñú•cÒ°{‡†Zꢿ¦daä×𻞲¤ê1•> î×2üye·¢òÃIÀ8x¨5N=H>Ê!­Åººûê­,ÿÒ¬þñš¨¥½¿¼8Ã_(gb29L쮡RžüG¥ÔTŸïâRYcØÅ˜’~¦wΗTÿ#0û{Dò0°­,21QIòÕ¯oóâ:B8kC&Yt¹ï ig?Ó™;ð¬5둲ÿ#çùE~!é}&ñz5VèðÃ[™dj ÙQNLVŒó›Ôò®öC¡ü¥{u%³!�Ôl F:Øùt^Õ½ÎO2ÿ‡™b£ÿ˜ñ8ç4˜FM#¿ÄÈüÆ?u �àÊ¼Žµrä -Ç(ÛÖõÁ‰z}íÄÙu”Õ�š?ˆŠX{êkrŽÇVű©=½àì0÷‰u[kþ%uƒ¯¤¾8¦¥Òò¿iEÕiÍ͉gq”2øF¤>NL¤ê>£ÏÀÇB* }wÄ_§úÅ.ÊVÌ%DoÊ3ñŸ ¨ŽË~�(z¿¤oÇî·üJüèL°á— ‘¤ò.W²Ê£§õÊw‹”Èö3�êž•êxÁ�܃é9”ÈËÀ·Až§Þ'AÓýk›Ž_üTûΞû0²‚Ú­©ûlFR>¢a,F‹NÂÏPtž¤š»+ýÄ©êÔàœan1ý&9&£$¿MaÓhC¦õÌÞ“�¯E­¡þ]ñ=[Ó¿‰x×Ö•e7cø;3ÅœìÍ+<¼eFMoGÔ˜}s 5%ªw÷�é>¬ù‹ ®gà‘ðo`>„ËŠýgÕö?�â_0ÙôB•nA8“bI§hæŒÊ<¤êsyØF¾@æw¶À‰M›†'¡âùM:fÝœFõ4ZXf`”î#ÚVw©íÅ©+D³^ðô§uŠ>¦ P“,00r2òR¼zÙÜž¬ô_Mè˜Ý7Ò½>¼zÕSà/Äí÷b6Oõ”Ù8ý¶qÌé: ¹ ÑqªÉ¯dÔ¡Ôûs�…Z‚ý¤âjŸÂ$·g9CšíS¯ñØ]R²y×2¹è ÛQÇÞg{©Öõ¿¨V½¨t;€’l¬”×k¶�ߘ�goið$EìýÎâ ²ÀuL¡YVäÁ"'eïa!ô s¸Öξšš5À±þdÀ,¡,tD TÌ·±rŠ�o¼9îÀ÷Œ@¾ ýýæWÃ6æ;±'ßí4ùK®Õ_jHì�Ÿy€�øÜ–0.ÄéDŠ®¼Æ4Xð°7äÓƒE·ä~š×»÷>ÒÎoÔ]HQ‘N°îÿ¹`ú}ûÿh¥wüEàÎo;&ÌÜër¬?=ŒXý¾Ó¯ôgD·ªÊÉq+<“þsô‡677h|h¤·åoqÁåIÞu}s ºÏ£¯aZ>AíjμèûÈu<³•˜Õa�à!×pðeªž¡‡éo‰ñÜ#6•Aú™Âðwøo µ4rxØ™};%–Íh�§z�'DJ:~ZZ‡}úî?X—HÆ=K"Ú[}ý»Ü,øÎõÚtk$3É ÉZ SŠ•Èôlüz†"²Wò­ÇÀÈÅ;t?¸äNVÏPÛV1¢›N�ƒ¿¤ôß\ÈÈÂ'ø€1½õ4ñ°ÆÒ—ašQrþKš�ÇÈ W`U±îÓ!ý¤.½¨!†ŠûÏBRõEÉìˆÇ“ nÅ[™±`#ƒ¨Í´­ô S�‰\êÈ|M°fŽXòˆ§Lr¬–¬ó-ðój°°ÐÎlZ<0‹h× £í6¢S:ÃP³æÔö»Sâõ;h¬ÛÚž£U«Î�€ÅÎ:o@hÅ2°+È­©º¤º¢yGÐ˺Õ-ß#qL„56Ç´`Q§@ÁPŒdÆ ü$ý~³Ë:ç¢ú¾[¶ë(vÃgî[“•çëôþsÚèqiähË êWBŽ ©Ñ4˜�#éµ ( öŽãdšo?IØ·§°W3æÄí^ížÖ:#é©ËzƒŽ�Öœv&½Ñò»ö‹ˆË5°ÙW}mü¥m*ÔäXìÅ»�ƒƒ˜Ô^ò†[ÝŽ-QjEÂ-®Hšè¤ê½7<|ÚªßfÎuó:—§ìí½NF'³t'MÖ1 Ø,SaÔpDá±ýMn%¯‰ÔâÖ¶G:„•;eûâôOSãwVQ.#Ûƒ¹ÆõKçt·f l§Ù”KvÇé×Ú2:~Q¢ÃΔëûFSÔ·tû/Qêχ™ûa˃ì¯\¸ò8ub¾G3Ö#[3´Ïé=7«Vr0lT°ó¡9\Η•ˆI²¾¸“6£Ø$èDžfM7¼ÐhÓ5<ê5O1-ó¸Õ¡-ŽÇ’Ú.–Pà‰›C³O¢$�È»êÙ¡Xà~hä ÆÀ;“sNâŽ�a"«/0`ç[§]nIJ«g$øwXøi}ƒ¼ü³§ÀÀÄ nª”®§¹áò”K‘Æz{Ð7föÛšß ?ÓîgªôoOôÞ›Z qÐ2�Õ®bT·Ã?,·ÁZà�@ž‡%;.é^@ˆ§V<*x|¬ì~—‚ùº¨Uß&q=×�?Ô]FÜWu¦åb+î:·ßíöSM­V/oÔÁ%¾¢^/H²åøˆèÊ~‡ÄÃÑMd÷º‰¯$gÅ”AXyâlÖýìôìTPÖ^íeè÷ ,u¨XQWñ,mª‚7ì=äÆåGr{n3fJ†ùQVÌ‹,:$è@ ü•iÿrÀ=øæÊéÖ—–ólIò`Ž÷¿hPtÀ�ìØ;Œéu y D;6D™­F¹þRg�i‰Yc¿i, |¨»œª:ÁÏÈü¦9Ý(y#üíÿ£ëùöôìnaüKŠÇü™?Kú8dZ¶2’Š~ka2�½"â¾”~–ô.OZ½lÉ V2òßSö�ß[³¦á×Òp¢ªö°_ò�§ï,ú§WÇ蘣/Å[ÿyƆk]�Ø–'d™4–Š´sÚŠN¾“§êØÇþ˜Âª´ß†:iÏ-¯Kw"ì{λ¢õ!f/më³®ÕpeÌã'&ÐÄœyYAб>[¦áº•aõ”^¬Æ|?ReR öØC¨ûÿ}Îï6ªzu‰oéÿ4O1ðzÇR§!i?gaÙÖ¾†Vn1�]35ŽRèâq:=Ïb3¡b@!Lì0q×”¨ $Ô:{bR �ܼ�{Êü<ë/³çâqøÓƳ.쵃ùrü-œ{Ë‹®˜î,þC ´þÓÙ¯ŒÅ2˧å5jjoÑÖZîûN �,1¬îP #bMGésÈæöBìR¼ëqG«ÛF] ‘£!fµOiÓM“"ŠBXq³ ^C¤�Õ½-«kþz� �à˜é³ÆêF·$GmêUÚša9â ó­Í¥�ûˆP캧.´n–4æ|‰Ìü®<ö´=2�0Õ Èœï©}4z‹~s_˜æBx}æ;EúÑ Ä²¦íþÐ@ysRôÙÙb±Nˆa¢%î ›¤3­ê'©&®O›Ù׆žÈè·t°]_âÓîu¢#HF“¼‚W�iæ^»ôÙéùc!ä:ž³Ó¨Kù £(ú÷CÎê-“MÕ÷U¯‘¦Y¤ã¬¼qLðñÝYIk"Ûo ØÅµâXg`¾U”X4Èut˜R»*ô Œ»±\5N˯¡–ú‚˱Ín$y•v!‹ˆ§Š9+—ÁÆr‡DËos]¦bsæ3Zws4èÈXƒ„¯1ƒOpƒ5öñ*À’Û&/ûÅÝuOjÀ;Û³#Ýη³¹ 1U †ÙÜ:9P 8†U2X�Z™:<˜ZžÃæem©áµhçc±ÇRA¶$[ÄÍ L–5å-�gKî´ Æ©í°7´è0zÅXˆ ž—‡—‹£¥mÎ.j¡žfw]Âé43µŠ;GÖpOÖ™ ¦8ãë8Ž£Ô²sXµÖ³oÛ|OE澉m"ßÖ>¸ÉëlØô±\mëƒú§–2YܬU�Ø ÉÞyâ/½M#ÐÓ;¯Oþ%õŽŒè·Ùùª\üÚýç¢a~"ô~«Û¬�‚íæ»Žˆ?¿‰à%à͇ë-YN™ô×çiȨ=#îàŽß�Ïœqº®fo*Ú�þ‡"Z'­:òë]Jî>âR“!Å~žîÕwµÞŒ‹+ä äxŠ= ïEãÿ»Xÿľ¯ñƒ*ÕÃß·`ÃØ¿ù;ÞÒO‰�€ÿ)ÇñV³^«èè­õø¿ûDñ.Íë �ÎÆÉ:‰åˆ½lô>Ý L5 O/ÈõÿXpU> }ÂnVßêþ»�…Ns(#_"�'Ú‡Àõ|¼Ü>ŸS[“‘]h¾K4®ÂëÔu¶²¬aXãâë_ÐO¹í½‹[c»%ŽÌí= m¦»®«ï¯Ösù'ë|;5ŹTŽÿ¥zN´·¾û€s<±÷Ü´êž §�ÉôУCEÇ�ûE:ŽJ]€ˆ–0ôƒ+*éäŽæþ’||®xÓa’6)i+bÒO†úN¨2¿3ÕÇ58Ù„ââé›®Âæ<…núÊâ;[^е۱ØÓJeån±¿?hT$åN=åFø–ªU€`yˆaX%ɦÊëºz÷mx1åm}àì$8þÆ+_”èï÷ME€myûKFs¾y%QÎÇ;ìHýJA›­Æõ,­§ž@ ÄlÇím¯ôŽÄ3[¸RË!½åMlÕè�uªÅØ yˆh¹ªí�ÃYÛu,¬Jú,8¬;wœ·æ?Ãz«Ô­ò±üçW‹zeQìv'ÕŠÝÕ¯j¼¯æ¥§DËuÒ±”MÓ8?Äž‹ù\á–‹ò¿SÎÝg¾zãu‰f†Ø ‰á„XTŽAÔæÈ©š&&Õ–‹YAÜ´e ”h“Wü2¾Ñ¼t™²ƒÄÚü§ˆÄ(�¹5 ÞîÛ¹1!Š[ÄX¶Ž¡­}˜»yâh�‰ ¿hºù�Uâ&„˜Â®¤PîAñ3`Cáîd7o$ØË ‚ðdí<ÅYãü9«èM—â@� É D˜ñ ~`Dß™€q¹Qu³x1;†�”—žH—Ö!Þõ*2iýM=<M$T[äŘÃÞtbŒy�ñ&&"LÑ2$îhQ„Ìf¦jHÅM¨ºÃ×äI`XÔÛ�)‰T¼FPL$а„"jOR 4w$D–“cª(Û1Ðyé}30ðêǬpƒÏÔû™ÉzWeæµî6”�¯»¼­tAf°Ž…'±ºZܰj�·Ò'Œ�ß1çƒI;Ùö‰ ± ¾{B ñæ0{qèÖþcZ…þ!óæ ÜÛfþ‘ЬžÎÀ�OI«òøèÇÉœÕJÍmj@Ù"uÚ(NßR64RuGÌ´©Ø&nœd¾�Thø‰Ø{¬2×§V `#€üDÁwôËäþ&-êwôVùO÷+ý'—cÞÕì6G°è~¯�MØ9Õd zl¬o€ÀŸöž/êŒèÖUðStÜ TÿQôýÄÆr‹—Ù¤fÒ¤+_Z¸Vk§j[ûOFôÇY¶ìT«%‹Xê>ÿûÏ:èØ{ük“Èž…Òq{lvñ®&NqÅÐNn{g\-A£"ÈTìDÐÙJÿXÚÙÞ ‰×�,r+FMQ5=¼ý%•`Ò¸”ï²;NüÉ¥º=º?¼°EúßÀ߃ Údý¼Q�•°U¥•«&·F|èÁl§™++nÇ »#[€½xæÊ÷í¯#áY£úc«`aµ;*€ŽÓÁ…Eía³ý&ÙNöæëÞà1ªˆ×K/5q1ÃÉ�õ0è°É�ÊN÷ü�ŠÞé{3�ÔvgAÓ¬©€`t`ú�Hø•üJG2¦¡~+rÔ¨²_g_’É~ÖH;ÀýCGäzÖEzÒ÷lO_¢ÛlçgSÌ}yOoR[>»2+CLç;û¦ÁØ‹Vúó 9ÊFØn‚9‡ò8‘dÐ…ÑU`Mš]Eì}y‡´DíÙ—K@�¶`ÉæLƒTƒâj„aë>Ð #tW²7u4Š5­CS3;É.fE@3wë3i5w "�<_‡cD(äLìÜ›$ý¦ÔÑŒ´Á¿‚"wc«VDfÆÑ�ò³§ œM“´ryt2XAˆ½s£êT�Õ©MbÏWKDØ‹.¤5eƒ×3¡2�ÍêS]±ØšD^cT/2dôtˆâ§‚¦¿´zºøœy2Q•í�uŽ5|EìMœrY1‘ßúcòý‚WMfÜñõñýµ/�ûĺE9}3³@|05ôÐÖ¥™¬)ÌôWE>Æqœ ùŒ,^¤Tk@hGbµwšEæ!ˆöA íþse¾#ïëæ`å´}¥Q#¸…2‡zÑ÷�uLŸò)ç\ʺ˜®J°ÔžE¦ÛXÄÆž€‚IÜ¿é ÝIR|F•1äKŽ”¶ Ž C@ýDæå_çu××|æy/¨™:‰Á¤|­°ñ½Äô�_gþ[Š™l²ÂÜ}ÿ’'Ÿb㛲C0îcöž�ë/?Ä:ØÇJÁbAö™ÖácP}„W(PŸyfç° �ìŸ3—“{`2Û-!)RXð$±hlÛñ ¹äìñ ‹[!$ûË p-µŠöüßxEÊí'} W‘]„«© >�ß y�hÆ/Dº›žÛ �ìË Š¸�k(3ч‘5©Oé΀TNA]o�¬åº¿X¿û^—ƒgDq9düJÎV!ðèuß¶Áÿy¦&9n—E¥g®¾BhÈ›G ÁYåÕþ&):·§�?ôÙÿ´jŸÄlFaÝ�z�±mÉ™ßdÒ �©þÒ4ÜÈA÷œŠzû§ZÀ0¹GÝGüÂ7­:`SÚö7CœC‹;dÌM­ÆÃ¤òg›ezáÙ{qqƒåœìÿIÕzsªþs1m·¼žiºCª;\:ÕgEϼŽb{ˆ•9 Ì=ùŠÊ9Œc7uZ1>¡†-¨²¯1Œk·ƒRH1ˆç)o„¥XhÏ3õ½‚ìà÷ž§Õ«Zë{Ç:õߘêNw°8Šo@‘F+ Iª�ÄâLW¡9›.ˆ ×L76£™²&mŒ¦ÄNú¥‹þÑ[Fá •ý¼Í‡+DéR ‚š7_ÊÑuC±UãcÄm€Ê7Ü'~Ž U€H-#s?£±Ï‹¯y’¬ä�Ì–’&Γ'Žb¨üÃd¶Ö$­£Æbu¼¸üàýç�eúªæÁì±Ë/Px2§¨=×—fóí"Y«ýV‰rã¤zWVõE,ƪÔðZsVú›%i·lù ñ9ÌÞ¢6tN‡Q5ÊZWóÙþóJsz¶ÈõüælC_q9çöœƒ©Ó3 åÞö‘ Oè"nœnzÞ>5ŽMhE¤Ñˆ“tæ@y� Ílx;�#Åñ¤½Èhh`?3»ôJµ­I>óÏ>'Í.½9Ôÿú’ZN��)S=‡'T?�@6Oîˆgul|Ìd¶«FõÏ2®Þ©]IË�þóxЙѯS5¶ÅÍøˆÖyáë”‘Éæ2¾¬¦ŒbüÀG'$ìºõ‡XLL2¡‡s ä¶Xmµœù'rǬõ‹z¥ÝÎ~QàJžîg<åf”|Ioˆ5i…¦T¦nD0¦!ñI…¦Â¤Ò8ø–•At·ø8Õþ�#ΔØ� âyâSôL•Í踹 Ï}ccï¥K[Û¹ØOü|ƈúûÄž‘fA ­2ÿ*“Úª§æ>Äq*뤣ڡWŽ @ÐG¯¶º“°oZ"YãÖn£G|h�¤T1ê é“{…©�NûCl�´CË­ eíeØ•`eßS(2qÝæT%e›~Ð%ŒâTŽ4G2‹ÕÙÍM4`©æÍ»€}�Ð×ÐN›*îbdýó¿P^Ï™fvQ‚t¡½”xœ¾Lš�/¥- t÷@ªç\îXæf×…�e–6”.ξ‚sý'ó¹_”°ÕÛ˺èwyÔ'¬pò-ôãäã?}(ËñF¼)<}O68¤¤“úhâÒ³Ï:·R~¥Ÿeí° Ò� ˆlŽD‘^f™è¤’¤s=°É�‘Qµ�Ø�‰i…×-¢«7_s‘¥×´£U.òß ²ÜÝ  �Þg’jš*)¾†ñoȶ‡{HZû»Žà²º‹d�Xâµð"¹7µƒ´pƒÚ,¯£+¿£d¨uë&Ú"(¶@û›jÀˆ¼Æ; �^„9‰¾ó0©ðæ {Xl#HZ�ù‡¦Í³Ub~¥#÷T’QèEÍ9Vªö­�¯¦ãKk¿êbe~2³ÒL°Z™Ê¤‹Ó³qÒ¼j/jñ�¡2$É·i,®é§³^óMLj»±&4¬–Æëmé؋R49� I’"Wq[Ö=Û¨ S{™®À«qÌXÕ•óØféŠ�ïS_É D 4Ï2¶æ ¦Ð�ÇBcJ»&Ðü³$°:šFë ºûXË_š±ίæž%S£–HF­ìK*[B!RóC­Kɱ!ÑÈš+4‡pžÓ›¢¬]Ö*ËÌ}ÇvM™¤d0 °`rΓqÔ¯˜ÌRõ’ņ„ãúwMªŠU|N›§`�ÔÀ9;œ9<©ÝD�2Á/ÈÎ?÷ Xÿ"�(œ¯¬ýS^.#áb?ñ\h�HŒúŸÔ•ôüC�ŒàÞx¾Ãë<Åë¿6òÏ¿˜ì“ï psw!Ý �ùèâgYéî“�ˆë›”Z§h§À?Xž%8ƒ¹¿T&GS uàMç‘u7?ì·ÔElß|êze}R�>'wóž#•žöÙ¥eGæË7˜ÕWlH”‡C½Çëª"�³«Ä" lNSÖ] ¾©ÒíR ¶¸:�RÁåV,¥�ÒÁ:gʸ텗e.9F"j»>YÑþ"`Œ/PXÀh?3�®ín`ãL¹J;Œ0¬k˜µ6¨È;Q"÷T MÓDêY:î+bèó%€¨Y b‘¹ñŒAÓ˜®:àëÎ¥X4+ðæF;&C‘%Åá]/ipÉ)m¯¶ÍûK GØxy—%g"v‚? bì6cw/ƒ>LÎ,‡¦ecQ…1`u ­ "“S1ÇЇ‘2zeØ«y�-Ú¦ט+Ðönkʇg9Ö/ùˆÜ sÜe§WR,'|JÐ7=ü (#pzâ †£}£Q{FŒèL“5ï0ùšÜ±’@I@dÃMî@Ijor$M€w©{Òº-–:Y}d!äï"RQVÀS¥t·Ì´3‚+Þw=;°… Ú�b/^M0 Œ'”ú«Ò÷aåÙ‘ˆ…éc²´»é¾¡²š�V±×±ó¨ÏøÚäƒRX�±Ï>!/„º:c(üg•6ÃhûLSÌéú¶fu¸Ù8J—)ýIîg7ZîÎÊŸH³ÄÊ$�ûKZíîsXìUåµ7k[‘7DD¶0V  ó2«AMï™§mó1l¡VR XëˆÁa¨½¤n+Mâ¼Â7ˆ»“¹h ÔÈ5?y’h‹:lŠÈ>&b¶›RÛ/x•_ª³í<[Õ3•*cî7\AŽŒui£¼v¹‘�n…&Hã àATwGË)ö+7[ó ±^ 8n$Ia<˜<•ÝFIO2W'uFJÔ‘¤YÅu3üBÎåxYuÕp˜¿z~Ò®ª XìlÏ£Ã$ñ£¥&.N lætCÓWÙ¦WLÛúO"ÃÛQîo •î‚úmèÈ×G&ÞdgPÞŒÎæ§èD¯ÎôçPÀO‰e%«ÿRÍ#šÒdK â¶Š�$&kS™¡™1 Z5„&Kïpãë:,,$ ”w}dNj"n�t¾Ž»_çØN‘o®¤ õâ ¨âBËÂŽLáÈÜÞÌÜ˜í¹­£óh}%.nqbT¬ÂÄö™WuÚä™PÇø lÞM£|˜§Ä$ìÈ;—bLŽçdaHÑh(m™cE}µúÊÊÏñåÚ/ðÇÓS!ÒHŒŽ�µ‹"ŽüÐÖè ÀVŸТdºÙ‡ÿ¥Ž:ü@ÓÜp¦§â íN»§t´»·D(÷ž^|û¨�•³—NŸ`?2ñ-ð½9‘��‡ ~³®ÿ ÂøõV>b|Ë<œQIJÐv¨úLÿ¹&ÙjqVúrücþ¢‘(­Åø9%ÀímòÄO¼‰¿Ž53¦Ã¢lÐÓMl†û¥Q$·µƒp5%©¦ñîdÑÌŽ‚�V¾ À™[n6ωnëØ äO�³Œ¥lbÄ­Ë "u‡_›Óƒ‚@–´ìMYÍWn�1´´0ÔNÔܺ3!æjÒ’´Ej’+¡¦ð}ãAÕ„ÆI¦4bîO{3@oÄßi�Í Ä²)pÝÈ�·«êîj‚¾½£lûIº÷WÀ�X²4»=,SuO¡<‡­Mdøñ:_M)³8œ×Â(û÷—8Htô63b–�Cظèô~©‹ÓmÀ=ý©`8|»qÿ.ôXT‘Çï9~¯êÌœËÊVÄ(ûÄü»¾bI?Y¢ƒ»è˜¸Æ5&)Õz>;ä³R;v}¥Ý2ÊßH{—s¤¹rIßÖG—e¼Ÿ¬í†Z‰Á›�èWÓXØäËa–‚Ä%Xo�Úñ1–NLåjMˆ]r •9LÄó;?ú`]^Ø™ÌõŽŠøLJ�ˆ¡%tÊõJŠ_�ÞÄEnbÍö…+ØOÀ°ævÁ$RDfMêl ¨¡;­Q/€Õ`}¥ÇMܲîÀ >Ó�É{HÇ7BW��Báv«‚D]ÎÚ3Xì¬rfRÿZ2£¡Â·¸‰ÔtÛœ�3“Ã^Ö^93¯éH;ŒñóÅ9´Î�§â³d#¹:–÷×Ý’‹¾>ñN™`dù½¦ò2—ó#n¹›â‚Q¥ôÙtg¨±“¦Tò£“<£;,ß�I3¨õ?¨™þ&56÷Vxœ3ÛÉ�\"�¢Òâ†ç˜U° _ñ¾òKaß™t!Ö°/‰©ÛÁXÓ)Di þg´y€³!›Þ,_FG¾%މm�¥Ä1ê2È nS«Ã¥š2g�2‰/î_2&öC°b×pã.v»œœx°½—]7©ºX»ißt¬ÕȬsÌòZnìaÌêzU5Ú£shMÅšÂO£Ð.Æ;‡™¼`G Œåz‡>ÓI��êâ�£T]Òáu®Ý‰AVGs,«¸"w1›&UÛ�)¨±:ž?øƒê1’ç§ãßS§õ_ªë­¾r5þ#Œ­ÐèŽOLKWÇ2Ÿ#¡oz¥ø€M5µ‘í:b£{OO»Ž�ÔWómW ;,ñSƒâqýJ�Üu4¥tÄÒÇÎWc«z‘ærµ³Vþe�Y€7#&ðqÖËÑÚãR}€ D1œ�sM::VP×ä�ɪëªËuŽŒ2¢!Ùί[¦uãvŽÜ¨³¹ÔË< … ¨ÿ\È£à�5¹Ê&K|M=YG”v6“Ó:Û²¨ï‰Tsk6ü²¶Ë™ÓdÅ>!WÞæxñ¤‚8ã³µÄ b�–˜Õ¥g|N/©µZ–Ôõ}¯&c/å“’QoGE‘Ô~ hNs:ÿÎ1 �ù¿y‰ü]2ÝÙpɶUg`�²¢SÙKƒúLëmždŽ- ä μ~UiœÙ§‡*ô˜Uǰÿ�ίò˜ãØI hÚ_ù‹ðÃØs˜¸–üQò™mv3ºt �ìI›ÒsåÌæí9r)ÇOrѱ€IAì#g!�5ù°$9É‘Lr¤W~Â\bg­@g2sL‡æÛs…7l;¿ú…1ë 6ÏÚQõ?QÛ’t§µGÒP|[\p ‹Ø·ò´RZ4Vº vIrI1Rä˜6,ÌšîšÐÒv¸Gãsæ˜êgrÒ4H}nß¼‘mˆšÂ�ñ3’ 4Ò2mv ˆ’$“wÌ"4fÐþ#žá,YþI_‰Y'qëjN<•È@{ù–Ý,‘j´ª¦¦±þÓ ÀÆ(Ô¨ãäÍctø¹Œµ�™a�s<¥ÇO–+•V:ùÐÇ(èZ.ë´T;˜Ê¾±êE¢¢¨Üý¥Rõ+<Îs#!îbÌÄÍn‹KëÔómÌ´»±;”ÖûÇ.o1[Ì �…ÚÙ‹€7°lÁvèËFfC!ârje†kÞHsÌ[¿P”¶Ì(mŒ ;‡]EÃk\Â+ƒï!¢D^ã'°b‘Ì‘ƒø+ô™ ÈXQÝ fˆ)³®¾vgÌ«‘ÃDë£ÜÖ°/o`•Ùyáó:qCC»,(<ĨyÓJ ¾¨ÌH ÄDõy3¡boaeæNk¶ÀiQ•q;Ù‹œðÞñLœ°Aæ\p»¶FÛ€&A2Ïv·+mÈÛIÐK¸�¾¤–ÊJŽ·þà6e—Å”X-Ú¢X|C<¼°\�=�‹»y‡[Å•žy•ªÛf˜°ª‘ÙŽZ(}@ḁ̊ƳoÌ{­ßñlÔª«†ó=¨¯à×–ö[±þU‰&M,îP ŸÂãs%¢Ü­R!^÷W`"ª4cƒ·áH™†ÕšüÇÞgæÖVÞYXëÄ‚ØÇÞh°Z³ A§E¸ÈÞoóz÷•�ÛSEÌ?Æ'ÖYœÁõ�9£ë+ŽüÈwÿÆAë-?8>°Ÿ•îÜ©SÏ2Æ�š½HɉEZ&P¤½Ø|Ë|n�Öâ5­ïâWâRIòLíÿÃs©Í9~YÉŒ#Ù¹*±ò'MGI:�ËꘋŒû¬ÝN~rü5�‰I¯æ˜ò`QaÖ„ ¯-«$¯ª2žL�ètYÛéÚ.çBr]s¦ ¾_ÚvXU,`§9ë�O�X99"ávsö3 ·žfÃàÎ÷�£J Rkf½àœš¨ó'×c¡…°0ª�¢ÃÌ*?l‰bˆËñ ^#ïÄÝ�­ËlfFsË’Ó%ÁÅÆ!G£‹Ýæ�¬™ YÑ™G)[Æ3�Š•è�G–ä¬y�e“þi2[·ƒ;cèÕ"ê¯™M•Öm¸��+oµ›{&+ÞA›"“,E½Çdɳñ®ÍÃãQf¬;;wcÄZÕ&Rh‰ ³ëÈX²‰+6$Âîa”0M¹µnÕÜÆ%†µ&A…»÷„K48‰ƒçPõ)1:"Æ~.äëm´¬Â„ÐÔÊL¤x™ 7©’w‰Ú9’k@µó�1+º˜P~iâAoGîvhE's–Íê-k¾$z‡SkIñ)¬¿fwãÃ{w»~LR˹óöïÌgdqÐ(„7‘ïe¬ÛækDÍšæ©$Z ±–•�D 4óâXÕ_jîFYü¤?Cö�K7+k1ºšyó‰1,¸‚¼3©Ô•\‰+GÉÚ<™Œ?Øëƒ9ŒÌW²ÃÛμÅ*ųâöêuƒQ“¦–\½‘Äõã-lÖ.ÞÊ«0îM§ˆæ"µ‹ØÃ™Ó®=OPØS‹]O°™ÉÚ)M]ß“mÈ\†´ó-ò,©cRƒ7,¹!f1R“:#6+cwn GÚN¤fò!¾úNø*Ta’›Ð2× k•ft™¨SY‘ì"4#˜–hê)Û%[mÈÉQ {GC‚@µ7õ�æ;�‚‡_.§žb\)÷�ŸIÌ[ñÂÈž>[Lä’¢Ð>¼ S©µB�O0¬Ýƒ™U˜ëqífМîV [(¯(,%DX±;"k©åUVGã�y1UÍã‘;#†i]ð’ÇøªýÀ‘ÖK[�¶äˆº�oq7›˜–ã•÷3l1šžÑ¬SúPê`â¤�YèŽ�†…W€@ê*Ú°„Å‘¡ë;2Z »Ü´éä—r´hBQ’h´iÏ›8º¢wXxêPnî—U ñÌC¤õ*í­A"[5ÚbyÏË1W‰’jÃS"Væ“ï+ïË'Þ&÷“ÎZa ) &ì´±óI2D� � ‘K@õ3³p£ô“ê>A`–¹?‡ ÛhHrb³uVe†’³NÖe.Äef7[D”�[s3š)Ô�L~ýJÌcâ]b·‰ËU3ªnœÌ8‰Ûˆøç¸¦Äé¨u#DI]Uv®ˆÐ[@Û³‘~ •AM›^BÖæ_äôJnK̨¿ÓL„šÉ­ÖÁKg;�ìÌWº-ðGvÉ–}+"†$�ÊöîBA¶5ÑÑìmUh ½%³ï& Л4D†¡ÆŒÓWôŠÀ¦ˆ’a©Ð�vîh¤˜]»……ųá¾�ƒ:Ž–Èß2¾šrŸpµ[v;m‰ÉŸÆöm39b¶zdŽÍ1âs½[«ÒŠÉQÝ’¢Þ«”éÛß¡+‰,vO3<r`¢IœØåØò|ÌG‰“¾‹°›š;3@Éoˆ‘íƒu…&@˜âkp„nh,«$ÄhÊ6¢áL'" iŒ|^ ÚØÄA³É¡¶Xbu1lXëé:¬.¼¶T7?yÀ|Nc4XAàêsçña“²3¶Èê ܃%GSeߘ¦æ>XË ›|îa@kËÉl†äñ+&š>gER£cKÄ=cbÞQ!›öš-0xæ#L8‹Z8Œ’"ö�2’‹Ždë^f˜s$§BY!ûx‹\fØ ,ÜÙªkÛî?]`�ÄSŽe�:ЄŒèÃ^„Rñ©bFÄVúÁJ_ñ»x™!jiø™.�F`™2dqúI§‰“$±_3gÌÉ’CÞcL™|'\8™2D†Dy‡¯ÌÉ’eÐ8ÞeÎ?�2däîucè²§Ä`{L™;bPZüÌ»ô™“&Ë¢YÏu_Ó9 ÿû†dȱ±¢èI|Ã/™“'XÐTò!ÄÉ“)vRþ ¼É’¢&M}¡G‰“#$&ÌÉ’Y@Z ø™2Z ÔÉ“#ƒÌ ñ2d– ‰�>&L€ˆÍÌ™‰¬—´É�6{À4É‘¡°^ñŠ|‰“ ÉE…>D°¦dÉ›ìÒ# %í2d†Y¡æM}æL’HY¹“#2L™Л~©™2P™dÉ‘¡2t~©iW‰“$ÌŸ¡×ôÀ]âdÉ( ÛTÉ“&ÈGÿÙpyx-project-pyx-21f71ce/examples/bitmap/jpeg.py000066400000000000000000000003011526513311100216070ustar00rootroot00000000000000from pyx import * i = bitmap.jpegimage("jpeg.jpg") c = canvas.canvas() c.insert(bitmap.bitmap(0, 0, i, compressmode=None)) c.writeEPSfile("jpeg") c.writePDFfile("jpeg") c.writeSVGfile("jpeg") pyx-project-pyx-21f71ce/examples/bitmap/jpeg.txt000066400000000000000000000045301526513311100220060ustar00rootroot00000000000000Insert JPEG images without and with recompression With the `bitmap.jpegimage` class, PyX allows you to directly insert a JPEG image into a canvas. It extracts the compressed JPEG data and makes the data available to a PyX bitmap without recompression (i.e. without loss of quality). ... ! Note that you need to set `compressmode` to `None` when creating the bitmap instance, since the data provided by the image instance `i` is already compressed. If you forget to do so, PyX will fail and report about this mistake. (The original source of the problem is that PyX tries to compress all images using the gzip method by default and you need to turn off this feature to prevent the data from being double compressed.) Since we have some image data in this example, let us also discuss how to use the [Python Imaging Libary PIL http://www.pythonware.com/products/pil/] to load the data and write it to the file. The straightforward solution would be to replace the creation of the `bitmap.jpegimage` instance by: import Image i = Image.open("jpeg.jpg") While this works perfectly, it will result in a totally uncompressed image. The size of the EPS file will for example become almost 1.1MB. In a next step, you may turn on the default gzip-based compression by omitting the 'compressmode=None' (or by setting `compressmode="Flate"` explicitely). This will reduce the file size down to about 727KB (EPS) which is still much larger than the version in the above example which used the JPEG compression. Note that this does not mean that the gzip based compression method is bad in general - it is just bad compared to the JPEG method for certain kind of image data like photos. Finally, since the image instance is a PIL instance, we can also use `compressmode="DCT"`, which turns on the lossy JPEG compression method. This will restore the file size to similar values as we got previously by using the `bitmap.jpegimage` instance. The file size and quality of the loosy compression can be adjusted by the `dctquality`, `dctoptimize`, and `dctprogression` parameters of the `bitmap` constructor. Nevertheless, it is important to note that you will always get some additional artifacts due to the recompression by the lossy JPEG compression method. It is also important to note that the original version shown in this example (using `bitmap.jpegimage`) does not use the PIL at all. pyx-project-pyx-21f71ce/examples/bitmap/minimal.py000066400000000000000000000007171526513311100223230ustar00rootroot00000000000000from pyx import * image_bw = bitmap.image(2, 2, "L", b"\0\377\377\0") image_rgb = bitmap.image(3, 2, "RGB", b"\77\77\77\177\177\177\277\277\277" b"\377\0\0\0\377\0\0\0\377") bitmap_bw = bitmap.bitmap(0, 1, image_bw, height=0.8) bitmap_rgb = bitmap.bitmap(0, 0, image_rgb, height=0.8) c = canvas.canvas() c.insert(bitmap_bw) c.insert(bitmap_rgb) c.writeEPSfile("minimal") c.writePDFfile("minimal") c.writeSVGfile("minimal") pyx-project-pyx-21f71ce/examples/bitmap/minimal.txt000066400000000000000000000015411526513311100225060ustar00rootroot00000000000000Store bitmap data using PyX While the main purpose of PyX is to create vector graphics, it is also possible to store bitmap data in the PyX output. In this example, we show how to create a simple data structure containing the bitmap data ... and how such data can then be transformed into an object which can be inserted into a PyX canvas. The first step of providing the bitmap data is creating an `image` instance. You need to specify the size of your data (in pixels) followed by strings describing the type of the bitmap and the bitmap data itself. ! The bitmap functionality currently uses a fixed color depth of 8 bits per color. The pixels are listed row by row, one after the other starting at the upper left corner of the image. Once the image data has been prepared, a `bitmap` instance can be created and inserted into a PyX canvas for later output. pyx-project-pyx-21f71ce/examples/bitmap/pil.py000066400000000000000000000004571526513311100214620ustar00rootroot00000000000000from pyx import * from PIL import Image im = Image.new("RGB", (3, 1)) im.putpixel((0, 0), (255, 0, 0)) im.putpixel((1, 0), (0, 255, 0)) im.putpixel((2, 0), (0, 0, 255)) c = canvas.canvas() c.insert(bitmap.bitmap(0, 0, im, height=0.8)) c.writeEPSfile("pil") c.writePDFfile("pil") c.writeSVGfile("pil") pyx-project-pyx-21f71ce/examples/bitmap/pil.txt000066400000000000000000000007701526513311100216470ustar00rootroot00000000000000Using image instances from the PIL You can use image instances from the [Python Image Library http://www.pythonware.com/products/pil] to create bitmaps. You then have an easy access to all the bitmap formats available in PIL, you may also use PIL features to create/load/modify bitmaps etc. ... In order to create an image pixel by pixel, the PIL is not necessary (by the way, it is slow to use putpixel for that). !! Using PIL image instances you can also pass indexed images to PyX's `bitmap` class. pyx-project-pyx-21f71ce/examples/drawing/000077500000000000000000000000001526513311100204755ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/drawing/INDEX000066400000000000000000000000561526513311100212700ustar00rootroot00000000000000path pathitem metapost style strokefill arrow pyx-project-pyx-21f71ce/examples/drawing/README000066400000000000000000000002711526513311100213550ustar00rootroot00000000000000Basic drawing In this first section we demonstrate basic drawing features of PyX. The goal is to present some of the basic concepts of the PyX package like canvases, paths and styles. pyx-project-pyx-21f71ce/examples/drawing/arrow.py000066400000000000000000000005631526513311100222050ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.stroke(path.curve(0, 0, 0, 4, 2, 4, 3, 3), [style.linewidth.THICK, style.linestyle.dashed, color.rgb.blue, deco.earrow([deco.stroked([color.rgb.red, style.linejoin.round]), deco.filled([color.rgb.green])], size=1)]) c.writeEPSfile("arrow") c.writePDFfile("arrow") c.writeSVGfile("arrow") pyx-project-pyx-21f71ce/examples/drawing/arrow.txt000066400000000000000000000056061526513311100223770ustar00rootroot00000000000000Adding an arrow when stroking a path The example shows how to use an arrow decorator instance to add an arrow to a path when it is stroked. Instead of using a default arrow instance, we create a highly customized arrow head. ... Apart from setting arrow specific features like the arrow size, a list of styles and decorators can be passed to the arrow. In this example, the arrow is stroked in red with round corners. In addition, the arrow is filled in green. ! Note that style properties are inherited from the outer towards the inner decorators. In this example, the linewidth is also used when stroking the arrow head. We could for example also skip the color.rgb.green value in the `deco.filled` decorator and the arrow would be filled in blue. ! To continue removing the deco.filled features, it is equivalent to write `deco.filled([])`, `deco.filled()` and `deco.filled`. This is due to the fact that `deco.filled` already is an instance, which can be ''modified by call''. An empty list does not really modify it. But you could even skip `deco.filled` completely and the arrow would still be filled with blue color. The reason is that the arrow is implemented in a way that it always ''merges'' the `filled` decorator. This step in the evaluation of the attributes is transparent to other settings: if we would replace the `deco.filled([color.rgb.green])` by `color.rgb.green`, we would still get a filled green arrow. You could then remove the `color.rgb.red` in `deco.stroked` inside of the arrow instance and the line would become green as well. Note that the order of the attributes is not important for this style delegation feature. ! Since we have learned that the arrow decorators always fill the arrow head by default, the question is now whether and how such a feature can be removed. This is done by ''clear'' instances available as a `clear` class attribute. Hence in case of `deco.filled`, it is available as `deco.filled.clear`. When you add this attribute to the earrow call, the arrowhead will not be filled anymore and you will notice that the blue line is not stroked inside the arrowhead. ! You might also have noticed, that the dashed linestyle is not used when stroking the arrowhead. This is similar to the default `filled` feature of the arrowhead: The arrowhead merges a `style.linestyle.normal` to ensure a solid line. Instead of manually setting `style.linestyle.dashed` in the arrowhead, you could use `style.linestyle.clear` to restore the linestyle setting of the path. !! The arrow head is a so-called ornament. Beside attaching stroke and fill styles during the process of converting a path into a decorated path, any number of ornaments can be added to the decorated path. When adding ornaments, parts of the path can also be marked as not-to-be-stroked. While this is taken into account in a final stroke operation, different decorators do not see this information such that decorators always commute. pyx-project-pyx-21f71ce/examples/drawing/metapost.py000066400000000000000000000015751526513311100227130ustar00rootroot00000000000000from pyx import * from pyx.metapost.path import beginknot, endknot, smoothknot, tensioncurve p1, p2, p3, p4, p5 = (0, 0), (2, 1.33), (1.3, 3), (0.33, 2.33), (1, 1.67) openpath = metapost.path.path([ beginknot(*p1), tensioncurve(), smoothknot(*p2), tensioncurve(), smoothknot(*p3), tensioncurve(), smoothknot(*p4), tensioncurve(), endknot(*p5)]) closedpath = metapost.path.path([ smoothknot(*p1), tensioncurve(), smoothknot(*p2), tensioncurve(), smoothknot(*p3), tensioncurve(), smoothknot(*p4), tensioncurve(), smoothknot(*p5), tensioncurve()]) c = canvas.canvas() for p in [p1, p2, p3, p4, p5]: c.fill(path.circle(*p, 0.05), [color.rgb.red]) c.fill(path.circle(*p, 0.05), [color.rgb.red, trafo.translate(2, 0)]) c.stroke(openpath) c.stroke(closedpath, [trafo.translate(2, 0)]) c.writeEPSfile("metapost") c.writePDFfile("metapost") c.writeSVGfile("metapost") pyx-project-pyx-21f71ce/examples/drawing/metapost.txt000066400000000000000000000020501526513311100230670ustar00rootroot00000000000000Creating paths with MetaPost-like parameters Some simple paths are created by prescribing five points on the path. The curves between them are automatically chosen such that the result looks smooth. ... Instead of constructing paths from their path elements, where all control points must be given explicitly, we here specify only five points which must lie on the path. The remaining control points are then internally determined by the constraint that the curve should look smooth. In the first curve, the geometrical constraints are the following. The three interior points have a continuous tangent and a continuous curvature. The two end points demand a curvature not too different from that at their neighbor (second/fourth point). For the closed curve, all points are of the continuous type. ! The algorithm for calculating the curves comes from MetaPost. In the syntax of MetaPost, the above example corresponds to the commands draw((0,0)..(2,1.33)..(1.3,3)..(0.33,2.33)..(1,1.67)); draw((0,0)..(2,1.33)..(1.3,3)..(0.33,2.33)..(1,1.67)..cycle); pyx-project-pyx-21f71ce/examples/drawing/path.py000066400000000000000000000003171526513311100220040ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.stroke(path.line(0, 0, 3, 0)) c.stroke(path.rect(0, 1, 1, 1)) c.fill(path.circle(2.5, 1.5, 0.5)) c.writeEPSfile("path") c.writePDFfile("path") c.writeSVGfile("path") pyx-project-pyx-21f71ce/examples/drawing/path.txt000066400000000000000000000024261526513311100221760ustar00rootroot00000000000000Basic paths This first path example demonstrates how to create a canvas, how to draw some simple geometric objects onto it and how to write the result into a PostScript or PDF file. ... First we import all top-level symbols of the PyX package by the usual Python import statement. In the further examples we will always use this form of the import statement to make the PyX package available to our scripts. Now we can create a canvas instance `c`, onto which our basic paths are drawn. The later is done by passing some path instances (a line, a rectangle and a circle) to the `strokes` or `fill` methods of the canvas instance we just created and stored in the variable `c`. Finally, we call the `writeEPSfile` and `writePDFfile` methods of the canvas to create an EPS and a PDF file of our drawing. While typically you will only create either a PostScript or a PDF file, in our examples we always create both output formats to have them both available for download. This example, in addition, shows some basics of the PyX coordinate system. The first coordinate (often referred to as `x`) goes horizontally from left to right and the second coordinate (`y`) goes vertically from the bottom to the top. The default unit is `1 cm`. The boundary of the resulting image is calculated automatically. pyx-project-pyx-21f71ce/examples/drawing/pathitem.py000066400000000000000000000013771526513311100226720ustar00rootroot00000000000000from pyx import * c = canvas.canvas() rect1 = path.path(path.moveto(0, 0), path.lineto(1, 0), path.moveto(1, 0), path.lineto(1, 1), path.moveto(1, 1), path.lineto(0, 1), path.moveto(0, 1), path.lineto(0, 0)) rect2 = path.path(path.moveto(2, 0), path.lineto(3, 0), path.lineto(3, 1), path.lineto(2, 1), path.lineto(2, 0)) rect3 = path.path(path.moveto(4, 0), path.lineto(5, 0), path.lineto(5, 1), path.lineto(4, 1), path.closepath()) c.stroke(rect1, [style.linewidth.THICK]) c.stroke(rect2, [style.linewidth.THICK]) c.stroke(rect3, [style.linewidth.THICK]) c.writeEPSfile("pathitem") c.writePDFfile("pathitem") c.writeSVGfile("pathitem") pyx-project-pyx-21f71ce/examples/drawing/pathitem.txt000066400000000000000000000041231526513311100230510ustar00rootroot00000000000000Constructing paths from pathitems In this example, some simple paths are constructed out of pathitems, which are the basic building blocks of paths. While we only use `moveto`, `lineto` and `closepath` instances, we can already see some features of paths in PyX. ... In the first path instance `rect1`, we alternatingly use `moveto` and `lineto` pathitem instances. A `moveto` instance sets an internal ''current point'', while a `lineto` instance additionally creates a straight line connecting the old and the new ''current point''. Due to the intermediate `moveto` instances, we generate a path which contains 4 separate subpaths. When stroking this path with a thick linewidth in order to show the details, the corners of the result exhibits that the individual lines are not connected. In the second case `rect2`, we skip the intermediate `moveto` instances. The default join method between pathitems within a single subpath is to miter them. This results in a different rendering except for the start and end point of the path. In order to get rid of the ragged effect at the corners, we close the path as shown by `rect3`. Here, one can (and should) skip the last connecting line since a `closepath` pathitem implicitly adds a straight connection line between the first and the last point of the subpath. ! PyX resembles the full PostScript path model. The whole PostScript path construction functionality is available by means of pathitems and the resulting PostScript code will make use of the corresponding PostScript operators. For PDF output, where some of the PostScript features are not available (all forms of arcs are missing in PDF), proper replacement code is generated automatically. !! You might ask why you should skip the last straight connection line of finite length when closing a path. This is not a question of reducing the file size but increasing the rendering stability of the drawing. The problem is that in case of rounding errors a very short connection line might mistakenly be inserted when rendering a `closepath`. Depending on the linejoin setting, this can create a major visual defect. pyx-project-pyx-21f71ce/examples/drawing/strokefill.py000066400000000000000000000004501526513311100232240ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.stroke(path.rect(0, 0, 1, 1), [style.linewidth.Thick, color.rgb.red, deco.filled([color.rgb.green])]) c.writeEPSfile("strokefill") c.writePDFfile("strokefill") c.writeSVGfile("strokefill") pyx-project-pyx-21f71ce/examples/drawing/strokefill.txt000066400000000000000000000041051526513311100234140ustar00rootroot00000000000000Stroke and fill paths at the same time In order to stroke and fill a path, you could call the `fill` and `stroke` methods of a canvas instance one after the other. However, such a solution is not optimal since the path would be written into the output file twice. Instead, you can use the `filled` decorator within a `stroke` method call as an additional attribute. ... In the example code, the filled decorator is called to pass additional styles, which will then only be used for the fill operation. Other styles passed in the second argument of the `stroke` method are used for both, the stroke and the fill operation. Here we set a linewidth, which only affects the stroke operation. A complementary functionality exists as well: you can use a `deco.stroked` instance to add a stroke operation within a `fill` method call. ! The `filled` and `stroked` are pre-defined instances, but they accept a ''modify by call'' operation. This is a common feature of decorators and other attributes. !! Internally, the `stroke` and the `fill` methods are implemented by adding either `deco.stroked` or `deco.filled` to the list passed as the second parameter to the `stroke` or `fill` method of a canvas. This whole construction is then evaluated by the `draw` method of the canvas instance. The draw method is really the basic operation to output a path. It transforms a path into a so-called decorated path. The mere path itself is a pure mathematical object without any information about how it should be drawn and which styles should be applied. Output-specific properties like dashing or the linewidth are not attached to the path at all. In contrast, the decorated path attaches styles and the two output operations stroke and fill to the mathematical path object. A symmetric stroke and fill operation therefore looks like c.draw(p, l1 + [deco.stroked(l2), deco.filled(l3)]) where `c` is the canvas instance, `p` is the path to be stroked and filled, `l1` is a list of styles used for both stroking and filling, `l2` are additional styles used for stroking, and `l3` are additional styles used for filling. pyx-project-pyx-21f71ce/examples/drawing/style.py000066400000000000000000000005621526513311100222120ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.stroke(path.line(0, 0, 4, 0), [style.linewidth.THICK, style.linestyle.dashed, color.rgb.red]) c.stroke(path.line(0, -1, 4, -1), [style.linewidth(0.2), style.linecap.round, color.rgb.green]) c.fill(path.rect(0, -3, 4, 1), [color.rgb.blue]) c.writeEPSfile("style") c.writePDFfile("style") c.writeSVGfile("style") pyx-project-pyx-21f71ce/examples/drawing/style.txt000066400000000000000000000025601526513311100224010ustar00rootroot00000000000000Stroke and fill attributes The previous example anticipated a simple case of setting an attribute when stroking paths. This example shows a few more use-cases. Attributes can be passed in a list as the second optional argument of the `stroke` or `fill` methods of a canvas instance. ... The attributes themselves are instances of certain attribute classes. A full list is available in the manual. In general, some useful attribute instances are predefined as class attributes of the corresponding attribute class. In the given example, the `style.linewidth.THICK`, `style.linestyle.dashed`, `style.linecap.round`, `color.rgb.red`, `color.rgb.green`, and `color.rgb.blue` are just some examples of this type of attribute instances. In contrast, `style.linewidth(0.2)` creates a new style instance for the given parameters. !! The linewidth instance created by `style.linewidth(0.2)` is different from the predefined linewidth instances in PyX in its use of ''user'' units. In the example ''Adding and joining paths'' of section ''Path features'', the linewidth is scaled independently of the ''user'' units, but if you try to double all linewidth by unit.set(wscale=2) in the beginning of the script, our self-defined linewidth will not be scaled. To obtain the proper scaling behaviour it would be necessary to attach the ''width'' unit by using style.linewidth(0.2*unit.w_cm) pyx-project-pyx-21f71ce/examples/drawing2/000077500000000000000000000000001526513311100205575ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/drawing2/INDEX000066400000000000000000000000521526513311100213460ustar00rootroot00000000000000ellipse insert smoothed parallel clipping pyx-project-pyx-21f71ce/examples/drawing2/README000066400000000000000000000004721526513311100214420ustar00rootroot00000000000000More drawing In this section we demonstrate more drawing features of PyX. The goal is to present the various attributes that can be used for stroking and filling paths in a canvas. Or, they are useful when one canvas is inserted into another one. In many cases, there are several ways to achieve the same result. pyx-project-pyx-21f71ce/examples/drawing2/clipping.py000066400000000000000000000005621526513311100227410ustar00rootroot00000000000000from pyx import * clippath = path.circle(0, 0, 1) drawpath = path.line(-2, -2, 1.2, 2) cl = canvas.canvas([canvas.clip(clippath)]) cl.stroke(drawpath, [color.rgb.red, style.linewidth(1.0)]) c = canvas.canvas() c.stroke(drawpath, [style.linewidth(1.0)]) c.insert(cl) c.stroke(clippath) c.writeEPSfile("clipping") c.writePDFfile("clipping") c.writeSVGfile("clipping") pyx-project-pyx-21f71ce/examples/drawing2/clipping.txt000066400000000000000000000010431526513311100231230ustar00rootroot00000000000000Clipping a canvas This example shows how drawing on a canvas can be clipped to a predefined region. The thick line is drawn two times, first in black onto an ordinary canvas, the second time in red onto a canvas which is clipped to the indicated circle. ... The clipping property of a canvas must be specified on creation with an instance of `canvas.clip`, which takes a path as an argument. Note that this way of clipping will probably be removed in future releases of PyX. Instead, it will become part of the [box concept ../../roadmap.html]. pyx-project-pyx-21f71ce/examples/drawing2/ellipse.py000066400000000000000000000007521526513311100225720ustar00rootroot00000000000000from pyx import * c = canvas.canvas() circ = path.circle(0, 0, 1) # variant 1: use trafo as a deformer c.stroke(circ, [style.linewidth.THIck, trafo.scale(sx=2, sy=0.9), trafo.rotate(45), trafo.translate(1, 0)]) # variant 2: transform a subcanvas sc = canvas.canvas() sc.stroke(circ, [style.linewidth.THIck]) c.insert(sc, [trafo.scale(sx=2, sy=0.9), trafo.rotate(45), trafo.translate(5, 0)]) c.writeEPSfile("ellipse") c.writePDFfile("ellipse") c.writeSVGfile("ellipse") pyx-project-pyx-21f71ce/examples/drawing2/ellipse.txt000066400000000000000000000100611526513311100227530ustar00rootroot00000000000000Applying transformations on a path or canvas: Drawing an ellipse PyX does not directly provide a path corresponding to an ellipse. This example shows two ways how to draw an ellipse using affine transformations. ... In order to create an ellipse, we best start from a unit circle centered around the point of origin of the coordinate system (here: `circ`). In variant 1, we tell PyX to apply a couple of affine transformations before stroking this circle on the canvas `c`. These affine transformations are contained in the `trafo` module. We first use `trafo.scale` to apply a non-uniform scaling, namely by a factor of 2 in x-direction and a factor of 0.9 in y-direction. Doing so, we define the two principle axes of the ellipse. In a next step, we rotate with `trafo.rotate` the ellipse by an angle of 45 degrees in the mathematical positive direction, i.e. counter-clockwise. Last, we shift the origin of the ellipse to the desired point by applying a `trafo.translate` operation. ! Note that the order of the transformations matters. If you, for instance, would first translate the ellipse, the later scaling would also affect the distance by which you have shifted the ellipse. PyX applies the transformations one after the other, from left to right, so the example shown above does the correct thing. ! You can also treat transformations as mathematical objects (they are represented by two-dimensional matrices together with an offset vector) and multiply them using the `*` operator. Note, however, that mathematically, transformations are applied from right to left, such that variant 1 would need to be written as c.stroke(circ, [trafo.translate(1,0) * trafo.rotate(45) * trafo.scale(sx=2, sy=1.5)]) ! PyX also provides some convenience methods for applying certain transformations with a given point as the origin. These allow one to write variant 1 in yet another form c.stroke(circ, [trafo.scale(sx=2, sy=1.5, x=1, y=0), trafo.rotate(45, x=1, y=0)]) where we have started already from a circle centered around the desired point 1,0. When telling the stroke method to apply a number of transformations, we use that a transformation is a so-called deformer. Deformers take an original path, do some operation on it and return the modified version. PyX thus internally converts the circle into a path representing the ellipse. Alternatively, we can also let the PostScript or PDF interpreter do the same transformation. This is what is shown in variant 2. There, we first stroke the circle on a new canvas `sc`. When inserting this canvas in the original canvas `c`, we again pass a set of transformations as arguments. Since PyX cannot deform an entire canvas, it just writes these transformations into the output file. If you compare the resulting output (the right ellipse) with the one of variant 1, you will notice a difference, though: when transforming a whole canvas, the lineshape is transformed as well. Often, this is not the intended result, so you better transform individual objects when stroking or filling them. !! When you look at the EPS or PDF output generated by the example, you will notice that the bounding box is too large. The reason for this artefact lies in the way PyX calculates the bounding box for a transformed canvas: It simply applies the transformation to the bounding box of the canvas and takes the bounding box of this new object. While this certainly yields a bounding box of the canvas, it does not necessarily yield a minimal one. To see this, you just have to consider the two extreme cases of a circle, which is rotationally invariant, and a square, which only posseses a discrete rotational symmetry. Whereas the minimal bounding box of the circle does not change under rotations around its center, the same is not true for the square. When you rotate a circle by applying a deformer (as in variant 1), PyX will thus calculate the correct bounding box. On the other hand, when you insert the circle into a canvas and afterwards transform this canvas (as in variant 2), PyX cannot distinguish between a circle and a square anymore and calculates a too large bounding box. pyx-project-pyx-21f71ce/examples/drawing2/insert.py000066400000000000000000000005531526513311100224400ustar00rootroot00000000000000from math import sin, cos, radians from pyx import * angle = 10 factor = 1.0 / (cos(radians(angle)) + sin(radians(angle))) cc = canvas.canvas() cc.stroke(path.rect(-2, -2, 4, 4)) c = canvas.canvas() for i in range(10): c.insert(cc, [trafo.rotate(i*angle), trafo.scale(factor**i)]) c.writeEPSfile("insert") c.writePDFfile("insert") c.writeSVGfile("insert") pyx-project-pyx-21f71ce/examples/drawing2/insert.txt000066400000000000000000000016211526513311100226240ustar00rootroot00000000000000Inserting transformed canvases into canvases Similar to the drawing of paths onto canvases, it is also possible to insert one canvas into another. You may specify additional transformations which are applied to the canvas which is inserted. ... The example code shows how a canvas `cc` containing a square can be inserted several times into another canvas `c`. The applied transformation first rotates the square around the origin and then performs a scaling. Note that not only the size of the square gets scaled, but everything that is drawn on the canvas, also the linewidth of the square. In geometrical operations, it is often necessary to perform calculations. This is conveniently done by importing the mathematics capability of Python. In the example, we calculate the scaling factor from the rotation angle such that the corners of the rotated smaller square reside on the sides of the larger square. pyx-project-pyx-21f71ce/examples/drawing2/parallel.py000066400000000000000000000004631526513311100227300ustar00rootroot00000000000000from pyx import * c = canvas.canvas() p = path.line(0, 0, 2, 2) p.append(path.curveto(2, 0, 3, 0, 4, 0)) c.stroke(p) c.stroke(p, [deformer.parallel(0.2), color.rgb.blue]) c.stroke(p, [deformer.parallel(-0.2), color.rgb.red]) c.writeEPSfile("parallel") c.writePDFfile("parallel") c.writeSVGfile("parallel") pyx-project-pyx-21f71ce/examples/drawing2/parallel.txt000066400000000000000000000023721526513311100231200ustar00rootroot00000000000000Paths with constant distance This example shows how to use the `deformer.parallel` class. It provides the path which has always constant (signed) distance to an original path. ... The correct geometrical solution to the "constant distance" problem is that a corner of the original curve gets surrounded by an arc. As an alternative, you can make the deformer deviate from the strict geometrical interpretation with the argument `sharpoutercorners=1`. The resulting parallel path will then exhibit corners with the same angle as the original path does. !! The parallel deformer tries to find the parallel path which consists of as few path elements as possible. This is a striking feature of the parallel deformer, resulting in small EPS and PDF files, as well as in paths which can be processed further in PyX. In the example, the parallel curves for the curved right part of the original path consists of a single Bézier curve only. ! Note that the order of the deformer attributes is not arbitrary, since the deforming operations do not commute. If you want first to smooth and then get the parallel curve to the smoothed curve, you have to say [deformer.smoothed(radius), deformer.parallel(dist)] since the stroke attributes are evaluated from left to right. pyx-project-pyx-21f71ce/examples/drawing2/smoothed.py000066400000000000000000000004621526513311100227550ustar00rootroot00000000000000from pyx import * c = canvas.canvas() p = path.line(0, 0, 2, 2) p.append(path.curveto(2, 0, 3, 0, 4, 0)) c.stroke(p) c.stroke(p, [deformer.smoothed(1.0), color.rgb.blue]) c.stroke(p, [deformer.smoothed(2.0), color.rgb.red]) c.writeEPSfile("smoothed") c.writePDFfile("smoothed") c.writeSVGfile("smoothed") pyx-project-pyx-21f71ce/examples/drawing2/smoothed.txt000066400000000000000000000017631526513311100231510ustar00rootroot00000000000000Smoothing paths This example shows how to use the `deformer` class. A deformer takes an original path and return a modified one, which is here a smoothed variant. The deformer can be used like any other attribute when stroking or filling a path. Here, we show the use of `deformer.smoothed`, which smoothes away corners in the original path. ... It operates on the `pathitem`s of the original path and cuts out pieces of a given length (`1.0` in the example) surrounding a corner and replaces them by a smooth curve. This new curve is determined to be ''geometrically smooth'', exhibiting the same tangents and curvatures as the original path at the connection points. Alltogether, the smoothing is performed not in a strictly ''geometrical'' sense but also depends on the parameterization of the path. If you try to smooth a path consisting of many short path elements, nothing will really change. ! In all deformers, the deformed path can be accessed directly by ps = deformer.smoothed(1.0).deform(p) pyx-project-pyx-21f71ce/examples/graphs/000077500000000000000000000000001526513311100203265ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/graphs/INDEX000066400000000000000000000001031526513311100211120ustar00rootroot00000000000000minimal function points lissajous axis change join grid components pyx-project-pyx-21f71ce/examples/graphs/README000066400000000000000000000023341526513311100212100ustar00rootroot00000000000000Basic plotting One of PyX's major strengths are its graph-plotting capabilities. PyX offers you a flexible system which, while providing sensible defaults, allows you to customize almost every aspect of the graph output. Such a flexibility comes at a price, though: you need to learn at least a little bit about the different components playing together in order to produce a graph. In this section, we try to give you a gentle introduction to one component after the other by by demonstrating how to plot various kind of data (from a file, a function mapping x values to y values, a parametric function). Furthermore, we explain how to do simple modifications to the axes of the graph and show how to add a graph key. After having gone through the introductory examples you should be able to freely go through the following sections of the examples, which examples will be devoted to a more detailed explanation of PyX's graph-plotting facilities. In particular, you might want to learn about the customization of the graph axes (see section [ Graph axes ../axis/index.html]), about further available graph styles (see section [Graph styles ../styles/index.html]) and about bar graphs (see section [Bar graphs ../bargraphs/index.html]). pyx-project-pyx-21f71ce/examples/graphs/axis.py000066400000000000000000000004601526513311100216440ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.log(min=1e-1, max=1e4, title=r"$x$-axis"), y=graph.axis.lin(max=5, title=r"$y$-axis")) g.plot(graph.data.function("y(x)=tan(log(1/x))**2")) g.writeEPSfile("axis") g.writePDFfile("axis") g.writeSVGfile("axis") pyx-project-pyx-21f71ce/examples/graphs/axis.txt000066400000000000000000000034121526513311100220330ustar00rootroot00000000000000Using a logarithmic axis and defining the axis range and its label Sometimes, you have to visualize rather pathological funtions containing divergencies and/or varying over a large parameter range. This is best done using an appropriate axis. Here, we show a simple example how to do this with PyX. ... In order to change the properties of the graph axes, we have to create appropriate instances of an axis class and pass them as keyword arguments to the `graph.graphxy` constructor. A number of predefined axes is contained in the `graph.axis` module. Here, we use a linear (abbreviated as `graph.axis.lin`) and a logarithmic (abbreviated as `graph.axis.log`) axis. In both cases, we pass a minimal and maximal value for the axis range. Whereas for the x-axis this is not strictly necessary (we could as well tell the `graph.data.function` instance to emit data in a certain x-range), it is important for the y-axis because the function diverges for certain x values. If we do not set the y range manually, we would obtain a rather compressed display of the function in the y-direction, which, moreover, would strongly depend on the sampling points choosen by PyX along the x-direction. Since the function only diverges towards positive y-values, we only need to set the maximal value of the y-axis (using the `max`-argument). Of course, you can also fix the lower end of the axis range by providing a `min`-argument. In order to introduce the `title` keyword, we give names to the axes. ! Note how PyX changes the way the x-axis is drawn. Instead of simple decimal numbers, an exponential notation is used. This happens automatically by default, if at least one of the values to be shown becomes 10,000 or bigger smaller than 0.001. This behaviour can be altered by using a different axis texter. pyx-project-pyx-21f71ce/examples/graphs/change.py000066400000000000000000000012031526513311100221210ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.linear(min=0, max=2), y=graph.axis.linear(min=0, max=2), key=graph.key.key(pos="br", dist=0.1)) g.plot([graph.data.function("x(y)=y**4", title=r"$x = y^4$"), graph.data.function("x(y)=y**2", title=r"$x = y^2$"), graph.data.function("x(y)=y", title=r"$x = y$"), graph.data.function("y(x)=x**2", title=r"$y = x^2$"), graph.data.function("y(x)=x**4", title=r"$y = x^4$")], [graph.style.line([color.gradient.Rainbow])]) g.writeEPSfile("change") g.writePDFfile("change") g.writeSVGfile("change") pyx-project-pyx-21f71ce/examples/graphs/change.txt000066400000000000000000000046621526513311100223240ustar00rootroot00000000000000Plotting more than one data set and adding a graph key In this example we demonstrate how to plot more than one data set in a graph. Furthermore, adding a graph key labelling the data is explained. ... In order to display more than one data set, we pass a list of data sets to the `plot` method of the graph. In the present case, we contruct this list out of three lists of `graph.data.function` instances. For each data set we also set a title using the corresponding keyword argument of the data class. For a more colorful output, we pass the `color.gradient.Rainbow` color gradient to the `graph.style.line` class. PyX then automatically chooses color spanning the whole range of the rainbow gradient. ! If you look at the output, you will notice that not only the colors are cycled through, but also the line style changes. The reason for this behavior is that the default line attributes of the `graph.style.line` style contain an `attr.changelist` comprising a couple of different line styles. When you pass additional line attributes, these are appended to the default attributes (this is generally the case in PyX). Consequently, you get a change of both the color and the line style. If you only want to change the color, either pass the desired line style explicitly, i.e., use graph.style.line([style.linestyle.solid, color.gradient.Rainbow]) or clear a previous setting of the line style using the `clear` attribute of the corresponding class: graph.style.line([style.linestyle.clear, color.gradient.Rainbow]) !! It is also possible to call the `plot` method several times. Note that the changing of the styles is also performed when the style instances are used on several plot commands within the same graph as long as the same set of style instances are passed at the `plot` method calls. Finally, when plotting more than one data set you might want to label them in your graph. We already have passed titles identifying each data set, so we only have to add a graph key. This is done by passing a `graph.key.key` instance as the `key` keyword argument to the graph. Usually, you only need to specify the position of the key using the `pos` argument of the `graph.key.key` constructor. The syntax should be self-explaining; here we use `br` to put the key at the bottom-right position of the graph. In order to save some space, we furthermore decreases the distance between the key entries a little bit by passing a value of 0.1 to the `dist` argument. pyx-project-pyx-21f71ce/examples/graphs/components.py000066400000000000000000000006411526513311100230660ustar00rootroot00000000000000from math import pi from pyx import * g = graph.graphxy(width=10, x_min=-4*pi, x_max=4*pi, x_painter_gridattrs=[], x_divisor=pi, x_texter=graph.axis.texter.rational(suffix=r"\pi"), y_painter_gridattrs=[attr.changelist([style.linestyle.dashed, None])]) g.plot(graph.data.function("y(x)=sin(x)/x", points=200)) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/examples/graphs/components.txt000066400000000000000000000034541526513311100232620ustar00rootroot00000000000000Shortcut for accessing graph-component attributes Changing attributes of graphs requires one to set attributes of various graph components. In order to simplify this, PyX provides a shortcut in the constructors of these components. ... A simple example is the following code snippet, which turns on the x-axis grid in a graph: graph.graphxy(x=graph.axis.lin(painter=graph.axis.painter.regular(gridattrs=[]))) The same effect can be obtained by the much shorter version graph.graphxy(x_painter_gridattrs=[]) Here, the hierarchy of components used in the `graphxy` constructor is indicated by underscores. The part before the first underscore denotes the axes to be modified. In this example, this is the x-axis. The second part defines the component of this axis which should be changed. Here, this is the axis `painter`. Note that the base for this change is the x-axis of the graphxy, which in the present case is the default value `graph.axis.lin`. Finally, the third part defines which attribute of the component should be set. In the example, we enable the grid by setting `gridattrs` to a value different from `None`. Again, this change assumes that the default painter `graph.axis.painter.regular` is used. If you want to replace a component, you have to set it explicitly. Suppose we want to have a log with a grid. This can be achieved by the following code: graph.graphxy(x=graph.axis.log(painter=graph.axis.painter.regular(gridattrs=[]))) The same effect can be obtained by the shorter version graph.graphxy(x=graph.axis.log(), x_painter_gridattrs=[]) or alternatively graph.graphxy(x=graph.axis.log(painter_gridattrs=[])) This example demonstrates this shorter form of graph-component attributes setting and produces the same result as the example [Drawing a graph with grid lines grid.html]. pyx-project-pyx-21f71ce/examples/graphs/function.py000066400000000000000000000002751526513311100225310ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.function("y(x)=sin(x)/x", min=-15, max=15)) g.writeEPSfile("function") g.writePDFfile("function") g.writeSVGfile("function") pyx-project-pyx-21f71ce/examples/graphs/function.txt000066400000000000000000000032261526513311100227170ustar00rootroot00000000000000Plotting a function graph Here, we explain how to plot the graph of a real-valued mathematical function of a single real parameter. ... As in the previous example, we first create a `graph.graphxy` instance passing the width as argument. We then pass a `graph.data.function` instance to the `plot` method of the graph. As first argument, we pass the function in the form "y(x) = f(x)". Here, the left-hand side of the equation defines which parameter is independent (here: `x`) and which one is dependent (here: `y`). We also need to inform PyX about the range of the independent variable. This is done by passing the parameters `min` and `max`. ! In order to increase the resolution of the function graph, you can use the parameter `points` of the `graph.data.function` class to increase the number of sampling points from its default value of `100`. Note that the default graph style for function data is `graph.style.line` since PyX assumes a continuous x-range. ! You only need to pass the `min` and `max` parameters to the `graph.data.function` class, if PyX cannot figure out an axis range by itself. Thus, an alternative way to achieve the above result would look like g = graph.graphxy(width=8, x=graph.axis.linear(min=-15, max=15)) g.plot(graph.data.function("y(x)=sin(x)/x")) Here, we explicitely define an x-axis range by passing an appropriate argument to the `x` parameter of the `graph.graphxy` class. ! For PyX it does not matter, whether you plot a function of a parameter `x` or a parameter `y`. Thus, you may as well write g.plot(graph.data.function("x(y)=sin(y)/y", min=-15, max=15)) to obtain a plot where the y-coordinate is the independent one. pyx-project-pyx-21f71ce/examples/graphs/grid.py000066400000000000000000000010621526513311100216240ustar00rootroot00000000000000from math import pi from pyx import * from pyx.graph import axis xgridpainter = axis.painter.regular(gridattrs=[]) ygridpainter = axis.painter.regular(gridattrs=[attr.changelist([style.linestyle.dashed, None])]) g = graph.graphxy(width=10, x=axis.lin(painter=xgridpainter, divisor=pi, texter=axis.texter.rational(suffix=r"\pi"), min=-4*pi, max=4*pi), y=axis.lin(painter=ygridpainter)) g.plot(graph.data.function("y(x)=sin(x)/x", points=200)) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/examples/graphs/grid.txt000066400000000000000000000025421526513311100220170ustar00rootroot00000000000000Drawing a graph with grid lines The drawing of grid lines is performed by the axis painters of the graph. ... In order to turn on a grid, one has to specify in the argument `gridattrs` a list of attributes defining the way the grid should look like. In order to enable a grid at the position of the axis ticks and subticks, it is enough to set `gridattrs` to an empty list. In the example, this is done for the grid corresponding to the x-axis. If one wants to control the style of the grid lines or even turn them off selectively for the main or subticks, one can pass `attr.changelist` instances in the list. The first item of the argument of this class is then used for the main ticks, the second for the first subticks, and so on. In the example, it is shown how to change the linestyle of the grid at the main tick positions and to turn off the grid for the subticks by setting the correpsonding value in the `attr.changelist` instance to `None`. ! The example also shows a neat trick how to create an axis with axis labels at fractions of pi. This can be achieved by passing a `divisor` argument to the axis itself, which means that for the axis handling, all values are divided by the corresponding value. Then, we automatically put ticks at the position of rational number by means of `axis.texter.rational` and add the missing factor pi at the end of the TeX output. pyx-project-pyx-21f71ce/examples/graphs/join.dat000066400000000000000000000021341526513311100217570ustar00rootroot000000000000000 -0.0416523 0.00370405 -0.0120944 0.0344828 0.0758855 0.144363 0.203587 0.0689655 0.105887 0.259478 0.3624 0.103448 0.170788 0.360286 0.542374 0.137931 0.20317 0.407522 0.704534 0.172414 0.311803 0.481457 0.80502 0.206897 0.338232 0.594614 0.821449 0.241379 0.302589 0.612485 0.906532 0.275862 0.335894 0.59561 0.898951 0.310345 0.286523 0.537869 0.842022 0.344828 0.241982 0.471199 0.78992 0.37931 0.201726 0.391884 0.645232 0.413793 0.115665 0.282956 0.499897 0.448276 0.126654 0.176257 0.328663 0.482759 0.066533 0.0198417 0.110219 0.517241 -0.0331831 -0.0761098 -0.141317 0.551724 -0.0927296 -0.219183 -0.241559 0.586207 -0.179708 -0.270902 -0.460771 0.62069 -0.162048 -0.456294 -0.575559 0.655172 -0.20805 -0.530463 -0.780346 0.689655 -0.242298 -0.528865 -0.822735 0.724138 -0.315267 -0.588264 -0.905236 0.758621 -0.305853 -0.643168 -0.903536 0.793103 -0.291477 -0.592055 -0.857436 0.827586 -0.289402 -0.484567 -0.76292 0.862069 -0.270358 -0.430461 -0.675236 0.896552 -0.231194 -0.328504 -0.512663 0.931034 -0.17519 -0.221731 -0.330941 0.965517 -0.0567209 -0.0880629 -0.200636 1 0.0449826 -0.0469508 0.0426738 pyx-project-pyx-21f71ce/examples/graphs/join.py000077500000000000000000000012231526513311100216400ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, key=graph.key.key()) As = [0.3, 0.6, 0.9] d = [graph.data.join([graph.data.function("y_a(x_a)=A*sin(2*pi*x_a)", context=dict(A=A)), graph.data.file("join.dat", x_b=1, y_b=i+2)], title=r"$A=%g$" % A) for i, A in enumerate(As)] attrs = [color.gradient.RedBlue] g.plot(d, [graph.style.pos(usenames=dict(x="x_a", y="y_a")), graph.style.line(attrs), graph.style.pos(usenames=dict(x="x_b", y="y_b")), graph.style.symbol(graph.style.symbol.changesquare, symbolattrs=attrs, size=0.1)]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/examples/graphs/join.txt000066400000000000000000000020301526513311100220210ustar00rootroot00000000000000Joing multiple datasets for grouping in the graph key If you want to group datasets in the graph key, e.g., to compare simulation results with measurement data ... or some approximate results with results from a more detailed calculation, you can pass a list of datasets to the `graph.data.join` class. When doing so, you have to assign unique names to the corresponding datasets. In the example, we have used `x_a` and `y_a` as well as `x_b` and `y_b` as names. Subsequently, one has to tell the graph style which data columns—identified by the given name—it has to plot. This can be done by inserting `graph.style.pos` instances before the respective graph style. By passing a dictionary to the `usenames` argument, one specifies the mapping from the data columns to the corresponding graph axes `x`, `y`, `x2`, and so on. ! When using the standard names `x`, `y`, etc. for the data columns, as is done in most cases, PyX does insert the `graph.style.pos` instance mapping those data columns to the axis with the same name, automatically. pyx-project-pyx-21f71ce/examples/graphs/lissajous.py000066400000000000000000000003421526513311100227130ustar00rootroot00000000000000from math import pi from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.paramfunction("k", 0, 2*pi, "x, y = sin(2*k), cos(3*k)")) g.writeEPSfile("lissajous") g.writePDFfile("lissajous") g.writeSVGfile("lissajous") pyx-project-pyx-21f71ce/examples/graphs/lissajous.txt000066400000000000000000000043061526513311100231060ustar00rootroot00000000000000Plotting a parametric function This example shows how to use a `paramfunction` as a data source for a graph. `paramfunction` defines a parameter variable name given as a string in the first argument, a minimal and a maximal value given as the second and third argument and an expression string as forth argument. ... This expression string assigns a tuple of expressions to a tuple of data names. As usual the styles will decide what those data names are responsible for. ! Like for the function, you can also access external data and functions in your expression. Suppose we want to provide the data for this example by means of the following python function: def lissajousdata(k): return sin(2*k), cos(3*k) Then we would need to modify the plot command to: g.plot(graph.data.paramfunction("t", min, max, "x, y = f(t)", context={"f": lissajousdata})) Note, that `t` and `f` in the string expression stand for `k` and `lissajousdata` respectively. You can also use the same names in the expression if you like. ! When you try this, you will notice, that you need to add `sin` and `cos` to the list of imported symbols from the math module. While this should be expected, it is more interesting to note, that it was not necessary to import those functions before. The reason is, that the string expressions are evaluated in a certain context. This context does not only contain the symbols given in the `context` keyword argument, but in addition some standard mathematical functions (and constants) including `sin` and `cos`. See the reference manual for a complete list. For the common case of plotting a parametric function providing data for `x` and `y` by means of an external function, there is a special `paramfunctionxy` which directly calls the external function instead of using a context in a string expression. A `lambda` expression could serve to provide the data inline, which results in: g.plot(graph.data.paramfunctionxy(lambda k: (sin(2*k), cos(3*k)), 0, 2*pi)) Note that the external expression is provided in the first argument here. Since the system just need to call the function, the parameter variable name does not have to be provided to `paramfunctionxy`. pyx-project-pyx-21f71ce/examples/graphs/minimal.dat000066400000000000000000000000441526513311100224440ustar00rootroot000000000000001 2 2 3 3 8 4 13 5 18 6 21 pyx-project-pyx-21f71ce/examples/graphs/minimal.py000066400000000000000000000002551526513311100223300ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.file("minimal.dat", x=1, y=2)) g.writeEPSfile("minimal") g.writePDFfile("minimal") g.writeSVGfile("minimal") pyx-project-pyx-21f71ce/examples/graphs/minimal.txt000066400000000000000000000052741526513311100225250ustar00rootroot00000000000000Plotting data contained in a file This example shows how to draw a graph representing data stored in a file. ... We assume that the data is arranged in the file `minimal.dat` in a whitespace-separated two-column form: # minimal.dat 1 2 2 3 3 8 4 13 5 18 6 21 The first step is to create an instance of the `graphxy` class which can be found in the `graph` module. By convention, we call it `g`. The constructor expects at least some information about the desired size of the graph. Here, we specify a width of 8 cm. ! If we only specify one dimension of the graph size, PyX calculates the other automatically, assuming a ratio corresponding to the golden ratio. Next, we add some data to the yet empty graph. In order to do so, we first create a `graph.data.file` instance, which reads the file with the name given as the first argument, i.e., in the present case, `"minimal.dat"`. In addition, we have to specify, how the data is organized in the file. To this end, we use the keyword arguments `x=1` and `y=2`, which tell PyX that the first (second) column of the file contains the x (y) values. The `graph.data.file` instance is then directly passed to the `plot` method of the graph `g`. ! Note that PyX by default ignores comments starting by a # sign when reading in the data from the file. !! The previous statement is actually not completely correct, as PyX uses the last comment preceding the actual data to give names to the columns. Thus, for a file looking like # my data (this line is ignored by PyX, but not the following) # x y 1 2 ... you wouldn't need to label the columns in the `graph.data.file` call at all. Finally, we write the graph to an EPS and PDF file. Here, we use that every graph is (by inheritance) an instance of the `canvas` class, as well, such that we can directly write it into a file. ! Of course, you can also insert a graph into another canvas and write this canvas later to a file. This way, you can, for instance, easily arrange more than one graph on a page. Later examples will make use of this fact. In PyX, the way data is plotted in a graph is defined by a so-called graph style. A couple of standard graph styles are contained in the module `graph.style`. Depending on the data source, PyX chooses a default style. Here, we are taking the data from a file and PyX assumes that the values represent a discrete set of data points. Hence, it chooses the symbol style `graph.style.symbol` to plot the data. To override this default behaviour, you can pass a list of styles as second argument to the `plot` method. For instance, to have PyX drawing a line through the data points, you can use g.plot(graph.data.file("minimal.dat", x=1, y=2), [graph.style.line()]) pyx-project-pyx-21f71ce/examples/graphs/points.py000066400000000000000000000006031526513311100222130ustar00rootroot00000000000000# suggested by Chris Spencer from pyx import * g = graph.graphxy(width=8) # either provide lists of the individual coordinates g.plot(graph.data.values(x=list(range(10)), y=list(range(10)))) # or provide one list containing the whole points g.plot(graph.data.points(list(zip(range(10), range(10))), x=1, y=2)) g.writeEPSfile("points") g.writePDFfile("points") g.writeSVGfile("points") pyx-project-pyx-21f71ce/examples/graphs/points.txt000066400000000000000000000020131526513311100223770ustar00rootroot00000000000000Plotting data contained in one or more lists Here, we explain how to plot data which has been calculated before and which is available in a list. ... The procedure is quite the same as for plotting a data file or a function in the above examples. It differs in that we use an instance of `graph.data.values` or `graph.data.points` in the `plot` method of the graph. The choice of one or the other variant depends on convenience and how the data has been generated: In `graph.data.values` the coordinate values are provided as individual lists. Alternatively, `graph.data.points` takes a list of data points which come as coordinate tuples. You will then have to say something like `x=1, y=2` to specify which entry in your tuples is to be used on which axis. Similarly to the plotting of a data file, the default plotting style here are symbols. Caution: This feature has been renamed/introduced between versions 0.9 and 0.10. In versions 0.9 and before the functionality of `graph.data.points` was provided by `graph.data.list`. pyx-project-pyx-21f71ce/examples/graphstyles/000077500000000000000000000000001526513311100214075ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/graphstyles/INDEX000066400000000000000000000000661526513311100222030ustar00rootroot00000000000000errorbar histogram density usesymbol changesymbol cal pyx-project-pyx-21f71ce/examples/graphstyles/README000066400000000000000000000002461526513311100222710ustar00rootroot00000000000000Graph styles The component architecture of the graph system make graphs highly customizeable. A typical case are personalized graph styles as shown in this section. pyx-project-pyx-21f71ce/examples/graphstyles/cal.py000066400000000000000000000071571526513311100225320ustar00rootroot00000000000000import calendar from pyx import * class daystyle(graph.style._style): def columnnames(self, privatedata, sharedata, graph, columnnames, dataaxisnames): # register the new column names usecolumnnames = ["day", "month", "weekday", "note"] for columnname in usecolumnnames: if columnname not in columnnames: raise ValueError("column '%s' missing" % columnname) return usecolumnnames def adjustaxis(self, privatedata, sharedata, graph, plotitem, columnname, data): # adjust axes ranges if columnname == "month": graph.axes["x"].adjustaxis([(x, 0) for x in data]) graph.axes["x"].adjustaxis([(x, 1) for x in data]) if columnname == "day": graph.axes["y"].adjustaxis([(x, 0) for x in data]) graph.axes["y"].adjustaxis([(x, 1) for x in data]) def drawpoint(self, privatedata, sharedata, graph, point): # draw a single day x1_pt, y1_pt = graph.pos_pt((point["month"], 0), (point["day"], 0)) x2_pt, y2_pt = graph.pos_pt((point["month"], 1), (point["day"], 1)) p = path.rect_pt(x1_pt, y1_pt, x2_pt - x1_pt, y2_pt - y1_pt) if point["weekday"] == calendar.day_abbr[-1]: graph.stroke(p, [deco.filled([color.gray(0.8)])]) else: graph.stroke(p) graph.text_pt(x1_pt+3, y2_pt-3, "%i %s" % (point["day"], point["weekday"]), [text.valign.top]) if point["note"]: graph.text_pt(x1_pt+3, y1_pt+3, point["note"], [text.size.tiny]) # create calendar data year = 2015 notes = {1: {17: r"\PyX{} 0.2 (2003)", 20: r"\PyX{} 0.5 (2004)", 22: r"\PyX{} 0.5.1 (2004)"}, 3: {30: r"\PyX{} 0.6 (2004)", 31: r"\PyX{} 0.3 ('03), \PyX{} 0.6.1 ('04)"}, 4: {4: r"\PyX{} 0.3.1 (2003)", 7: r"\PyX{} 0.6.2 (2004)", 27: r"\PyX{} 0.6.3 (2004)", 30: r"\PyX{} 0.14 (2015)"}, 5: {5: r"\PyX{} 0.11 (2011)", 20: r"\PyX{} 0.11.1 (2011)", 24: r"\PyX{} 0.9 (2006)"}, 7: {13: r"\PyX{} 0.8 (2005)", 14: r"\PyX{} 0.15 (2019)"}, 8: {13: r"\PyX{} 0.8.1 (2005)", 22: r"\PyX{} 0.4 (2003)"}, 9: {17: r"\PyX{} 0.4.1 (2003)"}, 10: {3: r"\PyX{} 0.10 (2007)", 7: r"\PyX{} 0.1 (2002)", 12: r"\PyX{} 0.12 (2012)", 16: r"\PyX{} 0.16 (2022)", 16: r"\PyX{} 0.18 (2026)", 21: r"\PyX{} 0.7 (2004)", 26: r"\PyX{} 0.12.1 (2012)"}, 11: {2: r"\PyX{} 0.14.1 ('15), \PyX{} 0.17 ('25)"}, 12: {15: r"\PyX{} 0.7.1 (2004)", 20: r"\PyX{} 0.13 (2013)"}} d = graph.data.points([(day, calendar.month_name[month], calendar.day_abbr[calendar.weekday(year, month, day)], notes.get(month, {}).get(day)) for month in range(1, 13) for day in range(1, calendar.monthrange(year, month)[1]+1)], day=1, month=2, weekday=3, note=4) # create the calendar g = graph.graphxy(width=40, x2=graph.axis.bar(dist=0, linkpainter=None), y=graph.axis.bar(dist=0, reverse=1, painter=None)) g.plot(d, [daystyle()]) # we could write the full calendar by # g.writeEPSfile("cal", paperformat=document.paperformat.A3, rotated=1) # instead we clip the result to show only a small part clip = canvas.clip(g.bbox().enlarged(0.1, bottom=-17, right=-25).path()) gc = canvas.canvas([clip]) gc.insert(g) # and add some dots at the clipped parts gcbb = gc.bbox() c = canvas.canvas() c.insert(gc) c.text(gcbb.right()+0.5, gcbb.center()[1], r"\dots") c.text(gcbb.center()[0], gcbb.bottom()-0.5, r"\dots") c.writeEPSfile("cal") c.writePDFfile("cal") c.writeSVGfile("cal") pyx-project-pyx-21f71ce/examples/graphstyles/cal.txt000066400000000000000000000003601526513311100227060ustar00rootroot00000000000000Making a calendar graph !! In this example we create a calendar graph style. The style uses bar axes for both graph coordinates and it is a simple and minimal example in the sense that it does not make use of other styles for positioning. pyx-project-pyx-21f71ce/examples/graphstyles/changesymbol.py000066400000000000000000000042301526513311100244330ustar00rootroot00000000000000import random from pyx import * # introduce a new symbol style where size and color are given by some data class changesymbol(graph.style.symbol): def __init__(self, sizecolumnname="size", colorcolumnname="color", gradient=color.gradient.Rainbow, symbol=graph.style.symbol.circle, symbolattrs=[deco.filled, deco.stroked([color.gray.black])], **kwargs): # add some configuration parameters and modify some other self.sizecolumnname = sizecolumnname self.colorcolumnname = colorcolumnname self.gradient = gradient graph.style.symbol.__init__(self, symbol=symbol, symbolattrs=symbolattrs, **kwargs) def columnnames(self, privatedata, sharedata, agraph, columnnames, dataaxisnames): # register the new column names if self.sizecolumnname not in columnnames: raise ValueError("column '%s' missing" % self.sizecolumnname) if self.colorcolumnname not in columnnames: raise ValueError("column '%s' missing" % self.colorcolumnname) return ([self.sizecolumnname, self.colorcolumnname] + graph.style.symbol.columnnames(self, privatedata, sharedata, agraph, columnnames, dataaxisnames)) def drawpoint(self, privatedata, sharedata, graph, point): # replace the original drawpoint method by a slightly revised one if sharedata.vposvalid and privatedata.symbolattrs is not None: x_pt, y_pt = graph.vpos_pt(*sharedata.vpos) color = self.gradient.getcolor(point[self.colorcolumnname]) privatedata.symbol(privatedata.symbolcanvas, x_pt, y_pt, privatedata.size_pt*point[self.sizecolumnname], privatedata.symbolattrs + [color]) g = graph.graphxy(width=10) g.plot(graph.data.points([[random.random() for i in range(4)] for i in range(1000)], x=1, y=2, size=3, color=4), [changesymbol()]) g.writeEPSfile("changesymbol") g.writePDFfile("changesymbol") g.writeSVGfile("changesymbol") pyx-project-pyx-21f71ce/examples/graphstyles/changesymbol.txt000066400000000000000000000011521526513311100246220ustar00rootroot00000000000000Add functionality to existing graph styles ! In this example demonstrate how graph styles can be modified to add further functionality to them. ... Here we create changesymbol styles based on PyX's symbol style. For that two additional column names are introduced that way, that they can be modified in the constructor of the style. The column names are then registered by the adjusted version of the `columnnames` method. After that we only need to replace the drawpoint method by a modified version, which implements the additional functionality. This new created style can than be used like any other graph style. pyx-project-pyx-21f71ce/examples/graphstyles/density.py000066400000000000000000000020271526513311100234410ustar00rootroot00000000000000from pyx import * # Mandelbrot calculation contributed by Stephen Phillips # Mandelbrot parameters re_min = -2 re_max = 0.5 im_min = -1.25 im_max = 1.25 gridx = 100 gridy = 100 max_iter = 10 # Set-up re_step = (re_max - re_min) / gridx im_step = (im_max - im_min) / gridy d = [] # Compute fractal for re_index in range(gridx): re = re_min + re_step * (re_index + 0.5) for im_index in range(gridy): im = im_min + im_step * (im_index + 0.5) c = complex(re, im) n = 0 z = complex(0, 0) while n < max_iter and abs(z) < 2: z = (z * z) + c n += 1 d.append([re, im, n]) # Plot graph g = graph.graphxy(height=8, width=8, x=graph.axis.linear(min=re_min, max=re_max, title=r"$\Re(c)$"), y=graph.axis.linear(min=im_min, max=im_max, title=r'$\Im(c)$')) g.plot(graph.data.points(d, x=1, y=2, color=3, title="iterations"), [graph.style.density(gradient=color.rgbgradient.Rainbow)]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/examples/graphstyles/density.txt000066400000000000000000000016311526513311100236300ustar00rootroot00000000000000Drawing a density plot 2 dimensional plots where the value of each point is represented by a color can be created by the density style. ... The data points have to be spaced equidistantly in each dimension with the possible exception of missing data. For data which is not equidistantly spaced but still arranged in a grid, `graph.style.surface` can be used, which also provides a smooth representation by means of a color interpolation between the mesh moints. Finally, for completely unstructured data, `graph.style.rect` can be used. !The plot is encoded in an efficient way using a bitmap. Unfortunately, this means, that the HSB color space cannot be used (due to limitations of the bitmap color spaces in PostScript and PDF). Some of the predefined gradients in PyX, e.g. `color.gradient.Rainbow`, cannot be used here. As a workaround, PyX provides those gradients in other color spaces as shown in the example. pyx-project-pyx-21f71ce/examples/graphstyles/errorbar.dat000066400000000000000000000001021526513311100237100ustar00rootroot000000000000001 2 0.7 2 3 0.9 3 8 0.8 4 13 1.2 5 18 1.1 6 21 1.3 pyx-project-pyx-21f71ce/examples/graphstyles/errorbar.py000066400000000000000000000003561526513311100236030ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.file("errorbar.dat", x=1, y=2, dy=3), [graph.style.symbol(), graph.style.errorbar()]) g.writeEPSfile("errorbar") g.writePDFfile("errorbar") g.writeSVGfile("errorbar") pyx-project-pyx-21f71ce/examples/graphstyles/errorbar.txt000066400000000000000000000034141526513311100237700ustar00rootroot00000000000000Combining several graph styles In this example several graph styles are applied one after the other to stroke symbols and errorbars for the given data. This can be achieved by passing a list of graph styles as the second parameter to the graph style. ... When you do set the second argument in the graphs plot command, default graph styles are used to plot the data. The default for the graph styles depend is a property of the data instance passed in the first argument of the plot command. While the list and file data instances use a `graph.style.symbol` instance by default, for functions and parametric functions a `graph.style.line` instance is used. The style instances parse the column names for appropriate entries to generate the corresponding output. In this case, the `x` and `y` values are used by both, the symbol and the errorbar style, whereas `dy` is used by the `errorbar` style only. ! You could also provide data for `ymin` and `ymax` to the errorbar style instead of `dy`. The errorbar style can also draw errorbars in x-direction using `dx` or `xmin` and `xmax`. You can add errorbars in both graph directions at the same time. !! The `x` and `y` data is not used by the symbol style nor the errorbar style directly (except for calculating the minimal and maximal value in y-direction by the errorbar due to the parametrization by `y` and `dy`). Instead a positioning style is inserted implicitly (a instance of graph.style.pos) as a position information is needed by the symbol and errorbar styles. By that the styles don't need to perform certain operations several times. Additionally the styles can also be used on graphs, which behave different in their positioning properties like bar graphs where you can use the same styles by just using a different positioning style. pyx-project-pyx-21f71ce/examples/graphstyles/histogram.py000066400000000000000000000005351526513311100237610ustar00rootroot00000000000000from pyx import * d = graph.data.points([(1, 0.3), (2, -0.7), (3, -0.3), (4, 0.8), (5, 0.5)], x=1, y=2) g = graph.graphxy(width=8) g.plot(d, [graph.style.histogram()]) g.writeEPSfile("histogram") g.writePDFfile("histogram") g.writeSVGfile("histogram") pyx-project-pyx-21f71ce/examples/graphstyles/histogram.txt000066400000000000000000000013201526513311100241410ustar00rootroot00000000000000Creating a histogram Styles can alter the way data is presented in arbitrary ways. Here the histogram style is used to generate a histogram. ... By default the histogram draws a box for each histogram value, but you can set the `step` parameter of the histogram style to use steps instead. ! In this basic use-case the histogram is calculated out of equal-spaced x-values automatically. You can also use errorbar like data in one graph dimension to generate histograms with different widths of the histogram boxes. ! Note that a histogram is very different from a bar graph in that it uses regular axes (like the default linear axes in this example) in both graph dimensions. Instead, bar graphs use a discrete axis. pyx-project-pyx-21f71ce/examples/graphstyles/usesymbol.py000066400000000000000000000015751526513311100240130ustar00rootroot00000000000000from pyx import * # colors and symbols to use (alternatingly) colors = [color.rgb.red, color.rgb.green, color.rgb.blue, color.gray.black] symbols = [graph.style._diamondsymbol, graph.style._trianglesymbol, graph.style._circlesymbol] # create the graph styles to be used below symbol = graph.style.symbol(symbol=attr.changelist(symbols), symbolattrs=[deco.stroked.clear, attr.changelist([deco.filled([cc]) for cc in colors])]) line = graph.style.line(lineattrs=[attr.changelist(colors), attr.changelist([style.linestyle.solid])]) g = graph.graphxy(width=8, x=graph.axis.linear(min=0, max=1)) g.plot([graph.data.function("y(x) = x**%d" % i, points=8) for i in range(1, 7)], styles=[line, symbol]) g.writeEPSfile("usesymbol") g.writePDFfile("usesymbol") g.writeSVGfile("usesymbol") pyx-project-pyx-21f71ce/examples/graphstyles/usesymbol.txt000066400000000000000000000011151526513311100241700ustar00rootroot00000000000000Using the functionality of existing graph styles This example demonstrates how linestyles, symboltypes, colors, and other decorations can be changed in existing graph styles. ... We make use of the `changelist` feature as an argument when using a style. Generally, all items in the attribute lists can be iterable `changelists`. If the end of such a list is reached, the changelist restarts from its beginning (see e.g. the colors which are used several times). The `attr.stroked.clear' in the symbol deletes the default property of the symbols, which says to stroke the symbol outline. pyx-project-pyx-21f71ce/examples/hello.py000066400000000000000000000002301526513311100205120ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.text(0, 0, "Hello, world!") c.stroke(path.line(0, 0, 2, 0)) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/examples/hello.txt000066400000000000000000000020221526513311100207020ustar00rootroot00000000000000Hello, world! As it is good practice to say "Hello, world!" in the first example, let's discuss how to do that in PyX. At first we import the PyX modules. Most PyX programs will start with a line like that. In order to produce some output we create a canvas instance `c`. Such an instance provides some useful methods to output some text at a certain position and for directly stroking a path, for which we use a `line` instance from the `path` module here. Once this is done, we write an EPS file and a PDF file containing all items inserted into the canvas instance. Since we did not pass a filename as argument to the write methods, the resulting files will just be named as the Python script - minus the extension, of course. This rather minimal example is quite useful for debugging your setup. In case of problems with your installation, you can add a `pyxinfo()` call immediately after the import. PyX will then write various information to `stderr`, which is quite helpful for yourself or when asking for help on the mailing list. pyx-project-pyx-21f71ce/examples/path/000077500000000000000000000000001526513311100177765ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/path/INDEX000066400000000000000000000000421526513311100205640ustar00rootroot00000000000000addjoin arclen at split intersect pyx-project-pyx-21f71ce/examples/path/README000066400000000000000000000003151526513311100206550ustar00rootroot00000000000000Path features In this section we demonstrate the capabilities of paths in PyX. The goal is to give an overview of those operations that are intrinsic to paths and do not affect their drawing on a canvas. pyx-project-pyx-21f71ce/examples/path/addjoin.py000066400000000000000000000010121526513311100217520ustar00rootroot00000000000000from pyx import * unit.set(wscale=10) c = canvas.canvas() c.stroke(path.line(0, 0, 1, 0) + path.line(1, 0, 1, 1) + path.line(1, 1, 0, 1) + path.line(0, 1, 0, 0)) c.stroke(path.line(2, 0, 3, 0) << path.line(3, 0, 3, 1) << path.line(3, 1, 2, 1) << path.line(2, 1, 2, 0)) p = path.line(4, 0, 5, 0) << path.line(5, 0, 5, 1) << path.line(5, 1, 4, 1) p.append(path.closepath()) c.stroke(p) c.writeEPSfile("addjoin") c.writePDFfile("addjoin") c.writeSVGfile("addjoin") pyx-project-pyx-21f71ce/examples/path/addjoin.txt000066400000000000000000000026261526513311100221550ustar00rootroot00000000000000Adding and joining paths The result of this example looks the same as the [''pathitem'' ../drawing/pathitem.html] example from the ''Basic drawing'' section. However, we are using a different approach to construct the paths in this example: we add and join paths. ... When ''adding'' two paths, the resulting path just contains all the subpaths from the first and the second path as its subpaths. The ''join'' operation between two paths is similar but it combines the last subpath from the first path and continues it by the first subpath of the second path. Thus, ''join'' does not increase the number of subpaths like the ''add'' operation. ! A similar result in terms of the line thickness could be achieved by setting a different scale for the linewidth by unit.set(wscale=10) immediately after the import statement. The unit system of PyX is aware of several length types (unscaleable ''true'' coordinates `t`, regular ''user'' coordinates `u`, ''visual'' coordinates `v` for arrows, symbols and other small visual components, line ''widths'' `w` and the ``text`` sizes `x`). The length types can be scaled independent of each other (except for ''true'' coordinates, which cannot be scaled at all). ! Note that joining two paths might insert a line connecting the first and the second path. For example, we could skip the second line when constructing `rect2` in our example above without any change in the result. pyx-project-pyx-21f71ce/examples/path/arclen.py000066400000000000000000000003331526513311100216130ustar00rootroot00000000000000from pyx import * c = canvas.canvas() p1 = path.curve(0, 0, 1, 0, 1, 1, 2, 1) p2 = path.line(0, 0, p1.arclen(), 0) c.stroke(p1) c.stroke(p2) c.writeEPSfile("arclen") c.writePDFfile("arclen") c.writeSVGfile("arclen") pyx-project-pyx-21f71ce/examples/path/arclen.txt000066400000000000000000000012501526513311100220010ustar00rootroot00000000000000Arc length of a path In this example we use the `arclen` method of the path instance `p1` to get the arc length and create a straight line `p2` with the same arc length. ... ! While here we use the return value of the arc length as a parameter to a path constructor, you might be interested in what kind of object the return value of the `arclen` method call really is: It is a PyX length in true coordinates, since the path already analyses the PyX units and the return value thus needs to be fixed and can not be scaled anymore. Printing the result of the `arclen` method call of path `p1` would show you: (0.023110 t + 0.000000 u + 0.000000 v + 0.000000 w + 0.000000 x) m pyx-project-pyx-21f71ce/examples/path/at.py000066400000000000000000000006521526513311100207570ustar00rootroot00000000000000from pyx import * def mark(x, y): return path.circle(x, y, 0.1) c = canvas.canvas() p1 = path.curve(0, 0, 1, 0, 1, 1, 2, 1) c.stroke(p1) c.fill(mark(*p1.atbegin())) c.fill(mark(*p1.at(0.5*p1.arclen()))) c.fill(mark(*p1.atend())) p2 = path.curve(3, 0, 4, 0, 4, 1, 5, 1) c.stroke(p2) c.fill(mark(*p2.at(p2.begin()+0.5))) c.fill(mark(*p2.at(p2.end()-0.5))) c.writeEPSfile("at") c.writePDFfile("at") c.writeSVGfile("at") pyx-project-pyx-21f71ce/examples/path/at.txt000066400000000000000000000034271526513311100211510ustar00rootroot00000000000000Positions along a path There are several methods to access certain positions at a path. At first there are `atbegin` and `atend` methods, which return a coordinate tuple. ... ! In this example, we have defined a small helper function `mark` to which we can pass the return value of the `at...` methods. We do this by transforming the sequence in to positional argument of the function call. This Python language feature is available by the `*` syntax in the call. ! The coordinates returned by the `at...` methods are PyX lengths in the unscaleable true units similar to the return value of the `arclen` method. For the left path `p1`, we also show how to use the `at` method, which can be used to get the coordinates of a certain point of the path depending on the arc length along the path. A different use of the `at` function is shown for the right path `p2`: It is also possible to pass parametrization instances of the path to the `at` method. In the shown case we first fetch such parametrization instances for the beginning and the end of the path by the `begin` and `end` methods. Note that the `atbegin` method is equal to call `at` with the result value of the `begin` method (except for optimizations: atbegin is faster than the two calls). Similar `atend` could be rewritten using the result value of `end`. As shown in the example you can use the parametrization instances to add and substract arc lengths from selected point. ! The `at` method of a path instance can not only handle a single value, in which case it returns a single result tuple. You can also pass a list to the method and the return value will contain a list of coordinate tuples. You should bear in mind that passing a list is much more efficient than multiple calls of the method performing single conversions at each time. pyx-project-pyx-21f71ce/examples/path/intersect.py000066400000000000000000000006641526513311100223560ustar00rootroot00000000000000from pyx import * p1 = path.curve(0, 0, 1, 0, 1, 1, 2, 1) p2 = path.circle(1, 0.5, 0.5) (a1, a2), (b1, b2) = p1.intersect(p2) x1, y1 = p1.at(a1) x2, y2 = p1.at(a2) c = canvas.canvas() c.fill(path.circle(x1, y1, 0.1), [color.rgb.blue]) c.fill(path.circle(x2, y2, 0.1), [color.rgb.blue]) c.stroke(p1, [color.rgb.red]) c.stroke(p2, [color.rgb.green]) c.writeEPSfile("intersect") c.writePDFfile("intersect") c.writeSVGfile("intersect") pyx-project-pyx-21f71ce/examples/path/intersect.txt000066400000000000000000000015231526513311100225400ustar00rootroot00000000000000Intersection points between paths The `intersect` method of a path allows for the calculation of intersection points between this path and the second path passed to the `intersect` method. ... The return value of the intersect method is a tuple of two lists, where each list contains parametrization instances for the intersection points. The first list are the parameters for the path the `intersect` method was called for. The second list are the parameter values for the path passed to the `intersect` method. Thus we can calculate the first intersection point `x1, y1` by x1, y1 = p1.at(a1) as done in the example or alternatively by x1, y1 = p2.at(b1) ! When several intersections between two paths occur, the order of the intersection points is defined by the order in which the points are passed when walking along the first path. pyx-project-pyx-21f71ce/examples/path/split.py000066400000000000000000000004521526513311100215040ustar00rootroot00000000000000from pyx import * p = path.curve(0, 0, 1, 0, 1, 1, 2, 1) p1, p2, p3 = p.split([0.5, p.end()-0.5]) c = canvas.canvas() c.stroke(p, [style.linewidth.Thin, color.rgb.red]) c.stroke(p2, [style.linewidth.Thick, color.rgb.green]) c.writeEPSfile("split") c.writePDFfile("split") c.writeSVGfile("split") pyx-project-pyx-21f71ce/examples/path/split.txt000066400000000000000000000023421526513311100216730ustar00rootroot00000000000000Splitting paths In this example we use the `split` method of a path to split it into several paths. Similar to the `at` method you can pass a list of numbers to the split method (or PyX length instances) to specify the splitting point by the arc length ... or you can use parametrization instances like the one returned by the `end` method, where you can substract a length to conventiently express a certain location measured from the end of the path. For a single splitting point, you can also pass the parameter directly instead of warpping this single value into a list. Note, however, that the return value of the `split` method is always a list; splitting a non-closed path at one point still yields two segments. ! When splitting at the beginning or the end of the path, one segment may be empty. Still PyX returns a corresponding path of length 0. ! When splitting at non-closed subpaths the result of the split method will be a list containing one path more than the number of splitting points. However, for a closed subpath a splitting at a single point will open the subpath but return a single path only. Consider a circle which you split at a single value: The result will still be a circle, but the path will not be closed anymore. pyx-project-pyx-21f71ce/examples/pyx.sty000066400000000000000000000000651526513311100204240ustar00rootroot00000000000000\def\PyX{P\kern-.3em\lower.5ex\hbox{Y}\kern-.18em X} pyx-project-pyx-21f71ce/examples/splitgraphs/000077500000000000000000000000001526513311100214025ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/splitgraphs/INDEX000066400000000000000000000000251526513311100221710ustar00rootroot00000000000000minimal splitatvalue pyx-project-pyx-21f71ce/examples/splitgraphs/README000066400000000000000000000012331526513311100222610ustar00rootroot00000000000000Split axes Split axes can be used to build axes containing axis breaks. While split axes work exactly like bar axes (they even share the same code except for the painter), their usage differs. A split axes has a tuple as its data value. The first value of the tuple identifies a sub-axis (for example by a unique integer) and the second is the value to be passed to the sub-axis. (For a bar axis, internally this is basically the same, but there the styles take care of the wrapping of the data into those tuples.) !! Note: Currently the graph styles are not aware of axis breaks. A generic notification mechanism for graph styles should be added at a later point. pyx-project-pyx-21f71ce/examples/splitgraphs/minimal.py000066400000000000000000000006401526513311100234020ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.split()) g.plot(graph.data.points([((0, 0.1), 0.1), ((0, 0.5), 0.2), ((0, 0.9), 0.3), ((1, 101), 0.7), ((1, 105), 0.8), ((1, 109), 0.9)], x=1, y=2)) g.writeEPSfile("minimal") g.writePDFfile("minimal") g.writeSVGfile("minimal") pyx-project-pyx-21f71ce/examples/splitgraphs/minimal.txt000066400000000000000000000006561526513311100236000ustar00rootroot00000000000000Minimal split-axis example This minimal example creates a split-axis by two simple modifications. ... First a splitaxis instance is passed to the graph constructor and secondly the data provided for this axis is modified to contain a tuple of two items. The first item is used as a dictionary key to identify the subaxis, to which the presented data belongs to. The second item in the tuple is used as the value on this subaxis. pyx-project-pyx-21f71ce/examples/splitgraphs/splitatvalue.py000066400000000000000000000004451526513311100244740ustar00rootroot00000000000000from pyx import * pf = graph.data.paramfunction g = graph.graphxy(width=8, x=graph.axis.split()) g.plot(pf("k", -1, 1, "x, y = splitatvalue(k, -0.9, 0.9), k**100", points=1000)) g.writeEPSfile("splitatvalue") g.writePDFfile("splitatvalue") g.writeSVGfile("splitatvalue") pyx-project-pyx-21f71ce/examples/splitgraphs/splitatvalue.txt000066400000000000000000000012641526513311100246630ustar00rootroot00000000000000Split axis at certain values A typical use-case for a split axis is to use some special positions on the axis to mark the axis breaks. ... For that the `splitatvalue` function is available in all places, where expressions are evaluated in the `graph.data` classes. Here we create a special parametric function where split positions for the x axis are added by the `splitatvalue` function and the y function is a simple polynomial of high order. Note that you can set several split positions by additional parameters of the `splitatvalue` function. In that case the `splitatvalue` function marks odd regions to be a "None", by which those data values are ignored by the `splitaxis` instance. pyx-project-pyx-21f71ce/examples/text/000077500000000000000000000000001526513311100200265ustar00rootroot00000000000000pyx-project-pyx-21f71ce/examples/text/INDEX000066400000000000000000000001301526513311100206120ustar00rootroot00000000000000halign valign font encoding marker color textengine unicodeengine textbox textalongpath pyx-project-pyx-21f71ce/examples/text/README000066400000000000000000000010151526513311100207030ustar00rootroot00000000000000Creating text One of the major features of PyX is to use the TeX typesetting engine to create text. PyX will start a single TeX or LaTeX instance as soon as text needs to be typeset. It passes the texts to this instance and directly reads the typeset information (dvi file) as created by the TeX interpreter. By this seamless and as far as we know unique integration, all advanced features of the TeX typesetting system like its high quality paragraph builder or the highly advanced math mode become available to PyX users. pyx-project-pyx-21f71ce/examples/text/color.py000066400000000000000000000006671526513311100215270ustar00rootroot00000000000000from pyx import * unit.set(uscale=2, xscale=2) col = color.cmyk.PineGreen text.set(text.LatexEngine) text.preamble(r"\usepackage{color}") text.preamble(r"\definecolor{COL}{cmyk}{%g,%g,%g,%g}" % (col.c, col.m, col.y, col.k)) c = canvas.canvas() c.text(0, 0, r"\textcolor{COL}{Text} and outline have the same color") c.stroke(path.rect(-0.2, -0.2, 6.2, 0.6), [col]) c.writeEPSfile("color") c.writePDFfile("color") c.writeSVGfile("color") pyx-project-pyx-21f71ce/examples/text/color.txt000066400000000000000000000023451526513311100217110ustar00rootroot00000000000000Using the same color in PyX and in LaTeX ! This example shows three different methods how to use a color defined in PyX also in LaTeX.... In the example code, we first define a cmyk color `col`, which is then used to define a color `COL` in LaTeX. The latter is then used in a LaTeX expression. ! The same behavior can be achieved by two different methods in `c.text`, r"\textcolor[named]{PineGreen}{Text} and outline ..." r"\textcolor[pyx]{color.cmyk.PineGreen}{Text} and outline ..." They are not as elegant as the above shown, since we need to insert the color definition `PineGreen` explicitly. The first alternative makes use of the `named` color model of color.sty. All colors of this model are predefined also in PyX. The other alternative allows to use PyX colors directly. !! Note that no graphics driver has been used for the color.sty LaTeX package. PyX performs a hack to enforce the use of its own LaTeX driver file pyx.def. In case that you have installed the three files `pyx.def`, `color.cfg`, and `graphics.cfg` from the PyX distribution somewhere in the LaTeX search path, it is possible to use text.set(mode="latex", pyxgraphics=0) text.preamble(r"\usepackage[pyx]{color}") which is the more aesthetic variant. pyx-project-pyx-21f71ce/examples/text/encoding.py000066400000000000000000000003271526513311100221700ustar00rootroot00000000000000from pyx import * text.set(text.LatexEngine, texenc='utf-8') text.preamble(r'\usepackage[utf8]{inputenc}') c = canvas.canvas() c.text(0, 0, r'Héllò, wørÅ‚d!') c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/examples/text/encoding.txt000066400000000000000000000007401526513311100223560ustar00rootroot00000000000000Typesetting non-ASCII characters with TeX TeX can typeset an enormous amount of characters. Historically it uses special TeX commands for individual characters. To directly use Unicode characters instead, the input encoding package of LaTeX can be used. To tell PyX to communicate with LaTeX in a certain character encoding differently from the default ASCII encoding, a `texenc` argument has to be passed to the `text.set` method as shown in the example for the UTF-8 encoding. pyx-project-pyx-21f71ce/examples/text/font.py000066400000000000000000000003701526513311100213460ustar00rootroot00000000000000from pyx import * text.set(text.LatexEngine) text.preamble(r"\usepackage{times}") c = canvas.canvas() c.text(0, 0, r"\LaTeX{} doesn't need to look like \LaTeX{} all the time.") c.writeEPSfile("font") c.writePDFfile("font") c.writeSVGfile("font") pyx-project-pyx-21f71ce/examples/text/font.txt000066400000000000000000000011771526513311100215430ustar00rootroot00000000000000Customize fonts In LaTeX, there are nice packages allowing to switch fonts. Hence, for a simple example we change the mode of the default textengine instance to LaTeX and use the `preamble` method to load the `times` package. ... !! In general, it is more easy to use LaTeX with it's NFSS (new font selection scheme) for font switching, although, in principle, this is also possible in TeX. The LaTeX Font Catalog at http://www.tug.dk/FontCatalogue/ lists common fonts, which can readily be used in LaTeX. Integrating other fonts into the LaTeX requires some work. Sometimes one can find ready-to-use adaptions on CTAN http://ctan.org/. pyx-project-pyx-21f71ce/examples/text/halign.py000066400000000000000000000017331526513311100216460ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.stroke(path.line(-5, 0, -5, 5)) c.stroke(path.line(0, 0, 0, 5)) c.stroke(path.line(5, 0, 5, 5)) c.text(-5, 5, r"boxleft", [text.halign.boxleft]) c.text(0, 5, r"boxcenter", [text.halign.boxcenter]) c.text(5, 5, r"boxright", [text.halign.boxright]) c.text(0, 4, r"boxcenter and flushleft", [text.parbox(3), text.halign.boxcenter, text.halign.flushleft]) c.text(0, 3, r"boxcenter and flushcenter", [text.parbox(3), text.halign.boxcenter, text.halign.flushcenter]) c.text(0, 2, r"boxcenter and flushright", [text.parbox(3), text.halign.boxcenter, text.halign.flushright]) c.text(-5, 0, r"left: boxleft and flushleft", [text.parbox(3), text.halign.left]) c.text(0, 0, r"center: boxcenter and flushcenter", [text.parbox(3), text.halign.center]) c.text(5, 0, r"right: boxright and flushright", [text.parbox(3), text.halign.right]) c.writeEPSfile("halign") c.writePDFfile("halign") c.writeSVGfile("halign") pyx-project-pyx-21f71ce/examples/text/halign.txt000066400000000000000000000027361526513311100220410ustar00rootroot00000000000000Horizontal alignment The example shows the result of the different text attributes for horizontal alignment. We first need to emphasize, that PyX distinguishes between the alignment of the text box and the alignment of the material within the text box. The first line in the output shows the effect of the box alignment created by `boxleft`, `boxcenter` and `boxright` leading to left, center, and right alignment of the text box with respect to the dotted lines. ... The middle part shows the examples for centering a box, but aligning the content differently inside the box, namely at the left box boundary by `flushleft`, at the center by `flushcenter` and at the right box boundary by `flushright`. Note, that such an alignment of material is available only when you create a parbox in TeX. This is easily done by means of the `parbox` attribute, where you have to specify the width of the box. At the bottom, you can see combinations of `boxleft` and `flushleft`, `boxcenter` and `flushcenter`, and `boxright` and `boxcenter` in action. These combinations are available by the attributes `left`, `center` and `right` to shortcut the setting of both corresponding attributes. You can use these shortcuts for box alignment as well, when you do not create a parbox. !! Note that the alignment features are implemented in such a way, that they work in both, TeX and LaTeX mode. Furthermore, you can always influence the alignment of the box contents by appropriate TeX and LaTeX commands as well. pyx-project-pyx-21f71ce/examples/text/marker.py000066400000000000000000000006741526513311100216700ustar00rootroot00000000000000from pyx import * unit.set(xscale=3) c = canvas.canvas() t = c.text(0, 0, r"Here\PyXMarker{id} is a marker.") center = t.marker("id") c.stroke(path.circle(center[0], center[1], 1), [color.rgb.red]) c.stroke(path.line(center[0]-1, center[1], center[0]+1, center[1]), [color.rgb.red]) c.stroke(path.line(center[0], center[1]-1, center[0], center[1]+1), [color.rgb.red]) c.writeEPSfile("marker") c.writePDFfile("marker") c.writeSVGfile("marker") pyx-project-pyx-21f71ce/examples/text/marker.txt000066400000000000000000000006401526513311100220500ustar00rootroot00000000000000Using markers The example shows how to obtain specific coordinates in a (La)TeX text. This allows to mark specific portions of text, setting arrows, braces and many more. A marker can be set with the command `\PyXMarker`... which takes the name of the marker as an argument (`id` in the example code). The position of the marker can then be obtained from the textbox, which is returned by the `canvas.text` method. pyx-project-pyx-21f71ce/examples/text/textalongpath.py000066400000000000000000000010301526513311100232540ustar00rootroot00000000000000from pyx import * c = canvas.canvas() p = path.path(path.moveto(-2, 0), path.curveto(-1, 0, -1, 1, 0, 1), path.curveto(1, 1, 1, 0, 2, 0)) c.stroke(p, [deco.curvedtext(r"\PyX{} is fun!"), deco.curvedtext("left", textattrs=[text.halign.left, text.vshift.mathaxis], arclenfrombegin=0.5, exclude=0.1), deco.curvedtext("right", textattrs=[text.halign.right, text.vshift.mathaxis], arclenfromend=0.5, exclude=0.1)]) c.writeEPSfile("textalongpath") c.writePDFfile("textalongpath") c.writeSVGfile("textalongpath") pyx-project-pyx-21f71ce/examples/text/textalongpath.txt000066400000000000000000000011001526513311100234410ustar00rootroot00000000000000Text along path In order to set text along a given path, you can use the `curvedtext()` decorator. The example shows a few useful parameter settings for this decorator. ! To output just the curved text, but not the path, you can use the draw method of the canvas instead of the stroke method. By that the path is omitted in the output completely. In contrast, if you set the linewidth to zero instead, the path will still be visible, as those lines will be rendered as the thinnest available linewidth on the output device according to the PostScript and PDF specification. pyx-project-pyx-21f71ce/examples/text/textbox.py000066400000000000000000000004611526513311100220760ustar00rootroot00000000000000from pyx import * unit.set(xscale=3) tbox = text.text(0, 0, r"Boxed text") tpath = tbox.bbox().enlarged(3*unit.x_pt).path() c = canvas.canvas() c.draw(tpath, [deco.filled([color.cmyk.Yellow]), deco.stroked()]) c.insert(tbox) c.writeEPSfile("textbox") c.writePDFfile("textbox") c.writeSVGfile("textbox") pyx-project-pyx-21f71ce/examples/text/textbox.txt000066400000000000000000000020271526513311100222650ustar00rootroot00000000000000Enlarge the surrounding of a textbox ! This example introduces the concept of the `textbox`, which is a canvas-like structure containing the text and its surrounding path and reference point. We demonstrate how to enlarge the surrounding box a little and use it as a decoration of the path. ... ! The `textbox` is a specialized version of the [`box` concept ../../roadmap.html] which has been introduced into PyX in a preliminary version. In the example, we obtain the bounding box (this is a `bbox` instance, not to be mixed up with the `box`) and enlarge it a bit. We then draw the path of the bounding box. ! In future releases of PyX, the boxes will have generic support for enlarging. The syntax will then be tpath = tbox.enlarged(3*unit.x_pt).path() ! An alternative, geometrically different approach to enlarging the textbox path is via an appropriate transformation, such as tbox = text.text(0, 0, r"Boxed text", [text.halign.boxcenter, text.valign.middle]) tpath = tbox.path().transformed(trafo.scale(1.5, 1.5, 0, 0)) pyx-project-pyx-21f71ce/examples/text/textengine.py000066400000000000000000000014301526513311100225500ustar00rootroot00000000000000from pyx import * # Set properties of the defaulttextengine, e.g. switch to LaTeX. text.set(text.LatexEngine) c = canvas.canvas() # The canvas, by default, uses the defaulttextengine from the text module. # This can be changed by the canvas method settextengine. c.text(0, 0, r"This is \LaTeX.") # If you want to use another textengine temporarily, you can just insert # a text box manually plaintex = text.TexEngine() # plain TeX engine c.insert(plaintex.text(0, -1, r"This is plain \TeX.")) # There also is the UnicodeEngine to output text directly without TeX/LaTeX. unicodetext = text.UnicodeEngine() # unicode engine c.insert(unicodetext.text(0, -2, "Simple unicode output without TeX/LaTeX.")) c.writeEPSfile("textengine") c.writePDFfile("textengine") c.writeSVGfile("textengine") pyx-project-pyx-21f71ce/examples/text/textengine.txt000066400000000000000000000024161526513311100227440ustar00rootroot00000000000000Running and controlling TeX ! Usually, all you will ever need is a single `textengine` instance which controls a single running TeX or LaTeX instance at a time or uses direct Unicode text typesetting. To make life easy to our users..., such an instance is created automatically upon startup and its called the `defaulttextengine`. Whenever you use the function shortcuts like `text.text()` and in particular `text.set()`, you are accessing this `defaulttextengine` instance. Also, the shortcut method `text` of any canvas instance uses this `defaulttextengine` by default. !! However, it is possible to create several textengine instances. In this example, we are using three of them. To make it a little more interesting, we instruct the `defaulttextengine` to use LaTeX, while keeping TeX for the `plaintex` instance. It is you turn to use expressions valid in TeX or LaTeX only at the different `textengine` instances. Additionally we show the use of a `unicodetext` instance to typeset Unicode text. !! Note that you do not have to worry about mixing the results of different textengines into a single output. Even the embedded fonts in the output are shared. You can, by the way, also restart a plain TeX or LaTeX engines including the `defaulttextengine`, which is a plain TeX engine. pyx-project-pyx-21f71ce/examples/text/unicodeengine.py000066400000000000000000000010031526513311100232060ustar00rootroot00000000000000from pyx import * text.set(text.UnicodeEngine) c = canvas.canvas() c.text(0, 2, "Hello, world!") # We support basic primitives for math typesetting of numbers. c.text(0, 1, ["a large value: 10", text.Text("100", shift=0.5, scale=0.8)]) c.text(0, 0, ["a fraction: ", text.StackedText([text.Text("1", shift=0.3), text.Text("42", shift=-0.9)], frac=True, align=0.5)]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/examples/text/unicodeengine.txt000066400000000000000000000004711526513311100234050ustar00rootroot00000000000000Unicode engine PyX supports basic text output without using TeX/LaTeX by `text.UnicodeEngine` instances.... The font defaults to Computer Modern at 10 pt. It can be set by parameters of the constructor and for the default engine via the set command: text.set(text.UnicodeEngine, fontname="cmss10", size=14) pyx-project-pyx-21f71ce/examples/text/valign.py000066400000000000000000000022071526513311100216610ustar00rootroot00000000000000from pyx import * c = canvas.canvas() # apply global TeX setting text.preamble(r"\parindent=0pt") w = 1.2 # an appropriate parbox width for spam & eggs # vertical alignments by margins c.stroke(path.line(0, 4, 8, 4), [style.linewidth.THin]) c.text(0, 4, r"spam \& eggs", [text.parbox(w), text.valign.top]) c.text(3, 4, r"spam \& eggs", [text.parbox(w), text.valign.middle]) c.text(6, 4, r"spam \& eggs", [text.parbox(w), text.valign.bottom]) # vertical alignments by baselines c.stroke(path.line(0, 2, 8, 2), [style.linewidth.THin]) c.text(0, 2, r"spam \& eggs", [text.parbox(w, baseline=text.parbox.top)]) c.text(3, 2, r"spam \& eggs", [text.parbox(w, baseline=text.parbox.middle)]) c.text(6, 2, r"spam \& eggs", [text.parbox(w, baseline=text.parbox.bottom)]) # vertical shifts c.stroke(path.line(0, 0, 8, 0), [style.linewidth.THin]) c.text(0, 0, r"x=0", [text.mathmode, text.vshift.topzero]) c.text(2, 0, r"x=0", [text.mathmode, text.vshift.middlezero]) c.text(4, 0, r"x=0", [text.mathmode, text.vshift.bottomzero]) c.text(6, 0, r"x=0", [text.mathmode, text.vshift.mathaxis]) c.writeEPSfile("valign") c.writePDFfile("valign") c.writeSVGfile("valign") pyx-project-pyx-21f71ce/examples/text/valign.txt000066400000000000000000000051361526513311100220540ustar00rootroot00000000000000Vertical alignment The example demonstrates the effect of several text attributes for vertical alignment. In the first line of the output, the extent of the whole text box is taken into account by various versions of valign. While in this case, the valign attributes are combined with a parbox each, the valign technique also perfectly works for single line text. ... In contrast, in the second line of the output a parbox is shown with different values for the baseline. Note that by default, text is vertically aligned at its baseline, that is, the line the letters are typed upon. For a parbox containing several lines, there are several choices. PyX allows you to use the top-most baseline (which is, by the way, the default when skipping the baseline keyword argument of the parbox completely), and the bottom-most baseline in your paragraph. Additionally you can also use the position just in the middle of these two cases. Since the alignment along a baseline does not depend on the size of the characters in your output, it is preferable to valign in most use-cases. In the last line of the output, the text.vshift is used to create some vertical shift of the output corresponding to certain criteria. The universal case is to use a certain fraction of a character height (or the height of any TeX expression). For `vshift.topzero` the full height of the character `0` is used, for `vshift.middlezero` half of the height of the character `0` is used and for `vshift.bottomzero`, no shift will be done at all and the usual alignment at the baseline will take place. Another interesting vertical shift value is the `vshift.mathaxis`, which shifts the material by the height of the mathematical axis. This axis is used by TeX to vertically align the mathematical operators and the equal sign but also brackets and objects like the sum and integral symbols. This shift typically is a little less in height as compared to `vshift.middlezero` and fits well in various cases to visually center a single line output in vertical direction. It is also useful to align text, although the value of the shift is based on the configuration of the mathematical mode. This means that the alignment might not be suitable for cases, where the text mode of TeX was reconfigured without also adapting the math mode configuration. ! Please don't get confused by the additional text.mathmode attribute in this vshift example, which leads the text to be rendered in TeX's mathematical mode. The `text.mathmode` attribute is by the way similar but not identical (due to the use of `\displaystyle`) to encapsulating your expression in TeX's mathmode delimiters `$`. pyx-project-pyx-21f71ce/faq/000077500000000000000000000000001526513311100157735ustar00rootroot00000000000000pyx-project-pyx-21f71ce/faq/.gitignore000066400000000000000000000000071526513311100177600ustar00rootroot00000000000000_build pyx-project-pyx-21f71ce/faq/Makefile000066400000000000000000000015321526513311100174340ustar00rootroot00000000000000# Makefile for Sphinx documentation # PYTHON ?= python3 # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean all html latexpdf all: html latexpdf @echo "Done." clean: -rm -rf $(BUILDDIR)/* *.eps *.pdf *.png html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." make -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." pyx-project-pyx-21f71ce/faq/conf.py000066400000000000000000000154061526513311100173000ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # pyxfaq documentation build configuration file, created by # sphinx-quickstart on Sun Jun 12 16:54:07 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os sys.path.insert(0, '..') import pyx.version # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.todo'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = 'pyxfaq' copyright = '2011, Gert-Ludwig Ingold' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '.'.join(pyx.version.version.split('.')[:1]) # The full version, including alpha/beta/rc tags. release = pyx.version.version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: today = pyx.version.date # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'pyx' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = {'sidebarwidth': 200} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['../manual/theme'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = 'PyX FAQ' # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} html_sidebars = { '**': ['localtoc.html', 'sourcelink.html', 'searchbox.html'] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'pyxfaqdoc' todo_include_todos = True # gli # -- Options for LaTeX output -------------------------------------------------- # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'pyxfaq.tex', 'Some frequently and not so frequently asked questions about PyX', 'Gert-Ludwig Ingold', 'manual'), ] latex_elements = { 'papersize': 'a4paper', 'preamble': r''' \hypersetup{pdftitle={%s}, pdfauthor={Gert-Ludwig Ingold }, pdfsubject={FAQ for PyX}, pdfkeywords={PyX, graphics, tipps and tricks, FAQ}} \DeclareUnicodeCharacter{028F}{{\fontsize{7}{7}\selectfont Y}} ''' % latex_documents[0][2] } # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'pyxfaq', 'pyxfaq Documentation', ['Gert-Ludwig Ingold'], 1) ] pyx-project-pyx-21f71ce/faq/general_aspects_plotting.rst000066400000000000000000000021701526513311100236040ustar00rootroot00000000000000==================================== General aspects of plotting with PyX ==================================== How do I generate multipage output? =================================== With versions 0.8 and higher it is possible to produce multipage output, i.e. a Postscript or PDF file containing more than one page. In order to achieve this, one creates pages by drawing on a canvas as usual and appends them in the desired order to a document from which Postscript or PDF output is produced. The following example serves as an illustration:: from pyx import * d = document.document() for i in range(3): c = canvas.canvas() c.text(0, 0, "page %i" % (i+1)) d.append(document.page(c, paperformat=document.paperformat.A4, margin=3*unit.t\_cm, fittosize=1)) d.writePSfile("multipage") Here, ``d`` is the document into which pages are inserted by means of the ``append`` method. When converting from a canvas to a document page, the page properties like the paperformat are specified. In the last line, output is produced from document ``d``. pyx-project-pyx-21f71ce/faq/general_aspects_pyx.rst000066400000000000000000000216621526513311100225730ustar00rootroot00000000000000====================== General aspects of PyX ====================== The name of the game ==================== Originally, the name PyX was constructed as a combination of **P**\ ostscript, i.e. the first output format supported by PyX, P\ **y**\ thon, i.e. the language in which PyX is written, and Te\ **X**, i.e. the program which PyX uses for typesetting purposes. Actually, the title of this question is a tribute to TeX because it is taken from the first chapter of the TeX book [#texbook]_ where the origin of the name TeX and its pronunciation are explained. Despite the ties between TeX and PyX, their pronunciation is quite different. According to the developers of PyX, it should be pronounced as [pÊ�ks]. Please do not pronounce it as [pÊ�x] or [pÊ�ç]. .. _where_do_I_get_PyX: Where do I get the latest version of PyX? ========================================= The current release of PyX (as well as older ones) is freely available from `https://pyx-project.org `_ where also a subversion repository with the latest patches can be found. In addition, PyX is registered on the Python Package Index at `https://pypi.org/project/PyX `_ and can be installed by ``easy_install`` and ``pip``. As PyX is hosted on PyPI, it can be directly downloaded and installed by ``pip``. Please see the `pip documentation `_ for details. Possibly older versions of PyX are also available as package for various Linux distributions: see, for instance, `https://packages.debian.org/stable/python3-pyx `_ for information on the PyX package in Debian GNU/Linux, `https://packages.ubuntu.com/jammy/python3-pyx `_ for Ubuntu, `https://software.opensuse.org/package/python-PyX `_ for OpenSUSE, and `https://archlinux.org/packages/extra/any/python-pyx `_ for Arch Linux. PyX has no dependencies on other Python packages. How can I determine the version of PyX running on my machine? ============================================================= Start a python session (usually by typing ``python`` at the system prompt) and then type the following two commands (``>>>`` is the python prompt) >>> import pyx >>> pyx.__version__ Note that there are two underscores before and after ``version``. How can I access older versions of PyX? ======================================= There are reasons which might make it necessary to use older versions of PyX. If you are using Python 2 you will need PyX version 0.12.1 or earlier (see :ref:`python_requirements`). Furthermore, as at present it is not guaranteed that PyX is backward compatible, it may be desirable to access an older version of PyX instead of adapting older code to a more recent version of PyX. In order to do that, one needs the corresponding PyX package (see :ref:`where_do_I_get_PyX` if you need to download it), which should be unpacked below a directory, e.g. ``/home/xyz/Python``, where you want to keep the various PyX versions. This will result in a subdirectory with a name like ``PyX-0.16`` which contains the contents of the corresponding package. You can then ask Python to first look in the appropriate directory before looking for the current version of PyX by inserting the following code (appropriately modified according to your needs) at the beginning of your program before importing the PyX module:: import sys sys.path.insert(0, "/home/xyz/Python/PyX-0.16") Including appropriate lines even if the current version of PyX is used, might turn out to be helpful when the current version has become an old version (unless you have no difficulties determining the PyX version by looking at your code). If your operating system supports path expansion, you might use as an alternative:: import sys, os sys.path.insert(0, os.path.expanduser("~/Python/PyX-0.16")) which will expand the tilde to your home directory. Does PyX run under my favorite operating system? ================================================ Yes, if you have installed Python (:ref:`what_is_python`) and TeX (:ref:`what_is_tex`). Both are available for a large variety of operating systems so chances are pretty good that you will get PyX to work on your system. .. _python_requirements: Under which versions of Python will PyX run? ============================================ Starting with version 0.13, PyX requires Python 3.2 or higher. If you still need to run PyX with Python 2, you should use version 0.12.1 which is designed to run with Python 2.3 up to 2.7. The version of your Python interpreter can be determined by calling it with the option ``-V``. Alternatively, you can simply start the interpreter and take a look at the startup message. Note that there may be different versions of Python installed on your system at the same time. The default Python version need not be the same for all users. Does PyX provide a GUI to view the produced image? ================================================== No, PyX itself does not provide a means to view the produced image. The result of a PyX run is an EPS (= Encapsulated PostScript) file, a PS (= PostScript) file, a PDF (= Portable Document Format) file or a SVG (= Scalable Vector Graphics) file, which can be viewed, printed or imported into other applications. There are several means of viewing PS and EPS files. A common way would be to use ``ghostview`` which provides a user interface to the PostScript interpreter ``ghostscript``. More information about this software, which is available for a variety of platforms, can be found at `http://www.cs.wisc.edu/~ghost/ `_. If you do not own a printer which is capable of printing PostScript files directly, ``ghostscript`` may also be useful to translate PS and EPS files produced by PyX into something your printer will understand. PDF files can be viewed by means of the ``Adobe Reader ®`` available from `http://www.adobe.com/products/acrobat/readstep2.html `_. On systems running X11, ``xpdf`` might be an alternative. It is available from `http://www.foolabs.com/xpdf/ `_. SVG files can be viewed by webbrowsers like Firefox available at `https://www.mozilla.org/en-US/firefox `_ or Chrome available at `https://www.google.com/chrome/ `_. If you want to do interactive development of a PyX graphics, you might consider to use an IPython notebook (see :ref:`pyx_ipython_notebook`). .. _pyx_ipython_notebook: Will I be able to embed PyX graphics output into an IPython notebook? ===================================================================== Yes, PyX canvas object and objects inheriting from the canvas class, in particular graphs and text, can be embedded into an IPython notebook. Suppose you have a canvas object called ``c`` on which you have done some drawing. Then entering ``c`` in an IPython notebook cell and executing that cell will automatically produce a SVG representation and embed it into the notebook. (Alternatively, also PNG is available by means of ghostscript, but the default display_order of IPython prefers SVG over PNG.) For more information on IPython and working with its notebooks see `http://www.ipython.org/ `_. I am a Gnuplot user and want to try PyX. Where can I get some help? =================================================================== There exists a tutorial by Titus Winters which explains how to perform standard Gnuplot tasks with \PyX. The tutorial can be found at `http://www.cs.ucr.edu/~titus/pyxTutorial/ `_. Where can I get help if my question is not answered in this FAQ? ================================================================ The PyX sources contain a reference manual which is also available online at `https://pyx-project.org/manual/ `_. Furthermore, there exists a set of examples demonstrating various features of PyX, which is available in the sources or can be browsed at `https://pyx-project.org/examples.html `_. If the feature you are looking for is among them, using the appropriate part of the example code or adapting it for your purposes may help. There is also a user discussion list about PyX which you can subscribe to at `http://lists.sourceforge.net/lists/listinfo/pyx-user `_. The archive of the discussion list is available at `http://sourceforge.net/mailarchive/forum.php?forum_name=pyx-user `_. Finally, it might be worth checking `https://pyx-project.org/pyxfaq.pdf `_ for an updated version of this FAQ. .. [#texbook] D.Knuth, *The TeX book* (Addison-Wesley, 1984) pyx-project-pyx-21f71ce/faq/index.rst000066400000000000000000000014441526513311100176370ustar00rootroot00000000000000.. pyxfaq documentation master file, created by sphinx-quickstart on Sun Jun 12 16:54:07 2011. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Some frequently and not so frequently asked questions about PyX =============================================================== .. topic:: Acknowledgements The following persons have in one way or the other, e.g. by asking good questions or providing answers, contributed to this FAQ: Walter Brisken, Alejandro Gaita-Arinyo, Pierre Joyot, Jörg Lehmann, John Owens, Michael Schindler, Gerhard Schmid, André Wobst. .. toctree:: :maxdepth: -1 general_aspects_pyx python general_aspects_plotting plotting_graphs other_plotting tex_latex unicode_text pyx-project-pyx-21f71ce/faq/other_plotting.rst000066400000000000000000000020461526513311100215700ustar00rootroot00000000000000==================== Other plotting tasks ==================== How can I rotate text? ====================== Text can be written at an arbitrary angle by specifying the appropriate transformation as an attribute. The command :: c.text(0, 0, "Text", [trafo.rotate(60)]) will write at an angle of 60 degrees relative to the horizontal axis. If no pivot is specified (like in this example), the text is rotated around the reference point given in the first two arguments of ``text``. In the following example, the pivot coincides with the center of the text:: c.text(0, 0, "Text", [text.halign.center,text.valign.middle,trafo.rotate(60)]) How can I clip a canvas? ======================== In order to use only a part of a larger canvas, one may want to clip it. This can be done by creating a clipping object which is used when creating a canvas instance:: clippath = path.circle(0.,0.,1.) clipobject = canvas.clip(clippath) c = canvas.canvas([clipobject]) In this example, the clipping path used to define the clipping object is a circle. pyx-project-pyx-21f71ce/faq/plotting_graphs.rst000066400000000000000000000402761526513311100217420ustar00rootroot00000000000000================== Plotting of graphs ================== General aspects =============== .. _mingraphdata: How do I generate a graph from data as simply as possible? ---------------------------------------------------------- Suppose that you have a data file ``x.dat`` containing values for ``x`` and ``y`` in two columns. Then the following code will do the job:: from pyx import * g = graph.graphxy(width=10) g.plot(graph.data.file("x.dat", x=1, y=2)) g.writeEPSfile("x") ``graphxy`` creates a canvas (called ``g`` in this example) onto which the graph will be drawn and it sets the default behavior including the axis. There is, however, no default value for the width of the graph. In ``plot`` you have to specify the name of the data file and the columns from which the data should be taken. Finally, ``writeEPSfile`` will generate the postscript file ``x.eps`` which you can view or print. A minimal example is also provided in the PyX distribution as ``examples/graphs/minimal.py``. .. _mingraphfunc: How do I generate a graph of a function as simply as possible? -------------------------------------------------------------- The following example will draw a parabola:: from pyx import * g = graph.graphxy(width=10, x=graph.axis.linear(min=-2, max=2) ) g.plot(graph.data.function("y(x)=x**2")) g.writeEPSfile("x") Most of the code has been explained in :ref:`mingraphdata`. The main difference is that here you need to specify minimum and maximum for the ``x``-axis so that PyX knows in which range to evaluate the function. Another, slightly more complex, example is also provided in the PyX distribution as ``examples/graphs/piaxis.py``. How can I stack graphs? ----------------------- PyX always needs a canvas to draw on. One possibility therefore consists in creating a new canvas with :: c = canvas.canvas() and inserting the graphs into this canvas with ``c.insert(…)``. Here, ``…`` has to be replaced by the name of the graph. Alternatively, the canvas created with ``graph.graphxy`` for one of the graphs can be used to insert the other graphs even if they will be positioned outside the first graph. The second issue to address is positioning of the graphs. By specifying ``xpos`` and ``ypos`` when calling ``graphxy`` you can define the position of a graph. Later on, the position and size of a graph ``g`` can be referred to as ``g.xpos`` ``g.ypos`` ``g.width`` and ``g.height`` even if for example the height has never been specified explicitly but is only defined by a PyX default. The following example shows how to put graph ``gupper`` above graph ``glower`` on a canvas ``c``:: from pyx import * from graph import graphxy c = canvas.canvas() glower = graphxy(width=10) glower.plot(...) c.insert(glower) gupper = graphxy(width=10, ypos=glower.ypos+glower.height+2) gupper.plot(...) c.insert(gupper) c.writeEPSfile(...) where ``…`` has to be replaced by the appropriate information like data and symbol specifications and the name of the output file. Here, ``c.insert`` is used to actually insert the subcanvasses for the graphs into the main canvas ``c`` and ``c.writeEPSfile`` in the last line requests to write the contents of this canvas to a file. How can I plot grid data? ------------------------- PyX offers support for plotting three-dimensional data as two-dimensional color plots or grey-scale plots and of vector fields by providing ways to plot rectangles and arrows in graphs. We start by considering the task of creating a two-dimensional color plot by plotting a number of filled rectangles. One first needs to create a data set which consists of five entries per data point. These are the lower left corner (*x*\ :sub:`min`, *y*\ :sub:`min`) and the upper right corner (*x*\ :sub:`max`, *y*\ :sub:`max`) of the triangle and a value between 0 and 1 determining the color via a PyX color palette. The following code gives an idea of how to proceed:: g.plot(graph.data.file("datafile.dat", xmin=1, xmax=2, ymin=3, ymax=4, color=5), [graph.style.rect(color.palette.ReverseRainbow)] ) g.dodata() Here, we assume that the data are stored in ``datafile.dat`` and the columns contain *x*\ :sub:`min`, *x* :sub:`max`, *y*\ :sub:`min`, *y*\ :sub:`max`, and the color value in this order. The columns are numbered from 1, since the 0th column contains the line number. To determine the color, we use the ``ReverseRainbow`` palette. The last line instructs PyX to plot the rectangles before plotting the axes. Otherwise, the axes might be covered partially by the rectangles and, in particular, the ticks might not be visible. Gray-scale plots can easily be generated by specifying the palette ``Gray`` or ``ReverseGray`` (cf. appendix C of the manual for a list of predefined palettes). At first sight, it seems surprising that plotting of grid data requires the specification of four coordinates for the rectangle. The reason is that this allows to draw rectangles of varying sizes which may help to reduce the size of the postscript file by combining rectangles of the same color in horizontal or vertical direction. For example, it may be sufficient to plot a grey-scale image in a small number of grey shades and then combining rectangles may be appropriate. Note, though, that this step is part of the data creation and not preformed by PyX. Another advantage of fully specifying each rectangle is that it is straightforward to leave parts of the graph blank. The same ideas as for the color plot can be applied to plot vector fields where each data point is represented by an arrow. In this case a data point is specified by the position of the arrow, its size and its direction as indicated in the following code snippet:: g.plot(graph.data.file("datafile.dat"), x=1, y=2, size=3, angle=4), [graph.style.arrow()] ) Complete code examples can be found in ``examples/graphs/mandel.py`` and ``examples/graphs/arrows.py`` . .. _problemcoord: How can I access points in problem coordinates of a graph? ---------------------------------------------------------- Sometimes it may be necessary to add graphical elements to a graph in addition to the data or function(s) which have been plotted as described in :ref:`mingraphdata` and :ref:`mingraphfunc`. For a graph instance ``g`` the positioning can easily be done in canvas coordinates by making use of the origin (``g.xpos``, ``g.ypos``) and the width (``g.width``) and height (``g.height``) of the graph. Occasionally, it may be more convenient to specify the position of the additional material in terms of problem coordinates. However, this requires that the mapping from problem coordinates to canvas coordinates is known. By default this is not the case before the content of the canvas is written to the output which is too late for our purpose. One therefore needs to explicitly instruct PyX to determine this mapping. One possibility is to ask PyX to finish the graph by means of ``g.finish()``. Now, problem coordinates can be used to insert additional material which will end up in front of the graph. If this is not desired, one should only fix the layout of the graph by means of ``g.dolayout()``. Then, the additional material can be put onto the canvas before the graph is drawn and it will therefore appear behind the graph. The conversion of problem coordinates (``px``, ``py``) to canvas coordinates (``x``, ``y``) is performed as follows:: x, y = g.pos(px, py) By default, the problem coordinates will refer to the ranges of the *x* and *y* axes. If several axes with different ranges exist, the instances of the desired axes should be passed to the ``pos`` method by means of the keyword arguments ``xaxis`` and ``yaxis``. We remark that the drawing of lines parallel to one of the axes at specific problem coordinates can also be done by adapting the method described in :ref:`zeroline`. I would like a key for only some of my data sets. How do I do that? ------------------------------------------------------------------- .. todo:: This still needs to be answered. Axis properties =============== How do I specify the tick increment? ------------------------------------ In the partition of a linear axis, the increments associated with ticks, subticks etc. can be specified as argument of ``parter.linear``. In the following example, ticks will be drawn at even values while subticks will be drawn at all integers:: from pyx.graph import axis tg = graph.graphxy(width=10, x=axis.linear(min=1, max=10, parter=axis.parter.linear(tickdists=[2,1])) ) .. _zeroline: How do I plot the zero line? ---------------------------- PyX releases before 0.6 offered the possibility to stroke a zero line by specifying ``zeropathattrs`` in the painter constructor. In more recent releases, one proceeds as follows. First one has to fix the layout information of the graph by means of the ``finish`` or ``dolayout`` method (see :ref:`problemcoord` for a more detailed explanation). Then, the ``xgridpath`` or ``ygridpath`` method of a graph will return a grid path parallel to the *y* or *x* axis, respectively, at the specified *y* value. As an example, a zero line in *x* direction can be drawn as follows:: g.finish() g.stroke(g.ygridpath(0)) How can I add grid lines to a graph? ------------------------------------ Specifying ``gridattrs`` for the painter of an axis will generate grid lines orthogonal to this axis. At least an empty list is needed like in :: g = graph.graphxy(width=10, x=graph.axis.linear(painter=graph.axis.painter.regular(gridattrs=[])), y=graph.axis.linear() ) where grid lines in vertical direction are drawn in default style. Occassionally, one might want to draw grid lines corresponding to ticks and subticks in a different style. This can be achieved by specifiying changeable attributes using ``changelist``. The following code :: my_xpainter = graph.axis.painter.regular(gridattrs= [attr.changelist([style.linestyle.solid, style.linestyle.dashed])] ) my_ypainter = graph.axis.painter.regular(gridattrs= [attr.changelist([color.rgb.red, color.rgb.blue])] ) g = graph.graphxy(width=10, x=graph.axis.linear(painter=my_xpainter), y=graph.axis.linear(painter=my_ypainter) ) will create vertical solid and dashed grid lines for ticks and subticks, respectively. The horizontal grid lines will be red for ticks and blue for subticks. The changeable attributes are applied in a cyclic manner. Therefore, in this example grid lines at subsubticks would be plotted in the same style as for ticks. If this is not desired, the list of attributes should be extended by an appropriate third style. The keyword ``None`` will switch off the respective level of grid lines in case you want to draw them only e.g. for ticks but not subticks. Data properties =============== How do I choose the symbol and its attributes? ---------------------------------------------- Suppose a graph called ``g`` has been initialized, e.g. by using ``graph.graphxy``. Then, data and the style of their representation in the graph are defined by calling ``g.plot`` like in the following example in which filled circles are requested:: g.plot(graph.data.file("test.dat"), [graph.style.symbol(graph.style.symbol.circle, symbolattrs=[deco.filled])] ) As another example, if the linewidth of the symbol is too thin for your purposes, you could use something like:: [graph.style.symbol(graph.style.symbol.plus, symbolattrs=[style.linewidth.Thick])] How do I choose the color of the symbols? ----------------------------------------- Colors are not properties of the symbol as such and can therefore not be specified in ``symbolattrs`` directly. The color is rather related to the plotting of the symbol as defined by ``deco.stroked`` or ``deco.filled``. With :: graph.style.symbol(graph.style.symbol.circle, symbolattrs=[deco.stroked([color.rgb.red]), deco.filled([color.rgb.green])] ) you will obtain a circle filled in green with a red borderline. How do I choose the line style? ------------------------------- If you do not want to use symbols, you can set the line style as in this example :: g.plot(graph.data.file("test.dat"), [graph.style.line([style.linewidth.Thin])] ) where the linewidth is set. If you also want to use symbols, you can combine the symbol and the line style as in :: g.plot(graph.data.file("test.dat"), [graph.style.line(lineattrs=[style.linewidth.Thin, style.linestyle.dashed]), graph.style.symbol(graph.style.symbolline.circle, symbolattrs=[deco.filled]) ] ) to plot the symbols on top of a thin, dashed line. You may alter the order of the styles to plot the line on top of the symbols. How can I change the color of symbols or lines according to a palette? ---------------------------------------------------------------------- If several data sets should be plotted in different colors, one can specify in ``symbolattrs`` and/or ``lineattrs`` a palette like ``color.palette.Rainbow``. Equidistant colors are chosen spanning the palette from one end to the other. For example, for three data sets the colors are chosen from the palette at 0, 0.5, and 1. For the rainbow palette, this would correspond to red, green, and blue, respectively. In the following example, symbols vary in form and change their color according to the rainbow palette at the same time as the connecting lines:: mystyle = [graph.style.symbol(graph.style.symbol.changecircle, symbolattrs=[color.palette.Rainbow]), graph.style.line(lineattrs=[color.palette.Rainbow])] See question :ref:`changelist` for a more complete example demonstrating how to use this style definition and for a comment on the necessity of defining ``mystyle`` (you are of course free to choose a different name). .. _changelist: How can I specify changing colors (or other attributes) for symbols or lines? ----------------------------------------------------------------------------- In ``symbolattrs`` and/or ``lineattrs`` so-called changelist can be used. As an example :: mystyle = graph.style.symbol(symbolattrs= [attr.changelist([color.rgb.red, color.rgb.green])]) g.plot(graph.data.file("x.dat", x=1, y=2), [mystyle]) g.plot(graph.data.file("y.dat", x=1, y=2), [mystyle]) g.plot(graph.data.file("z.dat", x=1, y=2), [mystyle]) will switch between red and green symbols each time a new data set is plotted. Several changelists can be specified. They are cycled independently and need not be of the same length. It should be noted that the definition of ``mystyle`` in this example ensures that there is only one instance of the definition of ``symbolattrs``. Putting an explicit definition of ``symbolattrs`` in each call to ``plot`` would not lead to the desired result because each time a new instance would be created which then starts with the first item in the changelist. It may be necessary to repeat attributes in order that several changelists cooperate to produce the desired result. A common situation is that one would like to cycle through a list of symbols which should be used in alternating colors. This can be achieved with the following code:: mystyle = graph.style.symbol( graph.style.symbol.changetriangletwice, symbolattrs=[attr.changelist([color.rgb.red, color.rgb.green])]) which will produce a red triangle, a green triangle, a red circle, a green circle and so on for diamond and square because ``changetriangletwice`` lists each symbol twice. If instead of changing between colors one would like to change between filled and open symbols, one can make use of a predefined changelist :: mystyle = graph.style.symbol( graph.style.symbol.changetriangletwice, symbolattrs=[graph.style.symbol.changefilledstroked]) pyx-project-pyx-21f71ce/faq/python.rst000066400000000000000000000053631526513311100200550ustar00rootroot00000000000000====== Python ====== .. _what_is_python: What is Python? =============== From `www.python.org `_: Python is an *interpreted, interactive, object-oriented* programming language. It is often compared to Tcl, Perl, Scheme or Java. Python combines remarkable power with very clear syntax. It has modules, classes, exceptions, very high level dynamic data types, and dynamic typing. There are interfaces to many system calls and libraries, as well as to various windowing systems (X11, Motif, Tk, Mac, MFC). New built-in modules are easily written in C or C++. Python is also usable as an extension language for applications that need a programmable interface. The Python implementation is portable: it runs on many brands of UNIX, on Windows, OS/2, Mac, Amiga, and many other platforms. If your favorite system isn't listed here, it may still be supported, if there's a C compiler for it. Ask around on `comp.lang.python `_ – or just try compiling Python yourself. The Python implementation is `copyrighted `_ but **freely usable and distributable, even for commercial use**. Where can I learn more about Python? ==================================== The place to start is `www.python.org `_ where you will find plenty of information on Python including tutorials. What do I need to import in order to use PyX? ============================================= It is recommended to begin your Python code with:: from pyx import * when using PyX. This allows you for example to write simply ``graph.graphxy`` instead of ``pyx.graph.graphxy``. The following modules will be loaded: ``attr``, ``box``, ``bitmap``, ``canvas``, ``color``, ``connector``, ``deco``, ``deformer``, ``document``, ``epsfile``, ``graph``, ``path``, ``pattern``, ``style``, ``trafo``, ``text``, and ``unit``. For convenience, you might import specific objects of a module like in:: from graph import graphxy which allows you to write ``graphxy()`` instead of ``graph.graphxy()``. All code segments in this document assume that the import line mentioned in the first code snippet is present. What is a raw string and why should I know about it when using PyX? =================================================================== The backslash serves in standard Python strings to start an escape sequence. For example ``\n`` corresponds to a newline character. On the other hand, TeX and LaTeX, which do the typesetting in PyX, use the backslash to indicate the start of a command. In order to avoid the standard interpretation, the string should be marked as a raw string by prepending it by an ``r`` like in:: c.text(0, 0, r"$\alpha\beta\gamma$") pyx-project-pyx-21f71ce/faq/tex_latex.rst000066400000000000000000000332011526513311100205210ustar00rootroot00000000000000============= TeX and LaTeX ============= General aspects =============== .. _what_is_tex: What is TeX/LaTeX? ------------------ TeX is a high quality typesetting system developed by Donald E. Knuth which is available for a wide variety of operating systems. LaTeX is a macro package originally developed by Leslie Lamport which makes life with TeX easier, in particular for complex typesetting tasks. The current version of LaTeX is referred to as LaTeX2e and offers e.g. improved font selection as compared to the long outdated LaTeX 2.09 which should no longer be used. Do I need to use TeX/LaTeX? --------------------------- Traditionally, typesetting in PyX is done with TeX or LaTeX. With PyX 0.15, the Unicode engine was introduced. This engine can be useful if one does not need the elaborate typesetting capabilities of TeX and LaTeX and wants to avoid installing the corresponding packages. A TeX installation may nevertheless be useful if one wants to make use of fonts distributed with it. For further information see :ref:`text_without_tex`. .. _intro_tex_latex: I don't know anything about TeX and LaTeX. Where can I read something about it? -------------------------------------------------------------------------------- Take a look at CTAN (cf. :ref:`ctan`) where in `CTAN:info `_ you may be able to find some useful information. There exists for example “A Gentle Introduction to TeXâ€� by M. Doob (`CTAN:gentle/gentle.pdf `_) and “The Not So Short Introduction to LaTeX2eâ€� (`CTAN:info/lshort/english/lshort.pdf `_) by T. Oetiker et al. The latter has been translated into a variety of languages among them korean (which you will not be able to read unless you have appropriate fonts installed) and mongolian. Of course, it is likely that these documents will go way beyond what you will need for generating graphics with PyX so you don't have to read all of it (unless you want to use TeX or LaTeX for typesetting which can be highly recommended). There exists also a number of FAQs on TeX at `CTAN:help `_. .. _ctan: What is CTAN? ------------- CTAN is the *Comprehensive TeX Archive Network* where you will find almost everything related to TeX and friends. The main CTAN server is `www.ctan.org `_ but there exists a large number of mirrors around the world. You can help to reduce the load on the main server by using `mirror.ctan.org `_ which will redirect you to a mirror nearby. A list of known mirrors is available at `http://mirror.ctan.org/README.mirrors `_. In this FAQ, ``CTAN:`` refers to the root of the CTAN tree, e.g. `http://www.ctan.org/tex-archive/ `_. The links to CTAN in this document point to the main server but you might consider using a server closer to you in order to reduce traffic load. Is there support for ConTeXt? ----------------------------- No, and as far as I know there no plans to provide it in the near future. Given the close ties between ConTeXt and MetaPost, ConTeXt users probably prefer to stick with the latter anyway. TeX and LaTeX commands useful for PyX ===================================== How do I get a specific symbol with TeX or LaTeX? ------------------------------------------------- A list of mathematical symbols together with the appropriate command name can be found at `CTAN:info/symbols/math/symbols.pdf `_. A comprehensive list containing almost 6000 symbols for use with LaTeX can be obtained from `CTAN:info/symbols/comprehensive/symbols-a4.pdf `_. In some cases it might be necessary to install fonts or packages available from CTAN (cf. :ref:`ctan`). TeX and LaTeX errors ==================== .. _undefined_usepackage: Undefined control sequence ``\usepackage`` ------------------------------------------ The command ``\usepackage`` is specific to LaTeX. Since by default PyX uses TeX, you have to specify the correct typesetting engine:: text.set(text.LatexEngine) Undefined control sequence ``\frac`` ------------------------------------ The command ``\frac`` is only available in LaTeX. The equivalent to ``\frac{a}{b}`` in TeX is ``{a \over b}``. As an alternative you may ask for the LaTeX engine as explained in :ref:`undefined_usepackage`. Missing ``$`` inserted ---------------------- You have specified TeX- or LaTeX-code which is only valid in math mode. Typical examples are greek symbols, sub- and superscripts or fractions. On the PyX level, you can specify math mode for the whole string by using ``text.mathmode`` as in :: c.text(0, 0, r"{\alpha}", text.mathmode) Keep also in mind that the standard Python interpretation of the backslash as introducing escape sequences needs to be prevented. On the TeX/LaTeX level you should enclose the commands requiring math mode in ``$``'s. As an example, ``$\alpha_i^j$`` will produce a greek letter alpha with a subscript i and a superscript j. The dollar sign thus allows you to specify math mode also for substrings. There exist other ways to specify math mode in TeX and LaTeX which are particularly useful for more complex typesetting tasks. To learn more about it, you should consult the documentation :ref:`intro_tex_latex`. Why do environments like ``itemize`` or ``eqnarray`` seem not to work? ---------------------------------------------------------------------- An itemize environment might result in a LaTeX error complaining about a ``missing \item`` or an eqnarray might lead to a LaTeX message ``missing \endgroup inserted`` even though the syntax appears to be correct. The TeXnical reason is that in PyX text is typeset in left-right mode (LR mode) which does not allow linebreaks to occur. There are two ways out. If the text material should go in a box of given width, a parbox can be used like in the following example:: text.set(text.LatexEngine) c = canvas.canvas() w = 2 c.text(0, 0, r"\begin{itemize}\item a\item b\end{itemize}", [text.parbox(w)]) Occasionally, one would like to have the box in which the text appears to be as small as possible. Then the ``fancybox`` package developed by Timothy Van Zandt is useful which provides several environments like ``Bitemize`` and ``Beqnarray`` which can be processed in LR mode. The relevant part of the code could look like:: text.set(text.LatexEngine) text.preamble(r"\usepackage{fancybox}") c = canvas.canvas() c.text(0, 0, r"\begin{Bitemize}\item a\item b\end{Bitemize}") Other environments provided by the ``fancybox`` package include ``Bcenter``, ``Bflushleft``, ``Bflushright``, ``Benumerate``, and ``Bdescription``. For more details, the documentation of the package should be consulted. .. _fontshape_undefined: Font shape ``OT1/xyz/m/n`` undefined ------------------------------------ You have asked to use font ``xyz`` which is not available. Make sure that you have this font available in Type1 format, i.e. there should be a file ``xyz.pfb`` somewhere. If your TeX system is TDS compliant (TDS=TeX directory structure, cf. `CTAN:tds/draft-standard/tds/tds.pdf `_) you should take a look at the subdirectories of ``$TEXMF/fonts/type1``. File ``…`` is not available or not readable ------------------------------------------- Such an error message might already occur when running the example file ``hello.py`` included in the PyX distribution. Usually, the error occurs due to an overly restrictive umask setting applied when unpacking the ``tar.gz`` sources. This may render the file mentioned in the error message unreadable because the python distutil installation package doesn't change the file permissions back to readable for everyone. If the file exists, the problem can be solved by changing the permissions to allow read access. No information for font ``cmr10`` found in font mapping file ------------------------------------------------------------ Such an error message can already be encountered by simply running the example file ``hello.py`` included in the PyX distribution. The likely reason is that the TeX system does not find the cmr fonts in Type1 format. PyX depends on these fonts as it does not work with the traditional pk fonts which are stored as bitmaps. Therefore, the first thing to make sure is that the cmr Type1 fonts are installed. In some TeX installations, the command ``kpsewhich cmr10.pfb`` will return the appropriate path if the cmr fonts exist in the binary Type1 format (extension ``pfb``) required by PyX. If the command does not work but the TeX system is TDS compliant (:ref:`fontshape_undefined`), a look should be taken at ``$TEXMF/fonts/type1/bluesky/cm`` where ``$TEXMF`` is the root of the ``texmf`` tree. If the Type1 fonts do not exist on the system, they may be obtained from the CTAN (cf. :ref:`ctan`) at `CTAN:fonts/cm/ps-type1/bluesky `_). See the ``README`` for information about who produced these fonts and why they are freely available. If the Type1 fonts exist, the next step is to take a look at ``psfonts.map``. There may be several files with this name on the system, so it is important to find out which one TeX is actually using. ``kpsewhich psfonts.map`` might give this information. The most likely problem is that this file does not contain a line telling TeX what to do if it encounters a request for font ``cmr10``, i.e. the following line may be missing :: cmr10 CMR10 `_ and its subdirectories as well as at the web page `http://home.vr-web.de/was/fonts.html `_ of Walter Schmidt. It is not unlikely that somebody has already done most of the work for you and created the files needed for the font to work properly with LaTeX. But remember: we are talking about commercial fonts here, so do not expect to find the fonts themselves for free. If none of these cases applies, you should spend some time reading manuals about font installation, e.g. `CTAN:macros/latex/doc/fntguide.pdf `_ (of course, I do not expect font wizards to read the last few lines). Can I use a TrueType font with PyX? ----------------------------------- Not directly as PyX only knows how to handle Type1 fonts (although it is possible to get LaTeX to work with TrueType fonts). However, you may use ``ttf2pt1`` (from `ttf2pt1.sourceforge.net `_) to convert a TrueType font into a Type1 font which you then install in your TeX system (cf. :ref:`other_font`). You will loose hinting information in the conversion process but this should not really matter on output devices with not too low resolution. pyx-project-pyx-21f71ce/faq/unicode_text.rst000066400000000000000000000067111526513311100212240ustar00rootroot00000000000000.. _text_without_tex: ======================= Text output without TeX ======================= General aspects =============== .. _unicode_engine: How can I typeset text in PyX without TeX? ------------------------------------------ Starting with PyX 0.15, an additional typesetting engine besides the TeX and LaTeX engine is available: the Unicode engine. It can be made the default typesetting engine by:: text.set(text.UnicodeEngine) The font and its size can be specified through additional parameters like in this example:: text.set(text.UnicodeEngine, fontname='cmss10', size=20) .. _font_configuration_for_the_unicode_engine: Do I still need a TeX installation? ----------------------------------- Not necessarily. However, PyX needs to have access to the Type1 fonts it is supposed to use in the typesetting. Specifically, it needs the corresponding ``pfb`` and ``afm`` files. There are different ways to provide them. The first possibility is indeed a TeX installation. This approach makes particularly sense if the fonts to be used are made available by a TeX distribution. For example, the Computer Modern fonts used by PyX as default fonts are provided by all TeX installations. If, on the other hand, a font is to be used for which no TeX support is readily available, its ``pfb`` and ``afm`` files can be put in the directory where the Python script is placed. The font will then be found by PyX if the parameter ``fontname`` corresponds to the basename of the ``pfb`` and ``afm`` files. The latter approach is not optimal if the font is used in different PyX scripts scattered over several directories or if a larger number of fonts is needed. Then it is better to store the Type1 font files in a central place and to tell PyX about the files as explained in the following example. Suppose the standard TeX fonts should be used without a TeX installation. The fonts can be obtained in Type1 format from `https://www.ams.org/publications/authors/tex/amsfonts `_. Extract the zip file somewhere on your file system and generate an index file (ls-R) by running ``ls -R > ls-R`` in the directory to which the fonts were extracted. Finally create a ``.pyxrc`` file in your home directory with the following content:: [filelocator] methods = local internal ls-R ls-R = //ls-R The generation of the index file can be skipped by using the ``recursivedir`` locator instead:: [filelocator] methods = local internal recursivedir recursivedir = / However, the use of an index file increases performance, as PyX does not need to crawl the directory structure to locate the actual files. .. _tex_and_unicode: Is it possible to use the Unicode engine in addition to the TeX engine? ----------------------------------------------------------------------- Yes, it is possible to use different typesetting engines in the same script. The following example uses the Unicode engine and the TeX engine to typeset text on a canvas ``c``:: unicode_engine = text.UnicodeEngine() c.insert(unicode_engine.text(0, 0, "Hello, world!")) tex_engine = text.TexEngine() c.insert(tex_engine.text(0, 1, "Hello, world!")) If needed, the font name and size can be passed as parameters to the ``UnicodeEngine`` constructor:: engine = text.UnicodeEngine(fontname='cmss10', size=20) pyx-project-pyx-21f71ce/gallery/000077500000000000000000000000001526513311100166635ustar00rootroot00000000000000pyx-project-pyx-21f71ce/gallery/.gitignore000066400000000000000000000000401526513311100206450ustar00rootroot00000000000000*.eps *.pdf *.svg *.ipynb *.png pyx-project-pyx-21f71ce/gallery/INDEX000066400000000000000000000000231526513311100174500ustar00rootroot00000000000000path/ graph/ misc/ pyx-project-pyx-21f71ce/gallery/Makefile000066400000000000000000000020331526513311100203210ustar00rootroot00000000000000PYTHON ?= python3 GS ?= gs files = $(foreach item, $(shell grep -v / INDEX), $(item)) $(foreach item, $(shell grep / INDEX), $(addprefix $(item), $(shell cat $(item)INDEX))) pyfiles = $(addsuffix .py, $(files)) epsfiles = $(addsuffix .eps, $(files)) pdffiles = $(addsuffix .pdf, $(files)) pngfiles = $(addsuffix .png, $(files)) svgfiles = $(addsuffix .svg, $(files)) ipynbfiles = $(addsuffix .ipynb, $(files)) thumbpngfiles = $(addsuffix _thumb.png, $(files)) .PRECIOUS: $(epsfiles) $(pngfiles) all: $(MAKE) $(ipynbfiles) $(MAKE) $(thumbpngfiles) clean: rm -f $(epsfiles) $(pdffiles) $(pngfiles) $(svgfiles) $(ipynbfiles) $(thumbpngfiles) %.eps: %.py cd $(dir $^); $(PYTHON) -W default $(notdir $^) %.ipynb: %.png $(PYTHON) $(CURDIR)/../www/mkipynb.py $@ %.png: %.eps $(GS) -r100 -dEPSCrop -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pngalpha -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sOutputFile=$@ $^ %_thumb.png: %.eps $(GS) -r50 -dEPSCrop -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pngalpha -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sOutputFile=$@ $^ pyx-project-pyx-21f71ce/gallery/README000066400000000000000000000003261526513311100175440ustar00rootroot00000000000000PyX gallery The PyX gallery contains a collection of user contributed examples. To contribute please submit a gallery example via a GitHub pull request containing a Python file and an optional description text. pyx-project-pyx-21f71ce/gallery/graph/000077500000000000000000000000001526513311100177645ustar00rootroot00000000000000pyx-project-pyx-21f71ce/gallery/graph/INDEX000066400000000000000000000001551526513311100205570ustar00rootroot00000000000000symbolline inset cycliclink arrows shift piaxis neglogsplit manyaxes integral partialfill washboard contours pyx-project-pyx-21f71ce/gallery/graph/arrows.py000066400000000000000000000020251526513311100216520ustar00rootroot00000000000000from math import pi, atan2 from pyx import * z1 = 2.5 + 4.5j z2 = 7.5 + 5.5j # we abuse a parametric function below, so we express everything in terms of a parameter k x = lambda k: int(k)//11 y = lambda k: int(k)%11 z = lambda k: x(k) + y(k) * 1j f = lambda k: 1/(z(k)-z1)/(z(k)-z2) # function to be plotted s = lambda k: 5*abs(f(k)) # magnitude of function value a = lambda k: 180/pi*atan2(f(k).imag, f(k).real) # direction of function value g = graph.graphxy(width=8, x=graph.axis.linear(min=0, max=10), y=graph.axis.linear(min=0, max=10)) g.plot(graph.data.paramfunction("k", 0, 120, "x, y, size, angle = x(k), y(k), s(k), a(k)", points=121, context=locals()),# access extern [graph.style.arrow()]) # variables&functions # by passing a context g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/contours.py000066400000000000000000000025301526513311100222120ustar00rootroot00000000000000import numpy as np from skimage.measure import find_contours from pyx import color, graph xmax = 1.6 xmin = -xmax ymin = -1.4 ymax = 1.8 npts = 101 x, y = np.mgrid[xmin:xmax:npts*1j, ymin:ymax:npts*1j] z = 0.5*(x*x+y*y)+(x*x*y-y**3/3) data = list(zip(x.flat, y.flat, z.flat)) g = graph.graphxy(height=8, width=8, x=graph.axis.linear(min=xmin, max=xmax, title="$x$"), y=graph.axis.linear(min=ymin, max=ymax, title="$y$")) g.plot(graph.data.points(data, x=1, y=2, color=3), [graph.style.density(gradient=color.gradient.Jet, coloraxis=graph.axis.linear(min=-0.5, max=6, title="$V$"))]) for contourlevel in np.concatenate((np.arange(-0.4, 0, 0.1), np.arange(0, 0.2, 0.05), np.arange(0.2, 6, 0.5) )): contours = find_contours(z, contourlevel) for contourdata in contours: contourdata_rescaled = [(xmin+(xmax-xmin)*x/(npts-1), ymin+(ymax-ymin)*y/(npts-1)) for x, y, in contourdata] g.plot(graph.data.points(contourdata_rescaled, x=1, y=2), [graph.style.line([color.rgb(1, 1, 1)])]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/cycliclink.py000066400000000000000000000011661526513311100224660ustar00rootroot00000000000000from pyx import * c = canvas.canvas() g1 = c.insert(graph.graphxy(width=8, x=graph.axis.linear(min=0, max=1), x2=graph.axis.linkedaxis())) g2 = c.insert(graph.graphxy(width=8, ypos=g1.height+0.5, x=graph.axis.linkedaxis(), x2=graph.axis.log(min=1, max=1000))) g1.axes["x2"].setlinkedaxis(g2.axes["x2"]) g2.axes["x"].setlinkedaxis(g1.axes["x"]) g1.plot(graph.data.function("y(x)=2*exp(-30*x)-exp(-3*x)")) g2.plot(graph.data.function("y(x)=cos(20*x)*exp(-2*x)")) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/inset.py000066400000000000000000000006231526513311100214610ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8, x=graph.axis.linear(min=-2, max=2)) g.plot(graph.data.function("y(x)=exp(x)")) g2 = g.insert(graph.graphxy(width=3.5, xpos=1, ypos=2, x=graph.axis.linear(min=0, max=3), y=graph.axis.linear(min=-2, max=2))) g2.plot(graph.data.function("y(x)=log(x)")) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/integral.py000066400000000000000000000022321526513311100221420ustar00rootroot00000000000000from pyx import * a, b = 2, 9 # integral area p = graph.axis.painter.regular(basepathattrs=[deco.earrow.normal], titlepos=0.98, titledirection=None) ticks = [graph.axis.tick.tick(a, label="$a$"), graph.axis.tick.tick(b, label="$b$")] g = graph.graphxy(width=8, x2=None, y2=None, x=graph.axis.linear(title="$x$", min=0, max=10, manualticks=ticks, parter=None, painter=p), y=graph.axis.linear(title="$y$", parter=None, painter=p)) d = g.plot(graph.data.function("y(x)=(x-3)*(x-5)*(x-7)")) g.finish() p = d.path # the path is available after the graph is finished pa = g.xgridpath(a) pb = g.xgridpath(b) (splita,), (splitpa,) = p.intersect(pa) (splitb,), (splitpb,) = p.intersect(pb) area = (pa.split([splitpa])[0] << p.split([splita, splitb])[1] << pb.split([splitpb])[0].reversed()) area[-1].close() g.stroke(area, [deco.filled([color.gray(0.8)])]) g.text(g.pos(0.5 * (a + b), 0)[0], 1, r"\int_a^b f(x){\rm d}x", [text.halign.center, text.mathmode]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/manyaxes.py000066400000000000000000000013361526513311100221660ustar00rootroot00000000000000import math, random from pyx import * # a xy-graph has linear x and y axes by default # they might be overwritten and further axes might be added as well g = graph.graphxy(width=8, y=graph.axis.log(), y2=graph.axis.lin(), y3=graph.axis.lin(min=0, max=1), y4=graph.axis.lin(min=0, max=2)) # we generate some data and a function with multiple arguments d = [[i, math.exp(0.8*i+random.random())] for i in range(1,10)] f = lambda x, a: x*a g.plot(graph.data.points(d, x=1, y=2)) g.plot(graph.data.function("y2(x)=f(x, 1)", context=locals())) g.plot(graph.data.function("x(y3)=5+sin(2*pi*y3)")) g.plot(graph.data.function("x(y4)=5+sin(2*pi*y4)")) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/neglogsplit.py000066400000000000000000000010721526513311100226650ustar00rootroot00000000000000from math import pi from pyx import * g = graph.graphxy(width=10, key=graph.key.key(), x_divisor=pi, x_texter=graph.axis.texter.rational(suffix=r'\pi'), y=graph.axis.split(reverse=1, subaxes={-1: graph.axis.log(min=-100), 1: graph.axis.log(max=100)})) g.plot(graph.data.function("y(x)=(sgn(sin(x)), abs(sin(x)) > 0.001 and 1/sin(x) or None)", min=0, max=6*pi, points=10001, title="y(x)=1/sin(x)")) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/partialfill.py000066400000000000000000000024301526513311100226400ustar00rootroot00000000000000# contributed by Michael Schindler from pyx import * # get the lines from the graph xax = graph.axis.linear(min=-1, max=1.0, painter=None) yax = graph.axis.linear(min=-1.3, max=1.3, painter=None) g = graph.graphxy(width=10, ratio=2, x=xax, y=yax) pifline = g.plot(graph.data.function("y(x)=sin(1.0/(x**2+0.02122))", points=1000)) pihoriz = g.plot(graph.data.function("y(x)=0.5*x", points=2)) g.finish() # fetch path from info returned by plot method of graph fline = pifline.path horiz = pihoriz.path # intersect the lines splith, splitf = horiz.intersect(fline) # create gray area (we do not use simple clipping) area = horiz.split([splith[0]])[0] for i in range(0, len(splith)-2, 2): area = area.joined(fline.split([splitf[i], splitf[i+1]])[1]) area = area.joined(horiz.split([splith[i+1], splith[i+2]])[1]) area = area.joined(fline.split([splitf[-2], splitf[-1]])[1]) area = area.joined(horiz.split([splith[-1]])[1]) area.append(path.lineto(*g.vpos(1, 0))) area.append(path.lineto(*g.vpos(0, 0))) area.append(path.closepath()) # not really needed (filling closes automatically) c = canvas.canvas() # draw first the area, then the function c.fill(area, [color.gray(0.6)]) c.stroke(fline, [style.linewidth.Thick, style.linejoin.round]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/piaxis.py000066400000000000000000000007761526513311100216450ustar00rootroot00000000000000from math import pi from pyx import * from pyx.graph import axis g = graph.graphxy(width=8, key=graph.key.key(pos="bl"), x=axis.linear(min=0, max=2*pi, title="$x$", divisor=pi, texter=axis.texter.rational(suffix=r"\pi")), y=axis.linear(title="$y$")) g.plot(graph.data.function("y(x)=sin(x)", title=r"$\sin(x)$")) g.plot(graph.data.function("y(x)=cos(x)", title=r"$\cos(x)$")) g.finish() g.stroke(g.ygridpath(0)) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/shift.dat000066400000000000000000000070641526513311100216020ustar00rootroot000000000000000.000000 0.093552 0.112454 0.179711 0.010000 0.010819 0.375696 0.409862 0.020000 0.185630 0.475497 0.459045 0.030000 0.085790 0.739999 0.705008 0.040000 0.048823 0.916421 0.983903 0.050000 0.175599 0.738313 0.721993 0.060000 0.133378 0.663194 0.637172 0.070000 0.017070 0.462168 0.432542 0.080000 0.142286 0.159476 0.076606 0.090000 0.175035 0.115659 0.168348 0.100000 0.065532 0.021641 0.099089 0.110000 0.338032 0.193684 0.075735 0.120000 0.501449 0.076071 0.052825 0.130000 0.714484 0.166160 0.260115 0.140000 1.044950 0.140046 0.113768 0.150000 0.761459 0.150199 0.091245 0.160000 0.580124 0.124991 0.148302 0.170000 0.366523 0.034990 0.015023 0.180000 0.086310 0.050342 0.193373 0.190000 0.183720 0.008756 0.065295 0.200000 0.148604 0.101561 0.106499 0.210000 0.129528 0.124659 0.194451 0.220000 0.111310 0.055354 0.137575 0.230000 0.240304 0.379149 0.310891 0.240000 0.197671 0.570959 0.479726 0.250000 0.026784 0.927620 0.902845 0.260000 0.133537 0.837585 0.858621 0.270000 0.043651 1.314035 1.465999 0.280000 0.198483 1.147673 1.166429 0.290000 0.127190 0.826202 0.748380 0.300000 0.131359 0.899580 0.940880 0.310000 0.119633 0.853252 1.219305 0.320000 0.148364 0.947769 0.845000 0.330000 0.319962 0.915448 0.716717 0.340000 0.593264 0.944451 0.787436 0.350000 0.875959 1.011230 0.490365 0.360000 0.856434 0.974125 1.161382 0.370000 1.371431 0.833430 1.640708 0.380000 1.090264 0.974813 1.526268 0.390000 0.783328 0.874536 1.527830 0.400000 0.976016 0.834380 1.833305 0.410000 1.240585 1.281413 1.710859 0.420000 0.735648 0.721365 1.712504 0.430000 0.694313 0.818321 2.118110 0.440000 0.771420 0.895332 2.568452 0.450000 0.464567 0.486208 2.164012 0.460000 1.028716 1.102470 2.585583 0.470000 1.666251 1.619384 2.008516 0.480000 1.482772 1.569979 2.424176 0.490000 1.526710 1.705879 2.563430 0.500000 1.681632 1.801579 2.115234 0.510000 1.648768 1.642538 2.155867 0.520000 1.640045 1.727319 1.835203 0.530000 2.129760 2.166372 2.190385 0.540000 2.538762 2.484445 2.062762 0.550000 2.128357 2.044120 2.186967 0.560000 2.563771 2.594849 2.466537 0.570000 2.091981 2.043196 2.652307 0.580000 2.319331 2.286016 2.363267 0.590000 2.546574 2.428293 2.150611 0.600000 2.241166 2.136176 1.720958 0.610000 2.153191 2.125280 1.762141 0.620000 1.762225 1.700132 1.668114 0.630000 2.302032 2.162618 1.833917 0.640000 1.944317 1.915787 1.659345 0.650000 2.126381 2.070251 1.763199 0.660000 2.405465 2.399447 1.790405 0.670000 2.776870 2.651151 1.777731 0.680000 2.328131 2.327470 1.752451 0.690000 2.142656 2.184793 1.666516 0.700000 1.702775 1.824695 1.739324 0.710000 1.793138 1.759536 1.733953 0.720000 1.280445 1.282639 1.412333 0.730000 1.085254 1.004976 1.001700 0.740000 1.584523 1.442157 1.462368 0.750000 1.033501 1.146581 1.149616 0.760000 1.172442 1.247916 1.239193 0.770000 1.438631 1.435911 1.545370 0.780000 1.802119 1.814190 1.911582 0.790000 1.623176 1.739982 1.722814 0.800000 1.321928 1.461423 1.430906 0.810000 1.073016 1.112029 1.209466 0.820000 1.273442 1.268402 1.137061 0.830000 1.075054 1.157114 1.099937 0.840000 1.377204 1.322320 1.241025 0.850000 1.675064 1.688645 1.833905 0.860000 1.566260 1.594175 1.556601 0.870000 1.487966 1.619798 1.564591 0.880000 1.420821 1.433038 1.360169 0.890000 1.052967 1.016814 0.967521 0.900000 0.731004 0.864763 0.770634 0.910000 0.698500 0.622465 0.677814 0.920000 1.022049 1.009725 0.936713 0.930000 0.981331 0.900933 0.995858 0.940000 1.314244 1.215228 1.250874 0.950000 1.138328 1.243438 1.282548 0.960000 0.817129 0.827435 0.791566 0.970000 0.681887 0.575078 0.606345 0.980000 0.577195 0.553300 0.538145 0.990000 0.212586 0.223119 0.296213 1.000000 0.141721 0.087720 0.002712 pyx-project-pyx-21f71ce/gallery/graph/shift.py000066400000000000000000000013331526513311100214530ustar00rootroot00000000000000# You can manually set the subaxes and exceed the axes ranges. # The width of the regular axes can be modified by a size parameter. # While most axes do not have a size parameter, it can be added to # any existing axis very easily. For linear axes so called sizedlinear # and autosizedlinear axes are defined by PyX already. from pyx import * subaxes = [graph.axis.linear(max=1), graph.axis.linear(max=1), graph.axis.sizedlinear(size=3, min=0, max=3)] g = graph.graphxy(width=8, y=graph.axis.split(subaxes=subaxes, epsilon=None)) g.plot([graph.data.file("shift.dat", x=1, y="i, $(i+2)", context={"i": i}) for i in range(3)], [graph.style.line()]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/symbolline.py000066400000000000000000000027521526513311100225210ustar00rootroot00000000000000# contributed by Francisco Borges from pyx import * from pyx.graph import graphxy, data, axis from pyx.graph.axis import painter, tick from pyx.deco import earrow range = 2.5 p = painter.regular(basepathattrs=[earrow.normal], titlepos=0.95, outerticklength=painter.ticklength.normal, titledist=-0.3, titledirection=None) # horizontal text g = graphxy(width=10, xaxisat=0, yaxisat=0, x=axis.linear(title="$x$", min=-range, max=+range, painter=p, # suppress some ticks by overwriting ... manualticks=[tick.tick(0, None, None), tick.tick(range, None, None)]), y=axis.linear(title=r"$x\sin(x^2)$", painter=p, manualticks=[tick.tick(0, None, None), tick.tick(3, None, None)])) g.plot(data.function("y(x)=x*sin(x**2)"), # Line style is set before symbol style -> symbols will be draw # above the line. [graph.style.line([style.linewidth.Thin, style.linestyle.solid]), graph.style.symbol(graph.style.symbol.circle, size=0.1, symbolattrs=[deco.filled([color.rgb.green]), deco.stroked([color.rgb.red])])]) # manually typeset "0" near the origin g.dolayout() x0, y0 = g.pos(0, 0) g.text(x0 - 0.2, y0 - 0.2, "0", [text.halign.right, text.valign.top]) g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/graph/washboard.py000066400000000000000000000026451526513311100223170ustar00rootroot00000000000000# contributed by Sigmund Kohler from math import pi, cos from pyx import * from pyx.deco import barrow, earrow from pyx.style import linewidth, linestyle from pyx.graph import graphxy from pyx.graph.axis import linear from pyx.graph.axis.painter import regular from pyx.graph.style import line from pyx.graph.data import function mypainter = regular(basepathattrs=[earrow.normal], titlepos=1) def mycos(x): return -cos(x)+.10*x g = graphxy(height=5, x2=None, y2=None, x=linear(min=-2.5*pi, max=3.3*pi, parter=None, painter=mypainter, title=r"$\delta\phi$"), y=linear(min=-2.3, max=2, painter=None)) g.plot(function("y(x)=mycos(x)", context=locals()), [line(lineattrs=[linewidth.Thick])]) g.finish() x1, y1 = g.pos(-pi+.1, mycos(-pi+.1)) x2, y2 = g.pos(-.1, mycos(-.1)) x3, y3 = g.pos(pi+.1, mycos(pi+.1)) g.stroke(path.line(x1-.5, y1, x1+.5, y1), [linestyle.dashed]) g.stroke(path.line(x1-.5, y3, x3+.5, y3), [linestyle.dashed]) g.stroke(path.line(x2-.5, y2, x3+.5, y2), [linestyle.dashed]) g.stroke(path.line(x1, y1, x1, y3), [barrow.normal, earrow.normal]) g.stroke(path.line(x3, y2, x3, y3), [barrow.normal, earrow.normal]) g.text(x1+.2, 0.5*(y1+y3), r"$2\pi\gamma k\Omega$", [text.vshift.middlezero]) g.text(x1-.6, y1-.1, r"$E_{\rm b}$", [text.halign.right]) g.text(x3+.15, y2+.20, r"$2J_k(\varepsilon/\Omega)+\pi\gamma k\Omega$") g.writeEPSfile() g.writePDFfile() g.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/000077500000000000000000000000001526513311100176165ustar00rootroot00000000000000pyx-project-pyx-21f71ce/gallery/misc/INDEX000066400000000000000000000000551526513311100204100ustar00rootroot00000000000000pattern pyxpyx vector connect box julia cube pyx-project-pyx-21f71ce/gallery/misc/box.py000066400000000000000000000010641526513311100207610ustar00rootroot00000000000000from math import sin, cos, pi from pyx import * r = 1.5 # create a box list of regular polygons boxes = [box.polygon([(-r*sin(i*2*pi/n), r*cos(i*2*pi/n)) for i in range(n)]) for n in range(3, 8)] # tile with spacing 0 horizontally box.tile(boxes, 0, 1, 0) c = canvas.canvas() for b in boxes: # plot the boxes path c.stroke(b.path(), [color.rgb.green]) # a second time with bezier rounded corners c.stroke(b.path(), [deformer.smoothed(radius=0.5), color.rgb.red]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/connect.py000066400000000000000000000014241526513311100216220ustar00rootroot00000000000000from pyx import * from pyx.connector import arc, curve unit.set(uscale=3) c = canvas.canvas() textattrs = [text.halign.center, text.vshift.middlezero] A = text.text(0, 0, r"\bf A", textattrs) B = text.text(1, 0, r"\bf B", textattrs) C = text.text(1, 1, r"\bf C", textattrs) D = text.text(0, 1, r"\bf D", textattrs) for X in [A, B, C, D]: c.draw(X.bbox().enlarged(0.1).path(), [deco.stroked(), deco.filled([color.grey(0.85)])]) c.insert(X) for X,Y in [[A, B], [B, C], [C, D], [D, A]]: c.stroke(arc(X, Y, boxdists=[0.2, 0.2], relangle=-45), [color.rgb.red, deco.earrow.normal]) c.stroke(curve(D, B, boxdists=[0.2, 0.2], relangle1=-45, relangle2=-45, relbulge=0.8), [color.rgb.blue, deco.earrow.normal]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/cube.py000066400000000000000000000013751526513311100211140ustar00rootroot00000000000000from itertools import product, combinations from operator import eq from pyx import * projector = graph.graphxyz.central(10, 20, -30).point a = 2 cube = list(product([-a, a], repeat=3)) edges = list(filter(lambda edge: sum(map(eq, edge[0], edge[1])) == 2, combinations(cube, 2))) c = canvas.canvas() for begin, end in edges: x1, y1 = projector(*begin) x2, y2 = projector(*end) if begin[0] != end[0]: col = color.rgb.blue elif begin[0] == a: col = color.rgb.red else: col = color.rgb.green c.stroke(path.line(x1, y1, x2, y2), [style.linewidth.Thick, col]) for vertex in cube: x, y = projector(*vertex) c.fill(path.circle(x, y, 0.2)) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/cube.txt000066400000000000000000000004731526513311100213010ustar00rootroot00000000000000cube The 3d graphs in PyX use projectors to transform the 3d data to two dimensions. Those projectors can be used for other drawing tasks as well, as shown for a simple cube here. ... In addition to the central projection, a parallel projection is available, too. Idea and initial version by Gert-Ludwig Ingold. pyx-project-pyx-21f71ce/gallery/misc/julia.py000066400000000000000000000020731526513311100212760ustar00rootroot00000000000000# contributed by Stefan Schenk from io import BytesIO from math import sqrt from pyx import * xiterations = yiterations = 250 Min_Im = -1.5 Max_Im = 1.5 Min_Re = -1.5 Max_Re = 1.5 c = 0.41 + 0.3j p = color.gradient.RedBlue def rgbcolortostring(c): return bytes([int(255*c.r), int(255*c.g), int(255*c.b)]) data = BytesIO() # compute fractal for y in range(yiterations): for x in range(xiterations): z = complex(1.0*(Max_Re-Min_Re)*x/xiterations + Min_Re, 1.0*(Max_Im-Min_Im)*y/yiterations + Min_Im) for k in range(256): z = z*z + c if abs(z) > 2: # append color(RGB) of the current pixel to the end of data data.write(rgbcolortostring(p.getcolor(1.0/sqrt(k+1)))) break else: data.write(b"\0\0\0") # generate image from data julia = bitmap.image(xiterations, yiterations, "RGB", data.getvalue()) juliabitmap = bitmap.bitmap(0, 0, julia, height=10) c = canvas.canvas() c.insert(juliabitmap) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/pattern.py000066400000000000000000000002631526513311100216460ustar00rootroot00000000000000from pyx import * p = pattern.pattern() p.text(0, 0, r"\PyX") c = canvas.canvas() c.text(0, 0, r"\PyX", [trafo.scale(25), p]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/pyxpyx.py000066400000000000000000000005661526513311100215600ustar00rootroot00000000000000from pyx import * textpath = text.text(0, 0, r"\PyX").textpath().reversed() decotext = r"\PyX{} is fun! "*50 scale = text.text(0, 0, decotext).width/textpath.arclen() c = canvas.canvas() c.draw(textpath, [trafo.scale(scale), deco.filled([color.gray(0.5)]), deco.curvedtext(decotext)]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/misc/vector.py000066400000000000000000000015251526513311100214750ustar00rootroot00000000000000from math import pi, sin, cos from pyx import * def vector(x1, y1, x2, y2, t, pos=0.5, distance=0.1): c = canvas.canvas() c.stroke(path.line(x1, y1, x2, y2), [deco.earrow.normal]) textbox = text.text((1-pos)*x1 + pos*x2, (1-pos)*y1 + pos*y2, t, [text.halign.center, text.vshift.mathaxis]) if distance < 0: textbox.linealign(-distance, y1 - y2, x2 - x1) else: textbox.linealign(distance, y2 - y1, x1 - x2) c.insert(textbox) return c r = 1.5 a = 150 c = canvas.canvas() dx, dy = cos(a * pi / 180), sin(a * pi / 180) x, y = r * dx, r * dy c.stroke(path.circle(0, 0, r)) c.insert(vector(0, 0, x, y, r"$\vec r$")) c.insert(vector(x, y, x - dy, y + dx, r"$\vec t$", pos=0.7)) c.insert(vector(x, y, x + dx, y + dy, r"$\vec n$", pos=0.7)) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/000077500000000000000000000000001526513311100176175ustar00rootroot00000000000000pyx-project-pyx-21f71ce/gallery/path/INDEX000066400000000000000000000000641526513311100204110ustar00rootroot00000000000000circles split springs parallel knot sierpinski tree pyx-project-pyx-21f71ce/gallery/path/circles.py000066400000000000000000000010431526513311100216130ustar00rootroot00000000000000from pyx import * circ1 = path.circle(0, 0, 1.5) circ2 = path.circle(1, 1, 1) (circ1a, circ1b), (circ2a, circ2b) = circ1.intersect(circ2) intersection = (circ2.split([circ2b, circ2a])[1] << circ1.split([circ1a, circ1b])[1]) intersection[-1].close() union = (circ1.split([circ1a, circ1b])[0] << circ2.split([circ2b, circ2a])[0]) union[-1].close() c = canvas.canvas() c.fill(union, [color.rgb.blue]) c.fill(intersection, [color.rgb.red]) c.stroke(circ1) c.stroke(circ2) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/knot.py000066400000000000000000000052111526513311100211430ustar00rootroot00000000000000from pyx import * unit.set(uscale=3, wscale=3) dist = 0.15 # distance between the ropes thick = 0.08 # thickness of the ropes # build the basepath of the knot. This is the curve that lies # between both ropes. A = 1.0, 0.1 # point where the knot starts after the straight line B = 1.3, 0 # point where the knot is curved, overlying the straight line t = -0.8, -0.1 # direction at A s = 0.3, 1.2 # direction at B pts = [ ( A[0]-t[0], A[1]-t[1]), ( A[0] , A[1] ), ( A[0]+t[0], A[1]+t[1]), (-B[0]-s[0],-B[1]-s[1]), (-B[0] ,-B[1] ), (-B[0]+s[0],-B[1]+s[1]), ( B[0]-s[0], B[1]-s[1]), ( B[0] , B[1] ), ( B[0]+s[0], B[1]+s[1]), (-A[0]-t[0],-A[1]-t[1]), (-A[0] ,-A[1] ), (-A[0]+t[0],-A[1]+t[1]) ] seam = path.path( path.moveto(*(pts[0])), path.lineto(*(pts[1])), path.curveto(pts[2][0],pts[2][1],pts[3][0],pts[3][1],pts[4][0],pts[4][1]), path.curveto(pts[5][0],pts[5][1],pts[6][0],pts[6][1],pts[7][0],pts[7][1]), path.curveto(pts[8][0],pts[8][1],pts[9][0],pts[9][1],pts[10][0],pts[10][1]), path.lineto(*(pts[11])) ) # We smooth this curve a little because we used curveto together with lineto seam = deformer.smoothed(0.6).deform(seam) # The ropes, when drawn later, will have to overlap in a very specific way. l = seam.arclen() epsilon = 0.002*l # small overlap between the segments seam_segs = seam.split([0.28*l+epsilon, 0.28*l-epsilon, 0.42*l+epsilon, 0.42*l-epsilon, 0.58*l+epsilon, 0.58*l-epsilon, 0.72*l+epsilon, 0.72*l-epsilon])[::2] # For each segment, two shifted paths build the boundaries of each rope ropes_segs = [] for seam_seg in seam_segs: ropes_segs.append([]) for ropeshift in [-0.5*dist, 0.5*dist]: ropes_segs[-1].append([]) for edgeshift in [-0.5*thick, 0.5*thick]: ropes_segs[-1][-1].append( deformer.parallel(ropeshift + edgeshift).deform(seam_seg)) # Now, ropes_segs is a list of segments, containing a list of ropes, # each containing the two bounding paths of the rope segment rope_colors = [color.rgb.blue, color.rgb.red] c = canvas.canvas() # Because the segments should overlap in a very specific manner # we have to draw them in the correct order for index in [1, 4, 2, 0, 3]: for rope_seg, col in zip(ropes_segs[index], rope_colors): seg = rope_seg[0].joined(rope_seg[1].reversed()) seg.append(path.closepath()) c.fill(seg, [col]) c.stroke(rope_seg[0], [style.linecap.round, style.linejoin.round]) c.stroke(rope_seg[1], [style.linecap.round, style.linejoin.round]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/knot.txt000066400000000000000000000014661526513311100213420ustar00rootroot00000000000000Paths with constant distance The example shows how to create paths with constant distance. This is achieved with the aid of `deformer.parallel`, which has already been used in the above example. ... The first part of the example code is only for creating the middle line of the knot. In order to obtain a nicely curved rope, we smooth the such defined curve a bit. The individual parts of the knot must be stroked in a very specific way in order to achieve the correct overlapping of the knot. To this end, we split the base curve into five pieces. The key element of the example is the use of `deformer.parallel` which creates the curves with constant distance from the base curve. We apply the deformer four times, thus creating the outline path of two individual ropes, which parallel follow the shape of the knot. pyx-project-pyx-21f71ce/gallery/path/parallel.py000066400000000000000000000007421526513311100217700ustar00rootroot00000000000000from pyx import * c = canvas.canvas() p = path.path(path.moveto(0, 0), path.arc(0, 0, 1, 210, 150), path.closepath()) c.stroke(p, [style.linewidth(0.4)]) pp = deformer.parallel(-0.2, sharpoutercorners=1).deform(p) + deformer.parallel( 0.2, sharpoutercorners=1).deform(p).reversed() c.stroke(pp, [trafo.translate(2.5, 0), deco.filled([color.rgb.red])]) # PyX gets the bounding box wrong, which leads to the clipping on the left c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/sierpinski.py000066400000000000000000000012471526513311100223550ustar00rootroot00000000000000# Sierpinski triangle # contributed by Gerhard Schmid from math import sqrt from pyx import * # triangle geometry l = 10 h = 0.5 * sqrt(3) * l # base triangle path p = path.path(path.moveto(0, 0), path.lineto(l, 0), path.lineto(0.5 * l, h), path.closepath()) for i in range(6): # path is scaled down ... p = p.transformed(trafo.scale(0.5)) # ... and three times plotted (translated accordingly) p += ( p.transformed(trafo.translate(0.5 * l, 0)) + p.transformed(trafo.translate(0.25 * l, 0.5 * h))) c = canvas.canvas() c.stroke(p, [style.linewidth.Thin]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/split.py000066400000000000000000000020211526513311100213170ustar00rootroot00000000000000import math from pyx import * circle = path.circle(0, 0, 5/math.pi) opencircle, = circle.split(circle.begin()) c = canvas.canvas() def showsplit(x, y, path, splitpoints, description): c.text(x, y, description, [text.halign.center, text.vshift.mathaxis]) segments = path.transformed(trafo.translate(x, y)).split(splitpoints) print("path sement lengths for ``%s'':" % description) for segment, segment_color in zip(segments, [color.rgb.red, color.rgb.green, color.rgb.blue]): print(" %s" % segment.arclen()) c.stroke(segment, [deco.earrow.normal, style.linestyle.dashed, segment_color]) print() showsplit(0, 0, opencircle, [opencircle.begin()+1, opencircle.end()-1], "open, $p_1 < p_2$") showsplit(0, -5, opencircle, [opencircle.end()-1, opencircle.begin()+1], "open, $p_1 > p_2$") showsplit(5, 0, circle, [circle.begin()+1, circle.end()-1], "closed, $p_1 < p_2$") showsplit(5, -5, circle, [circle.end()-1, circle.begin()+1], "closed, $p_1 > p_2$") c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/split.txt000066400000000000000000000037611526513311100215220ustar00rootroot00000000000000split Splitting of paths at several points, which are not ordered along the path, might look a little stange at first. This gallery example will show you the basic procedure PyX applies for that case. ... First of all, the order of the points is always preserved. The first segment returned by the split method ends at the first splitting point, the second segment goes from the first splitting point to the second splitting point (and maybe this path element will thus have a different orientation than the original path). Finally, for an open path the last item in the list of returned segments will go from the last splitting point to the end of the path. However, for a closed path this last path item is prepended to the first segment returned by the split method. Thus for a closed path the first segment will always go from the last to the first splitting point. In the given example four circles are shown, which have a circumference of 10 cm each and a counter clockwise orientation. We always use two split points, one is located 1 cm after the beginning of the path, the other is located 1 cm before the end of the path. On the left side the circle is open on the right point of the horizontal line going through the center of the circle. The three segments are stroked in red, green, and blue. Note that on the bottom, where the point close to the end of the path is used as the first splitting point, the second segment (shown in green, best visible by the arrow) has a reverse orientation. Still, the sum of all segments is the full path, when taking into account the reverse orientation of the second segment. Please also note the lengths of the segment shown in the output of the script. Now the result on the right side should not be surprising anymore. The red segment is given by joining the blue and the red segment from the version shown on the left. However, this means that the red arrow in the lower right is longer than one loop of the path, in fact it is 18 cm long, almost two times the circumference. pyx-project-pyx-21f71ce/gallery/path/springs.py000066400000000000000000000015401526513311100216560ustar00rootroot00000000000000# contributed by Gert-Ludwig Ingold from pyx import * n = 3 # number of masses r = 3.0 # system radius rcyc = 0.3 # radius of cycloid nl = 13 # number of loops rc = 0.5 # radius of masses eps = 0.03 # extra spacing for surrounding circles c = canvas.canvas() springcircle = path.circle(0, 0, r) masspositions = [i*springcircle.arclen()/n for i in range(n)] for springsegment in springcircle.split(masspositions): c.stroke(springsegment, [deformer.cycloid(rcyc, nl), deformer.smoothed(radius=0.1)]) for x, y in springcircle.at(masspositions): c.fill(path.circle(x, y, rc)) c.stroke(springcircle, [deformer.parallel(rc+eps)]) c.stroke(springcircle, [deformer.parallel(-rc-eps)]) c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/gallery/path/springs.txt000066400000000000000000000020401526513311100220410ustar00rootroot00000000000000Deforming paths In this example, another type of stroke attributes is demonstrated, namely the `deformers`. They take an original curve and return a modified one. ... Here, the first deformer bends three arcs into spirals, the next one smooths the result a bit. In the example code, a circle is first created and then split into three segments. Each segment of the arc is then stroked with `deformer.cycloid` and `deformer.smoothed`, which create the spring-like look of the segments. The cycloid does not start at the very beginning of the original path. Instead, it first follows the original path for a certain length and then starts, yielding a sharp corner. This corner is smoothed a bit by the second deformer. ! Note that the order of the deformer attributes is not arbitrary, since the deforming operations do not commute. The two circles surrounding the springs are not created as simple circles but rather as the curves with constant distance to the original circle. This demonstrates the use of a third deformer, namely `deformer.parallel`. pyx-project-pyx-21f71ce/gallery/path/tree.py000066400000000000000000000021331526513311100211270ustar00rootroot00000000000000# fractal tree # contributed by Gerhard Schmid and André Wobst from pyx import * # base tree length l = 5 # base transformations for the left, center, and right part of the tree ltrafo = trafo.rotate(65).scaled(0.4).translated(0, l * 2.0 / 3.0) ctrafo = trafo.rotate(-4).scaled(0.75).translated(0, l) rtrafo = trafo.mirror(90).rotated(-65).scaled(0.35).translated(0, l) def tree(depth): "return transformations for a recursive tree of given depth" r = [trafo.rotate(5)] if depth > 0: subtree = tree(depth - 1) r.extend([t*ltrafo for t in subtree]) r.extend([t*ctrafo for t in subtree]) r.extend([t*rtrafo for t in subtree]) return r c = canvas.canvas() for t in tree(7): # apply the transformation to a "sub"-canvas and insert it into the "main" canvas c.insert(canvas.canvas([t])).stroke(path.line(0, 0, 0, l)) # note that there is a difference when only transforming the line as in: # c.stroke(path.line(0, 0, 0, l), [t]) # The difference is, that the linewidth would not be scaled down. c.writeEPSfile() c.writePDFfile() c.writeSVGfile() pyx-project-pyx-21f71ce/manual/000077500000000000000000000000001526513311100165015ustar00rootroot00000000000000pyx-project-pyx-21f71ce/manual/.gitignore000066400000000000000000000000241526513311100204650ustar00rootroot00000000000000*.png *.pdf _build/ pyx-project-pyx-21f71ce/manual/.latex2html-init000066400000000000000000000000521526513311100215240ustar00rootroot00000000000000$LATEX_COLOR = "\\pagecolor[gray]{1}"; 1; pyx-project-pyx-21f71ce/manual/Makefile000066400000000000000000000022521526513311100201420ustar00rootroot00000000000000# Makefile for Sphinx documentation # PYTHON ?= python3 GS ?= gs # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean all html latexpdf figs all: html latexpdf @echo "Done." clean: -rm -rf $(BUILDDIR)/* *.pdf *.png html: figs $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." latexpdf: figs $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." doctest: cd ../pyx;$(SPHINXBUILD) -b doctest ../manual ../manual/$(BUILDDIR)/doctest figs: $(patsubst %.py, %.png, $(filter-out conf.py,$(wildcard *.py))) %.pdf: %.py $(PYTHON) $^ %.png: %.pdf $(GS) -r100 -dNOPAUSE -dQUIET -dBATCH -sDEVICE=pngalpha -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -sOutputFile=$@ $^ pyx-project-pyx-21f71ce/manual/arct.py000077500000000000000000000011111526513311100200010ustar00rootroot00000000000000#!/bin/python3 from pyx import * c = canvas.canvas() def bluedot(x, y): c.fill(path.circle_pt(x, y, 2), [color.rgb.blue]) c.stroke(path.path(path.moveto(0, 0), path.arct(2, 0, 1.5, 1, 0.5))) def bluedot(x, y): c.fill(path.circle(x, y, 0.03), [color.rgb.blue]) bluedot(0, 0) bluedot(2, 0) bluedot(1.5, 1) margin=0.1 c.text(0-margin, 0, r"current point $(0, 0)$", [text.halign.right, text.valign.baseline]) c.text(2+margin, 0, r"$(2, 0)$", [text.halign.left, text.valign.baseline]) c.text(1.5-margin, 1, r"$(1.5, 1)$", [text.halign.right, text.valign.baseline]) c.writePDFfile() pyx-project-pyx-21f71ce/manual/arrows.py000077500000000000000000000022331526513311100203730ustar00rootroot00000000000000from pyx import * text.set(text.LatexRunner) text.preamble(r"\renewcommand{\familydefault}{\ttdefault}") c = canvas.canvas() # positioning is quite ugly ... but it works at the moment x = 0 y = 0 dx = 6 dy = -0.65 length = 1.2 def drawdeco(name, showpath=0, default=0): global x,y p = path.path(path.moveto(x + 0.1, y+0.1 ), path.rlineto(length/2.0, 0.3), path.rlineto(length/2.0, -0.3)) c.stroke(p, [style.linewidth.THIck, eval("deco."+name)]) if showpath: c.stroke(p, [style.linewidth.Thin, color.gray.white]) if default: name = name + r"\rm\quad (default)" c.text(x + 1.5, y + 0.15, name, [text.size.footnotesize]) y += dy if y < -16: y = 0 x += dx drawdeco("earrow.Small") drawdeco("earrow.small") drawdeco("earrow.normal") drawdeco("earrow.large") drawdeco("earrow.Large") y += dy drawdeco("barrow.normal") y += dy drawdeco("earrow.Large([deco.filled([color.rgb.red]), style.linewidth.normal])") drawdeco("earrow.normal(constriction=None)") drawdeco("earrow.Large([style.linejoin.round])") drawdeco("earrow.Large([deco.stroked.clear])") c.writePDFfile() pyx-project-pyx-21f71ce/manual/arrows.rst000066400000000000000000000007401526513311100205510ustar00rootroot00000000000000.. _arrows: ************************************** Appendix: Arrows in :mod:`deco` module ************************************** The following figure illustrates the predefined ending (:data:`deco.earrow`) and beginning (:data:`deco.barrow`) arrow decorators and their customization in the :mod:`deco` module (see section :ref:`deco` for detailed documentation). .. _fig_arrows: .. figure:: arrows.* :align: center Predefined arrow decorators in the :mod:`deco` module. pyx-project-pyx-21f71ce/manual/axis.rst000066400000000000000000000760511526513311100202100ustar00rootroot00000000000000.. module:: graph.axis :synopsis: Modular graph axes, ticks, partitioners, texters, painters, and raters .. _axis: **** Axes **** Component Architecture ====================== Axes in PyX convert data values into normalized graph coordinates :math:`v \in [0, 1]` and render the visual axis elements (baseline, tick marks, grid lines, tick labels, and axis title). Although most commonly used inside a :class:`graph.graphxy` or :class:`graph.graphxyz`, axes can also be drawn standalone along any arbitrary path using :func:`graph.axis.pathaxis`. Internally, each axis delegates its work to six modular components located in submodules of :mod:`graph.axis`: ``axis`` (:mod:`graph.axis.axis`) Defines the mathematical mapping between data values and normalized graph coordinates :math:`[0, 1]`, orchestrates automatic range adjustment, and combines the partitioner, texter, painter, and rater to choose the optimal tick layout. Because an axis instance itself is stateless, a graph wraps each axis in an :class:`~graph.axis.axis.anchoredaxis` container that pairs the axis with a geometric :class:`~graph.axis.positioner.positioner` and holds per-graph range and tick data. ``tick`` (:mod:`graph.axis.tick`) Represents individual ticks and subticks placed along an axis, using exact rational arithmetic (:class:`~graph.axis.tick.rational`) to avoid floating-point rounding artifacts. ``parter`` (:mod:`graph.axis.parter`) Short for *partitioner*: generates one or more candidate lists of tick and subtick positions for a given data range. ``texter`` (:mod:`graph.axis.texter`) Formats numeric or rational tick positions into label strings (using decimal, scientific/exponential, or fraction notation). ``painter`` (:mod:`graph.axis.painter`) Paints the axis baseline, ticks, grid lines, tick labels, and axis title onto an axis canvas. ``rater`` (:mod:`graph.axis.rater`) Evaluates candidate tick partitionings by scoring the number of ticks/labels and checking the painted label boxes for overlaps or crowding. The candidate with the lowest penalty score is selected. ``positioner`` (:mod:`graph.axis.positioner`) Defines the geometric curve (straight line or arbitrary path), tick direction, and grid paths of an anchored axis on the canvas. Customizing Axes and Subcomponents via Keyword Splitting -------------------------------------------------------- Every axis, painter, and texter instance in :mod:`graph.axis` is callable (implementing ``__call__`` via :func:`utils.merge_members_kwargs`) and supports underscore-separated keyword forwarding (:func:`utils.kwsplit`). This means you can customize nested components without verbose boilerplate: .. code-block:: python from pyx import * # Equivalent ways to enable grid lines and set a custom label prefix on a linear axis: ax1 = graph.axis.linear(min=0, max=10, painter=graph.axis.painter.regular(gridattrs=[color.gray(0.8)]), texter=graph.axis.texter.default(mantissatexter_prefix=r"\$")) ax2 = graph.axis.linear(min=0, max=10, painter_gridattrs=[color.gray(0.8)], texter_mantissatexter_prefix=r"\$") .. module:: graph.axis.axis :synopsis: Linear, logarithmic, bar, and split axes Module :mod:`graph.axis.axis`: Axis Classes =========================================== All classes in :mod:`graph.axis.axis` are also exposed directly in :mod:`graph.axis` (e.g. ``graph.axis.linear``, ``graph.axis.log``, ``graph.axis.bar``). Continuous Regular Axes (:class:`linear` and :class:`logarithmic`) ------------------------------------------------------------------ .. class:: linear(min=None, max=None, reverse=0, divisor=None, title=None, parter=parter.autolinear(), manualticks=[], rater=rater.linear(), maxworse=2, texter=texter.default(), painter=painter.regular(), linkpainter=painter.linked(), fallbackrange=None, **kwargs) A linear axis mapping :math:`[\text{min}, \text{max}]` linearly onto :math:`[0, 1]`. Also available under the short alias :class:`lin`. * *min*, *max*: Fixed lower and upper bounds of the axis. When left as ``None``, the bounds are determined automatically from the plotted data and extended to the nearest outer tick if allowed by *parter*. If ``min > max``, the bounds are swapped and *reverse* is toggled automatically. * *reverse*: When true, reverses the direction of the axis so values decrease from ``0`` to ``1`` in graph coordinates. * *divisor*: Optional number by which all data values are divided before partitioning and formatting ticks (for example, ``divisor=math.pi`` paired with ``texter=graph.axis.texter.rational(suffix=r"\pi")`` labels ticks in multiples of :math:`\pi`). * *title*: Axis title string, typeset using the graph's text engine. * *parter*: Partitioner instance (default :class:`parter.autolinear`) or ``None`` to draw only *manualticks*. * *manualticks*: List of :class:`~graph.axis.tick.tick` instances merged with the ticks generated by *parter* (manual ticks override automatic ticks at identical positions). * *rater*, *maxworse*: Rater instance (:class:`rater.linear`) and maximum number of consecutively worse partitioning candidates to explore before stopping the search in each direction. * *texter*: Texter instance (default :class:`texter.default`) used to format unlabeled ticks. * *painter*: Painter instance (default :class:`painter.regular`) used to draw the primary axis. * *linkpainter*: Painter instance (default :class:`painter.linked`) used when an opposite linked axis (such as ``x2`` or ``y2``) is created automatically. * *fallbackrange*: Minimal range width (or ``(min, max)`` tuple) used when the plotted data has zero span (for example, a constant function). * *\*\*kwargs*: Underscore-split keyword arguments forwarded to ``painter``, ``texter``, ``linkpainter``, ``parter``, or ``rater`` (e.g. ``painter_gridattrs=...``). .. class:: lin(...) Alias for :class:`linear`. .. class:: logarithmic(min=None, max=None, reverse=0, divisor=None, title=None, parter=parter.autologarithmic(), linearparter=parter.autolinear(extendtick=None), manualticks=[], maxworse=2, rater=rater.logarithmic(), texter=texter.default(), painter=painter.regular(), linkpainter=painter.linked(), fallbackrange=None, **kwargs) A logarithmic axis mapping positive (or negative) values logarithmically onto :math:`[0, 1]`. Also available under the short alias :class:`log`. All arguments work as in :class:`linear`, with defaults tailored for logarithmic scales (:class:`parter.autologarithmic` and :class:`rater.logarithmic`). If the data spans such a narrow interval that no valid logarithmic partitioning without overlapping labels can be found, the axis logs a warning and automatically falls back to *linearparter* (unless ``linearparter=None``). .. class:: log(...) Alias for :class:`logarithmic`. Discrete and Segmented Axes (:class:`bar`, :class:`nestedbar`, and :class:`split`) ---------------------------------------------------------------------------------- .. class:: bar(subaxes=None, defaultsubaxis=linear(painter=None, linkpainter=None, parter=None), dist=0.5, firstdist=None, lastdist=None, title=None, reverse=0, epsilon=1e-10, painter=painter.bar(), linkpainter=painter.linkedbar(), **kwargs) Discrete categorical axis for bar charts (:class:`graph.style.bar`). A bar axis maps a 2-tuple ``(name, subvalue)`` to a normalized graph coordinate: * ``name`` selects one of the discrete categories along the bar axis (ordered by their appearance in the data, or reversed when ``reverse=1``). * ``subvalue`` is converted by the subaxis associated with ``name`` and mapped into the sub-interval of :math:`[0, 1]` allocated to that category. * *subaxes*: Optional dictionary or sequence mapping category names to explicit subaxis instances; any category not in *subaxes* uses a copy of *defaultsubaxis*. * *dist*, *firstdist*, *lastdist*: Spacing between consecutive category intervals, before the first category, and after the last category, measured relative to a unit subaxis size of ``1`` (default ``dist=0.5``, with *firstdist* and *lastdist* defaulting to ``0.5 * dist``). * *\*\*kwargs*: Underscore-split keyword arguments forwarded to ``defaultsubaxis``, ``painter``, or ``linkpainter``. .. class:: nestedbar(subaxes=None, defaultsubaxis=bar(dist=0, painter=None, linkpainter=None), dist=0.5, firstdist=None, lastdist=None, title=None, reverse=0, painter=painter.bar(), linkpainter=painter.linkedbar(), **kwargs) A two-level hierarchical bar axis for grouped side-by-side bar charts, where *defaultsubaxis* is itself a :class:`bar` axis with ``dist=0``. Data values passed to a :class:`nestedbar` axis have the nested tuple form ``((category, subcategory), subvalue)``. .. class:: split(subaxes=None, defaultsubaxis=linear(), dist=0.5, firstdist=0, lastdist=0, title=None, reverse=0, painter=painter.split(), linkpainter=painter.linkedsplit(), **kwargs) A segmented continuous axis divided into multiple continuous sub-ranges separated by visual break markers (painted by :class:`painter.split`). Data values can be routed to subaxes automatically using :func:`graph.data.splitatvalue`. .. class:: sizedlinear(size=1, **kwargs) .. class:: autosizedlinear(**kwargs) Subclasses of :class:`linear` (also aliased as :class:`sizedlin` and :class:`autosizedlin`) for use as subaxes in a :class:`bar` or :class:`split` axis. :class:`sizedlinear` assigns a fixed relative width *size* to the subaxis, whereas :class:`autosizedlinear` scales the width of each subaxis proportionally to its data span ``max - min``. Anchored, Linked, and Standalone Path Axes ------------------------------------------ .. class:: anchoredaxis(axis, textengine, errorname) Combines an :class:`_axis` instance with a :class:`positioner.positioner` and per-graph storage (``self.data`` and ``self.canvas``). Graph instances store their anchored axes in ``g.axes[name]``. Once the axis layout has been created, :class:`anchoredaxis` provides the following geometric methods: .. method:: basepath(x1=None, x2=None) .. method:: vbasepath(v1=None, v2=None) Returns a :class:`path.path` along the axis baseline between data values *x1* and *x2* (or graph coordinates *v1* and *v2*). .. method:: gridpath(x) .. method:: vgridpath(v) Returns the grid line :class:`path.path` across the graph at data value *x* (or graph coordinate *v*), or ``None`` if no grid path is defined. .. method:: tickpoint(x) .. method:: tickpoint_pt(x) .. method:: vtickpoint(v) .. method:: vtickpoint_pt(v) Returns the canvas coordinates ``(x, y)`` of the point on the axis baseline corresponding to data value *x* (or graph coordinate *v*). .. method:: tickdirection(x) .. method:: vtickdirection(v) Returns the unit normal vector ``(dx, dy)`` pointing toward the interior of the graph at data value *x* (or graph coordinate *v*). .. class:: linkedaxis(linkedaxis=None, errorname="manual-linked", painter=_marker, **kwargs) An anchored axis that shares the data range, scaling, and tick positions of another :class:`anchoredaxis` instance *linkedaxis* (for example, to link an axis in one graph to the axis of an adjacent graph in a multi-panel figure). .. method:: setlinkedaxis(linkedaxis) Binds or updates the target *linkedaxis* after construction. .. class:: anchoredpathaxis(path, axis, textengine=text.defaulttextengine, direction=1) .. function:: pathaxis(path, axis, **kwargs) Creates and paints a standalone *axis* (which must have explicit *min* and *max* bounds) along an arbitrary geometric :class:`path.path`. *direction* specifies whether ticks point to the left (``1``, default) or right (``-1``) of the path tangent. :func:`pathaxis` immediately builds the axis and returns its painted :class:`canvas.canvas` so it can be inserted directly into any canvas: .. code-block:: python c = canvas.canvas() c.insert(graph.axis.pathaxis(path.curve(0, 0, 2, 2, 4, -2, 6, 0), graph.axis.linear(min=0, max=10))) .. module:: graph.axis.timeaxis :synopsis: Axes for Python datetime data Module :mod:`graph.axis.timeaxis`: Date and Time Axes ===================================================== The :mod:`graph.axis.timeaxis` module provides classes for plotting Python :class:`datetime.datetime` (or :class:`datetime.date`) objects along a continuous axis: .. class:: timeaxis(parter=None, rater=rater.linear(), **args) A continuous axis (inheriting from :class:`~graph.axis.linear`) whose data bounds and values are Python :class:`datetime.datetime` instances. .. class:: timetick(year, month, day, ticklevel=0, labellevel=0, label=None, labelattrs=[], **kwargs) A tick subclassing :class:`datetime.datetime` with tick and label hierarchy levels *ticklevel* and *labellevel* and optional explicit *label*. .. class:: timetexter(format="%c") Formats :class:`timetick` positions using :meth:`datetime.datetime.strftime` with the given *format* string. .. module:: graph.axis.tick :synopsis: Rational numbers and axis ticks Module :mod:`graph.axis.tick`: Axis Ticks ========================================= .. class:: rational(x, power=1, floatprecision=10) Exact rational number ``num / denom`` used internally by partitioners and texters to avoid floating-point rounding errors. *x* can be: * A ``float`` (converted using precision *floatprecision*), * A decimal or fraction string (such as ``"0.25"`` or ``"1/3"``), * A 2-tuple of integers ``(num, denom)``, or * Any object with ``.num`` and ``.denom`` integer attributes (or a Python :class:`fractions.Fraction`). If *power* is given, the rational number is raised to the integer exponent *power*. .. class:: tick(x, ticklevel=0, labellevel=0, label=None, labelattrs=[], power=1, floatprecision=10) Represents a tick mark and/or label at position *x* (interpreted as a :class:`rational`). Instances of :class:`tick` can be passed to the ``manualticks`` list of any regular axis: .. code-block:: python ax = graph.axis.linear(min=0, max=4, manualticks=[graph.axis.tick.tick(math.pi, label=r"$\pi$")]) * *ticklevel*: Non-negative integer specifying the tick hierarchy level (``0`` for a major tick, ``1`` for a subtick, ``2`` for a sub-subtick, etc.), or ``None`` to draw no tick mark at this position. * *labellevel*: Non-negative integer specifying the label hierarchy level (``0`` for a major label, ``1`` for a sublabel, etc.), or ``None`` to omit the label at this position. * *label*: Explicit label string, or ``None`` to let the axis's :mod:`~graph.axis.texter` generate the label automatically. * *labelattrs*: Additional text attributes applied to this specific tick's label. .. module:: graph.axis.parter :synopsis: Automatic and manual axis partitioners Module :mod:`graph.axis.parter`: Axis Partitioners ================================================== Partitioners generate candidate lists of :class:`~graph.axis.tick.tick` instances for a given axis range. Linear Partitioners ------------------- .. class:: linear(tickdists=None, labeldists=None, extendtick=0, extendlabel=None, epsilon=1e-10) .. class:: lin(...) Places ticks at fixed equidistant intervals specified in *tickdists* (a list of intervals ``[major_step, subtick_step, ...]``, where each step can be a number, string, or :class:`~graph.axis.tick.rational`). * *labeldists*: Optional list of step sizes for labeled ticks. When ``None`` (default), labels are placed at major ticks (level ``0``) only. * *extendtick*, *extendlabel*: Tick or label level (default ``0`` for *extendtick*, ``None`` for *extendlabel*) to which an auto-ranged axis is expanded if the data exceeds the outermost tick by more than *epsilon*. .. class:: autolinear(variants=defaultvariants, extendtick=0, epsilon=1e-10) .. class:: autolin(...) Automatically generates candidate :class:`linear` partitionings by scaling the base step patterns in *variants* by powers of 10 to match the data span. .. attribute:: autolinear.defaultvariants ``[[1, 1/2], [2, 1], [5/2, 5/4], [5, 5/2]]`` (represented as :class:`~graph.axis.tick.rational` pairs of ``[tick_step, subtick_step]``). Logarithmic Partitioners ------------------------ .. class:: preexp(pres, exp) Specifies a repeating sequence of logarithmic tick positions of the form :math:`p_i \cdot \text{exp}^n` for all integers :math:`n` and prefixes :math:`p_i \in \text{pres}`. .. class:: logarithmic(tickpreexps=None, labelpreexps=None, extendtick=0, extendlabel=None, epsilon=1e-10) .. class:: log(...) Places ticks on a logarithmic axis according to the list of :class:`preexp` instances in *tickpreexps* (for ticks, subticks, …) and *labelpreexps* (for labels, sublabels, …). Predefined :class:`preexp` constants on :class:`logarithmic`: * :attr:`logarithmic.pre1exp` — powers of 10 (:math:`10^n`) * :attr:`logarithmic.pre125exp` — :math:`1, 2, 5 \times 10^n` * :attr:`logarithmic.pre1to9exp` — :math:`1, 2, \dots, 9 \times 10^n` .. class:: autologarithmic(variants=defaultvariants, extendtick=0, extendlabel=None, autoexponent=10, epsilon=1e-10) .. class:: autolog(...) Evaluates candidate logarithmic tick and label patterns from *variants* (ordered from densest to sparsest) for rating by the axis rater. .. module:: graph.axis.texter :synopsis: Tick label formatters Module :mod:`graph.axis.texter`: Axis Texters ============================================= Texters format the numeric value of each :class:`~graph.axis.tick.tick` whose ``labellevel`` is not ``None`` and whose ``label`` is not already set manually. All texters are callable so you can clone and tweak them via keyword arguments. .. class:: default(multiplicationtex=r"\cdot{}", multiplicationunicode="·", base=Fraction(10), skipmantissaunity=skipmantissaunity.all, minusunity="-", minexponent=4, minnegexponent=None, uniformexponent=True, mantissatexter=decimal(), basetexter=decimal(), exponenttexter=decimal(), labelattrs=[text.mathmode], **kwargs) The default texter for linear and logarithmic axes. Formats moderate numbers in plain decimal notation and automatically switches to scientific notation (:math:`m \cdot 10^e`) for large or small exponents, producing a :class:`text.MultiEngineText` that works seamlessly with both TeX/LaTeX engines and :class:`text.UnicodeEngine`. * *multiplicationtex*, *multiplicationunicode*: Multiplication symbol placed between the mantissa and base for TeX engines and :class:`text.UnicodeEngine`, respectively. * *base*: Exponent base (default ``Fraction(10)``). * *skipmantissaunity*: Controls when a mantissa of ``1`` is omitted (so :math:`1 \cdot 10^5` is written simply as :math:`10^5`): - :attr:`skipmantissaunity.never` (``0``): Always write :math:`1 \cdot 10^e`. - :attr:`skipmantissaunity.each` (``1``): Omit ``1`` on any individual tick whose mantissa is unity. - :attr:`skipmantissaunity.all` (``2``, default): Omit ``1`` only when *all* exponentially formatted ticks on the axis have a mantissa of unity (as on a standard logarithmic axis). * *minexponent*, *minnegexponent*: Minimum positive exponent (default ``4``, i.e. :math:`10^4`) and minimum negative exponent magnitude (defaults to *minexponent*, i.e. :math:`10^{-4}`) at which exponential notation is used. * *uniformexponent*: When ``True`` (default), if any non-zero tick on the axis triggers exponential notation, all non-zero ticks on the axis are formatted in exponential notation for visual consistency. * *mantissatexter*, *basetexter*, *exponenttexter*: :class:`decimal` texters used to format the mantissa, base, and exponent (can also be configured via underscore-split keywords such as ``mantissatexter_equalprecision=True``). * *labelattrs*: Text attributes added to each formatted tick (default ``[text.mathmode]``). .. class:: decimal(prefix="", infix="", suffix="", equalprecision=False, decimalsep=".", thousandsep="", thousandthpartsep="", plus="", minus="-", period=r"\overline{%s}", labelattrs=[text.mathmode]) Formats ticks in fixed-point decimal notation. * *prefix*, *infix*, *suffix*: Strings inserted before the sign, immediately after the sign, and at the end of the number, respectively. * *equalprecision*: When ``True``, pads all decimal tick labels on the axis with trailing zeros to match the tick with the most decimal places. * *decimalsep*, *thousandsep*, *thousandthpartsep*: Separators for the decimal point and 3-digit groups in the integer and fractional parts. * *plus*, *minus*: Sign strings for non-negative and negative values. * *period*: Format string with a single ``%s`` placeholder used to render repeating decimal periods (default ``r"\overline{%s}"``). .. class:: rational(prefix="", infix="", suffix="", numprefix="", numinfix="", numsuffix="", denomprefix="", denominfix="", denomsuffix="", plus="", minus="-", minuspos=0, over=r"{{%s}\over{%s}}", equaldenom=False, skip1=True, skipnum0=True, skipnum1=True, skipdenom1=True, labelattrs=[text.mathmode]) Formats ticks as exact reduced fractions :math:`\frac{a}{b}` (especially useful for axes partitioned in multiples of :math:`\pi` or rational fractions). * *prefix*, *infix*, *suffix*: Strings placed around the entire fraction. * *numprefix*, *numinfix*, *numsuffix*: Strings placed around the numerator (for example, ``numsuffix=r"\pi"``). * *denomprefix*, *denominfix*, *denomsuffix*: Strings placed around the denominator. * *minuspos*: Placement of the sign: ``0`` (in front of the fraction), ``1`` (in the numerator), or ``-1`` (in the denominator). * *over*: Format string with two ``%s`` placeholders for numerator and denominator (default ``r"{{%s}\over{%s}}"``; use ``r"{{%s}/{%s}}"`` for inline slash fractions). * *equaldenom*: When ``True``, expresses all fractions on the axis over their least common denominator instead of reducing each fraction individually. * *skip1*, *skipnum0*, *skipnum1*, *skipdenom1*: Booleans controlling automatic simplification when the fraction is :math:`\pm 1`, the numerator is ``0`` or :math:`\pm 1`, or the denominator is ``1``. .. module:: graph.axis.painter :synopsis: Axis painters Module :mod:`graph.axis.painter`: Axis Painters =============================================== Painters draw the visual representation of an axis onto an :class:`axiscanvas`. Helper Classes (:class:`rotatetext` and :class:`ticklength`) ------------------------------------------------------------ .. class:: rotatetext(direction, epsilon=1e-10) Computes a :class:`trafo.rotate` transformation for axis labels or titles at angle *direction* (in degrees) relative to the inward tick direction, automatically flipping the text by 180° whenever it would otherwise appear upside-down. .. attribute:: rotatetext.parallel ``rotatetext(90)`` — orients text parallel to the axis baseline. .. attribute:: rotatetext.orthogonal ``rotatetext(180)`` — orients text perpendicular to the axis baseline. .. class:: ticklength(initial, factor) A changeable attribute (:class:`attr.changeattr`) that generates a geometric progression of visual lengths :math:`\text{initial} \cdot \text{factor}^k` for major ticks (:math:`k = 0`), subticks (:math:`k = 1`), sub-subticks (:math:`k = 2`), etc. Predefined instances with ``factor = 1 / goldenmean`` and base length ``0.12 * unit.v_cm`` scaled by powers of :math:`\sqrt{2}` are provided as class attributes: ``ticklength.SHORT``, ``ticklength.SHORt``, ``ticklength.SHOrt``, ``ticklength.SHort``, ``ticklength.Short``, ``ticklength.short``, ``ticklength.normal``, ``ticklength.long``, ``ticklength.Long``, ``ticklength.LOng``, ``ticklength.LONg``, and ``ticklength.LONG``. Painter Classes --------------- .. class:: regular(innerticklength=ticklength.normal, outerticklength=None, tickattrs=[], gridattrs=None, basepathattrs=[], labeldist=0.3*unit.v_cm, labelattrs=[], labeldirection=None, labelhequalize=0, labelvequalize=1, titledist=0.3*unit.v_cm, titleattrs=[], titledirection=rotatetext.parallel, titlepos=0.5, textengine=None) Default painter for continuous axes (:class:`~graph.axis.axis.linear`, :class:`~graph.axis.axis.logarithmic`, :class:`~graph.axis.timeaxis.timeaxis`). * *innerticklength*, *outerticklength*: Visual length (or changeable :class:`ticklength`) of ticks pointing inside and outside the graph, or ``None`` to omit inner or outer ticks. * *tickattrs*: Stroke attributes for ticks (supports changeable attributes to style major ticks and subticks differently), or ``None`` to suppress ticks. * *gridattrs*: Stroke attributes for grid lines across the graph (for example, ``[color.gray(0.8)]`` or ``[attr.changelist([style.linestyle.solid, style.linestyle.dotted])]``), or ``None`` (default) to disable grid lines. * *basepathattrs*: Stroke attributes for the axis baseline (merged with ``[style.linecap.square]``), or ``None`` to omit the baseline. * *labeldist*: Visual distance between the axis baseline (or outer ticks) and the tick labels (default ``0.3 * unit.v_cm``). * *labelattrs*: Text attributes for tick labels (merged with ``[text.halign.center, text.vshift.mathaxis]``), or ``None`` to suppress tick labels. * *labeldirection*: Optional :class:`rotatetext` instance to rotate tick labels relative to the axis. * *labelhequalize*, *labelvequalize*: Aligns all tick labels along a common horizontal or vertical line on straight vertical or horizontal axes. * *titledist*, *titleattrs*, *titledirection*, *titlepos*: Distance, text attributes (or ``None`` to hide), rotation (:attr:`rotatetext.parallel` by default), and normalized position (:math:`0.5` = centered) of the axis title. * *textengine*: Optional text engine override (defaults to the graph's text engine). .. class:: linked(innerticklength=ticklength.short, outerticklength=None, tickattrs=[], gridattrs=None, basepathattrs=[], labeldist=0.3*unit.v_cm, labelattrs=None, labeldirection=None, labelhequalize=0, labelvequalize=1, titledist=0.3*unit.v_cm, titleattrs=None, titledirection=rotatetext.parallel, titlepos=0.5, textengine=None) Subclass of :class:`regular` used by default for opposite linked axes (``x2``, ``y2``), with ``innerticklength=ticklength.short`` and labels and titles disabled (``labelattrs=None, titleattrs=None``). .. class:: bar(innerticklength=None, outerticklength=None, tickattrs=[], basepathattrs=[], namedist=0.3*unit.v_cm, nameattrs=[], namedirection=None, namepos=0.5, namehequalize=0, namevequalize=1, titledist=0.3*unit.v_cm, titleattrs=[], titledirection=rotatetext.parallel, titlepos=0.5, textengine=None) .. class:: linkedbar(...) Painters for :class:`~graph.axis.axis.bar` and :class:`~graph.axis.axis.nestedbar` axes. The ``name*`` parameters control the placement and formatting of the categorical bar labels, while *innerticklength* and *outerticklength* optionally mark the boundaries of each bar subaxis. :class:`linkedbar` disables category names and the axis title by default. .. class:: split(breaklinesdist=0.05*unit.v_cm, breaklineslength=0.5*unit.v_cm, breaklinesangle=-60, titledist=0.3*unit.v_cm, titleattrs=[], titledirection=rotatetext.parallel, titlepos=0.5, textengine=None) .. class:: linkedsplit(...) Painters for :class:`~graph.axis.axis.split` axes, drawing parallel break slashes separated by *breaklinesdist* of length *breaklineslength* at angle *breaklinesangle* (in degrees) between adjacent subaxes. .. module:: graph.axis.rater :synopsis: Rating of candidate axis partitionings Module :mod:`graph.axis.rater`: Axis Raters =========================================== When an automatic partitioner (:class:`~graph.axis.parter.autolinear` or :class:`~graph.axis.parter.autologarithmic`) produces multiple candidate tick lists, an axis :class:`rater` assigns a non-negative penalty score to each candidate (where smaller scores are better): 1. **Tick count and range rating**: Scores the number of ticks, subticks, and labels against target optima (:class:`cube`) and penalizes excessive range expansion beyond the data bounds. 2. **Label layout rating**: For the top-ranked candidates, paints the axis and checks the spacing between adjacent label boxes (:class:`distance`). Any candidate whose labels overlap is rejected completely. .. class:: cube(opt, left=None, right=None, weight=1) Cubic penalty function :math:`\text{weight} \cdot ((x - \text{opt}) / (\text{other} - \text{opt}))^3` evaluating how far a count :math:`x` deviates from the optimal value *opt*, where *other* is *left* (default ``0``) for :math:`x < \text{opt}` and *right* (default ``3 * opt``) for :math:`x > \text{opt}`. .. class:: distance(opt=1*unit.v_cm, weight=0.1) Rates the visual separation between adjacent tick label boxes against the optimal separation *opt* (rejecting negative separations where labels overlap). .. class:: rater(ticks, labels, range, distance=distance(1*unit.v_cm), density=1) Combines lists of :class:`cube` raters for *ticks* and *labels* at each hierarchy level, a :class:`cube` rater for *range* extension, and a :class:`distance` rater for label spacing. Increasing *density* (e.g. ``density=1.5`` or ``2``) scales the optimal tick and label counts upward to favor denser ticks; decreasing *density* (e.g. ``density=0.7``) favors fewer ticks. .. class:: linear(ticks=[cube(4), cube(10, weight=0.5)], labels=[cube(4)], range=cube(1, weight=2), **kwargs) .. class:: lin(...) Default rater for linear axes. .. class:: logarithmic(ticks=[cube(5, right=20), cube(20, right=100, weight=0.5)], labels=[cube(5, right=20), cube(5, right=20, weight=0.5)], range=cube(1, weight=2), **kwargs) .. class:: log(...) Default rater for logarithmic axes. .. module:: graph.axis.positioner :synopsis: Geometric positioning of axes Module :mod:`graph.axis.positioner`: Axis Positioners ===================================================== Positioner instances define the geometric placement of an axis on a canvas and are created automatically by :class:`graph.graphxy`, :class:`graph.graphxyz`, and :func:`graph.axis.pathaxis`. Every positioner implements the following interface: .. class:: _positioner() .. method:: vbasepath(v1=None, v2=None) Returns the :class:`path.path` of the axis baseline between normalized graph coordinates *v1* and *v2*. .. method:: vgridpath(v) Returns the grid line :class:`path.path` at normalized coordinate *v*, or ``None`` if no grid is defined. .. method:: vtickpoint_pt(v) Returns ``(x_pt, y_pt)`` in PostScript points on the baseline at normalized coordinate *v*. .. method:: vtickdirection(v) Returns the unit normal vector ``(dx, dy)`` pointing toward the graph interior at normalized coordinate *v*. pyx-project-pyx-21f71ce/manual/bbox.rst000066400000000000000000000207341526513311100201730ustar00rootroot00000000000000.. _bbox_module: .. _bbox: .. module:: bbox :synopsis: Axis-aligned bounding boxes ****************** Module :mod:`bbox` ****************** The :mod:`bbox` module defines axis-aligned bounding boxes (:class:`bbox`, :class:`bbox_pt`, and :class:`empty`) used throughout PyX to compute the spatial extent of paths, text boxes, canvases, and pages. While you most commonly obtain a bounding box by calling an object's ``bbox()`` method (such as :meth:`canvas.canvas.bbox` or :meth:`path.path.bbox`), you can also construct and manipulate bounding boxes directly—for example, to pass a custom clipping or page bounding box to :meth:`canvas.canvas.writeEPSfile` or :class:`document.page`. Constructing Bounding Boxes =========================== .. class:: bbox(llx, lly, urx, ury) Constructs a bounding box with lower-left corner ``(llx, lly)`` and upper-right corner ``(urx, ury)`` specified in user units or PyX lengths. .. class:: bbox_pt(llx_pt, lly_pt, urx_pt, ury_pt) Constructs a bounding box with coordinates ``(llx_pt, lly_pt)`` and ``(urx_pt, ury_pt)`` specified directly in PostScript points. All ``bbox()`` methods on PyX objects return :class:`bbox_pt` instances. .. class:: empty() Constructs an empty bounding box (containing no points, with ``llx_pt=None``). An empty bounding box evaluates to ``False`` in a boolean context (``bool(bbox.empty()) == False``), whereas any non-empty bounding box evaluates to ``True``. Set Operations and Methods ========================== Two bounding boxes ``b1`` and ``b2`` can be combined using arithmetic operators: * **Union** (``b1 + b2`` or ``b1 += b2``): Returns the smallest bounding box enclosing both ``b1`` and ``b2``. Adding an :class:`empty` bounding box leaves the other bounding box unchanged. * **Intersection** (``b1 * b2`` or ``b1 *= b2``): Returns the overlapping region of ``b1`` and ``b2`` (or an :class:`empty` bounding box if either input is empty). In addition, :class:`bbox` and :class:`bbox_pt` provide the following methods (where measurement methods without a ``_pt`` suffix return true PyX lengths :data:`unit.t_pt`, and ``_pt`` variants take or return plain floats in PostScript points): +---------------------------------------------------------+---------------------------------------------------------------+ | Method | Description | +=========================================================+===============================================================+ | ``copy()`` | Returns a copy of the bounding box. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``set(other)`` | Copies the coordinates of *other* into ``self``. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``intersects(other)`` | Returns ``True`` if ``self`` and *other* overlap (and neither | | | is empty), or ``False``/``0`` otherwise. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``includepoint_pt(x_pt, y_pt)`` | Expands ``self`` in place to include the point | | | ``(x_pt, y_pt)``. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``transform(trafo)`` | Transforms the four corners of ``self`` in place by *trafo* | | | and updates ``self`` to their enclosing axis-aligned box. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``transformed(trafo)`` | Returns a new bounding box enclosing ``self`` after | | | transformation by *trafo*. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``enlarge(all=0, bottom=None, left=None,`` | Expands ``self`` in place on each side by the specified PyX | | ``top=None, right=None)`` | lengths (using *all* for any side left as ``None``). Also | | | available as ``enlarge_pt(...)``. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``enlarged(all=0, bottom=None, left=None,`` | Returns a new bounding box expanded on each side by the | | ``top=None, right=None)`` | specified amounts (using *all* for any side left as | | | ``None``). Also available as ``enlarged_pt(...)``. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``path()`` / ``rect()`` | Returns a rectangular :class:`path.rect_pt` path tracing the | | | boundary of the bounding box. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``width()`` / ``width_pt()`` | Returns the horizontal width of the bounding box. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``height()`` / ``height_pt()`` | Returns the vertical height of the bounding box. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``left()`` / ``left_pt()`` | Returns the *x*-coordinate of the left edge (``llx``). | +---------------------------------------------------------+---------------------------------------------------------------+ | ``right()`` / ``right_pt()`` | Returns the *x*-coordinate of the right edge (``urx``). | +---------------------------------------------------------+---------------------------------------------------------------+ | ``bottom()`` / ``bottom_pt()`` | Returns the *y*-coordinate of the bottom edge (``lly``). | +---------------------------------------------------------+---------------------------------------------------------------+ | ``top()`` / ``top_pt()`` | Returns the *y*-coordinate of the top edge (``ury``). | +---------------------------------------------------------+---------------------------------------------------------------+ | ``center()`` / ``center_pt()`` | Returns the ``(x, y)`` coordinates of the center of the | | | bounding box. | +---------------------------------------------------------+---------------------------------------------------------------+ | ``lowrestuple_pt()`` | Returns ``(floor(llx_pt), floor(lly_pt), ceil(urx_pt),`` | | | ``ceil(ury_pt))`` as integer points (used for PostScript | | | ``%%BoundingBox``). | +---------------------------------------------------------+---------------------------------------------------------------+ | ``highrestuple_pt()`` | Returns ``(llx_pt, lly_pt, urx_pt, ury_pt)`` in exact | | | floating-point points (used for ``%%HiResBoundingBox``). | +---------------------------------------------------------+---------------------------------------------------------------+ pyx-project-pyx-21f71ce/manual/bitmap.py000066400000000000000000000006231526513311100203300ustar00rootroot00000000000000from pyx import * image_bw = bitmap.image(2, 2, "L", b"\0\377\377\0") image_rgb = bitmap.image(3, 2, "RGB", b"\77\77\77\177\177\177\277\277\277" b"\377\0\0\0\377\0\0\0\377") bitmap_bw = bitmap.bitmap(0, 1, image_bw, height=0.8) bitmap_rgb = bitmap.bitmap(0, 0, image_rgb, height=0.8) c = canvas.canvas() c.insert(bitmap_bw) c.insert(bitmap_rgb) c.writePDFfile() pyx-project-pyx-21f71ce/manual/bitmap.rst000066400000000000000000000151771526513311100205220ustar00rootroot00000000000000.. module:: bitmap :synopsis: Bitmap image containers, JPEG reader, and canvas placement .. _bitmap: ******* Bitmaps ******* Introduction ============ Although PyX is primarily designed for scalable vector graphics, the :mod:`bitmap` module provides full support for embedding raster (bitmap) images in PostScript, EPS, PDF, and SVG output. You can construct images directly from raw byte buffers in Python, load JPEG files natively via :class:`jpegimage`, or pass any `Pillow (PIL) `_ ``Image`` object directly to :class:`bitmap`. Example: Creating a Bitmap from Raw Bytes ----------------------------------------- To create a bitmap from raw binary pixel data, first wrap the byte buffer in an :class:`image` instance and then place it at a canvas position with :class:`bitmap`: .. code-block:: python from pyx import * image_bw = bitmap.image(2, 2, "L", b"\0\377\377\0") image_rgb = bitmap.image(3, 2, "RGB", b"\77\77\77\177\177\177\277\277\277" b"\377\0\0\0\377\0\0\0\377") bitmap_bw = bitmap.bitmap(0, 1, image_bw, height=0.8) bitmap_rgb = bitmap.bitmap(0, 0, image_rgb, height=0.8) c = canvas.canvas() c.insert(bitmap_bw) c.insert(bitmap_rgb) c.writeEPSfile("bitmap") Here ``image_bw`` is a :math:`2\times 2` 8-bit grayscale (``"L"``) image containing two black (``0``) and two white (``255``) pixels, ordered row by row from the top-left corner. ``image_rgb`` is a :math:`3\times 2` RGB image whose top row contains three shades of gray and whose bottom row contains red, green, and blue pixels. Because raw :class:`image` buffers do not carry DPI metadata, we specify ``height=0.8`` when constructing the :class:`bitmap` canvas items. Figure :ref:`fig_bitmap` shows the resulting output. .. _fig_bitmap: .. figure:: bitmap.* :align: center Placing grayscale and RGB :class:`bitmap` instances on a canvas. Image Containers and File Readers ================================= .. class:: image(width, height, mode, data, compressed=None, palette=None) Container for 8-bit-per-channel pixel data. * *width*, *height*: Image dimensions in pixels. * *mode*: Color mode string. Supported modes are: - ``"L"`` (8-bit grayscale), ``"RGB"`` (24-bit RGB), ``"CMYK"`` (32-bit CMYK) - Modes with an 8-bit alpha channel: ``"LA"``, ``"RGBA"``, ``"CMYKA"`` (trailing alpha) or ``"AL"``, ``"ARGB"``, ``"ACMYK"`` (leading alpha) - ``"P"`` (8-bit palette-indexed color, requiring a :class:`palette` instance in *palette*) * *data*: A ``bytes`` object containing the pixel values row by row from top left to bottom right. For uncompressed data, ``len(data)`` must equal ``len(mode) * width * height``. * *compressed*: ``None`` for uncompressed pixel bytes, or ``"Flate"`` / ``"DCT"`` if *data* is already Flate- or JPEG-compressed. * *palette*: Optional :class:`palette` instance when ``mode="P"``. .. class:: palette(mode, data) Container for palette color tables used by indexed-color (``mode="P"``) :class:`image` instances, where *mode* is ``"L"``, ``"RGB"``, or ``"CMYK"`` and *data* is a ``bytes`` object containing the palette entries. .. class:: jpegimage(file) Reads a JPEG/JFIF image from *file* (either a filename string or an open binary file-like object). :class:`jpegimage` parses the JPEG headers to extract the pixel dimensions, color components (``"L"``, ``"RGB"``, or ``"CMYK"``), and embedded DPI resolution (if present), and embeds the DCT-compressed stream directly into the output without decoding and re-encoding—preserving 100% of the original image quality and minimizing file size. Placing Bitmaps on a Canvas =========================== .. class:: bitmap(xpos, ypos, image, width=None, height=None, ratio=None, PSstoreimage=0, PSmaxstrlen=4093, PSbinexpand=1, compressmode="Flate", flatecompresslevel=6, dctquality=75, dctoptimize=0, dctprogression=0) Creates a canvas item that places *image* with its lower-left corner at ``(xpos, ypos)`` (in user units or PyX lengths). A point-based variant :class:`bitmap_pt` takes ``xpos_pt``, ``ypos_pt``, ``width_pt``, and ``height_pt`` in PostScript points, and the lower-level base class :class:`bitmap_trafo` accepts an arbitrary :class:`trafo.trafo_pt` mapping the unit square to the target image rectangle. * *image*: An instance of :class:`image`, :class:`jpegimage`, or any Pillow (``PIL.Image``) object. * *width*, *height*, *ratio*: Target physical dimensions of the bitmap on the canvas. If *image* does not provide DPI metadata (in ``image.info["dpi"]``), at least *width* or *height* must be specified. When only one dimension is given, the other is computed from *ratio* (or from the pixel aspect ratio if ``ratio=None``). * *PSstoreimage*: When true, stores the compressed image data in PostScript interpreter memory as a reusable resource rather than streaming it inline. This avoids duplicating image bytes when the same bitmap is drawn multiple times in PostScript output. * *PSmaxstrlen*: Maximum PostScript string length (default ``4093``) used when *PSstoreimage* is enabled. * *PSbinexpand*: Expansion factor (``1`` or ``2``) used when converting low-bit-depth PIL images for PostScript output. * *compressmode*: Stream compression method used in PostScript and PDF output: ``"Flate"`` (lossless zlib compression, the default for uncompressed images), ``"DCT"`` (JPEG compression, supported for :class:`jpegimage` and Pillow images), or ``None`` (uncompressed). When *image* is already compressed (such as a :class:`jpegimage`), *compressmode* is automatically set to ``None`` so the compressed stream is passed through untouched. * *flatecompresslevel*: Zlib compression level (``1``–``9``, default ``6``) when ``compressmode="Flate"``. * *dctquality*, *dctoptimize*, *dctprogression*: JPEG encoding parameters passed to Pillow when ``compressmode="DCT"``. Keep ``dctprogression=0`` and ``dctoptimize=0`` for maximum PostScript printer compatibility. .. note:: * **Alpha channels (transparency)**: Images with an alpha channel (``"LA"``, ``"RGBA"``, ``"CMYKA"``, etc.) are automatically split into a color image and a soft-mask (``/SMask``) in PDF output, or exported as RGBA PNG data in SVG output. Standard PostScript does not support soft masks and logs a warning while ignoring the alpha channel. * **SVG output**: When writing SVG output, :class:`bitmap` embeds the image as a base64-encoded ``data:image/png`` or ``data:image/jpeg`` URI inside an SVG ```` element. pyx-project-pyx-21f71ce/manual/box.rst000066400000000000000000000136711526513311100200330ustar00rootroot00000000000000.. module:: box :synopsis: Convex polygon and rectangular boxes for alignment and connectors .. _box: ************************************** Module :mod:`box`: Convex box handling ************************************** The :mod:`box` module provides convex polygon (:class:`polygon`) and rectangular (:class:`rect`) box classes with an associated reference point (``center``). Boxes are used throughout PyX to represent the outer boundary and anchor point of text labels (:class:`text.textbox`), align multiple objects along lines or circles, tile objects with uniform spacing, and compute boundary intersections for :mod:`connector` paths. All direction arguments ``(dx, dy)`` in :mod:`box` are 2D direction vectors where at least one of *dx* or *dy* must be non-zero (their length is normalized automatically). Class :class:`polygon` ====================== .. class:: polygon(corners=None, center=None) Represents a convex polygon defined by a sequence of ``(x, y)`` vertex tuples in *corners* ordered counter-clockwise, and an optional reference point ``(x, y)`` in *center* (in user units or PyX lengths). If *center* is ``None``, the arithmetic mean (centroid) of *corners* is used. A point-based base class :class:`polygon_pt` takes all coordinates in PostScript points. .. method:: path(centerradius=None) Returns a closed :class:`path.path` tracing the polygon's perimeter. If *centerradius* is given, an additional small circle of radius *centerradius* is included at the box's ``center``. .. tip:: To round the corners of a box path, apply :class:`deformer.smoothed` to the returned path—for example, ``deformer.smoothed(0.2).deform(mybox.path())``. .. method:: transform(*trafos, keep_anchor=False) Applies one or more :class:`trafo.trafo` transformations in place to the polygon's corners (and to ``center``, unless ``keep_anchor=True``). .. method:: reltransform(*trafos) Applies one or more transformations in place relative to the box's ``center`` (translating ``center`` to the origin, applying *trafos*, and translating back). .. _fig_boxalign: .. figure:: boxalign.* :align: center Aligning boxes on a circle (:meth:`circlealign`) and along a line (:meth:`linealign`) for identical direction vectors and distances. .. method:: circlealignvector(a, dx, dy) .. method:: circlealignvector_pt(a_pt, dx, dy) Returns the displacement vector ``(vx, vy)`` required to move the box along the direction ``(dx, dy)`` so that its boundary touches a circle of radius *a* centered at the box's current ``center`` (see figure :ref:`fig_boxalign`). .. method:: linealignvector(a, dx, dy) .. method:: linealignvector_pt(a_pt, dx, dy) Returns the displacement vector ``(vx, vy)`` required to move the box along the direction ``(dx, dy)`` so that its boundary touches a line perpendicular to ``(dx, dy)`` at distance *a* from the box's current ``center`` (see figure :ref:`fig_boxalign`). .. method:: circlealign(a, dx, dy) .. method:: circlealign_pt(a_pt, dx, dy) Translates the box in place by :meth:`circlealignvector` and returns ``self``. .. method:: linealign(a, dx, dy) .. method:: linealign_pt(a_pt, dx, dy) Translates the box in place by :meth:`linealignvector` and returns ``self``. .. method:: extent(dx, dy) .. method:: extent_pt(dx, dy) Returns the total projected width of the box along the direction ``(dx, dy)``. .. method:: pointdistance(x, y) .. method:: pointdistance_pt(x_pt, y_pt) Returns the shortest Euclidean distance from an exterior point ``(x, y)`` to the boundary of the box. .. method:: boxdistance(other) .. method:: boxdistance_pt(other, epsilon=1e-10) Returns the shortest Euclidean distance between ``self`` and another box *other*. Raises :exc:`BoxCrossError` if the two boxes intersect. .. method:: bbox() Returns the axis-aligned :class:`bbox.bbox_pt` enclosing the box. .. exception:: BoxCrossError Raised by :meth:`polygon.boxdistance` when two boxes have intersecting edges. Aligning and Tiling Lists of Boxes ================================== .. function:: circlealignequal(polygons, a, dx, dy) .. function:: circlealignequal_pt(polygons, a_pt, dx, dy) Computes the :meth:`~polygon.circlealignvector` for each box in *polygons* and translates all boxes by the longest of those vectors. .. function:: linealignequal(polygons, a, dx, dy) .. function:: linealignequal_pt(polygons, a_pt, dx, dy) Computes the :meth:`~polygon.linealignvector` for each box in *polygons* and translates all boxes by the longest of those vectors. Axis painters use this function when ``labelvequalize`` or ``labelhequalize`` is enabled so that all tick labels share a uniform baseline alignment. .. function:: tile(polygons, a, dx, dy) .. function:: tile_pt(polygons, a_pt, dx, dy) Translates the boxes in *polygons* sequentially along ``(dx, dy)`` with step size equal to the maximum box extent in direction ``(dx, dy)`` plus separation *a*, and returns the step size. Class :class:`rect` =================== .. class:: rect(x, y, width, height, relcenter=(0, 0), abscenter=(0, 0)) Convenience subclass of :class:`polygon` representing an axis-aligned rectangle with lower-left corner ``(x, y)`` and dimensions *width* and *height* (in user units or PyX lengths). A point-based variant :class:`rect_pt` takes coordinates in PostScript points. The reference ``center`` of the rectangle is placed at .. math:: (x + \text{relcenter}_x \cdot \text{width} + \text{abscenter}_x,\; y + \text{relcenter}_y \cdot \text{height} + \text{abscenter}_y)\ , which defaults to the lower-left corner ``(x, y)`` when ``relcenter=(0, 0)`` and ``abscenter=(0, 0)``. Set ``relcenter=(0.5, 0.5)`` to place the anchor at the geometric center of the rectangle. pyx-project-pyx-21f71ce/manual/boxalign.py000066400000000000000000000014451526513311100206620ustar00rootroot00000000000000import math from pyx import * c = canvas.canvas() t1 = text.text(0, 0, "circle align", [text.halign.center, text.size.huge]) x, y = t1.circlealignvector(1, 1, 1) t1.circlealign(1, 1, 1) c.stroke(path.path(path.arc(0, 0, 1, -30, 120)), [style.linestyle.dashed]) c.stroke(t1.path(centerradius=0.05), [style.linewidth.THin]) c.stroke(path.line(0, 0, x, y), [deco.earrow.normal]) c.insert(t1) t2 = text.text(5, 0, "line align", [text.halign.center, text.size.huge]) x, y = t2.linealignvector(1, 1, 1) t2.linealign(1, 1, 1) c.stroke(path.line(5 + 1.5 * math.sqrt(2), -0.5 * math.sqrt(2), 5 - 0.5 * math.sqrt(2), 1.5 * math.sqrt(2)), [style.linestyle.dashed]) c.stroke(t2.path(centerradius=0.05), [style.linewidth.THin]) c.stroke(path.line(5, 0, 5 + x, y), [deco.earrow.normal]) c.insert(t2) c.writePDFfile() pyx-project-pyx-21f71ce/manual/canvas.rst000066400000000000000000000231301526513311100205050ustar00rootroot00000000000000.. _canvas: ****** Canvas ****** .. module:: canvas :synopsis: Canvas container and drawing operations A :class:`canvas` is the central workspace in PyX. It acts both as a drawing surface—providing methods to stroke, fill, and draw paths and to typeset text—and as a hierarchical container that groups canvas items (paths, text boxes, sub-canvases, bitmaps, and embedded EPS, PDF, or SVG files) with shared visual attributes, transformations, clipping paths, and drawing layers. Working with canvases ===================== Drawing and grouping -------------------- Every drawing operation on a canvas (:meth:`canvas.stroke`, :meth:`canvas.fill`, :meth:`canvas.draw`, :meth:`canvas.text`) creates a :class:`baseclasses.canvasitem` and inserts it into the canvas via :meth:`canvas.insert`, returning the inserted item. Because a :class:`canvas` is itself a :class:`baseclasses.canvasitem`, you can create sub-canvases, draw on them in local coordinates, and insert them into a parent canvas with transformations or styles applied to the entire group:: from pyx import * # Create a reusable sub-canvas in local coordinates badge = canvas.canvas() badge.fill(path.circle(0, 0, 0.5), [color.rgb.red]) badge.text(0, 0, "1", [text.halign.center, text.valign.middle, color.gray.white]) # Insert the sub-canvas multiple times at different positions and scales c = canvas.canvas() c.insert(badge, [trafo.translate(1, 1)]) c.insert(badge, [trafo.scale(1.5), trafo.translate(3, 1)]) c.writePDFfile("badges") Layers ------ By default, items on a canvas are drawn in the exact order in which they are inserted (later items paint over earlier items). When constructing complex figures, it is often convenient to organize drawing operations into named *layers* (such as ``"background"``, ``"fill"``, ``"main"``, ``"labels"``) whose back-to-front order is independent of when individual items are added. The :meth:`canvas.layer` method creates or retrieves a sub-canvas associated with a layer name and allows you to position it relative to existing layers using the *above* and *below* parameters:: c = canvas.canvas() bg = c.layer("background") fg = c.layer("foreground", above="background") # Even if we draw on fg first and bg second, bg is rendered behind fg fg.text(1, 1, "Foreground text", [text.halign.center, text.valign.middle]) bg.fill(path.rect(0, 0.5, 2, 1), [color.rgb.yellow]) Clipping -------- A canvas can be clipped to the interior of an arbitrary closed :class:`path.path` by passing a :class:`clip` instance in the canvas constructor's *attrs* list:: clipped = canvas.canvas([canvas.clip(path.circle(1, 1, 1))]) clipped.fill(path.rect(0, 0, 2, 2), [color.rgb.blue]) c = canvas.canvas() c.insert(clipped) Class :class:`canvas` ===================== .. class:: canvas(attrs=[], textengine=None) Constructs a new canvas. - *attrs*: Optional list of canvas-wide attributes applied to all contents of the canvas. Allowed attributes are :class:`style.strokestyle`, :class:`style.fillstyle` (including :class:`color.color` and :class:`pattern.pattern`), :class:`trafo.trafo_pt`, and :class:`clip`. - *textengine*: Optional text engine instance (such as a custom :class:`text.TexEngine`, :class:`text.LatexEngine`, or :class:`text.UnicodeEngine`) used by :meth:`text` and :meth:`text_pt` on this canvas. When ``None`` (the default), ``text.defaulttextengine`` is used at the time :meth:`text` is called. .. attribute:: items List of :class:`baseclasses.canvasitem` objects contained in the canvas. .. attribute:: layers Dictionary mapping layer names to their corresponding sub-canvas instances. .. attribute:: trafo The cumulative :class:`trafo.trafo_pt` transformation applied to the canvas. .. method:: bbox() Returns the enclosing :class:`bbox.bbox` of all items in the canvas (taking canvas transformations and any :class:`clip` path into account). Note that for stroked paths, the bounding box reflects the geometric path rather than the stroke width. .. method:: draw(path, attrs) Draws *path* on the canvas according to the attributes in *attrs*, which may contain :class:`baseclasses.deformer`, :class:`baseclasses.deco`, :class:`style.strokestyle`, :class:`style.fillstyle`, and :class:`trafo.trafo_pt` instances. Returns the inserted :class:`deco.decoratedpath` canvas item. .. method:: stroke(path, attrs=[]) Strokes *path* on the canvas; equivalent to ``self.draw(path, [deco.stroked] + list(attrs))``. Returns the inserted :class:`deco.decoratedpath` canvas item. .. method:: fill(path, attrs=[]) Fills *path* on the canvas; equivalent to ``self.draw(path, [deco.filled] + list(attrs))``. Returns the inserted :class:`deco.decoratedpath` canvas item. .. method:: insert(item, attrs=[]) Inserts *item* (an instance of :class:`baseclasses.canvasitem`, such as another :class:`canvas`, a :class:`text.textbox_pt`, a :class:`bitmap.bitmap`, an :class:`epsfile.epsfile`, a :class:`pdffile.pdffile`, or an :class:`svgfile.svgfile`) into the canvas. If *attrs* is non-empty, *item* is wrapped in a sub-canvas with *attrs* applied. Returns *item*. .. method:: layer(name, above=None, below=None) Creates or retrieves the layer sub-canvas identified by the string *name*. Dotted names (such as ``"axes.ticks"``) create nested sub-layers inside the parent layer ``"axes"``. - *above*: Name of an existing layer immediately above which the layer should be positioned. - *below*: Name of an existing layer immediately below which the layer should be positioned (cannot be combined with *above*). Returns the :class:`canvas` instance representing the layer. .. method:: text(x, y, expr, textattrs=[], **kwargs) text_pt(x_pt, y_pt, expr, textattrs=[], **kwargs) Typesets *expr* at :math:`(x, y)` (in PyX user lengths or points) using the canvas's text engine, inserts the resulting text box into the canvas, and returns it. See :meth:`text.SingleEngine.text_pt` for details on *textattrs* and *kwargs*. .. method:: settextengine(textengine) Sets the text engine (:class:`text.TexEngine`, :class:`text.LatexEngine`, or :class:`text.UnicodeEngine`) to be used by subsequent :meth:`text` and :meth:`text_pt` calls on this canvas. Output and Ghostscript conversion methods ----------------------------------------- For single-page figures, :class:`canvas` provides shortcut methods that wrap the canvas in a :class:`document.page` and a single-page :class:`document.document` and write the output directly. Any keyword arguments accepted by :class:`document.page` (such as ``paperformat``, ``rotated``, ``centered``, ``fittosize``, ``margin``, ``bboxenlarge``, ``bbox``) as well as any keyword arguments accepted by the respective writer (such as ``title``, ``stripfonts``, ``textaspath``, ``writebbox``; see :ref:`document`) can be passed directly to these methods: .. method:: writeEPSfile(file=None, **kwargs) writePSfile(file=None, **kwargs) writePDFfile(file=None, **kwargs) writeSVGfile(file=None, **kwargs) Writes the canvas to an EPS, PostScript, PDF, or SVG file. *file* can be a filename string (the extension ``.eps``, ``.ps``, ``.pdf``, or ``.svg`` is appended automatically if omitted), a binary writable stream, ``"-"`` to write to ``sys.stdout.buffer``, or ``None`` to derive the filename automatically from ``sys.argv[0]``. .. method:: writetofile(filename, **kwargs) Determines the output format from the extension of *filename* (``.eps``, ``.ps``, ``.pdf``, or ``.svg``) and writes the canvas accordingly. .. method:: pipeGS(filename=None, device="png16m", resolution=100, gs="gs", gsoptions=[], textalphabits=4, graphicsalphabits=4, ciecolor=False, input="eps", **kwargs) Renders the canvas using Ghostscript (``gs``) into any output format supported by Ghostscript (such as PNG or JPEG). - *filename*: Output filename. If *filename* does not end with a file extension and *device* starts with ``"png"`` or ``"jpeg"``, the extension ``.png`` or ``.jpg`` is appended automatically. If *filename* is ``None``, the base name is derived from ``sys.argv[0]``. If *filename* is ``"-"``, Ghostscript writes to standard output and :meth:`pipeGS` returns the resulting output as a :class:`bytes` object! - *device*: Ghostscript output device (default ``"png16m"`` for 24-bit RGB PNG; use e.g. ``"pngalpha"`` for PNG with transparent background or ``"jpeg"`` for JPEG). - *resolution*: Rendering resolution in DPI (default ``100``). - *gs*: Ghostscript executable name (default ``"gs"``). - *gsoptions*: Additional command-line option strings passed to Ghostscript. - *textalphabits*, *graphicsalphabits*: Antialiasing subsampling factors (default ``4``; pass ``None`` to omit). - *ciecolor*: When ``True``, passes ``-dUseCIEColor`` to Ghostscript. - *input*: Format piped from PyX into Ghostscript: ``"eps"`` (default) or ``"pdf"``. - *kwargs*: Additional keyword arguments forwarded to :class:`document.page` and the EPS/PDF writer. Class :class:`clip` =================== .. class:: clip(path) Constructs a clipping attribute from the closed :class:`path.path` *path*. When passed in the *attrs* list of :class:`canvas`, all drawing inside that canvas is restricted to the interior of *path*. pyx-project-pyx-21f71ce/manual/color.py000077500000000000000000000003721526513311100201760ustar00rootroot00000000000000from pyx import * c = canvas.canvas() c.fill(path.rect(0, 0, 7, 3), [color.gray(0.8)]) c.fill(path.rect(1, 1, 1, 1), [color.rgb.red]) c.fill(path.rect(3, 1, 1, 1), [color.rgb.green]) c.fill(path.rect(5, 1, 1, 1), [color.rgb.blue]) c.writePDFfile() pyx-project-pyx-21f71ce/manual/color.rst000066400000000000000000000144271526513311100203610ustar00rootroot00000000000000.. module:: color :synopsis: Color models, named colors, gradients, and transparency .. _color: ******************* Module :mod:`color` ******************* The :mod:`color` module provides classes representing colors in four device color spaces (:class:`gray`, :class:`rgb`, :class:`cmyk`, and :class:`hsb`), continuous color gradients (:class:`gradient`), and opacity attributes (:class:`transparency`). Because all color and transparency instances act as both :class:`style.strokestyle` and :class:`style.fillstyle` attributes, they can be passed directly to :meth:`canvas.canvas.stroke`, :meth:`canvas.canvas.fill`, :meth:`canvas.canvas.draw`, :meth:`canvas.canvas.text`, or :meth:`canvas.canvas.set`. Color Models and Named Colors ============================= PyX provides four color classes corresponding to standard PostScript/PDF color models. All color component values are floating-point numbers in the range ``[0.0, 1.0]``: .. class:: gray(g) Grayscale color with intensity *g* from ``0.0`` (black) to ``1.0`` (white). ``grey`` is provided as an alias for :class:`gray`. .. method:: gray() .. method:: rgb() .. method:: cmyk() .. method:: hsb() Converts the color to a :class:`gray`, :class:`rgb`, :class:`cmyk`, or :class:`hsb` instance. .. class:: rgb(r=0.0, g=0.0, b=0.0) RGB color with red (*r*), green (*g*), and blue (*b*) components in ``[0.0, 1.0]``. Provides conversion methods :meth:`gray`, :meth:`rgb`, :meth:`cmyk`, and :meth:`hsb`, as well as :meth:`rgbhex` (returning a ``"#RRGGBB"`` hex string). .. class:: cmyk(c=0.0, m=0.0, y=0.0, k=0.0) CMYK color with cyan (*c*), magenta (*m*), yellow (*y*), and black/key (*k*) ink components in ``[0.0, 1.0]``. Provides conversion methods :meth:`gray`, :meth:`rgb`, :meth:`cmyk`, and :meth:`hsb`. .. class:: hsb(h=0.0, s=0.0, b=0.0) HSB (hue, saturation, brightness) color with *h*, *s*, and *b* in ``[0.0, 1.0]``. Provides conversion methods :meth:`gray`, :meth:`rgb`, :meth:`cmyk`, and :meth:`hsb`. In addition to constructing colors numerically, PyX predefines a rich palette of named colors as attributes on :class:`gray`, :class:`rgb`, and :class:`cmyk` (such as ``color.gray.black``, ``color.rgb.red``, ``color.cmyk.CornflowerBlue``). All predefined named colors are illustrated in appendix :ref:`colorname`. Color Conversion Configuration ------------------------------ When converting between RGB, CMYK, and Grayscale via ``c.rgb()``, ``c.cmyk()``, or ``c.gray()``, PyX uses configurable transfer functions that can be adjusted via :func:`color.set`: .. autofunction:: set Example ------- .. code-block:: python from pyx import * c = canvas.canvas() c.fill(path.rect(0, 0, 7, 3), [color.gray(0.8)]) c.fill(path.rect(1, 1, 1, 1), [color.rgb.red]) c.fill(path.rect(3, 1, 1, 1), [color.rgb.green]) c.fill(path.rect(5, 1, 1, 1), [color.rgb.blue]) c.writeEPSfile("color") The resulting figure is shown in figure :ref:`fig_color`. .. _fig_color: .. figure:: color.* :align: center Filling rectangles with grayscale and predefined RGB colors. Color Gradients =============== The :class:`gradient` hierarchy represents continuous transitions across a color space parameterized by a floating-point value in :math:`[0, 1]`. Gradients serve two roles in PyX: 1. **Continuous color scales** (used by :class:`deco.colorgradient`, :class:`graph.style.rect`, :class:`graph.style.surface`, and :class:`graph.style.density`) via :meth:`gradient.getcolor`. 2. **Changeable attributes** (:class:`attr.changeattr`) that automatically step through *N* evenly spaced colors across a multi-dataset plot or :class:`graph.style.bar` chart via :meth:`gradient.select`. All predefined gradients are listed and illustrated in appendix :ref:`gradientname`. Note that all predefined non-gray gradients are defined in the RGB color space except for ``gradient.Rainbow``, ``gradient.ReverseRainbow``, ``gradient.Hue``, and ``gradient.ReverseHue``, which are defined in HSB space; pre-converted RGB and CMYK versions of those four are provided as ``rgbgradient.Rainbow``, ``cmykgradient.Rainbow``, etc. .. class:: gradient() Base class for all color gradients. .. method:: getcolor(parameter) Returns the :class:`color` instance corresponding to *parameter* in ``[0.0, 1.0]``. .. method:: select(index, n_indices) Implements the :class:`attr.changeattr` interface: returns the *index*-th color out of *n_indices* evenly spaced samples along the gradient (evaluating ``getcolor(index / (n_indices - 1))`` when ``n_indices > 1``, or ``getcolor(0)`` when ``n_indices == 1``). .. class:: functiongradient_gray(f_gray) .. class:: functiongradient_rgb(f_r, f_g, f_b) .. class:: functiongradient_cmyk(f_c, f_m, f_y, f_k) .. class:: functiongradient_hsb(f_h, f_s, f_b) Constructs a custom gradient in the respective color space where each component callable ``f_*(x)`` maps a parameter :math:`x \in [0, 1]` to a component value in :math:`[0, 1]`. .. function:: lineargradient_gray(mincolor, maxcolor) .. function:: lineargradient_rgb(mincolor, maxcolor) .. function:: lineargradient_cmyk(mincolor, maxcolor) .. function:: lineargradient_hsb(mincolor, maxcolor) Factory functions that return a :class:`functiongradient_*` instance interpolating linearly between *mincolor* (at ``0.0``) and *maxcolor* (at ``1.0``) in the respective color space. .. class:: rgbgradient(gradient) .. class:: cmykgradient(gradient) Wraps an existing *gradient* (such as an HSB gradient) and converts all returned colors to :class:`rgb` or :class:`cmyk`. This is particularly useful for :class:`graph.style.surface` and :class:`graph.style.density` plots in PostScript and PDF, which require shading meshes and bitmaps to use Gray, RGB, or CMYK color spaces rather than HSB. Transparency ============ .. class:: transparency(value) Makes stroking and filling operations partially transparent, where *value* is in the range ``0.0`` (completely opaque) to ``1.0`` (completely transparent). .. note:: Transparency is natively supported in PDF and SVG output. Standard PostScript does not support alpha transparency; when writing PostScript or EPS, PyX emits a Ghostscript-specific transparency extension (supported by ``ps2pdf``) and logs a warning. pyx-project-pyx-21f71ce/manual/colorname.py000077500000000000000000000031211526513311100210320ustar00rootroot00000000000000import re from pyx import * text.set(text.LatexRunner) text.preamble(r"\renewcommand{\familydefault}{\ttdefault}") c = canvas.canvas() # positioning is quite ugly ... but it works at the moment x = 0 y = 0 dx = 4.8 dy = -0.65 lastmodel = 0 # we could use (gray|rgb|cmyk).__dict__ to get the instances, but we # would loose the ordering ... instead we just parse the file: # TODO: code something along the lines of c.l.p post cbs38g$2kp$04$1@news.t-online.com p = re.compile("(?P(?P[a-z]+)\\.(?P[a-z]+)) += (?P=model)\\([0-9\\., ]+\\)\n", re.IGNORECASE) with open(color.__file__) as f: for line in f: m = p.match(line) if m: if lastmodel and (m.group("model") != lastmodel): y += dy myc = color.__dict__[m.group("model")].__dict__[m.group("name")] c.stroke(path.line(x + 0.1, y + 0.1, x + 0.4, y + 0.4), [myc]) c.stroke(path.line(x + 0.4, y + 0.1, x + 0.1, y + 0.4), [myc]) c.fill(path.rect(x + 0.5, y, 1, 0.5), [myc]) c.stroke(path.line(x + 0.6, y + 0.1, x + 0.9, y + 0.4), [color.gray.black]) c.stroke(path.line(x + 0.9, y + 0.1, x + 0.6, y + 0.4), [color.gray.black]) c.stroke(path.line(x + 1.1, y + 0.1, x + 1.4, y + 0.4), [color.gray.white]) c.stroke(path.line(x + 1.4, y + 0.1, x + 1.1, y + 0.4), [color.gray.white]) c.text(x + 1.7, y + 0.15, m.group("id"), [text.size.footnotesize]) y += dy lastmodel = m.group("model") if y < -16.5: y = 0 x += dx c.writePDFfile() pyx-project-pyx-21f71ce/manual/colorname.rst000066400000000000000000000005261526513311100212150ustar00rootroot00000000000000.. _colorname: ********************** Appendix: Named colors ********************** The following chart lists the predefined grayscale, RGB, and CMYK colors available in the :mod:`color` module (see chapter :ref:`color`). .. _fig_colorname: .. figure:: colorname.* :align: center Predefined named colors in the :mod:`color` module. pyx-project-pyx-21f71ce/manual/conf.py000066400000000000000000000231431526513311100200030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # PyX documentation build configuration file, created by # sphinx-quickstart on Thu May 19 17:32:57 2011. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os sys.path.insert(0, '../pyx') sys.path.insert(0, '..') import pyx.version # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.mathjax', 'sphinx.ext.todo', 'sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx_selective_exclude.eager_only'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'manual' # General information about the project. project = 'PyX' copyright = pyx.version.date.split('/')[0] + ', Jörg Lehmann, Michael Schindler, André Wobst' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '.'.join(pyx.version.version.split('.')[:1]) # The full version, including alpha/beta/rc tags. release = pyx.version.version # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: today = pyx.version.date # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ['_build'] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = 'pyx' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. html_theme_path = ['theme'] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". html_title = 'PyX %s Manual' % release # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. #html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} html_sidebars = { '**': ['localtoc.html', 'sourcelink.html', 'searchbox.html'] } # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_domain_indices = True # If false, no index is generated. #html_use_index = True # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. #html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. #html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'PyXdoc' todo_include_todos = True # -- Options for LaTeX output -------------------------------------------------- # The paper size ('letter' or 'a4'). latex_paper_size = 'a4' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('manual', 'manual.tex', 'PyX Manual', 'Jörg Lehmann, Michael Schindler, André Wobst', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Additional stuff for the LaTeX preamble. latex_preamble = r''' \hypersetup{pdftitle={PyX Manual}, pdfauthor={Joerg Lehmann , Michael Schindler , Andre Wobst }, pdfsubject={PyX Manual}, pdfkeywords={PyX, graphics, manual}} ''' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('manual', 'pyx', 'PyX Manual', ['Jörg Lehmann, Michael Schindler, André Wobst'], 1) ] # -- Other options ------------------------------------------------------------ mathjax_path = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/MathJax.js?config=default' todo_include_todos = True autoclass_content = 'both' autodoc_member_order = 'bysource' # -- unprocessed function signature extractor ---------------------------------- # This feature is not robust. It does not parse the code properly, removes # comments and whitespace doubtfully, requires '):' without space for # termination, etc. import inspect def function_signature_lines(lines): # extract the lines of the function definition removing comments # and stripping spaces for line in lines: code = line.split("#", 1)[0].strip() yield code if code.endswith("):"): break def unprocessed_function_signature(app, what, name, obj, options, sig, retann): # extract the unprocessed signature from the source if what not in ["class", "method", "staticmethod", "function"]: return if what == "class": # get the constructor (code copied from autodoc) obj = getattr(obj, "__init__", None) if obj is None or obj is object.__init__ or not \ (inspect.ismethod(obj) or inspect.isfunction(obj)): return elif hasattr(obj, '__wrapped__'): obj = obj.__wrapped__ src, line = inspect.findsource(obj) code = " ".join(function_signature_lines(src[line:])).split("(", 1)[1][:-2] if code.startswith("self, "): code = code[6:] elif code == "self": code = "" return "({})".format(code), retann def remove_default_constructor_docstring(app, what, name, obj, options, lines): # remove default constructor docstring, i.e. when no own constructor is defined for i, line in enumerate(lines): lines[i] = line.replace("x.__init__(...) initializes x; see help(type(x)) for signature", "") def setup(app): app.connect('autodoc-process-signature', unprocessed_function_signature) app.connect('autodoc-process-docstring', remove_default_constructor_docstring) pyx-project-pyx-21f71ce/manual/connector.py000077500000000000000000000115501526513311100210520ustar00rootroot00000000000000from math import * from pyx import * try: from math import radians, degrees except ImportError: # fallback implementation for Python 2.1 def radians(x): return x*pi/180 def degrees(x): return x*180/pi startbox = box.polygon(corners=[[0,-0.6], [0.5,0.1], [-0.25,0.1]]) endbox = box.polygon(corners=[[4.5,3.9], [5.5,4.0], [5.2,3.4]]) # the arc connector <<< c1 = canvas.canvas() for b in [startbox, endbox]: c1.stroke(b.path(), [style.linewidth.Thick, style.linejoin.round]) c1.fill(path.circle_pt(b.center[0], b.center[1], 2)) absangle = degrees(atan2(endbox.center[1] - startbox.center[1], endbox.center[0] - startbox.center[0])) relangle = 60 len = 2 # the direct connection direct = path.line_pt(startbox.center[0], startbox.center[1], endbox.center[0], endbox.center[1]) c1.stroke(direct, [style.linestyle.dashed]) # the arc connector l = connector.arc(startbox, endbox, relangle=relangle, boxdists=[0.0,0.0]) c1.stroke(l, [style.linewidth.Thick, color.rgb.red, deco.earrow.Large]) # the relangle parameter comp1 = path.path(path.moveto(*direct.atbegin()), path.rlineto(len*cos(radians(absangle + relangle)), len*sin(radians(absangle + relangle)))) c1.stroke(comp1) ang = path.path(path.arc(direct.atbegin()[0], direct.atbegin()[1], 0.8*len, absangle, absangle+relangle)) c1.stroke(ang, [deco.earrow.large]) pos = ang.at(0.5*ang.arclen()) c1.text(pos[0], pos[1], r"~relangle", [text.halign.left]) # the bulge parameter bulge = 0.5 * direct.arclen() * tan(0.5*radians(relangle)) bul = path.path(path.moveto(*direct.at(0.5*direct.arclen())), path.rlineto(bulge * cos(radians(absangle+90)), bulge * sin(radians(absangle+90)))) c1.stroke(bul, [deco.earrow.large]) pos = bul.at(0.5*bul.arclen()) c1.text(pos[0], pos[1], r"~(rel)bulge", [text.halign.left]) # >>> # the curve connector <<< c2 = canvas.canvas() for b in [startbox, endbox]: c2.stroke(b.path(), [style.linewidth.Thick, style.linejoin.round]) c2.fill(path.circle_pt(b.center[0], b.center[1], 2)) absangle = degrees(atan2(endbox.center[1] - startbox.center[1], endbox.center[0] - startbox.center[0])) relangle1 = 60 relangle2 = 30 absbulge = 0 relbulge = 0.5 len = 2 # the direct connection direct = path.line_pt(startbox.center[0], startbox.center[1], endbox.center[0], endbox.center[1]) c2.stroke(direct, [style.linestyle.dashed]) # the arc connector l = connector.curve(startbox, endbox, relangle1=relangle1, relangle2=relangle2, absbulge=absbulge, relbulge=relbulge, boxdists=[0.0,0.0]) #l = connector.curve(startbox, endbox, absangle1=absangle+relangle1, absangle2=absangle+relangle2, absbulge=absbulge, relbulge=relbulge, boxdists=[0.0,0.0]) c2.stroke(l, [style.linewidth.Thick, color.rgb.red, deco.earrow.Large]) # the relangle parameters # relangle1 c2.stroke(path.path(path.moveto(*direct.atbegin()), path.rlineto(len*cos(radians(absangle + relangle1)), len*sin(radians(absangle + relangle1))))) ang = path.path(path.arc(direct.atbegin()[0], direct.atbegin()[1], 0.8*len, absangle, absangle+relangle1)) c2.stroke(ang, [deco.earrow.large]) pos = ang.at(0.5*ang.arclen()) c2.text(pos[0], pos[1], r"~relangle1", [text.halign.left]) # absangle1 c2.stroke(path.path(path.moveto(*direct.atbegin()), path.rlineto(len, 0))) ang = path.path(path.arc(direct.atbegin()[0], direct.atbegin()[1], 0.5*len, 0, absangle+relangle1)) c2.stroke(ang, [deco.earrow.large]) pos = ang.at(0.2*ang.arclen()) c2.text(pos[0], pos[1], r"~absangle1", [text.halign.left]) # relangle2 c2.stroke(path.path(path.moveto(*direct.atend()), path.rlineto(len*cos(radians(absangle)), len*sin(radians(absangle))))) c2.stroke(path.path(path.moveto(*direct.atend()), path.rlineto(len*cos(radians(absangle + relangle2)), len*sin(radians(absangle + relangle2))))) ang = path.path(path.arc(direct.atend()[0], direct.atend()[1], 0.8*len, absangle, absangle+relangle2)) c2.stroke(ang, [deco.earrow.large]) pos = ang.at(0.5*ang.arclen()) c2.text(pos[0], pos[1], r"~relangle2", [text.halign.left]) # the bulge parameter bulge = absbulge + direct.arclen() * relbulge bul = path.path(path.moveto(*direct.atbegin()), path.rlineto(bulge * cos(radians(absangle+relangle1)), bulge * sin(radians(absangle+relangle1)))) c2.stroke(bul, [deco.earrow.large]) pos = bul.at(0.7*bul.arclen()) c2.text(pos[0], pos[1], r"~(rel)bulge", [text.halign.left]) bul = path.path(path.moveto(*direct.atend()), path.rlineto(-bulge * cos(radians(absangle+relangle2)), -bulge * sin(radians(absangle+relangle2)))) c2.stroke(bul, [deco.earrow.large]) pos = bul.at(0.7*bul.arclen()) c2.text(pos[0], pos[1], r"~(rel)bulge", [text.halign.left, text.vshift(1)]) # >>> # write everything c1.insert(c2, [trafo.translate(6.5, 0)]) c1.writePDFfile() # vim:foldmethod=marker:foldmarker=<<<,>>> pyx-project-pyx-21f71ce/manual/connector.rst000066400000000000000000000117271526513311100212350ustar00rootroot00000000000000.. module:: connector :synopsis: Connecting paths (lines, arcs, curves, and polylines) between boxes .. _connector: *********************** Module :mod:`connector` *********************** The :mod:`connector` module constructs paths (:class:`normpath.normpath` subclasses) that connect two :class:`box.polygon` instances (such as :class:`text.textextbox_pt` / :class:`text.unicodetextbox_pt` objects or :class:`box.rect` boxes) using straight lines, circular arcs, cubic Bézier curves, or two-segment polylines. Geometry, Angles, and Bulges ============================ All connector classes take two box instances (*box1* and *box2*) as their first two arguments and construct a path leading from *box1* to *box2*: 1. The geometric curve is constructed between the centers (``box1.center`` and ``box2.center``) of the two boxes. 2. The path is then trimmed at its intersections with the boundary outlines of *box1* and *box2*. 3. Finally, the trimmed path can be shortened at its start and end by the distances specified in *boxdists* (a 2-element sequence ``[dist1, dist2]``, defaulting to ``[0, 0]``). .. code-block:: python from pyx import * c = canvas.canvas() b1 = c.text(0, 0, "Start", [text.halign.center, text.vshift.mathaxis]) b2 = c.text(4, 1, "End", [text.halign.center, text.vshift.mathaxis]) c.stroke(connector.arc(b1, b2, boxdists=[0.2, 0.2]), [deco.earrow.normal]) Angles and Bulge Parameters --------------------------- Connectors that bend (:class:`arc`, :class:`curve`, and :class:`twolines`) are parameterized by tangent angles and/or bulge distances (illustrated in figure :ref:`fig_connector`): * **Relative vs. absolute angles**: Relative angles (*relangle*, *relangle1*, *relangle2*) are measured in degrees relative to the straight line connecting ``box1.center`` to ``box2.center``. Absolute angles (*absangle1*, *absangle2*) are measured counter-clockwise from the positive *x*-axis. Whenever both an absolute and a relative angle are specified for the same endpoint, the absolute angle takes precedence. * **Bulge distances**: Bulge parameters (*relbulge* and *absbulge*) control how far the connector deviates from the straight line between the box centers. *relbulge* is a dimensionless fraction of the center-to-center distance, whereas *absbulge* is an absolute PyX length. If both *relbulge* and *absbulge* are given, their contributions are summed. .. _fig_connector: .. figure:: connector.* :align: center Geometric meaning of the angle and bulge parameters for :class:`connector.arc` (left) and :class:`connector.curve` (right). Connector Classes ================= Each connector class is available both in user units (e.g. :class:`line`, :class:`arc`, :class:`curve`, :class:`twolines`) and in PostScript points (with a ``_pt`` suffix, where *boxdists* and *absbulge* are given in points). .. class:: line(box1, box2, boxdists=(0, 0)) Connects *box1* and *box2* with a straight line segment between their centers, trimmed at the box outlines and shortened by *boxdists*. .. class:: arc(box1, box2, relangle=45, absbulge=None, relbulge=None, boxdists=[0, 0]) Connects *box1* and *box2* with a circular arc. * *relangle*: Angle (in degrees) between the chord connecting the box centers and the arc's tangent at the centers (default ``45``). * *absbulge*, *relbulge*: Maximum perpendicular distance (sagitta) between the arc and the straight chord connecting the box centers. Specifying either *absbulge* or *relbulge* overrides *relangle*. .. class:: curve(box1, box2, relangle1=45, relangle2=45, absangle1=None, absangle2=None, absbulge=0, relbulge=0.39, boxdists=[0, 0]) Connects *box1* and *box2* with a cubic Bézier curve. Here the bulge specifies the distance from each box center to the corresponding Bézier control point along the departure/arrival tangent direction (see the right panel of figure :ref:`fig_connector` for sign conventions). * *relangle1*, *relangle2*: Departure and arrival tangent angles relative to the center-to-center line (default ``45`` for both). * *absangle1*, *absangle2*: Absolute departure and arrival tangent angles in degrees (override *relangle1* / *relangle2* if given). * *absbulge*, *relbulge*: Control-point distances (default ``relbulge=0.39``, which closely approximates a circular arc when ``relangle1 = relangle2 = 45``). .. class:: twolines(box1, box2, absangle1=None, absangle2=None, relangle1=None, relangle2=None, relangleM=None, length1=None, length2=None, bezierradius=None, beziersoftness=1, arcradius=None, boxdists=[0, 0]) Connects *box1* and *box2* with a two-segment polyline meeting at an intermediate corner point. You must supply an unambiguous combination of two constraints chosen from the departure angle (*absangle1* or *relangle1*), arrival angle (*absangle2* or *relangle2*), interior angle between the two segments (*relangleM*), first segment length (*length1*), or second segment length (*length2*). pyx-project-pyx-21f71ce/manual/deformer.rst000066400000000000000000000173101526513311100210400ustar00rootroot00000000000000.. _deformer: ********* Deformers ********* .. module:: deformer :synopsis: Geometric path deformers Deformers take an existing path and replace it with a geometrically modified :class:`normpath.normpath`—for example, rounding sharp corners, constructing an offset curve at a constant parallel distance, or wrapping a spring-like cycloid along the path. All deformers inherit from :class:`baseclasses.deformer` and can be used in two ways: 1. **As drawing attributes** passed to :meth:`canvas.canvas.stroke`, :meth:`canvas.canvas.fill`, or :meth:`canvas.canvas.draw`. When drawing a path, PyX applies all deformers in the attribute list in order before applying decorators and styles:: from pyx import * c = canvas.canvas() p = path.rect(0, 0, 3, 2) c.stroke(p, [style.linestyle.dotted]) c.stroke(p, [deformer.smoothed(0.5), color.rgb.red]) c.writePDFfile("smoothed") 2. **Directly as path transformations** by calling the deformer's :meth:`~smoothed.deform` method on a path or normalized path to obtain the deformed :class:`normpath.normpath` for further geometric operations (such as intersections or splitting):: rounded_rect = deformer.smoothed(0.5).deform(path.rect(0, 0, 3, 2)) Every deformer instance is also callable: calling an existing instance with keyword arguments returns a new deformer with those parameters updated. Each deformer class also provides a ``.clear`` attribute (e.g. ``deformer.smoothed.clear``, ``deformer.cycloid.clear``) to remove preceding instances of that deformer from an attribute list. Corner smoothing: :class:`smoothed` =================================== .. class:: smoothed(radius, softness=1, obeycurv=0, relskipthres=0.01) cornersmoothed(radius, softness=1, obeycurv=0, relskipthres=0.01) Replaces corners between consecutive segments of a path with smooth cubic Bézier curves. Within each subpath item, the path is cut back at arc length *radius* from the corner (or at the midpoint of the segment if the segment is shorter than ``2 * radius``), and the removed corner is bridged as follows: - **Between two straight lines**: Two optimized cubic Bézier curves are inserted whose curvature vanishes at the transition points to the straight lines and whose curvature derivative vanishes at the midpoint of the corner. The shape is controlled by *softness* :math:`\in (0, 1]`. - **When at least one adjacent segment is curved**: A single cubic Bézier curve is inserted that matches the tangents and curvatures of the adjacent segments at the cut points. Parameters: - *radius*: Arc-length distance from each corner at which the original path is cut and replaced by the smoothing curve(s). - *softness*: Factor in :math:`(0, 1]` controlling how tightly corners between straight lines are rounded (default ``1``). Smaller values produce sharper bends closer to the original corner. - *obeycurv*: When ``0`` (the default), only the magnitude of the curvature is matched at curved segments while its sign is chosen to avoid cusps or loops; when ``1``, the signed curvature of the adjacent curve is strictly preserved. - *relskipthres*: Segments shorter than ``relskipthres * radius`` are skipped during smoothing (default ``0.01``). :class:`cornersmoothed` is the canonical class name; :class:`smoothed` is provided as a convenient alias. .. method:: deform(basepath) Returns a new :class:`normpath.normpath` with all corners of *basepath* smoothed. Parallel offset curves: :class:`parallel` ========================================= .. class:: parallel(distance, relerr=0.05, sharpoutercorners=False, dointersection=True, checkdistanceparams=[0.5], lookforcurvatures=11, searchstep=0.01, debug=None) Constructs a parallel offset curve at a constant normal *distance* from the original path. A positive *distance* offsets the curve to the **left** of the original path (relative to its parameterization direction); a negative *distance* offsets it to the **right**. For a counter-clockwise closed path (such as :class:`path.rect` or :class:`path.circle`), a negative *distance* therefore expands the shape outward, while a positive *distance* shrinks it inward. The parallel path is constructed in two stages: 1. For each segment of the normalized path, an offset line or cubic Bézier approximation is built. At convex corners, either a circular arc of radius ``abs(distance)`` is inserted around the corner (default) or the offset segments are extended to a sharp corner (*sharpoutercorners=True*). Regions where the original curve bends more tightly than ``1 / distance`` toward the offset side are split at points of infinite curvature. 2. When *dointersection* is ``True`` (the default), self-intersections and loops in the offset path are detected and trimmed away so that only the true envelope at distance ``abs(distance)`` from the original path remains. Parameters: - *distance*: Signed normal offset distance (PyX length). - *relerr*: Maximum allowed relative error ``relerr * abs(distance)`` when approximating offset Bézier curves (default ``0.05``). - *sharpoutercorners*: When ``True``, outer (convex) corners are joined with sharp mitered lines instead of circular arcs (default ``False``). - *dointersection*: When ``True`` (default), self-intersecting loops in the offset curve are removed. Set to ``False`` to keep the raw untrimmed offset curve. - *checkdistanceparams*: List of parameter values in :math:`(0, 1)` at which the normal distance between the original curve and its cubic Bézier approximation is verified before subdividing (default ``[0.5]``). - *lookforcurvatures*: Number of sample points per curve segment used to locate critical curvature crossings :math:`\kappa = 1 / \text{distance}` (default ``11``). .. method:: deform(basepath) Returns the offset :class:`normpath.normpath` at *distance* from *basepath*. Spring / coil paths: :class:`cycloid` ===================================== .. class:: cycloid(radius=0.5*unit.t_cm, halfloops=10, skipfirst=1*unit.t_cm, skiplast=1*unit.t_cm, curvesperhloop=3, sign=1, turnangle=45) Wraps a cycloid (the 2D projection of a 3D helical spring) along the path, using the original path as the central axis of the coil. This deformer is commonly used in physics and engineering diagrams to draw springs, inductors, or gluons. Parameters: - *radius*: Radius of the cycloid loops perpendicular to the base path (default ``0.5 * unit.t_cm``). - *halfloops*: Total number of half-loops along the deformed portion of the path (default ``10``). - *skipfirst*: Arc length at the beginning of each subpath left undeformed as a lead-in segment (default ``1 * unit.t_cm``). - *skiplast*: Arc length at the end of each subpath left undeformed as a lead-out segment (default ``1 * unit.t_cm``). - *curvesperhloop*: Number of cubic Bézier segments used to approximate each half-loop (default ``3``). - *sign*: ``1`` (default) to start the first half-loop to the left of the path, or ``-1`` to start to the right. - *turnangle*: Viewing angle in degrees of the 3D helix projection (default ``45``). Setting ``turnangle=0`` produces a sine-like wave without loops; increasing ``turnangle`` toward ``90`` produces tightly overlapping circular coils. .. method:: deform(basepath) Returns a new :class:`normpath.normpath` with the cycloid wrapped along each subpath of *basepath* (subpaths shorter than ``skipfirst + skiplast + 2 * radius * sin(turnangle)`` are left unchanged with a warning). pyx-project-pyx-21f71ce/manual/document.rst000066400000000000000000000204011526513311100210460ustar00rootroot00000000000000.. _document: ********* Documents ********* .. module:: document :synopsis: Multi-page documents, pages, paper formats, and output writers While a :class:`canvas.canvas` represents an unbounded 2D drawing surface, the :mod:`document` module places one or more canvases onto physical pages with optional paper formats, margins, centering, rotation, and scaling, and writes the resulting single- or multi-page document to PostScript, EPS, PDF, or SVG files. Creating single- and multi-page documents ========================================= For a single-page figure without specific page layout options, you can call :meth:`canvas.canvas.writeEPSfile`, :meth:`canvas.canvas.writePDFfile`, or :meth:`canvas.canvas.writeSVGfile` directly on a canvas. Internally, those methods create a :class:`page` and a :class:`document` for you. To create a multi-page PostScript or PDF document, or to control page layout explicitly, wrap each :class:`canvas.canvas` in a :class:`page` and collect them in a :class:`document`:: from pyx import * d = document.document() for i in range(1, 4): c = canvas.canvas() c.text(0, 0, f"Page {i}", [text.halign.center]) d.append(document.page(c, paperformat=document.paperformat.A4, centered=1)) d.writePSfile("multipage") d.writePDFfile("multipage") Class :class:`page` =================== .. class:: page(canvas, pagename=None, paperformat=None, rotated=0, centered=1, fittosize=0, margin=1*unit.t_cm, bboxenlarge=1*unit.t_pt, bbox=None) Wraps a :class:`canvas.canvas` as a document page and configures its placement and bounding box. Parameters: - *canvas*: The :class:`canvas.canvas` containing the page graphics. - *pagename*: Optional string naming the page (written in the ``%%Page:`` DSC comment in PostScript output; defaults to the 1-based page number). - *paperformat*: Optional :class:`paperformat` instance (such as ``document.paperformat.A4`` or ``document.paperformat.Letter``) defining the physical dimensions of the page. - *rotated*: When set to ``1`` (or ``True``), rotates the page content by 90 degrees counterclockwise (landscape orientation) on the specified *paperformat* (default ``0``). - *centered*: When set to ``1`` (default) and a *paperformat* is specified, centers the canvas bounding box on the paper. - *fittosize*: When set to ``1`` and a *paperformat* is specified, scales the canvas uniformly so that its bounding box fits within the paper dimensions minus *margin* on all four sides (default ``0``). - *margin*: Margin around the page content used when *fittosize* is enabled (default ``1 * unit.t_cm``). - *bboxenlarge*: Amount by which the automatically computed canvas bounding box is enlarged on all four sides to account for finite line widths at the edges of the figure (default ``1 * unit.t_pt``). - *bbox*: Explicit :class:`bbox.bbox` overriding the canvas's automatically computed bounding box (when specified, *bboxenlarge* is not applied). Class :class:`paperformat` ========================== .. class:: paperformat(width, height, name=None) Defines a paper size of the given *width* and *height* (PyX lengths) and optional PostScript media *name*. Predefined standard paper formats available as attributes of :class:`paperformat` are: ================== ============================ ========================= Attribute Dimensions Notes ================== ============================ ========================= ``paperformat.A5`` 148.5 mm |times| 210 mm ISO A5 ``paperformat.A4`` 210 mm |times| 297 mm ISO A4 ``paperformat.A3`` 297 mm |times| 420 mm ISO A3 ``paperformat.A2`` 420 mm |times| 594 mm ISO A2 ``paperformat.A1`` 594 mm |times| 840 mm ISO A1 ``paperformat.A0`` 840 mm |times| 1188 mm ISO A0 ``paperformat.A0b`` 910 mm |times| 1370 mm Oversized poster format ``paperformat.Letter`` 8.5 inch |times| 11 inch US Letter ``paperformat.Legal`` 8.5 inch |times| 14 inch US Legal ================== ============================ ========================= Class :class:`document` and output writers ========================================== .. class:: document(pages=None) Represents a sequence of :class:`page` instances. - *pages*: Optional initial list of :class:`page` instances (defaults to an empty list). .. method:: append(page) Appends a :class:`page` instance to the document. .. method:: writeEPSfile(file=None, title=None, stripfonts=True, textaspath=False, meshasbitmap=False, meshasbitmapresolution=300) Writes a single-page document as an Encapsulated PostScript (EPS) file. Raises :exc:`ValueError` if the document does not contain exactly one page. .. method:: writePSfile(file=None, writebbox=False, title=None, stripfonts=True, textaspath=False, meshasbitmap=False, meshasbitmapresolution=300) Writes the document as a PostScript (PS) file. .. method:: writePDFfile(file=None, title=None, author=None, subject=None, keywords=None, fullscreen=False, writebbox=False, compress=True, compresslevel=6, stripfonts=True, textaspath=False, meshasbitmap=False, meshasbitmapresolution=300) Writes the document as a PDF file. .. method:: writeSVGfile(file=None, textaspath=True, meshasbitmapresolution=300) Writes a single-page document as an SVG 1.1 file. Raises :exc:`ValueError` if the document does not contain exactly one page. .. method:: writetofile(filename, **kwargs) Determines the output writer from the extension of *filename* (``.eps``, ``.ps``, ``.pdf``, or ``.svg``) and writes the document with the given *kwargs*. Writer options -------------- In all output methods above, *file* may be: - a filename string (the appropriate file extension ``.eps``, ``.ps``, ``.pdf``, or ``.svg`` is appended automatically if not already present), - an open binary writable stream (such as an :class:`io.BytesIO` instance), - ``"-"`` to write the binary output to standard output (``sys.stdout.buffer``), or - ``None`` to derive the base filename automatically from the running script name ``sys.argv[0]`` (replacing ``.py`` with the appropriate extension). .. note:: For reproducible builds, both the PostScript and PDF writers honor the ``SOURCE_DATE_EPOCH`` environment variable when writing creation timestamps. The keyword arguments controlling the output writers are: - *stripfonts* (bool, default ``True``; EPS, PS, PDF): When ``True``, embedded Type 1 and OpenType fonts are subsetted so that only the glyphs actually used in the document are included, substantially reducing file size. - *textaspath* (bool, default ``False`` for EPS/PS/PDF and ``True`` for SVG): When ``True``, all text glyphs are converted into vector outline paths instead of embedding font resources. In SVG output, this defaults to ``True`` so that SVG files render identically in all browsers and vector editors without requiring SVG font support. - *meshasbitmap* (bool, default ``False``; EPS, PS, PDF): When ``True``, Gouraud-shaded triangular meshes (:mod:`mesh`, used e.g. by :class:`graph.style.surface`) are rasterized into a bitmap image instead of using native PostScript Level 3 / PDF shading objects. This avoids rendering artifacts and large file sizes in some viewers and printers. (In SVG output, meshes are always rendered as bitmaps.) - *meshasbitmapresolution* (int, default ``300``): Resolution in DPI used when rasterizing meshes into bitmaps. - *writebbox* (bool, default ``False``; PS, PDF): In PostScript output, writes ``%%BoundingBox`` and ``%%PageBoundingBox`` comments even when a paper format is used. In PDF output, writes a ``/CropBox`` entry alongside the ``/MediaBox`` when a paper format is used. - *title* (str or ``None``; EPS, PS, PDF): Document title metadata. - *author*, *subject*, *keywords* (str or ``None``; PDF): Document metadata strings written to the PDF ``/Info`` dictionary. - *fullscreen* (bool, default ``False``; PDF): Requests that the PDF viewer open the document in full-screen presentation mode (``/PageMode /FullScreen``). - *compress* (bool, default ``True``; PDF) and *compresslevel* (int, default ``6``; PDF): Controls ``zlib``/Flate compression of PDF content and font streams. pyx-project-pyx-21f71ce/manual/epsfile.rst000066400000000000000000000117541526513311100206720ustar00rootroot00000000000000.. module:: epsfile :synopsis: Inclusion of Encapsulated PostScript (EPS) files .. _epsfile: ***************************************** Module :mod:`epsfile`: EPS file inclusion ***************************************** The :mod:`epsfile` module allows you to embed external Encapsulated PostScript (EPS) files into a PyX :class:`canvas.canvas`, with full control over position, scaling, alignment, and clipping: .. code-block:: python from pyx import * c = canvas.canvas() c.insert(epsfile.epsfile(0, 0, "figure.eps", width=6, align="cc")) c.writeEPSfile("output") Class :class:`epsfile` ====================== .. class:: epsfile(x, y, filename, width=None, height=None, scale=None, align="bl", clip=1, translatebbox=True, bbox=None, kpsearch=False) Creates a canvas item representing the external EPS file *filename* placed at ``(x, y)`` (in user units or PyX lengths). +--------------------------+---------------------------------------------------------------+ | Argument | Description | +==========================+===============================================================+ | ``x``, ``y`` | Coordinates of the reference point at which the EPS graphic | | | is placed. | +--------------------------+---------------------------------------------------------------+ | ``filename`` | Path to the EPS file. | +--------------------------+---------------------------------------------------------------+ | ``width=None`` | Desired width of the graphic, or ``None`` to use its natural | | | bounding-box width (or scale proportionally from *height*). | | | Cannot be combined with *scale*. | +--------------------------+---------------------------------------------------------------+ | ``height=None`` | Desired height of the graphic, or ``None`` to use its natural | | | bounding-box height (or scale proportionally from *width*). | | | Cannot be combined with *scale*. | +--------------------------+---------------------------------------------------------------+ | ``scale=None`` | Uniform scaling factor, or ``None`` for no scaling. Cannot be | | | combined with *width* or *height*. | +--------------------------+---------------------------------------------------------------+ | ``align="bl"`` | Two-character alignment string specifying how the graphic is | | | aligned relative to ``(x, y)``. The first character sets | | | vertical alignment (``"b"`` bottom, ``"c"`` center, ``"t"`` | | | top) and the second sets horizontal alignment (``"l"`` left, | | | ``"c"`` center, ``"r"`` right). | +--------------------------+---------------------------------------------------------------+ | ``clip=1`` | When true (default), clips the EPS graphic to its bounding | | | box. | +--------------------------+---------------------------------------------------------------+ | ``translatebbox=True`` | When true (default), translates the EPS graphic so that the | | | lower-left corner of its bounding box sits at the reference | | | origin before scaling and alignment. | +--------------------------+---------------------------------------------------------------+ | ``bbox=None`` | Optional :class:`bbox.bbox` overriding the ``%%BoundingBox`` | | | / ``%%HiResBoundingBox`` comments read from the EPS file. | +--------------------------+---------------------------------------------------------------+ | ``kpsearch=False`` | When true, locates *filename* via the TeX ``kpathsea`` file | | | search system (:mod:`config`). | +--------------------------+---------------------------------------------------------------+ Output Format Compatibility --------------------------- * **PostScript and EPS output**: The EPS file is embedded directly as vector PostScript inside a ``BeginDocument`` / ``EndDocument`` wrapper. * **PDF output**: Because PDF viewers cannot execute arbitrary PostScript code, PyX automatically rasterizes the included EPS file to a PNG bitmap using Ghostscript (:meth:`canvas.canvas.pipeGS`) when writing PDF output. To include vector graphics natively in PDF output, convert the file to PDF and use the :mod:`pdffile` module instead. pyx-project-pyx-21f71ce/manual/gradientname.py000077500000000000000000000033121526513311100215130ustar00rootroot00000000000000import sys, re sys.path[:0] = [".."] from pyx import * text.set(text.LatexRunner) text.preamble(r"\renewcommand{\familydefault}{\ttdefault}") c = canvas.canvas() # data to be plotted pf = graph.data.paramfunction("k", 0, 1, "color, xmin, xmax, ymin, ymax= k, k, 1, 0, 1") # positioning is quite ugly ... but it works at the moment y = 0 dy = -0.65 # we could use gradient.__dict__ to get the instances, but we # would loose the ordering ... instead we just parse the file: # see comment in colorname.py firstgraph = None p = re.compile("(?Pgradient\\.(?P[a-z]+)) += [a-z]*gradient_[a-z]+\\(", re.IGNORECASE) with open(color.__file__) as f: for line in f: m = p.match(line) if m: if firstgraph is None: xaxis = graph.axis.lin( parter=graph.axis.parter.lin(tickdists=["0.5","0.1"], labeldists=["1"]), painter=graph.axis.painter.regular( innerticklength=None, outerticklength=graph.axis.painter.ticklength.normal), linkpainter=graph.axis.painter.regular(innerticklength=None, labelattrs=None)) firstgraph = g = graph.graphxy(ypos=y, width=10, height=0.5, x2=xaxis, y=graph.axis.lin(parter=None)) else: g = graph.graphxy(ypos=y, width=10, height=0.5, x2=graph.axis.linkedaxis(firstgraph.axes["x2"]), y=graph.axis.lin(parter=None)) g.plot(pf, [graph.style.rect(gradient=getattr(color.gradient, m.group("name")), keygraph=None)]) g.doplot() g.finish() c.insert(g) c.text(10.2, y + 0.15, m.group("id"), [text.size.footnotesize]) y += dy c.writePDFfile() pyx-project-pyx-21f71ce/manual/gradientname.rst000066400000000000000000000006361526513311100216760ustar00rootroot00000000000000.. _gradientname: ************************* Appendix: Named gradients ************************* The following chart illustrates the predefined color gradients available on :class:`color.gradient`, :class:`color.rgbgradient`, and :class:`color.cmykgradient` (see chapter :ref:`color`). .. _fig_gradientname: .. figure:: gradientname.* :align: center Predefined color gradients in the :mod:`color` module. pyx-project-pyx-21f71ce/manual/graph.dat000066400000000000000000000000441526513311100202720ustar00rootroot000000000000001 2 2 3 3 8 4 13 5 18 6 21 pyx-project-pyx-21f71ce/manual/graph.py000077500000000000000000000001551526513311100201600ustar00rootroot00000000000000from pyx import * g = graph.graphxy(width=8) g.plot(graph.data.file("graph.dat", x=1, y=2)) g.writePDFfile() pyx-project-pyx-21f71ce/manual/graph.rst000066400000000000000000001270361526513311100203450ustar00rootroot00000000000000.. module:: graph :synopsis: 1D, 2D, and 3D data and function plotting .. _graph: ****** Graphs ****** Introduction ============ PyX provides a flexible, publication-quality plotting system for 1D, 2D (*x*–*y*), and 3D (*x*–*y*–*z*) data and mathematical functions. Its modular component architecture (described in section :ref:`graph_components`) cleanly separates graph geometry, data sources, plotting styles, legends (keys), and axes. A Minimal Plot -------------- Creating a graph in PyX takes three steps: 1. Instantiate a graph object such as :class:`graph.graphxy`: .. code-block:: python from pyx import * g = graph.graphxy(width=8) 2. Call :meth:`~graph.graphxy.plot` with one or more data sources (and optional plot styles). For example, given a data file :file:`graph.dat` containing two columns of numbers: .. include:: graph.dat :literal: we can plot column 1 against column 2 with: .. code-block:: python g.plot(graph.data.file("graph.dat", x=1, y=2)) When no explicit style list is passed to :meth:`~graph.graphxy.plot`, each data source uses its own default style—symbols (:class:`graph.style.symbol`) for tabular data such as :class:`graph.data.file`, and continuous lines (:class:`graph.style.line`) for analytical functions such as :class:`graph.data.function`. 3. Write the finished graph to a file. Because every graph instance is a subclass of :class:`canvas.canvas`, you can call any canvas output method (or insert the graph into another canvas): .. code-block:: python g.writeEPSfile("graph") The resulting plot :file:`graph.eps` is shown in figure :ref:`fig_graph`. .. _fig_graph: .. figure:: graph.* :align: center A minimal scatter plot of the data in :file:`graph.dat`. Combining Multiple Datasets and Functions ----------------------------------------- You can overlay multiple datasets and analytical functions on the same graph by calling :meth:`~graph.graphxy.plot` several times before writing the output. For example, to plot the parabola :math:`y(x) = x^2` alongside the data file: .. code-block:: python g.plot(graph.data.function("y(x)=x**2")) .. _fig_graph2: .. figure:: graph2.* :align: center Plotting tabular data from a file together with an analytical function. Configuring Axes and Keyword-Splitting Shortcuts ------------------------------------------------ In the examples above, the *x* and *y* axes were created automatically as linear axes (:class:`graph.axis.linear`) and their ranges were determined from the plotted data. When plotting only an analytical function, or when you want fixed axis bounds, titles, or logarithmic scaling, you can pass explicit axis instances (see chapter :ref:`axis`): .. include:: graph3.py :literal: The resulting plot with a logarithmic *y*-axis is shown in figure :ref:`fig_graph3`. .. _fig_graph3: .. figure:: graph3.* :align: center Plotting a function over a fixed *x*-range with a logarithmic *y*-axis. .. tip:: **Concise axis configuration via underscore keyword splitting**: Instead of instantiating :class:`graph.axis.linear` or :class:`graph.axis.painter.regular` explicitly just to set a few options, you can pass underscore-separated keyword arguments directly to :class:`graph.graphxy` (powered by :func:`utils.kwsplit`). For example: .. code-block:: python g = graph.graphxy(width=8, x_min=0, x_max=10, x_title=r"$x$", y_title=r"$f(x)$", x_painter_gridattrs=[color.gray(0.8)]) Here ``x_min``, ``x_max``, and ``x_title`` are automatically forwarded to the ``x`` axis, and ``x_painter_gridattrs`` is forwarded to the ``painter`` of the ``x`` axis! .. _graph_components: Component Architecture and Canvas Layers ======================================== PyX splits the work of constructing a graph across five cooperating modules: ``graph`` (:mod:`graph.graph`) Defines the overall geometry of the plot area using normalized *graph coordinates* :math:`v \in [0, 1]` along each dimension, manages the canvas layers, coordinates axis range adjustment and style selection, and provides geometric transformation methods between data coordinates, graph coordinates, and canvas coordinates. ``data`` (:mod:`graph.data`) Reads, generates, or transforms data columns (from files, Python lists, or mathematical expressions) and supplies points to the styles. ``style`` (:mod:`graph.style`) Translates data values into visual marks on the graph canvas (symbols, lines, error bars, histograms, bars, 3D surfaces, heatmaps/densities, arrows, and text labels). ``key`` (:mod:`graph.key`) Builds and positions the graph legend from the titles and style samples of the plotted items. ``axis`` (:mod:`graph.axis`) Maps data values to normalized graph coordinates :math:`[0, 1]` and partitions, formats, rates, and paints axis baselines, ticks, labels, titles, and grids (covered in detail in chapter :ref:`axis`). Canvas Layer Ordering in a Graph -------------------------------- Every :class:`graph.graph` instance is a :class:`canvas.canvas` pre-initialized with nine named layers in back-to-front drawing order: 1. ``"background"`` — graph background fill and border 2. ``"grid"`` — axis grid lines 3. ``"filldata"`` — filled data regions (such as bars, rectangles, and density bitmaps) 4. ``"axes.baseline"`` — axis baselines 5. ``"axes.ticks"`` — axis tick marks 6. ``"axes.labels"`` — axis tick labels 7. ``"axes.title"`` — axis titles 8. ``"data"`` — stroked data lines, symbols, and error bars 9. ``"key"`` — graph legend (key) Because drawing order is governed by these layers rather than the order in which internal ``do*()`` methods are executed, grid lines always appear behind data and axes labels always remain legible on top of grid lines. If you draw custom annotations onto a graph canvas ``g``, you can target any layer directly via ``g.layer("filldata").fill(...)`` or ``g.layer("data").stroke(...)``. .. module:: graph.graph :synopsis: 1D, 2D, and 3D graph geometries Module :mod:`graph.graph`: Graph Geometry ========================================= The classes :class:`graphxy`, :class:`graphx`, and :class:`graphxyz` are defined in :mod:`graph.graph` and re-exported at the top level of :mod:`graph` as ``graph.graphxy``, ``graph.graphx``, and ``graph.graphxyz``. 2D Graphs (:class:`graphxy`) ---------------------------- .. class:: graphxy(xpos=0, ypos=0, width=None, height=None, ratio=goldenmean, key=None, backgroundattrs=None, axesdist=0.8*unit.v_cm, flipped=False, xaxisat=None, yaxisat=None, **axes) Constructs a two-dimensional *x*–*y* graph. * *xpos*, *ypos*: Lower-left corner of the plot area on the graph canvas (in user units or PyX lengths; default ``0``). * *width*, *height*, *ratio*: Dimensions of the rectangular plot area (excluding the space occupied by ticks, labels, and titles outside the box). At least *width* or *height* must be specified; if only one is given, the other is computed using *ratio* (which defaults to the golden ratio :math:`(1 + \sqrt{5})/2 \approx 1.618`). * *key*: Optional :class:`graph.key.key` instance to generate a graph legend, or ``None`` (default) to omit the legend. * *backgroundattrs*: List of fill/stroke attributes (e.g. ``[deco.filled([color.gray(0.95)])]``) used to draw the rectangular plot background in the ``"background"`` layer, or ``None`` (default) for a transparent background. * *axesdist*: Distance between multiple parallel axes stacked on the same side of the graph (default ``0.8 * unit.v_cm``). * *flipped*: When ``True``, swaps the geometric orientation of the *x* and *y* axes so that the *x*-axis runs vertically and the *y*-axis runs horizontally (default ``False``). * *xaxisat*, *yaxisat*: Data value along the orthogonal axis (*y* or *x*, respectively) at which the main ``x`` or ``y`` axis should be positioned inside the plot (for example, ``xaxisat=0, yaxisat=0`` to cross the axes at the origin). Setting *xaxisat* or *yaxisat* disables automatic creation of the opposite linked axis (``x2`` or ``y2``). * *\*\*axes*: Axis instances or underscore-split axis parameters. Valid axis names are ``x``, ``x2``, ``x3``, … and ``y``, ``y2``, ``y3``, …. - If neither ``x`` nor ``x2`` is specified, ``x`` defaults to :class:`graph.axis.linear`. - If ``x2`` (or ``y2``) is not specified and *xaxisat* (or *yaxisat*) is ``None``, PyX automatically creates a :class:`graph.axis.linkedaxis` at the opposite side of the plot box (top for ``x2``, right for ``y2``). Pass ``x2=None`` or ``y2=None`` to suppress the top or right axis. - Odd-numbered axes (``x``, ``x3``, … and ``y``, ``y3``, …) are placed at the bottom and left of the plot; even-numbered axes (``x2``, ``x4``, … and ``y2``, ``y4``, …) are placed at the top and right, spaced outward by *axesdist*. - Any keyword argument of the form ``_