Source code for PyICe.LTC_plot

#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
Marcom Compliant Plot Generator

This program can be used to generate plots for general lab use or to
generate Marcom specific plots that can be imported directly into the
datasheet in SVG format.


The objects that can be created with this program are:
  1) plot
  2) Page
  3) Multipage_pdf

The basic model is simple. You create one or more plots and add things to them
like traces, histograms, legends, arrows, notes, etc. Once your plots are populated
you create one or more pages and determine how you want the plots to arrange on
each page. For instance you can create an 8.5x11 page and add 9 plots to it in
a standard 3x3 grid. You can make one big page if you want. It doesn't have to be
a standard size if you don't care what the printer does with it and it won't affect
your SVG files to Marcom. If you want to have multiple pages of plots you can
create a Mulipage_pdf and add one or more pages to it.

If you want larger plots with just one plot per page as in plot_tools.py you can
create a page per plot, add a plot to each page and add all of the pages to a
Multipage_pdf.

So to start, you'll need to create a python work file and import this program:
e.g.

::
  
   ----------- LTCXXXX_plots.py -------------- 
  |import sys                                 |
  |sys.path.append("../../../PyICe")          |
  |import LTC_plot                            |
  |    .                                      |
  |    .                                      |
  |    .                                      |
   ------------------------------------------- 

Next you want to create your plots. A generally preferable work flow would be to
create all of your plots without regard to reference on a Page or Multipage_pdf.

::
  
  G0 = LTC_plot.plot(
                      plot_title      = "EN/FBIN Thresholds",
                      plot_name       = "8709 G0",
                      xaxis_label     = "TEMPERATURE (" + DEGC + ")",
                      yaxis_label     = "FBIN CHIP ENABLE (V)",
                      xlims           = (-50, 125),
                      ylims           = (1.2, 1.4),
                      xminor          = 0,
                      xdivs           = 7,
                      yminor          = 0,
                      ydivs           = 10,
                      logx            = False,
                      logy            = False)

A plot is nothing more than a record of the plot you want to create. It doesn't
support any outputting methods itself. A plot must eventually be added to a Page
to be useful. Only a Page can be generated as an SVG file, even if there's only
one plot on the page.

The arguments of a plot instance are shown below. All plot arguments are required.

plot_title  : "string"
plot_name   : "string"
xaxis_label : "string"
yaxis_label : "string"
  Accepts control characters such as \\n to start a second line. 
  These text fields also respond to Tex formatting for subscripting
  There are a few unicode characters available in LTC_plot
  to help with greek characters and degree signs, etc. Be aware
  that the Marcom minus sign is not the same as the one you type.
  You may wan to use LTC_plot.minus.                            
xlims : (xmin, xmax)
ylims : (ymin, ymax)
  These two fields also accept python None or string "auto"
  for automatic scaling. Autoscaling is useful to view the
  data for the first time and then the final values can be
  entered later once the data is understood.
xminor : 0
  This is the number of minor X divisions per major X division.
xdivs : 7
  This is the number of major X divisions.
yminor : 0
  This is the number of minor Y divisions per major XY division.
ydivs : 10
  This is the number of major Y divisions.
logx : False
  Sets the X axis to a log scale with locators at [1,2,3,4,5,6,7,8,9].
logy : False
  Sets the Y axis to a log scale with locators at [1,2,3,4,5,6,7,8,9].

Once you have a plot you can add things to it such as:
  - add_trace()
  - add_histogram()
  - add_note()
  - add_legend()
  - add_arrow()
  - make_second_y_axis()

The most common element is a trace. You can add as many traces as you like. The same is true of histograms.
You can also put traces and histograms on the same plot (for instance to show the Gaussian normal curve).

When you add a trace you have the option to specify line style and marker. Linear datasheets often use
dotted or dot dash lines for improved black and white readability but rarely if even use markers so use
them judiciously.

Valid linestyles are:
  - '-'
  - '--'
  - '-.'
  - ':'

and valid markers are:
  - ':'
  - '.'
  - ','
  - 'o'
  - 'v'
  - '^'
  - '<'
  - '>'
  - '1'
  - '2'
  - '3'
  - '4'
  - '8'
  - 's'
  - 'p'
  - '*'
  - 'h'
  - 'H'
  - '+'
  - 'x'
  - 'D'
  - 'd'
  - '|'
  - '_'
  - TICKLEFT
  - TICKRIGHT
  - TICKUP
  - TICKDOWN
  - CARETLEFT
  - CARETRIGHT
  - CARETUP
  - CARETDOWN


Please see matplot lib docs online for more details.

Trace colors currently supported are:
  - LT_RED_1
  - LT_BLUE_1
  - LT_GREEN_1
  - LT_COPPER_1
  - LT_BLACK
  - LT_COPPER_2
  - LT_RED_2
  - LT_BLUE_2
  - LT_GREEN_2
  - LT_YELLOW_2
  - LT_BLUE_2_40PCT
  - LT_RED_1_40PCT

You can make your own colors by entering a list of RGB colors (r,g,b), all of which should be between 0 and 1 rather than 0 to 255.
**This is strongly discouraged however, as it will not be in compliance with LTC standards and should not make its way to Marcom.**

add_legend takes arguments:
  - axis
  - location
  - justification
  - use_axes_scale

axis
  The axis from which the legend items have been added.
location
  Coordinates in an xy list (x, y) of where to place the legend.
  These are relative, see use_axes_scale.
justification
  Justification of the test of the legend. Accepts:
    - "best"
    - "upper right"
    - "upper left"
    - "lower left"
    - "lower right"
    - "right"
    - "center left"
    - "center right"
    - "lower center"
    - "upper center"
    - "center"
    
    
use_axes_scale:
  True means place the legend by the scale of the data values whereas False means use values from 0 to 1 representing data independent percentage of the graph size.

Notes, on the other hand, need to have coordinates given.
Both support the use_axes_scale argument which defaults to True referencing the item to the data values rather than as a percentage (0..1) of the graph limits.

Data can come from a number of sources such as a CSV file or a .sqlite database and should be a zipped list
of (x,y) values for a trace and just a list for a histogram. Consult the examples file for details.

You can also add as many notes as you like. The position of the notes can be set by either referring them
to the axes_scale, a scale relative to your data or a percentage scale (0..1) of the axes extents. The default
is to use the scale of your data. This should be easier to help you locate the notes, etc as the graticules
will more precisely help you picture where the item will be.

You can only add one legend. For each trace on a given axis, it will place a label preceded by a line stub
in the same color and width of the trace. Generally the legend will placed along side the axis to which it
belongs but you can specify where it goes.

