123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762 |
- #Copyright ReportLab Europe Ltd. 2000-2017
- #see license.txt for license details
- #history https://hg.reportlab.com/hg-public/reportlab/log/tip/src/reportlab/graphics/charts/linecharts.py
- __version__='3.3.0'
- __doc__="""This modules defines a very preliminary Line Chart example."""
- from reportlab.lib import colors
- from reportlab.lib.validators import isNumber, isNumberOrNone, isColor, isColorOrNone, isListOfStrings, \
- isListOfStringsOrNone, SequenceOf, isBoolean, NoneOr, \
- isListOfNumbersOrNone, isStringOrNone, OneOf, Percentage
- from reportlab.lib.attrmap import *
- from reportlab.lib.utils import flatten
- from reportlab.graphics.widgetbase import Widget, TypedPropertyCollection, PropHolder, tpcGetItem
- from reportlab.graphics.shapes import Line, Rect, Group, Drawing, Polygon, PolyLine
- from reportlab.graphics.widgets.signsandsymbols import NoEntry
- from reportlab.graphics.charts.axes import XCategoryAxis, YValueAxis
- from reportlab.graphics.charts.textlabels import Label
- from reportlab.graphics.widgets.markers import uSymbol2Symbol, isSymbol, makeMarker
- from reportlab.graphics.charts.areas import PlotArea
- from reportlab.graphics.charts.legends import _objStr
- from .utils import FillPairedData
- class LineChartProperties(PropHolder):
- _attrMap = AttrMap(
- strokeWidth = AttrMapValue(isNumber, desc='Width of a line.'),
- strokeColor = AttrMapValue(isColorOrNone, desc='Color of a line or border.'),
- fillColor = AttrMapValue(isColorOrNone, desc='fill color of a bar.'),
- strokeDashArray = AttrMapValue(isListOfNumbersOrNone, desc='Dash array of a line.'),
- symbol = AttrMapValue(NoneOr(isSymbol), desc='Widget placed at data points.',advancedUsage=1),
- shader = AttrMapValue(None, desc='Shader Class.',advancedUsage=1),
- filler = AttrMapValue(None, desc='Filler Class.',advancedUsage=1),
- name = AttrMapValue(isStringOrNone, desc='Name of the line.'),
- lineStyle = AttrMapValue(NoneOr(OneOf('line','joinedLine','bar')), desc="What kind of plot this line is",advancedUsage=1),
- barWidth = AttrMapValue(isNumberOrNone,desc="Percentage of available width to be used for a bar",advancedUsage=1),
- inFill = AttrMapValue(isBoolean, desc='If true flood fill to x axis',advancedUsage=1),
- )
- class AbstractLineChart(PlotArea):
- def makeSwatchSample(self,rowNo, x, y, width, height):
- baseStyle = self.lines
- styleIdx = rowNo % len(baseStyle)
- style = baseStyle[styleIdx]
- color = style.strokeColor
- yh2 = y+height/2.
- lineStyle = getattr(style,'lineStyle',None)
- if lineStyle=='bar':
- dash = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None))
- strokeWidth= getattr(style, 'strokeWidth', getattr(style, 'strokeWidth',None))
- L = Rect(x,y,width,height,strokeWidth=strokeWidth,strokeColor=color,strokeLineCap=0,strokeDashArray=dash,fillColor=getattr(style,'fillColor',color))
- elif self.joinedLines or lineStyle=='joinedLine':
- dash = getattr(style, 'strokeDashArray', getattr(baseStyle,'strokeDashArray',None))
- strokeWidth= getattr(style, 'strokeWidth', getattr(style, 'strokeWidth',None))
- L = Line(x,yh2,x+width,yh2,strokeColor=color,strokeLineCap=0)
- if strokeWidth: L.strokeWidth = strokeWidth
- if dash: L.strokeDashArray = dash
- else:
- L = None
- if hasattr(style, 'symbol'):
- S = style.symbol
- elif hasattr(baseStyle, 'symbol'):
- S = baseStyle.symbol
- else:
- S = None
- if S: S = uSymbol2Symbol(S,x+width/2.,yh2,color)
- if S and L:
- g = Group()
- g.add(L)
- g.add(S)
- return g
- return S or L
- def getSeriesName(self,i,default=None):
- '''return series name i or default'''
- return _objStr(getattr(self.lines[i],'name',default))
- class LineChart(AbstractLineChart):
- pass
- # This is conceptually similar to the VerticalBarChart.
- # Still it is better named HorizontalLineChart... :-/
- class HorizontalLineChart(LineChart):
- """Line chart with multiple lines.
- A line chart is assumed to have one category and one value axis.
- Despite its generic name this particular line chart class has
- a vertical value axis and a horizontal category one. It may
- evolve into individual horizontal and vertical variants (like
- with the existing bar charts).
- Available attributes are:
- x: x-position of lower-left chart origin
- y: y-position of lower-left chart origin
- width: chart width
- height: chart height
- useAbsolute: disables auto-scaling of chart elements (?)
- lineLabelNudge: distance of data labels to data points
- lineLabels: labels associated with data values
- lineLabelFormat: format string or callback function
- groupSpacing: space between categories
- joinedLines: enables drawing of lines
- strokeColor: color of chart lines (?)
- fillColor: color for chart background (?)
- lines: style list, used cyclically for data series
- valueAxis: value axis object
- categoryAxis: category axis object
- categoryNames: category names
- data: chart data, a list of data series of equal length
- """
- _attrMap = AttrMap(BASE=LineChart,
- useAbsolute = AttrMapValue(isNumber, desc='Flag to use absolute spacing values.',advancedUsage=1),
- lineLabelNudge = AttrMapValue(isNumber, desc='Distance between a data point and its label.',advancedUsage=1),
- lineLabels = AttrMapValue(None, desc='Handle to the list of data point labels.'),
- lineLabelFormat = AttrMapValue(None, desc='Formatting string or function used for data point labels.'),
- lineLabelArray = AttrMapValue(None, desc='explicit array of line label values, must match size of data if present.'),
- groupSpacing = AttrMapValue(isNumber, desc='? - Likely to disappear.'),
- joinedLines = AttrMapValue(isNumber, desc='Display data points joined with lines if true.'),
- lines = AttrMapValue(None, desc='Handle of the lines.'),
- valueAxis = AttrMapValue(None, desc='Handle of the value axis.'),
- categoryAxis = AttrMapValue(None, desc='Handle of the category axis.'),
- categoryNames = AttrMapValue(isListOfStringsOrNone, desc='List of category names.'),
- data = AttrMapValue(None, desc='Data to be plotted, list of (lists of) numbers.'),
- inFill = AttrMapValue(isBoolean, desc='Whether infilling should be done.',advancedUsage=1),
- reversePlotOrder = AttrMapValue(isBoolean, desc='If true reverse plot order.',advancedUsage=1),
- annotations = AttrMapValue(None, desc='list of callables, will be called with self, xscale, yscale.',advancedUsage=1),
- )
- def __init__(self):
- LineChart.__init__(self)
- # Allow for a bounding rectangle.
- self.strokeColor = None
- self.fillColor = None
- # Named so we have less recoding for the horizontal one :-)
- self.categoryAxis = XCategoryAxis()
- self.valueAxis = YValueAxis()
- # This defines two series of 3 points. Just an example.
- self.data = [(100,110,120,130),
- (70, 80, 80, 90)]
- self.categoryNames = ('North','South','East','West')
- self.lines = TypedPropertyCollection(LineChartProperties)
- self.lines.strokeWidth = 1
- self.lines[0].strokeColor = colors.red
- self.lines[1].strokeColor = colors.green
- self.lines[2].strokeColor = colors.blue
- # control spacing. if useAbsolute = 1 then
- # the next parameters are in points; otherwise
- # they are 'proportions' and are normalized to
- # fit the available space.
- self.useAbsolute = 0 #- not done yet
- self.groupSpacing = 1 #5
- self.lineLabels = TypedPropertyCollection(Label)
- self.lineLabelFormat = None
- self.lineLabelArray = None
- # This says whether the origin is above or below
- # the data point. +10 means put the origin ten points
- # above the data point if value > 0, or ten
- # points below if data value < 0. This is different
- # to label dx/dy which are not dependent on the
- # sign of the data.
- self.lineLabelNudge = 10
- # If you have multiple series, by default they butt
- # together.
- # New line chart attributes.
- self.joinedLines = 1 # Connect items with straight lines.
- self.inFill = 0
- self.reversePlotOrder = 0
- def demo(self):
- """Shows basic use of a line chart."""
- drawing = Drawing(200, 100)
- data = [
- (13, 5, 20, 22, 37, 45, 19, 4),
- (14, 10, 21, 28, 38, 46, 25, 5)
- ]
- lc = HorizontalLineChart()
- lc.x = 20
- lc.y = 10
- lc.height = 85
- lc.width = 170
- lc.data = data
- lc.lines.symbol = makeMarker('Circle')
- drawing.add(lc)
- return drawing
- def calcPositions(self):
- """Works out where they go.
- Sets an attribute _positions which is a list of
- lists of (x, y) matching the data.
- """
- self._seriesCount = len(self.data)
- self._rowLength = max(list(map(len,self.data)))
- if self.useAbsolute:
- # Dimensions are absolute.
- normFactor = 1.0
- else:
- # Dimensions are normalized to fit.
- normWidth = self.groupSpacing
- availWidth = self.categoryAxis.scale(0)[1]
- normFactor = availWidth / normWidth
- self._normFactor = normFactor
- self._yzero = yzero = self.valueAxis.scale(0)
- self._hngs = hngs = 0.5 * self.groupSpacing * normFactor
- pairs = set()
- P = [].append
- cscale = self.categoryAxis.scale
- vscale = self.valueAxis.scale
- data = self.data
- n = len(data)
- for rowNo,row in enumerate(data):
- if isinstance(row, FillPairedData):
- other = row.other
- if 0<=other<n:
- if other==rowNo:
- raise ValueError('data row %r may not be paired with itself' % rowNo)
- t = (rowNo,other)
- pairs.add((min(t),max(t)))
- else:
- raise ValueError('data row %r is paired with invalid data row %r' % (rowNo, other))
- line = [].append
- for colNo,datum in enumerate(row):
- if datum is not None:
- groupX, groupWidth = cscale(colNo)
- x = groupX + hngs
- y = yzero
- height = vscale(datum) - y
- line((x, y+height))
- P(line.__self__)
- P = P.__self__
- #if there are some paired lines we ensure only one is created
- for rowNo, other in pairs:
- P[rowNo] = FillPairedData(P[rowNo],other)
- self._pairInFills = len(pairs)
- self._positions = P
- def _innerDrawLabel(self, rowNo, colNo, x, y):
- "Draw a label for a given item in the list."
- labelFmt = self.lineLabelFormat
- labelValue = self.data[rowNo][colNo]
- if labelFmt is None:
- labelText = None
- elif type(labelFmt) is str:
- if labelFmt == 'values':
- try:
- labelText = self.lineLabelArray[rowNo][colNo]
- except:
- labelText = None
- else:
- labelText = labelFmt % labelValue
- elif hasattr(labelFmt,'__call__'):
- labelText = labelFmt(labelValue)
- else:
- raise ValueError("Unknown formatter type %s, expected string or function"%labelFmt)
- if labelText:
- label = self.lineLabels[(rowNo, colNo)]
- if not label.visible: return
- # Make sure labels are some distance off the data point.
- if y > 0:
- label.setOrigin(x, y + self.lineLabelNudge)
- else:
- label.setOrigin(x, y - self.lineLabelNudge)
- label.setText(labelText)
- else:
- label = None
- return label
- def drawLabel(self, G, rowNo, colNo, x, y):
- '''Draw a label for a given item in the list.
- G must have an add method'''
- G.add(self._innerDrawLabel(rowNo,colNo,x,y))
- def makeLines(self):
- g = Group()
- labelFmt = self.lineLabelFormat
- P = self._positions
- if self.reversePlotOrder: P.reverse()
- lines = self.lines
- styleCount = len(lines)
- _inFill = self.inFill
- if (_inFill or self._pairInFills or
- [rowNo for rowNo in range(len(P))
- if getattr(lines[rowNo%styleCount],'inFill',False)]
- ):
- inFillY = self.categoryAxis._y
- inFillX0 = self.valueAxis._x
- inFillX1 = inFillX0 + self.categoryAxis._length
- inFillG = getattr(self,'_inFillG',g)
- yzero = self._yzero
- # Iterate over data rows.
- for rowNo, row in enumerate(reversed(P) if self.reversePlotOrder else P):
- styleIdx = rowNo % styleCount
- rowStyle = lines[styleIdx]
- strokeColor = rowStyle.strokeColor
- fillColor = getattr(rowStyle,'fillColor',strokeColor)
- inFill = getattr(rowStyle,'inFill',_inFill)
- dash = getattr(rowStyle, 'strokeDashArray', None)
- lineStyle = getattr(rowStyle,'lineStyle',None)
- if hasattr(rowStyle, 'strokeWidth'):
- strokeWidth = rowStyle.strokeWidth
- elif hasattr(lines, 'strokeWidth'):
- strokeWidth = lines.strokeWidth
- else:
- strokeWidth = None
- # Iterate over data columns.
- if lineStyle=='bar':
- barWidth = getattr(rowStyle,'barWidth',Percentage(50))
- if isinstance(barWidth,Percentage):
- hbw = self._hngs*barWidth*0.01
- else:
- hbw = barWidth*0.5
- for x, y in row:
- g.add(Rect(x-hbw,min(y,yzero),2*hbw,abs(y-yzero),strokeWidth=strokeWidth,strokeColor=strokeColor,fillColor=fillColor))
- elif self.joinedLines or lineStyle=='joinedLine':
- points = flatten(row)
- if inFill or isinstance(row,FillPairedData):
- filler = getattr(rowStyle, 'filler', None)
- if isinstance(row,FillPairedData):
- fpoints = points + flatten(reversed(P[row.other]))
- else:
- fpoints = [inFillX0,inFillY] + points + [inFillX1,inFillY]
- if filler:
- filler.fill(self,inFillG,rowNo,fillColor,fpoints)
- else:
- inFillG.add(Polygon(fpoints,fillColor=fillColor,strokeColor=strokeColor if strokeColor==fillColor else None,strokeWidth=strokeWidth or 0.1))
- if not inFill or inFill==2 or strokeColor!=fillColor:
- line = PolyLine(points,strokeColor=strokeColor,strokeLineCap=0,strokeLineJoin=1)
- if strokeWidth:
- line.strokeWidth = strokeWidth
- if dash:
- line.strokeDashArray = dash
- g.add(line)
- if hasattr(rowStyle, 'symbol'):
- uSymbol = rowStyle.symbol
- elif hasattr(lines, 'symbol'):
- uSymbol = lines.symbol
- else:
- uSymbol = None
- if uSymbol:
- for colNo,(x,y) in enumerate(row):
- symbol = uSymbol2Symbol(tpcGetItem(uSymbol,colNo),x,y,rowStyle.strokeColor)
- if symbol: g.add(symbol)
- # Draw item labels.
- for colNo, (x, y) in enumerate(row):
- self.drawLabel(g, rowNo, colNo, x, y)
- return g
- def draw(self):
- "Draws itself."
- vA, cA = self.valueAxis, self.categoryAxis
- vA.setPosition(self.x, self.y, self.height)
- if vA: vA.joinAxis = cA
- if cA: cA.joinAxis = vA
- vA.configure(self.data)
- # If zero is in chart, put x axis there, otherwise
- # use bottom.
- xAxisCrossesAt = vA.scale(0)
- if ((xAxisCrossesAt > self.y + self.height) or (xAxisCrossesAt < self.y)):
- y = self.y
- else:
- y = xAxisCrossesAt
- cA.setPosition(self.x, y, self.width)
- cA.configure(self.data)
- self.calcPositions()
- g = Group()
- g.add(self.makeBackground())
- if self.inFill:
- self._inFillG = Group()
- g.add(self._inFillG)
- g.add(cA)
- g.add(vA)
- cAdgl = getattr(cA,'drawGridLast',False)
- vAdgl = getattr(vA,'drawGridLast',False)
- if not cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
- if not vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
- g.add(self.makeLines())
- if cAdgl: cA.makeGrid(g,parent=self,dim=vA.getGridDims)
- if vAdgl: vA.makeGrid(g,parent=self,dim=cA.getGridDims)
- for a in getattr(self,'annotations',()): g.add(a(self,cA.scale,vA.scale))
- return g
- def _fakeItemKey(a):
- '''t, z0, z1, x, y = a[:5]'''
- return (-a[1],a[3],a[0],-a[4])
- class _FakeGroup:
- def __init__(self):
- self._data = []
- def add(self,what):
- if what: self._data.append(what)
- def value(self):
- return self._data
- def sort(self):
- self._data.sort(key=_fakeItemKey)
- #for t in self._data: print t
- class HorizontalLineChart3D(HorizontalLineChart):
- _attrMap = AttrMap(BASE=HorizontalLineChart,
- theta_x = AttrMapValue(isNumber, desc='dx/dz'),
- theta_y = AttrMapValue(isNumber, desc='dy/dz'),
- zDepth = AttrMapValue(isNumber, desc='depth of an individual series'),
- zSpace = AttrMapValue(isNumber, desc='z gap around series'),
- )
- theta_x = .5
- theta_y = .5
- zDepth = 10
- zSpace = 3
- def calcPositions(self):
- HorizontalLineChart.calcPositions(self)
- nSeries = self._seriesCount
- zSpace = self.zSpace
- zDepth = self.zDepth
- if self.categoryAxis.style=='parallel_3d':
- _3d_depth = nSeries*zDepth+(nSeries+1)*zSpace
- else:
- _3d_depth = zDepth + 2*zSpace
- self._3d_dx = self.theta_x*_3d_depth
- self._3d_dy = self.theta_y*_3d_depth
- def _calc_z0(self,rowNo):
- zSpace = self.zSpace
- if self.categoryAxis.style=='parallel_3d':
- z0 = rowNo*(self.zDepth+zSpace)+zSpace
- else:
- z0 = zSpace
- return z0
- def _zadjust(self,x,y,z):
- return x+z*self.theta_x, y+z*self.theta_y
- def makeLines(self):
- labelFmt = self.lineLabelFormat
- P = list(range(len(self._positions)))
- if self.reversePlotOrder: P.reverse()
- inFill = self.inFill
- assert not inFill, "inFill not supported for 3d yet"
- #if inFill:
- #inFillY = self.categoryAxis._y
- #inFillX0 = self.valueAxis._x
- #inFillX1 = inFillX0 + self.categoryAxis._length
- #inFillG = getattr(self,'_inFillG',g)
- zDepth = self.zDepth
- _zadjust = self._zadjust
- theta_x = self.theta_x
- theta_y = self.theta_y
- F = _FakeGroup()
- from reportlab.graphics.charts.utils3d import _make_3d_line_info
- tileWidth = getattr(self,'_3d_tilewidth',None)
- if not tileWidth and self.categoryAxis.style!='parallel_3d': tileWidth = 1
- # Iterate over data rows.
- for rowNo in P:
- row = self._positions[rowNo]
- n = len(row)
- styleCount = len(self.lines)
- styleIdx = rowNo % styleCount
- rowStyle = self.lines[styleIdx]
- rowColor = rowStyle.strokeColor
- dash = getattr(rowStyle, 'strokeDashArray', None)
- z0 = self._calc_z0(rowNo)
- z1 = z0 + zDepth
- if hasattr(self.lines[styleIdx], 'strokeWidth'):
- strokeWidth = self.lines[styleIdx].strokeWidth
- elif hasattr(self.lines, 'strokeWidth'):
- strokeWidth = self.lines.strokeWidth
- else:
- strokeWidth = None
- # Iterate over data columns.
- if self.joinedLines:
- if n:
- x0, y0 = row[0]
- for colNo in range(1,n):
- x1, y1 = row[colNo]
- _make_3d_line_info( F, x0, x1, y0, y1, z0, z1,
- theta_x, theta_y,
- rowColor, fillColorShaded=None, tileWidth=tileWidth,
- strokeColor=None, strokeWidth=None, strokeDashArray=None,
- shading=0.1)
- x0, y0 = x1, y1
- if hasattr(self.lines[styleIdx], 'symbol'):
- uSymbol = self.lines[styleIdx].symbol
- elif hasattr(self.lines, 'symbol'):
- uSymbol = self.lines.symbol
- else:
- uSymbol = None
- if uSymbol:
- for colNo in range(n):
- x1, y1 = row[colNo]
- x1, y1 = _zadjust(x1,y1,z0)
- symbol = uSymbol2Symbol(uSymbol,x1,y1,rowColor)
- if symbol: F.add((2,z0,z0,x1,y1,symbol))
- # Draw item labels.
- for colNo in range(n):
- x1, y1 = row[colNo]
- x1, y1 = _zadjust(x1,y1,z0)
- L = self._innerDrawLabel(rowNo, colNo, x1, y1)
- if L: F.add((2,z0,z0,x1,y1,L))
- F.sort()
- g = Group()
- for v in F.value(): g.add(v[-1])
- return g
- class VerticalLineChart(LineChart):
- pass
- def sample1():
- drawing = Drawing(400, 200)
- data = [
- (13, 5, 20, 22, 37, 45, 19, 4),
- (5, 20, 46, 38, 23, 21, 6, 14)
- ]
- lc = HorizontalLineChart()
- lc.x = 50
- lc.y = 50
- lc.height = 125
- lc.width = 300
- lc.data = data
- lc.joinedLines = 1
- lc.lines.symbol = makeMarker('FilledDiamond')
- lc.lineLabelFormat = '%2.0f'
- catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
- lc.categoryAxis.categoryNames = catNames
- lc.categoryAxis.labels.boxAnchor = 'n'
- lc.valueAxis.valueMin = 0
- lc.valueAxis.valueMax = 60
- lc.valueAxis.valueStep = 15
- drawing.add(lc)
- return drawing
- class SampleHorizontalLineChart(HorizontalLineChart):
- "Sample class overwriting one method to draw additional horizontal lines."
- def demo(self):
- """Shows basic use of a line chart."""
- drawing = Drawing(200, 100)
- data = [
- (13, 5, 20, 22, 37, 45, 19, 4),
- (14, 10, 21, 28, 38, 46, 25, 5)
- ]
- lc = SampleHorizontalLineChart()
- lc.x = 20
- lc.y = 10
- lc.height = 85
- lc.width = 170
- lc.data = data
- lc.strokeColor = colors.white
- lc.fillColor = colors.HexColor(0xCCCCCC)
- drawing.add(lc)
- return drawing
- def makeBackground(self):
- g = Group()
- g.add(HorizontalLineChart.makeBackground(self))
- valAxis = self.valueAxis
- valTickPositions = valAxis._tickValues
- for y in valTickPositions:
- y = valAxis.scale(y)
- g.add(Line(self.x, y, self.x+self.width, y,
- strokeColor = self.strokeColor))
- return g
- def sample1a():
- drawing = Drawing(400, 200)
- data = [
- (13, 5, 20, 22, 37, 45, 19, 4),
- (5, 20, 46, 38, 23, 21, 6, 14)
- ]
- lc = SampleHorizontalLineChart()
- lc.x = 50
- lc.y = 50
- lc.height = 125
- lc.width = 300
- lc.data = data
- lc.joinedLines = 1
- lc.strokeColor = colors.white
- lc.fillColor = colors.HexColor(0xCCCCCC)
- lc.lines.symbol = makeMarker('FilledDiamond')
- lc.lineLabelFormat = '%2.0f'
- catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
- lc.categoryAxis.categoryNames = catNames
- lc.categoryAxis.labels.boxAnchor = 'n'
- lc.valueAxis.valueMin = 0
- lc.valueAxis.valueMax = 60
- lc.valueAxis.valueStep = 15
- drawing.add(lc)
- return drawing
- def sample2():
- drawing = Drawing(400, 200)
- data = [
- (13, 5, 20, 22, 37, 45, 19, 4),
- (5, 20, 46, 38, 23, 21, 6, 14)
- ]
- lc = HorizontalLineChart()
- lc.x = 50
- lc.y = 50
- lc.height = 125
- lc.width = 300
- lc.data = data
- lc.joinedLines = 1
- lc.lines.symbol = makeMarker('Smiley')
- lc.lineLabelFormat = '%2.0f'
- lc.strokeColor = colors.black
- lc.fillColor = colors.lightblue
- catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
- lc.categoryAxis.categoryNames = catNames
- lc.categoryAxis.labels.boxAnchor = 'n'
- lc.valueAxis.valueMin = 0
- lc.valueAxis.valueMax = 60
- lc.valueAxis.valueStep = 15
- drawing.add(lc)
- return drawing
- def sample3():
- drawing = Drawing(400, 200)
- data = [
- (13, 5, 20, 22, 37, 45, 19, 4),
- (5, 20, 46, 38, 23, 21, 6, 14)
- ]
- lc = HorizontalLineChart()
- lc.x = 50
- lc.y = 50
- lc.height = 125
- lc.width = 300
- lc.data = data
- lc.joinedLines = 1
- lc.lineLabelFormat = '%2.0f'
- lc.strokeColor = colors.black
- lc.lines[0].symbol = makeMarker('Smiley')
- lc.lines[1].symbol = NoEntry
- lc.lines[0].strokeWidth = 2
- lc.lines[1].strokeWidth = 4
- catNames = 'Jan Feb Mar Apr May Jun Jul Aug'.split(' ')
- lc.categoryAxis.categoryNames = catNames
- lc.categoryAxis.labels.boxAnchor = 'n'
- lc.valueAxis.valueMin = 0
- lc.valueAxis.valueMax = 60
- lc.valueAxis.valueStep = 15
- drawing.add(lc)
- return drawing
- def sampleCandleStick():
- from reportlab.graphics.widgetbase import CandleSticks
- d = Drawing(400, 200)
- chart = HorizontalLineChart()
- d.add(chart)
- chart.y = 20
- boxMid = (100, 110, 120, 130)
- hi = [m+10 for m in boxMid]
- lo = [m-10 for m in boxMid]
- boxHi = [m+6 for m in boxMid]
- boxLo = [m-4 for m in boxMid]
- boxFillColor = colors.pink
- boxWidth = 20
- crossWidth = 10
- candleStrokeWidth = 0.5
- candleStrokeColor = colors.black
- chart.valueAxis.avoidBoundSpace = 5
- chart.valueAxis.valueMin = min(min(boxMid),min(hi),min(lo),min(boxLo),min(boxHi))
- chart.valueAxis.valueMax = max(max(boxMid),max(hi),max(lo),max(boxLo),max(boxHi))
- lines = chart.lines
- lines[0].strokeColor = None
- I = range(len(boxMid))
- chart.data = [boxMid]
- lines[0].symbol = candles = CandleSticks(chart=chart, boxFillColor=boxFillColor, boxWidth=boxWidth, crossWidth=crossWidth, strokeWidth=candleStrokeWidth, strokeColor=candleStrokeColor)
- for i in I: candles[i].setProperties(dict(position=i,boxMid=boxMid[i],crossLo=lo[i],crossHi=hi[i],boxLo=boxLo[i],boxHi=boxHi[i]))
- return d
|