An arrow is based on the matplotlib annotate() object and consists of a text box with an arrow emanating
from it. You control where the lower left corner of the text goes as well as the arrow tip.

If you add a second y axis you have to, once again, specify a few required items in a similar manner to when
you created the plot:
1)  yaxis_label
2)  ylims
3)  yminor
4)  ydivs
5)  logy

As you add traces and histograms you'll need to specify to which axis they belong (1 or 2).

Once you have created all of your plots you will need to add them to a page:

::

  Page1 = Page(rows_x_cols = (3, 3), page_size = (8.5, 11))

Defaults for rows_x_cols = (1, 1) and for page_size is None. If you omit the page_size
or specify None, the page will shrink to fit the plots you add to it. If, on the other
hand, you specify a page size and the plots you add to it don't quite fit, the plots
will overlap a bit. That won't matter for datasheet importation as you'll see later.
Alternately, if your plots are swimming on your page, they'll be spread out to roughly
fill the Page.

Pages support the following methods:
  1. add_plot()
  2. create_pdf()
  3. create_svg()
  4. kit_datasheet()

add_plot() has options to change the plot size on the page such as plot_sizex and
plot_sizey. These values are extremely specific to datasheets and should not be changed
if the plots are to be sent to Marcom. It's best to enter the plot instance and position
and leave the rest alone.

::

  Page1.add_plot(G01, position = 1)
  Page1.add_plot(G02, position = 2)
  Page1.add_plot(G03, position = 3)

As you add plots to the page with a given position, the plots appear on the page top to
bottom, left to right.

So a Page that was specified as 3x3 would add up to 9 plots in the following order:

::
  
   ---------------------------
  |                           |
  |   [1]     [2]     [3]     |
  |                           |
  |                           |
  |   [4]     [5]     [6]     |
  |                           |
  |                           |
  |   [7]     [8]     [9]     |
  |                           |
   ---------------------------


Or a 2x2 Page would be positioned as:

::
  
   -------------------
  |                   |
  |   [1]     [2]     |
  |                   |
  |                   |
  |   [3]     [4]     |
  |                   |
   -------------------

Pages support the following methods:
  1. create_pdf("LTCXXXX_Page1")
  2. create_svg("LTCXXXX_Page1")
  3. kit_datasheet("LTCXXXX_Page1")

Each of these takes just a file_basename. The file extension is added to match the
output.

**All output data you request is place in a newly created folder under your work area called "/plots".**

kit_datasheet() performs the following sequence for you:
  1. Creates a zip file.
  2. Creates a disposable page.
  3. Adds one plot that is found on your Page.
  4. Creates an SVG file of the disposable page and adds it to the zip file.
  5. Repeats for each plot on your Page. The disposable Page evaporates.
  6. Creates a PDF of your entire page for reference and dumps it in the zip file.

If you end up needing more than one page of plots you can add your pages to
a Multipage_pdf:

::

  LTCXXXX_typcurves = Multipage_pdf("LTCXXXX_typcurves")
  LTCXXXX_typcurves.add_page(Page1)
  LTCXXXX_typcurves.add_page(Page2)
  LTCXXXX_typcurves.kit_datasheet()

Multipage_pdfs support the methods:
  1. kit_datasheet("LTCXXXX_Page1")
  2. create_pdf("LTCXXXX_Page1")

To really get going and find more example see:

\PyICe\Examples\LTC_plot_example\LTC_plot_example.py

*** TIP ***
  If you get a warning about missing Linear fonts and you have them installed,
  try deleting: "C:\\\\Users\\\\%username%\\\\.matplotlib\\\\fontList.cache and tex.cache"

'''


import numpy as np
import matplotlib, matplotlib.ticker
import sqlite3, math
from matplotlib.backends.backend_pdf import PdfPages
from matplotlib.backends.backend_pdf import FigureCanvasPdf
from matplotlib.backends.backend_svg import FigureCanvasSVG
from matplotlib.font_manager import FontProperties
from matplotlib.lines import Line2D
import os
import shutil
import StringIO

        
class PyICe_data_base():
    def __init__(self, table_name, file_name = "data_log.sqlite"):
        print ##############################################################
        print #                                                            #
        print # PyICe_data_base() from inside LTC_plot is deprecated.      #
        print # please switch to lab_utils.sqlite_data().                  #
        print # Speak to Steve or Dave for help.                           #
        print # Sorry for the inconvenience.                               #
        print #                                                            #
        print ##############################################################
class plot(object):
    def __init__(self, plot_title, plot_name, xaxis_label, yaxis_label, xlims, ylims, xminor, xdivs, yminor, ydivs, logx, logy):
        '''A plot is just a record of what you want to plot and how you want it to look.
        It must be added to a Page before it can be exported.
        Start by creating as many plots as you like and adding data and various annotations to them.
        Once you add your plot or plots to a Page you can generate an SVG or PDF of the Page.'''
        self.plot_title         = plot_title
        self.plot_name          = plot_name
        self.xaxis_label        = xaxis_label
        self.xlims              = xlims
        self.xdivs              = xdivs
        self.xminor             = xminor
        self.logx               = logx
        self.notes              = []
        self.arrows             = []
        self.y1_axis_params     = {}
        self.y2_axis_params     = {}
        self.plot_type          = "regular"
        for y_axis_params in [self.y1_axis_params, self.y2_axis_params]:
            y_axis_params["yaxis_label"]    = yaxis_label 
            y_axis_params["ylims"]          = ylims
            y_axis_params["yminor"]         = yminor
            y_axis_params["ydivs"]          = ydivs
            y_axis_params["logy"]           = logy
            y_axis_params["autoscaley"]     = True
            y_axis_params["place_legend"]   = False
            y_axis_params["legend_loc"]     = None
            y_axis_params["trace_data"]     = []
            y_axis_params["histo_data"]     = []
        self.y1_axis_params["axis_is_used"] = True
        self.y2_axis_params["axis_is_used"] = False
        self.styles = []
        for style in ['-','--','-.',':']:
            for color in MARCOM_COLORSfracRGB:
                self.styles.append( (style,color,) )
        self.current_style_index = 0
    def add_trace(self, axis, data, color, marker = None, markersize = 0, linestyle = "-", legend = ""):
        trace_data = {  "axis"          : axis,
                        "data"          : data,
                        "color"         : color,
                        "marker"        : marker,
                        "markersize"    : markersize,
                        "linestyle"     : linestyle,
                        "legend"        : legend.replace("-",u"−")
                     }
        if axis == 1:
            self.y1_axis_params["trace_data"].append(trace_data)
        else:
            self.y2_axis_params["trace_data"].append(trace_data)
    def add_histogram(self, axis, xdata, num_bins, color, normed = False, legend = "", edgecolor = "black", linewidth = 0.5, alpha = 1):
        histo_data = { "axis"           : axis,
                       "xdata"          : xdata,
                       "num_bins"       : num_bins,
                       "color"          : color,
                       "normed"         : normed,
                       "legend"         : legend,
                       "edgecolor"      : edgecolor,
                       "linewidth"      : linewidth,
                       "alpha"          : alpha,
                    }
        if axis == 1:
            self.y1_axis_params["histo_data"].append(histo_data)
        else:
            self.y2_axis_params["histo_data"].append(histo_data)
    def make_second_y_axis(self, yaxis_label, ylims, yminor, ydivs, logy):
        self.y2_axis_params["axis_is_used"] = True
        self.y2_axis_params["yaxis_label"]  = yaxis_label
        self.y2_axis_params["ylims"]        = ylims
        self.y2_axis_params["yminor"]       = yminor
        self.y2_axis_params["ydivs"]        = ydivs
        self.y2_axis_params["logy"]         = logy
    def add_legend(self, axis, location = (0,0), justification = 'lower left', use_axes_scale = False):
        if axis == 1:
            self.y1_axis_params["place_legend"]         = True
            self.y1_axis_params["legend_loc"]           = location
            self.y1_axis_params["legend_justification"] = justification
            self.y1_axis_params["use_axes_scale"]       = use_axes_scale
        else:
            self.y2_axis_params["place_legend"]         = True
            self.y2_axis_params["legend_loc"]           = location
            self.y2_axis_params["legend_justification"] = justification
            self.y2_axis_params["use_axes_scale"]       = use_axes_scale
    def add_note(self, note, location = [0.05, 0.5], use_axes_scale = True):
        self.notes.append({"note" : note, "location" : location, "use_axes_scale": use_axes_scale})
    def add_arrow(self, text, text_location, arrow_tip, use_axes_scale = True):
        self.arrows.append({   "text"           : text,
                                "text_location" : text_location,
                                "arrow_tip"     : arrow_tip,
                                "use_axes_scale": use_axes_scale
                           })
class scope_plot(plot):
    def __init__(self, plot_title, plot_name, xaxis_label, xlims, ylims):
        '''A plot is just a record of what you want to plot and how you want it to look.
        It must be added to a Page before it can be exported.
        Start by creating as many plots as you like and adding data and various annotations to them.
        Once you add your plot or plots to a Page you can generate an SVG or PDF of the Page.'''
        self.plot_title                             = plot_title
        self.plot_name                              = plot_name
        self.xaxis_label                            = xaxis_label
        self.xlims                                  = xlims
        self.xdivs                                  = 10
        self.xminor                                 = None
        self.logx                                   = False
        self.notes                                  = []
        self.arrows                                 = []
        self.ref_markers                            = []
        self.trace_labels                           = []
        self.y1_axis_params                         = {}
        self.y2_axis_params                         = {}
        self.plot_type                              = "scope_plot"
        for y_axis_params in [self.y1_axis_params, self.y2_axis_params]:
            y_axis_params["ylims"]                  = ylims
            y_axis_params["yminor"]                 = None
            y_axis_params["ydivs"]                  = 8
            y_axis_params["logy"]                   = False
            y_axis_params["autoscaley"]             = True
            y_axis_params["place_legend"]           = False
            y_axis_params["legend_loc"]             = None
            y_axis_params["trace_data"]             = []
            y_axis_params["ref_marker_loc"]         = 0
            y_axis_params["ref_marker_color"]       = LT_BLACK
            y_axis_params["marker_use_axes_scale"]  = False
        self.y1_axis_params["axis_is_used"]         = True
        self.y2_axis_params["axis_is_used"]         = False
        self.styles = []
        for style in ['-','--','-.',':']:
            for color in MARCOM_COLORSfracRGB:
                self.styles.append( (style,color,) )
        self.current_style_index = 0
    def make_second_y_axis(self, ylims):
        self.y2_axis_params["axis_is_used"]         = True
        self.y2_axis_params["ylims"]                = ylims
    def add_ref_marker(self, axis, ylocation, marker_color, use_axes_scale):
        self.ref_markers.append({"axis" : axis, "ylocation" : ylocation, "marker_color" : marker_color, "use_axes_scale": use_axes_scale})
    def add_trace_label(self, trace_label, axis, ylocation, use_axes_scale):
        self.trace_labels.append({"trace_label" : trace_label, "axis" : axis, "ylocation" : ylocation, "use_axes_scale": use_axes_scale})
class Page():
    def __init__(self, rows_x_cols = None, page_size = None, plot_count = None):
        '''A Page containing one or more plots can be exported as a PDF or SVG.
        Alternately you can kit the page for datasheet submission.
        This is where the plots are actually "constructed" from matplotlib objects.'''
        #################################################################
        # Create the matplotlib Figure and do some datasheet setup      #
        #################################################################
        self.Figure = matplotlib.figure.Figure()
        if rows_x_cols is not None and plot_count is None:
            self.rows_x_cols = rows_x_cols
        elif rows_x_cols is None and plot_count is not None:
            if plot_count <=3:
                self.rows_x_cols = (1,plot_count)
            else:
                self.rows_x_cols = ((plot_count-1)/3+1,3)
        else:
            raise Exception('Specify exactly one of rows_x_cols or plot_count agruments. rows_x_cols should be a two-element list or tuple.')
        self.page_size      = page_size
        self.plot_list      = []
        self.page_type      = None
        self.next_position = 0
        matplotlib.rcParams['axes.linewidth']           = 0.6
        matplotlib.rcParams['font.family']              = 'Linear Helv Cond'
        matplotlib.rcParams['text.color']               = LT_TEXT
        matplotlib.rcParams['axes.labelcolor']          = LT_TEXT
        matplotlib.rcParams['svg.fonttype']             = "none"    # Prevents characters from being converted to paths.
        matplotlib.rcParams['text.usetex']              = False     # Not Sure
        matplotlib.rcParams['text.latex.unicode']       = True      # Doesn't seem to do anything
        matplotlib.rcParams['mathtext.default']         = 'regular' # Prevents subscripts from changing fonts.
        matplotlib.rcParams['axes.unicode_minus']       = True
        matplotlib.mathtext.SHRINK_FACTOR               = 6.0/7.0   # Makes subscripts kind of OK
        matplotlib.mathtext.GROW_FACTOR                 = 1 / matplotlib.mathtext.SHRINK_FACTOR
        # matplotlib.mathtext.GROW_FACTORSUBDROP    = 1         # Didn't seem to do anything
        # matplotlib.mathtext.GROW_FACTORSUB1       = 1         # Didn't seem to do anything
    def LTC_LOG10_Formatter(self, x):
        if x >= 1:
            return str(int(x))
        else:
            return str(x)
    def add_plot(   self, plot,
                    position        = None,        # This is if there's just one plot.
                    plot_sizex      = 11.0/6.0, # Graphs are exactly 11 pica which is 1/6 of an inch
                    plot_sizey      = 11.0/6.0, # Graphs are exactly 11 pica which is 1/6 of an inch
                    left_border     = 0.7,      # in inches
                    right_border    = 0.7,      # in inches
                    top_border      = 0.7,      # in inches
                    bottom_border   = 0.7,      # in inches
                    x_gap           = 0.8,      # in inches
                    y_gap           = 0.8):     # in inches
        #################################################################
        # Create subplots                                               #
        #################################################################
        if self.page_type is None:
            self.page_type = plot.plot_type
        elif self.page_type != plot.plot_type:
            raise Exception("\n\n\n**************************************************\nPlots of different types not allowed on same page.\nPlease combine only common plot types per page.\n**************************************************\n\n\n")
        if position is None:
            self.next_position += 1
        else:
            self.next_position = position
        graph = self.Figure.add_subplot(self.rows_x_cols[0], self.rows_x_cols[1], self.next_position)
        self.plot_list.append(plot)
        rows, columns   = self.rows_x_cols
        plot_sizex =  float(plot_sizex)
        if plot.plot_type == "scope_plot":
            plot_sizey  = float(8.8/6.0)  # Graphs are exactly 11x8.8 pica which make perfect squares on a 10x8 grid. Bob Reay's tool uses 8.6667 pica. Not sure why.
            trace_width = 0.6
        else:
            plot_sizey  =  float(plot_sizey)
            trace_width = 1.2
        left_border     =  float(left_border)
        right_border    =  float(right_border)
        top_border      =  float(top_border)
        bottom_border   =  float(bottom_border)
        x_gap           =  float(x_gap)
        y_gap           =  float(y_gap)
        if self.page_size is not None:
            x_gap           = (self.page_size[0] - columns * plot_sizex) / (columns + 1)
            y_gap           = (self.page_size[1] - rows * plot_sizey) / (rows + 1)
            left_border     = x_gap
            right_border    = x_gap
            top_border      = y_gap
            bottom_border   = y_gap
            x_total         = self.page_size[0]
            y_total         = self.page_size[1]
        else:
            x_total = left_border + right_border + plot_sizex * columns + x_gap * (columns - 1)
            y_total = bottom_border + top_border + plot_sizey * rows + y_gap * (rows - 1)
        left        = left_border / x_total
        right       = (x_total - right_border) / x_total
        bottom      = bottom_border / y_total
        top         = (y_total - top_border) / y_total
        hspace      = y_gap / plot_sizey # hspace and wspace are percentages of a plot scale
        wspace      = x_gap / plot_sizex # for example, wspace = 1 makes gaps the size of the x dimension of a plot
        self.Figure.set_size_inches(x_total, y_total)
        graph.figure.subplots_adjust(left = left, right = right, bottom = bottom, top = top, wspace = wspace, hspace = hspace)
        graph.set_axisbelow(True) # Puts data in front of axes
        try:
            graph.set_title(plot.plot_title, fontsize = 9.5, fontweight = "bold", color = 'black', loc = "left")
        except:
            graph.set_title(plot.plot_title, fontsize = 9.5, fontweight = "bold", color = 'black')
            print "\nYou have an older version of matplotlib, consider upgrading to winpython 2.7.6.4\n"
        if plot.plot_type == "scope_plot":
            graph.axes.get_xaxis().set_ticklabels([]) # Kill the conventional X axis labels
            graph.axes.get_yaxis().set_ticklabels([]) # Kill the conventional Y axis labels
            #Add X label back in as text
            note_props = dict(boxstyle = 'square, pad = 0.125', facecolor = 'white', edgecolor = "white", alpha = 1)
            graph.text(0.4, -0.02, plot.xaxis_label, fontsize = 7, transform = graph.transAxes, horizontalalignment = 'left', verticalalignment = 'top', bbox = note_props)
            #Add Y label back in as text
            # graph.text(-0.02, 0.4, plot.y1_axis_params["yaxis_label"], fontsize = 7, transform = graph.transAxes, horizontalalignment = 'right', verticalalignment = 'bottom', bbox = note_props)
        else:
            graph.set_xlabel(plot.xaxis_label, fontsize = 7)
            graph.set_ylabel(plot.y1_axis_params["yaxis_label"], fontsize = 7)
        note_props = dict(boxstyle = 'square, pad = 0.125', facecolor = 'white', edgecolor = "white", alpha = 1)
        if plot.plot_type == "scope_plot":
            for trace_label in plot.trace_labels:
                if trace_label["axis"] == 1:
                    justification = "right"
                    if trace_label["use_axes_scale"] == True:
                        coordinate_system = graph.transData
                        x = plot.xlims[0] - 0.02 * (plot.xlims[1] - plot.xlims[0])
                        # x = -0.02 / 10 * ()
                        y = trace_label["ylocation"]
                    else:
                        coordinate_system = graph.transAxes
                        x = -0.02
                        y = trace_label["ylocation"]
                else: # must be axis 2
                    justification = "left"
                    if trace_label["use_axes_scale"] == True:
                        coordinate_system = graph.transData
                        x = plot.xlims[1] + 0.01 * (plot.xlims[1] - plot.xlims[0])
                        # x = 1.02 / 10 * ()
                        y = trace_label["ylocation"]
                    else:
                        coordinate_system = graph.transAxes
                        x = 1.01
                        y = trace_label["ylocation"]
                graph.text(x, y, trace_label["trace_label"], fontsize = 7, transform = coordinate_system, horizontalalignment = justification, verticalalignment = 'center', bbox = note_props)
        #################################################################
        # Add plot_name in lower right corner                           #
        #################################################################
        plotname_props = dict(boxstyle = 'square', facecolor = 'white', edgecolor = "white", alpha = 1)
        graph.text(x = 1, y = -0.2, s = "", text = plot.plot_name, fontsize = 4, transform = graph.transAxes, verticalalignment = 'top', horizontalalignment = 'right', bbox = plotname_props)
        #############################################################################################
        # Deal with second axis first (seems to keep first axis tick marks from coming back)        #
        #############################################################################################
        if plot.y2_axis_params["axis_is_used"]:
            twin = graph.twinx()
            if plot.plot_type == "scope_plot":
                twin.axes.get_yaxis().set_ticklabels([]) # Kill the conventional Y axis labels
                #Add Y label back in as text
                # note_props = dict(boxstyle = 'square, pad = 0.125', facecolor = 'white', edgecolor = "white", alpha = 1)
                # twin.text(1.02, 0.4, plot.y2_axis_params["yaxis_label"], fontsize = 7, transform = twin.transAxes, horizontalalignment = 'left', verticalalignment = 'bottom', bbox = note_props)
            else:
                twin.set_ylabel(plot.y2_axis_params["yaxis_label"], fontsize = 7, rotation = -90)
            twin.yaxis.labelpad = 17 # TODO, this should be a function of the number of digits in the axes numbers
            for label in twin.yaxis.get_majorticklabels():
                label.set_fontsize(7)
            if plot.y2_axis_params["logy"]:
                twin.set_yscale('log')
                twin.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: self.LTC_LOG10_Formatter(x)))
                if plot.y2_axis_params["yminor"] != 0:
                    twin.yaxis.set_minor_locator(matplotlib.ticker.LogLocator(subs = [2,3,4,5,6,7,8,9]))
                else:
                    twin.yaxis.set_minor_locator(matplotlib.ticker.LogLocator(subs = []))
            else:
                if plot.plot_type == "regular":
                    twin.get_yaxis().get_major_formatter().set_useOffset(False)
                    twin.yaxis.set_major_locator(matplotlib.ticker.LinearLocator(plot.y2_axis_params["ydivs"] + 1))
                    if plot.y2_axis_params["yminor"] not in [None, 0]:
                        twin.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(plot.y2_axis_params["yminor"]))
            if plot.y2_axis_params["ylims"] not in [None, "auto"]:
                plot.y2_axis_params["autoscale"] = False
                twin.set_ylim(ymin = plot.y2_axis_params["ylims"][0], ymax = plot.y2_axis_params["ylims"][1])
            else:
                plot.y2_axis_params["autoscaley"] = True
            for tic in twin.yaxis.get_major_ticks():
                tic.tick1On = False
                tic.tick2On = False
            for tic in twin.yaxis.get_minor_ticks():
                tic.tick1On = False
                tic.tick2On = False
            for tic in twin.yaxis.get_major_ticks():
                tic.tick1On = False
                tic.tick2On = False
        #################################################################
        # Deal with first axis limits                                   #
        #################################################################
        if plot.xlims in [None, "auto"]:
            autoscalex = True
        else:
            autoscalex = False
            graph.axis(xmin = plot.xlims[0], xmax = plot.xlims[1])
        if plot.y1_axis_params["ylims"] in [None, "auto"]:
            plot.y1_axis_params["autoscaley"] = True
        else:
            plot.y1_axis_params["autoscaley"] = False
            graph.axis(ymin = plot.y1_axis_params["ylims"][0], ymax = plot.y1_axis_params["ylims"][1])
        if plot.logx:
            graph.set_xscale('log')
            graph.xaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: self.LTC_LOG10_Formatter(x)))
            if plot.xminor != 0:
                graph.xaxis.set_minor_locator( matplotlib.ticker.LogLocator(subs = [2,3,4,5,6,7,8,9]))
            else:
                graph.xaxis.set_minor_locator( matplotlib.ticker.LogLocator(subs = []))
        else:
            graph.xaxis.set_major_locator(matplotlib.ticker.LinearLocator(plot.xdivs + 1))
            if plot.plot_type == "regular":
                graph.get_xaxis().get_major_formatter().set_useOffset(False)
                if plot.xminor not in [None, 0]:
                    graph.xaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(plot.xminor))
        if plot.y1_axis_params["logy"]:
            graph.set_yscale('log')
            graph.yaxis.set_major_formatter(matplotlib.ticker.FuncFormatter(lambda x, pos: self.LTC_LOG10_Formatter(x)))
            if plot.y1_axis_params["yminor"] != 0:
                graph.yaxis.set_minor_locator(matplotlib.ticker.LogLocator(subs = [2,3,4,5,6,7,8,9]))
            else:
                graph.yaxis.set_minor_locator(matplotlib.ticker.LogLocator(subs = []))
        else:
            if plot.plot_type == "regular":
                graph.get_yaxis().get_major_formatter().set_useOffset(False)
            graph.yaxis.set_major_locator(matplotlib.ticker.LinearLocator(plot.y1_axis_params["ydivs"] + 1))
            if plot.y1_axis_params["yminor"] not in [None, 0]:
                graph.yaxis.set_minor_locator(matplotlib.ticker.AutoMinorLocator(plot.y1_axis_params["yminor"]))
        if plot.plot_type == "scope_plot":
            grid_color = LT_SCOPE_GRID
        else:
            grid_color = LT_GRID
        graph.grid(b = True, which = 'both', color = grid_color, linestyle='-', linewidth = 0.35)
        graph.tick_params(axis = 'both', colors = LT_GRID, gridOn = True, tick1On = False, tick2On = False, labelsize = 7, labelcolor = LT_TEXT)
        if plot.plot_type == "scope_plot":
            TIC_LENGTH = 0.00644 # percentage of graph width
            # Make my own Y axis tics manually
            for major in range(8): # 0..7
                for minor in range(1,5): # 1..4
                    line = [(0.5 - TIC_LENGTH, major/8. + minor/40.), (0.5 + TIC_LENGTH, major/8. + minor/40.)]
                    (line_xs, line_ys) = zip(*line)
                    graph.add_line(Line2D(line_xs, line_ys, linewidth=0.35, color=LT_SCOPE_GRID, transform=graph.transAxes))
            # Make my own X axis tics manually
            for major in range(10): # 0..9
                for minor in range(1,5): # 1..4
                    line = [(major/10. + minor/50., 0.5 - TIC_LENGTH), ( major/10. + minor/50., 0.5 + TIC_LENGTH)]
                    (line_xs, line_ys) = zip(*line)
                    graph.add_line(Line2D(line_xs, line_ys, linewidth=0.35, color=LT_SCOPE_GRID, transform=graph.transAxes))
        for tic in graph.xaxis.get_major_ticks():
            tic.tick1On = False
            tic.tick2On = False
        for tic in graph.xaxis.get_minor_ticks():
            tic.tick1On = False
            tic.tick2On = False
        #################################################################
        # Add the data                                                  #
        #################################################################
        plot.y1_axis_params["axis"] = graph
        if plot.y2_axis_params["axis_is_used"]:
            plot.y2_axis_params["axis"] = twin
        for y_axis_params in [plot.y1_axis_params, plot.y2_axis_params]:
            if y_axis_params["axis_is_used"]:
                for trace in y_axis_params["trace_data"]:
                    y_axis_params["axis"].plot(         zip(*trace["data"])[0],
                                                        zip(*trace["data"])[1],
                                        color           = trace["color"],
                                        linewidth       = trace_width,
                                        marker          = trace["marker"],
                                        markersize      = trace["markersize"],
                                        label           = trace["legend"],
                                        linestyle       = trace["linestyle"],
                                        alpha           = 1,
                                        scalex          = y_axis_params["autoscaley"],
                                        scaley          = y_axis_params["autoscaley"])
                if plot.plot_type != "scope_plot":
                    for histogram in y_axis_params["histo_data"]:
                        y_axis_params["axis"].hist(  x  = histogram["xdata"],
                                            bins        = histogram["num_bins"],
                                            range       = None,
                                            normed      = histogram["normed"],
                                            weights     = None,
                                            cumulative  = False,
                                            bottom      = None,
                                            histtype    = 'bar',
                                            align       = 'mid',
                                            orientation = 'vertical',
                                            rwidth      = None,
                                            log         = False,
                                            color       = histogram["color"],
                                            label       = histogram["legend"],
                                            stacked     = False,
                                            linewidth   = histogram["linewidth"],
                                            alpha       = histogram["alpha"],
                                            edgecolor   = histogram["edgecolor"])
        #################################################################
        # Place the legends                                             #
        #################################################################
                if y_axis_params["place_legend"]:
                    if y_axis_params == plot.y1_axis_params:
                        if plot.y1_axis_params["use_axes_scale"]:
                            coordinate_system = graph.transData
                        else:
                            coordinate_system = graph.transAxes
                    if y_axis_params == plot.y2_axis_params:
                        if plot.y2_axis_params["use_axes_scale"]:
                            coordinate_system = graph.transData
                        else:
                            coordinate_system = graph.transAxes
                    legend = y_axis_params["axis"].legend(frameon = True, fontsize = 7, loc = y_axis_params["legend_justification"], bbox_to_anchor = y_axis_params["legend_loc"], framealpha = 1, borderpad = 0.25, bbox_transform = coordinate_system)
                    legend.get_frame().set_linewidth(0)
        #################################################################
        # Add the reference marker (scope_plot only)                    #
        #################################################################
                if plot.plot_type == "scope_plot":
                    for ref_marker in plot.ref_markers:
                        if ref_marker["use_axes_scale"]:
                            coordinate_system = graph.transData
                            if ref_marker['axis'] == 1:
                                x = plot.xlims[0]
                                y = ref_marker["ylocation"] - 0.03 / 8 * (plot.y1_axis_params['ylims'][1] - plot.y1_axis_params['ylims'][0])
                                marker = u"►"
                            else: # must be second y axis
                                x = plot.xlims[1] - 0.038 * (plot.xlims[1] - plot.xlims[0]) # Not sure why offset is needed, text arrow not centered with its bbox?
                                y = ref_marker["ylocation"] - 0.03 / 8 * (plot.y2_axis_params['ylims'][1] - plot.y2_axis_params['ylims'][0])
                                marker = u"◄"
                        else: # must be absolute scale (0 - 1)
                            coordinate_system = graph.transAxes
                            if ref_marker['axis'] == 1:
                                x = 0
                                marker = u"►"
                            else: # must be second y axis
                                x = 1 - 0.038                                               # Not sure why offset is needed, text arrow not centered with its bbox?
                                marker = u"◄"
                            y = ref_marker["ylocation"] - 0.0038                            # Not sure why offset is needed, text arrow not centered with its bbox?
                        note_props = dict(boxstyle = 'square, pad = 0.125', facecolor = 'white', edgecolor = "white", alpha = 0)
                        color = ref_marker["marker_color"]
                        graph.text(x, y, marker, fontsize = 5, color = color, family = 'Arial', transform = coordinate_system, horizontalalignment = 'left', verticalalignment = 'center', bbox = note_props)
        #################################################################
        # Add the notes                                                 #
        #################################################################
        note_props = dict(boxstyle = 'square, pad = 0.125', facecolor = 'white', edgecolor = "white", alpha = 1)
        for note_dict in plot.notes:
            note    = note_dict["note"].replace("-",u"-")
            x       = note_dict["location"][0]
            y       = note_dict["location"][1]
            if note_dict["use_axes_scale"]:
                coordinate_system = graph.transData
            else:
                coordinate_system = graph.transAxes
            graph.text(x, y, note, fontsize = 7, transform = coordinate_system, horizontalalignment = 'left', verticalalignment = 'bottom', bbox = note_props)
        #################################################################
        # Add the arrows (matplotlib "annotation")                      #
        #################################################################
        # White Stripe, useless arrowhead
        arrowprops1 = dict(arrowstyle    = "-|>, head_length=0, head_width=1e-37",
                                connectionstyle = "arc3, rad = 0",
                                facecolor       = "white",
                                edgecolor       = "white",
                                linewidth       = 1.4
                                )
        # Main arrow and head
        arrowprops2 = dict(arrowstyle    = "-|>, head_length=0.8, head_width=0.24",
                                connectionstyle = "arc3, rad = 0",
                                facecolor       = "black",
                                edgecolor       = "white",
                                linewidth       = 0
                                )
        # Offset white arrow over top to make the "barb"
        arrowprops3 = dict(arrowstyle    = "-|>, head_length=0.2, head_width=0.31",
                                connectionstyle = "arc3, rad = 0",
                                facecolor       = "white",
                                edgecolor       = "black",
                                linewidth       = 0,
                                shrinkA         = 0,
                                shrinkB         = 6.5,
                                alpha           = 1 # change this to barb arrow.
                                )
        # Rebuild black line, skip arrow head
        arrowprops4 = dict(arrowstyle    = "-|>, head_length=0, head_width=1e-37",
                                connectionstyle = "arc3, rad = 0",
                                facecolor       = "black",
                                edgecolor       = "black",
                                linewidth       = 0.3,
                                shrinkA         = 0,
                                shrinkB         = 5
                                )
        arrowprops = []
        arrowprops.append(arrowprops1)
        arrowprops.append(arrowprops2)
        arrowprops.append(arrowprops3)
        arrowprops.append(arrowprops4)
        bbox = dict(boxstyle            = "square, pad = -0.05",
                    facecolor           = "white",
                    edgecolor           = "white")
        for arrow_dict in plot.arrows:
            if arrow_dict["use_axes_scale"]:
                coordinate_system = "data"
            else:
                coordinate_system = "axes fraction"
            text            = arrow_dict["text"]
            arrow_tip       = arrow_dict["arrow_tip"]
            text_location   = arrow_dict["text_location"]
                            
            for arrowprop in arrowprops:
                graph.annotate( text,
                                xy          = arrow_tip,
                                xycoords    = coordinate_system,
                                xytext      = text_location,
                                textcoords  = coordinate_system,
                                arrowprops  = arrowprop,
                                bbox        = bbox,
                                size        = 7)

    def create_svg(self, file_basename=None):
        filepath = './plots/'
        try:
            os.makedirs(filepath)
        except OSError:
            pass
        FigureCanvasSVG(self.Figure)
        figdata = StringIO.StringIO()
        self.Figure.savefig(figdata, format="svg")
        output = figdata.getvalue().replace("Linear Helv Cond", "LinearHelvCond").replace("font-size:9.5px;font-style:normal", "font-size:9.5px;font-weight:bold").replace("font-size:8.14285714286px;font-style:bold", "font-size:8.14285714286px;font-weight:bold").replace("font-size:9.5px;font-style:bold", "font-size:9.5px;font-weight:bold")
        if file_basename is not None:
            file_basename = filepath + "{}.svg".format(file_basename).replace(" ", "_")
            output_file = open(file_basename, 'w')
            output_file.write(output)
            output_file.close()
        return output
    def create_pdf(self, file_basename):
        filepath = '.\\plots\\'
        try:
            os.makedirs(filepath)
        except OSError:
            pass
        file_basename = filepath + "{}.pdf".format(file_basename).replace(" ", "_")
        FigureCanvasPdf(self.Figure)
        self.Figure.savefig(file_basename, format="pdf")
    def kit_datasheet(self, file_basename = "datasheet_kit"):
        filepath = '{}\\'.format(file_basename)
        try:
            os.makedirs('.\\plots\\' + filepath)
        except OSError:
            pass
        print "\nKitting datasheet plots in .\\plots\\\n"
        for plot in self.plot_list:
            plot_name = "{}".format(plot.plot_name).replace(" ", "_")
            DummyPage = Page(rows_x_cols = (1, 1))
            DummyPage.add_plot(plot)
            DummyPage.create_svg(filepath + plot_name)
        self.create_pdf('\\{}\\PDFView'.format(file_basename))
        shutil.make_archive('.\\plots\\{}'.format(file_basename), 'zip', '.\\plots\\' + filepath)
        shutil.rmtree('.\\plots\\{}'.format(file_basename))
        print "\nWrote file: {}.zip\n".format(file_basename)
        
[docs]class Multipage_pdf(): '''Add one or more Pages to a Multipage_pdf to keep your page sizes manageable (such as 8.5x11). Multipage_pdf also support kit_datasheet().''' def __init__(self): self.page_list = [] def add_page(self, page): FigureCanvasPdf(page.Figure) self.page_list.append(page) def create_pdf(self, file_basename): filepath = '.\\plots\\' filename = filepath + "{}.pdf".format(file_basename).replace(" ", "_") try: os.makedirs(filepath) except OSError: pass self.pdf_file = PdfPages(filename) for page in self.page_list: self.pdf_file.savefig(page.Figure) self.pdf_file.close() def kit_datasheet(self, file_basename = "datasheet_kit"): filepath = 'datasheet_kit\\' try: os.makedirs('.\\plots\\' + filepath) except OSError: pass print "\nKitting datasheet plots in .\\plots\\\n" for page in self.page_list: for plot in range(len(page.plot_list)): plot_name = "{}".format(page.plot_list[plot].plot_name).replace(" ", "_") DummyPage = Page(rows_x_cols = (1, 1)) DummyPage.add_plot(page.plot_list[plot]) DummyPage.create_svg(filepath + plot_name) self.create_pdf("\\datasheet_kit\\PDFView") shutil.make_archive('.\\plots\\{}'.format(file_basename), 'zip', '.\\plots\\' + filepath) shutil.rmtree('.\\plots\\datasheet_kit') print "\nWrote file: {}.zip\n".format(file_basename)
[docs]class color_gen(object): '''Color yielding generator. Returns a new color each time an instance is called''' def __init__(self, rollover=True): '''set rollover False to cause an IndexError exception when colors are exhausted''' self.colors = MARCOM_COLORSfracRGB[:] self.reset() self.rollover = rollover def __call__(self): color = self.colors[self.index] self.index += 1 if self.rollover: self.index %= len(self.colors) return color
[docs] def reset(self): '''start color sequence over''' self.index = 0
[docs]def list_markers(): '''Valid linestyles are ['-' '--' '-.' ':' 'None' ' ' ''] Valid markers are [':' '.' ',' 'o' 'v' '^' '<' '>' '1' '2' '3' '4' '8' 's' 'p' '*' 'h' 'H' '+' 'x' 'D' 'd' '|' '_' TICKLEFT TICKRIGHT TICKUP TICKDOWN CARETLEFT CARETRIGHT CARETUP CARETDOWN]''' print print "Valid markers are: " + "[':' '.' ',' 'o' 'v' '^' '<' '>' '1' '2' '3' '4' '8' 's' 'p' '*' 'h' 'H' '+' 'x' 'D' 'd' '|' '_' TICKLEFT TICKRIGHT TICKUP TICKDOWN CARETLEFT CARETRIGHT CARETUP CARETDOWN]" print print "Valid linestyles are: " + "['-' '--' '-.' ':' 'None' ' ' '']" print
def smooth(data, window = 5): print "##########################################################" print "# #" print "# WARNING, LTC_plot.smooth() is deprecated!!! #" print "# Please create a lab_utils.ordered_pair() #" print "# and use its better supported smoothing feature. #" print "# #" print "##########################################################" # exit() # data = window * [data[0]] + list(data) + window * [data[-1]] # Extend data end points left/right # data = np.convolve(data, np.ones(int(window))/float(window), 'same') # to assist running average algorithm # data = data.ravel().tolist() # Convert array to list # data[0:window] = [] # Strip off left padding # data[len(data)-window:] = [] # Strip off right padding # return data def smooth_y_vector(data, window = 5): print "##########################################################" print "# #" print "# WARNING, LTC_plot.smooth_y_vector() is deprecated!!! #" print "# Please create a lab_utils.ordered_pair() #" print "# and use its better supported smoothing feature. #" print "# #" print "##########################################################" # xdata, ydata = zip(*data) # ydata = smooth(ydata, window) # return zip(xdata, ydata) def data_from_file(filename): x = [] y = [] input_file = open(filename, 'r') for line in input_file: x.append(float(line.split(",")[0])) y.append(float(line.split(",")[1])) input_file.close() return zip(x,y) def CMYK_to_fracRGB(CMYK): R = (1 - CMYK[0]) * (1 - CMYK[3]) G = (1 - CMYK[1]) * (1 - CMYK[3]) B = (1 - CMYK[2]) * (1 - CMYK[3]) return (R,G,B) def fracRGB_to_CMYK(RGB): C = 1 - RGB[0] M = 1 - RGB[1] Y = 1 - RGB[2] K = min(C,M,Y) if ( K == 1 ): # Really Black C = 0 M = 0 Y = 0 else: C = ( C - K ) / ( 1 - K ) M = ( M - K ) / ( 1 - K ) Y = ( Y - K ) / ( 1 - K ) return (C,M,Y,K) def webRGB_to_fracRGB(webRGB): R = int(webRGB[0:2],16) / 255.0 G = int(webRGB[2:4],16) / 255.0 B = int(webRGB[4:6],16) / 255.0 return (R,G,B) def webRGB_to_RGB(webRGB): R = int(webRGB[0:2],16) G = int(webRGB[2:4],16) B = int(webRGB[4:6],16) return (R,G,B) def RGB_to_webRGB(RGB): R = hex(int(RGB[0])) G = hex(int(RGB[1])) B = hex(int(RGB[2])) return (R,G,B) def fracRGB_to_RGB(fracRGB): R = int(round(fracRGB[0] * 255.0)) G = int(round(fracRGB[1] * 255.0)) B = int(round(fracRGB[2] * 255.0)) return (R,G,B) def RGB_to_fracRGB(RGB): R = RGB[0] / 255.0 G = RGB[1] / 255.0 B = RGB[2] / 255.0 return (R,G,B) def fracRGB_to_webRGB(fracRGB): return RGB_to_webRGB(fracRGB_to_RGB(fracRGB)) def _escape_attrib_reversal(s): # Don't know why SVG backend does this, need to reverse it to include html entities. # 12/26/2016 Bill had complained that he couldn't use & character which as true because the I had the next line uncommented. # This was here to accommodate html entities exactly such as include and & but in retrospect this was a bad idea. # It's easier to just declare the text unicode by preceding the text with a u such as u"Ω" rather than &#937;. # s = s.replace("&amp;", "&") # s = s.replace(u"&apos;", u"'") # s = s.replace(u"&quot;", u"\"") # s = s.replace(u"&lt;", u"<") # s = s.replace(u"&gt;", u">") return s # These are the Reay colors and they don't match the CMYK values using the simple transforms above. # They look like they were pulled out of the "GSM Complete Book 0315.pdf" with a color picker program like pain. # I found them to be with a few codes using that method. The spec doesn't have RGB values for the secondary colors # so I have Reay's colors here. # Bob also had the text color and black trace color as 231f20 which is kind of grey. REAY_COLORS = ["900027", "3a52a4", "36864b", "b57233", "000000", "da2031", "cdb33c", "537ebc", "cc7b4a", "40ad48"] MARCOM_COLORS = ["990033", "336699", "339933", "996633", "000000"] MARCOM_COLORSfracRGB = [webRGB_to_fracRGB(color) for color in MARCOM_COLORS] # The CMYK values are included here just for reference. They come from the document "LT Graph Color Palette and Styles.pdf" LT_RED_1 = webRGB_to_fracRGB(MARCOM_COLORS[0]) # CMYK_to_RGB([0.00, 1.00, 0.65, 0.47]) LT_BLUE_1 = webRGB_to_fracRGB(MARCOM_COLORS[1]) # CMYK_to_RGB([0.88, 0.77, 0.00, 0.00]) LT_GREEN_1 = webRGB_to_fracRGB(MARCOM_COLORS[2]) # CMYK_to_RGB([0.80, 0.25, 0.90, 0.10]) LT_COPPER_1 = webRGB_to_fracRGB(MARCOM_COLORS[3]) # CMYK_to_RGB([0.24, 0.58, 0.92, 0.09]) LT_BLACK = webRGB_to_fracRGB(MARCOM_COLORS[4]) # CMYK_to_RGB([0.00, 0.00, 0.00, 1.00]) LT_GREEN_2 = webRGB_to_fracRGB(REAY_COLORS[9]) # CMYK_to_RGB([0.75, 0.05, 1.00, 0.00]) LT_COPPER_2 = webRGB_to_fracRGB(REAY_COLORS[8]) # CMYK_to_RGB([0.20, 0.60, 0.80, 0.00]) LT_BLUE_2 = webRGB_to_fracRGB(REAY_COLORS[7]) # CMYK_to_RGB([0.70, 0.45, 0.01, 0.01])?? LT_YELLOW_2 = webRGB_to_fracRGB(REAY_COLORS[6]) # CMYK_to_RGB([0.22, 0.25, 0.92, 0.00]) LT_RED_2 = webRGB_to_fracRGB(REAY_COLORS[5]) # CMYK_to_RGB([0.10, 1.00, 0.90, 0.00]) LT_BLUE_2_40PCT = RGB_to_fracRGB([187, 204, 228]) # Use for histograms LT_RED_1_40PCT = RGB_to_fracRGB([228, 192, 187]) # Use for histograms LT_GRID = CMYK_to_fracRGB([0, 0, 0, 0.8]) # This comes out as #333333 whereas Bob Reay's value is #323232 LT_SCOPE_GRID = CMYK_to_fracRGB([0, 0, 0, 0.2]) # LT_TEXT = webRGB_to_fracRGB("000000") # This makes the most sense - Black # # These are special characters that can be used in labels, notes and arrows. # Bob Reay's version outputs web values which seems to import into Illustrator # but these unicodes work just fine as well. Some characters such as sigma will # an error upon importation because LinearHelvCond doesn't have the character # but I found in my trial copy that Illustrator will just find a place a substitute. # Web values will only work if _escape_attrib_reversal() is called because for some # reason svg_backend is replacing things like "&" with "&amp;". # S.L.M. # DELTA = u"\u0394" DEGC = u"\u00B0C" DEG = u"\u00B0" mu = u"\u00B5" # "&#181;" sigma = u"\u03C3" # "&#963;" SIGMA = u"\u03A3" minus = u"\u2212" # From the 4630A G02 SVG sent from Dan: # GRID width = 0.35 # border width = 0.6 # subscripts are size 6 # text color is not set and comes out 000000 # LT_ BORDER = 000000 # LT_GRID = 58595B # LT_RED_1 = 981B1E # LT_BLUE_1 = 3953A4 # LT_GREEN_1 = 37864B # LT_COPPER_1 = B57233 # LT_BLACK = 000000 # LT_RED_2 = DA2032 # LT_BLUE_2 = 547FBC # LT_YELLOW_2 = CFB43D #(MUSTARD) if __name__ == "__main__": import pydoc pydoc.writedoc('LTC_plot') os.startfile("LTC_plot.html") #print __doc__