import ROOT
class _StyleContainer(object):
"""
Base class for grouping together an input style with ROOT and matplotlib
styles.
"""
def __init__(self, value, function):
self._input = value
self._root = function(value, 'root')
self._mpl = function(value, 'mpl')
def __call__(self, output_type=None):
if not output_type:
output_type = 'input'
return getattr(self, '_' + output_type)
def __repr__(self):
return str(self._input)
##############################
#### Markers #################
markerstyles_root2mpl = {
1: '.',
2: '+',
3: '*',
4: 'o',
5: 'x',
20: 'o',
21: 's',
22: '^',
23: 'v',
24: 'o',
25: 's',
26: '^',
27: 'd',
28: '+',
29: '*',
30: '*',
31: '*',
32: 'v',
33: 'D',
34: '+',
}
for i in range(6, 20):
markerstyles_root2mpl[i] = '.'
markerstyles_mpl2root = {
'.': 1,
',': 1,
'o': 4,
'v': 23,
'^': 22,
'<': 23,
'>': 22,
'1': 23,
'2': 22,
'3': 23,
'4': 22,
's': 25,
'p': 25,
'*': 3,
'h': 25,
'H': 25,
'+': 2,
'x': 5,
'D': 33,
'd': 27,
'|': 2,
'_': 2,
0: 1, # TICKLEFT
1: 1, # TICKRIGHT
2: 1, # TICKUP
3: 1, # TICKDOWN
4: 1, # CARETLEFT
5: 1, # CARETRIGHT
6: 1, # CARETUP
7: 1, # CARETDOWN
'None': '.',
' ': '.',
'': '.',
}
markerstyles_text2root = {
"smalldot": 6,
"mediumdot": 7,
"largedot": 8,
"dot": 9,
"circle": 20,
"square": 21,
"triangle": 22,
"triangleup": 22,
"triangledown": 23,
"opencircle": 24,
"opensquare": 25,
"opentriangle": 26,
"opendiamond": 27,
"diamond": 33,
"opencross": 28,
"cross": 34,
"openstar": 29,
"fullstar": 30,
"star": 29,
}
[docs]def convert_markerstyle(inputstyle, mode, inputmode=None):
"""
Convert *inputstyle* to ROOT or matplotlib format.
Output format is determined by *mode* ('root' or 'mpl'). The *inputstyle*
may be a ROOT marker style, a matplotlib marker style, or a description
such as 'star' or 'square'.
"""
mode = mode.lower()
if mode != 'mpl' and mode != 'root':
raise ValueError("%s is not an understood value for mode" % mode)
if inputmode is None:
if inputstyle in markerstyles_root2mpl:
inputmode = 'root'
elif inputstyle in markerstyles_mpl2root or '$' in str(inputstyle):
inputmode = 'mpl'
elif inputstyle in markerstyles_text2root:
inputmode = 'root'
inputstyle = markerstyles_text2root[inputstyle]
else:
raise ValueError("%s is not a recognized marker style!"
% inputstyle)
if inputmode == 'root':
if inputstyle not in markerstyles_root2mpl:
raise ValueError("%s is not a recognized ROOT marker style!"
% inputstyle)
if mode == 'root':
return inputstyle
return markerstyles_root2mpl[inputstyle]
else:
if '$' in str(inputstyle):
if mode == 'root':
return 1
else:
return inputstyle
if inputstyle not in markerstyles_mpl2root:
raise ValueError("%s is not a recognized matplotlib marker style!"
% inputstyle)
if mode == 'mpl':
return inputstyle
return markerstyles_mpl2root[inputstyle]
[docs]class MarkerStyle(_StyleContainer):
"""
Container for grouping together ROOT and matplotlib marker styles.
The *style* argument to the constructor may be a ROOT marker style,
a matplotlib marker style, or one of the following descriptions:
"""
__doc__ = __doc__[:__doc__.rfind('\n') + 1]
__doc__ += '\n'.join([" '%s'" % x
for x in markerstyles_text2root])
del x
__doc__ += """
Examples:
>>> style = MarkerStyle('opentriangle')
>>> style('root')
26
>>> style('mpl')
'^'
"""
def __init__(self, style):
_StyleContainer.__init__(self, style, convert_markerstyle)
##############################
#### Lines ###################
linestyles_root2mpl = {
1: 'solid',
2: 'dashed',
3: 'dotted',
4: 'dashdot',
5: 'dashdot',
6: 'dashdot',
7: 'dashed',
8: 'dashdot',
9: 'dashed',
10: 'dashdot',
}
linestyles_mpl2root = {
'solid': 1,
'dashed': 2,
'dotted': 3,
'dashdot': 4,
}
linestyles_text2root = {
'solid': 1,
'dashed': 2,
'dotted': 3,
'dashdot': 4,
'longdashdot': 5,
'longdashdotdotdot': 6,
'longdash': 7,
'longdashdotdot': 8,
'verylongdash': 9,
'verylongdashdot': 10
}
[docs]def convert_linestyle(inputstyle, mode, inputmode=None):
"""
Convert *inputstyle* to ROOT or matplotlib format.
Output format is determined by *mode* ('root' or 'mpl'). The *inputstyle*
may be a ROOT line style, a matplotlib line style, or a description
such as 'solid' or 'dotted'.
"""
mode = mode.lower()
if mode != 'mpl' and mode != 'root':
raise ValueError("%s is not an understood value for mode" % mode)
try:
inputstyle = int(inputstyle)
if inputstyle < 1:
inputstyle = 1
except ValueError:
pass
if inputmode is None:
if inputstyle in linestyles_root2mpl:
inputmode = 'root'
elif inputstyle in linestyles_mpl2root:
inputmode = 'mpl'
elif inputstyle in linestyles_text2root:
inputmode = 'root'
inputstyle = linestyles_text2root[inputstyle]
else:
raise ValueError("%s is not a recognized line style!"
% inputstyle)
if inputmode == 'root':
if inputstyle not in linestyles_root2mpl:
raise ValueError("%s is not a recognized ROOT line style!"
% inputstyle)
if mode == 'root':
return inputstyle
return linestyles_root2mpl[inputstyle]
else:
if inputstyle not in linestyles_mpl2root:
raise ValueError("%s is not a recognized matplotlib line style!"
% inputstyle)
if mode == 'mpl':
return inputstyle
return linestyles_mpl2root[inputstyle]
[docs]class LineStyle(_StyleContainer):
"""
Container for grouping together ROOT and matplotlib line styles.
The *style* argument to the constructor may be a ROOT line style,
a matplotlib line style, or one of the following descriptions:
"""
__doc__ = __doc__[:__doc__.rfind('\n') + 1]
__doc__ += '\n'.join([" '%s'" % x
for x in linestyles_text2root])
del x
__doc__ += """
Examples:
>>> style = LineStyle('verylongdashdot')
>>> style('root')
10
>>> style('mpl')
'dashdot'
"""
def __init__(self, style):
_StyleContainer.__init__(self, style, convert_linestyle)
##############################
#### Fills ###################
fillstyles_root2mpl = {
0: None,
1001: None,
3003: '.',
3004: '/',
3005: '\\',
3006: '|',
3007: '-',
3011: '*',
3012: 'o',
3013: 'x',
3019: 'O',
}
fillstyles_mpl2root = {}
for key, value in fillstyles_root2mpl.items():
fillstyles_mpl2root[value] = key
fillstyles_text2root = {
'hollow': 0,
'solid': 1001,
}
[docs]def convert_fillstyle(inputstyle, mode, inputmode=None):
"""
Convert *inputstyle* to ROOT or matplotlib format.
Output format is determined by *mode* ('root' or 'mpl'). The *inputstyle*
may be a ROOT fill style, a matplotlib hatch style, 'hollow', or 'solid'.
"""
mode = mode.lower()
if mode != 'mpl' and mode != 'root':
raise ValueError("'%s' is not a valid mode" % mode)
if inputmode is None:
try:
# inputstyle is a ROOT linestyle
inputstyle = int(inputstyle)
inputmode = 'root'
except (TypeError, ValueError):
if inputstyle is None:
inputmode = 'mpl'
elif inputstyle in fillstyles_text2root:
inputmode = 'root'
inputstyle = fillstyles_text2root[inputstyle]
elif inputstyle[0] in fillstyles_mpl2root:
inputmode = 'mpl'
else:
raise ValueError("'%s' is not a valid fill style!"
% inputstyle)
if inputmode == 'root':
if mode == 'root':
return inputstyle
if inputstyle in fillstyles_root2mpl:
return fillstyles_root2mpl[inputstyle]
raise ValueError("'%s' is not a valid fill style!" % inputstyle)
else:
if inputstyle is not None and inputstyle[0] not in fillstyles_mpl2root:
raise ValueError("'%s' is not a valid matplotlib fill style!"
% inputstyle)
if mode == 'mpl':
return inputstyle
if inputstyle is None:
return fillstyles_mpl2root[inputstyle]
return fillstyles_mpl2root[inputstyle[0]]
[docs]class FillStyle(_StyleContainer):
"""
Container for grouping together ROOT and matplotlib fill styles.
The *style* argument to the constructor may be a ROOT fill style,
a matplotlib fill style, or one of the following descriptions:
"""
__doc__ = __doc__[:__doc__.rfind('\n') + 1]
__doc__ += '\n'.join([" '%s'" % x
for x in fillstyles_text2root])
del x
__doc__ += """
For an input value of 'solid', the matplotlib hatch value will be set to None,
which is the same value as for 'hollow'. The root2matplotlib functions will
all check the ROOT value to see whether to make the fill solid or hollow.
Examples:
>>> style = FillStyle('hollow')
>>> style('root')
0
>>> print style('mpl')
None
"""
def __init__(self, style):
_StyleContainer.__init__(self, style, convert_fillstyle)
##############################
#### Colors ##################
_cnames = {
'r' : '#FF0000', #@IgnorePep8
'g' : '#00FF00',
'b' : '#0000FF',
'c' : '#00BFBF',
'm' : '#BF00BF',
'y' : '#BFBF00',
'k' : '#000000',
'w' : '#FFFFFF',
'aliceblue' : '#F0F8FF',
'antiquewhite' : '#FAEBD7',
'aqua' : '#00FFFF',
'aquamarine' : '#7FFFD4',
'azure' : '#F0FFFF',
'beige' : '#F5F5DC',
'bisque' : '#FFE4C4',
'black' : '#000000',
'blanchedalmond' : '#FFEBCD',
'blue' : '#0000FF',
'blueviolet' : '#8A2BE2',
'brown' : '#A52A2A',
'burlywood' : '#DEB887',
'cadetblue' : '#5F9EA0',
'chartreuse' : '#7FFF00',
'chocolate' : '#D2691E',
'coral' : '#FF7F50',
'cornflowerblue' : '#6495ED',
'cornsilk' : '#FFF8DC',
'crimson' : '#DC143C',
'cyan' : '#00FFFF',
'darkblue' : '#00008B',
'darkcyan' : '#008B8B',
'darkgoldenrod' : '#B8860B',
'darkgray' : '#A9A9A9',
'darkgreen' : '#006400',
'darkkhaki' : '#BDB76B',
'darkmagenta' : '#8B008B',
'darkolivegreen' : '#556B2F',
'darkorange' : '#FF8C00',
'darkorchid' : '#9932CC',
'darkred' : '#8B0000',
'darksalmon' : '#E9967A',
'darkseagreen' : '#8FBC8F',
'darkslateblue' : '#483D8B',
'darkslategray' : '#2F4F4F',
'darkturquoise' : '#00CED1',
'darkviolet' : '#9400D3',
'deeppink' : '#FF1493',
'deepskyblue' : '#00BFFF',
'dimgray' : '#696969',
'dodgerblue' : '#1E90FF',
'firebrick' : '#B22222',
'floralwhite' : '#FFFAF0',
'forestgreen' : '#228B22',
'fuchsia' : '#FF00FF',
'gainsboro' : '#DCDCDC',
'ghostwhite' : '#F8F8FF',
'gold' : '#FFD700',
'goldenrod' : '#DAA520',
'gray' : '#808080',
'green' : '#008000',
'greenyellow' : '#ADFF2F',
'honeydew' : '#F0FFF0',
'hotpink' : '#FF69B4',
'indianred' : '#CD5C5C',
'indigo' : '#4B0082',
'ivory' : '#FFFFF0',
'khaki' : '#F0E68C',
'lavender' : '#E6E6FA',
'lavenderblush' : '#FFF0F5',
'lawngreen' : '#7CFC00',
'lemonchiffon' : '#FFFACD',
'lightblue' : '#ADD8E6',
'lightcoral' : '#F08080',
'lightcyan' : '#E0FFFF',
'lightgoldenrodyellow' : '#FAFAD2',
'lightgreen' : '#90EE90',
'lightgrey' : '#D3D3D3',
'lightpink' : '#FFB6C1',
'lightsalmon' : '#FFA07A',
'lightseagreen' : '#20B2AA',
'lightskyblue' : '#87CEFA',
'lightslategray' : '#778899',
'lightsteelblue' : '#B0C4DE',
'lightyellow' : '#FFFFE0',
'lime' : '#00FF00',
'limegreen' : '#32CD32',
'linen' : '#FAF0E6',
'magenta' : '#FF00FF',
'maroon' : '#800000',
'mediumaquamarine' : '#66CDAA',
'mediumblue' : '#0000CD',
'mediumorchid' : '#BA55D3',
'mediumpurple' : '#9370DB',
'mediumseagreen' : '#3CB371',
'mediumslateblue' : '#7B68EE',
'mediumspringgreen' : '#00FA9A',
'mediumturquoise' : '#48D1CC',
'mediumvioletred' : '#C71585',
'midnightblue' : '#191970',
'mintcream' : '#F5FFFA',
'mistyrose' : '#FFE4E1',
'moccasin' : '#FFE4B5',
'navajowhite' : '#FFDEAD',
'navy' : '#000080',
'oldlace' : '#FDF5E6',
'olive' : '#808000',
'olivedrab' : '#6B8E23',
'orange' : '#FFA500',
'orangered' : '#FF4500',
'orchid' : '#DA70D6',
'palegoldenrod' : '#EEE8AA',
'palegreen' : '#98FB98',
'palevioletred' : '#AFEEEE',
'papayawhip' : '#FFEFD5',
'peachpuff' : '#FFDAB9',
'peru' : '#CD853F',
'pink' : '#FFC0CB',
'plum' : '#DDA0DD',
'powderblue' : '#B0E0E6',
'purple' : '#800080',
'red' : '#FF0000',
'rosybrown' : '#BC8F8F',
'royalblue' : '#4169E1',
'saddlebrown' : '#8B4513',
'salmon' : '#FA8072',
'sandybrown' : '#FAA460',
'seagreen' : '#2E8B57',
'seashell' : '#FFF5EE',
'sienna' : '#A0522D',
'silver' : '#C0C0C0',
'skyblue' : '#87CEEB',
'slateblue' : '#6A5ACD',
'slategray' : '#708090',
'snow' : '#FFFAFA',
'springgreen' : '#00FF7F',
'steelblue' : '#4682B4',
'tan' : '#D2B48C',
'teal' : '#008080',
'thistle' : '#D8BFD8',
'tomato' : '#FF6347',
'turquoise' : '#40E0D0',
'violet' : '#EE82EE',
'wheat' : '#F5DEB3',
'white' : '#FFFFFF',
'whitesmoke' : '#F5F5F5',
'yellow' : '#FFFF00',
'yellowgreen' : '#9ACD32',
}
[docs]def convert_color(color, mode):
"""
Convert *color* to a TColor if *mode='root'* or to (r,g,b) if 'mpl'.
The *color* argument can be a ROOT TColor or color index, an *RGB*
or *RGBA* sequence or a string in any of several forms:
1) a letter from the set 'rgbcmykw'
2) a hex color string, like '#00FFFF'
3) a standard name, like 'aqua'
4) a float, like '0.4', indicating gray on a 0-1 scale
if *arg* is *RGBA*, the transparency value will be ignored.
"""
mode = mode.lower()
if mode not in ['mpl', 'root']:
raise ValueError("%s is not an understood value for mode" % mode)
try:
# color is an r,g,b tuple
color = tuple([float(x) for x in color[:3]])
if max(color) > 1.:
color = tuple([x / 255. for x in color])
if mode == 'root':
return ROOT.TColor.GetColor(*color)
return color
except (ValueError, TypeError):
pass
if isinstance(color, basestring):
if color in _cnames:
# color is a matplotlib letter or an html color name
color = _cnames[color]
if color[0] == '#':
# color is a hex value
color = color.lstrip('#')
lv = len(color)
color = tuple(int(color[i:i + lv / 3], 16) for i in range(0, lv, lv / 3))
if lv == 3:
color = tuple(x * 16 + x for x in color)
return convert_color(color, mode)
# color is a shade of gray, i.e. '0.3'
return convert_color((color, color, color), mode)
try:
# color is a TColor
color = ROOT.TColor(color)
color = color.GetRed(), color.GetGreen(), color.GetBlue()
return convert_color(color, mode)
except (TypeError, ReferenceError):
pass
try:
# color is a ROOT color index
if color < 1:
color = 1
color = ROOT.gROOT.GetColor(color)
# Protect against the case a histogram with a custom color
# is saved in a ROOT file
if not color:
# Just return black
color = ROOT.gROOT.GetColor(1)
color = color.GetRed(), color.GetGreen(), color.GetBlue()
return convert_color(color, mode)
except (TypeError, ReferenceError):
pass
raise ValueError("'%s' is not a valid color" % str(color))
[docs]class Color(_StyleContainer):
"""
Container for grouping together ROOT and matplotlib colors.
The *color* argument to the constructor can be a ROOT TColor or color index.
If matplotlib is available, it can also accept an *RGB* or *RGBA* sequence,
or a string in any of several forms:
1) a letter from the set 'rgbcmykw'
2) a hex color string, like '#00FFFF'
3) a standard name, like 'aqua'
4) a float, like '0.4', indicating gray on a 0-1 scale
if *color* is *RGBA*, the *A* will simply be discarded.
Examples:
>>> color = Color(2)
>>> color()
2
>>> color('mpl')
(1.0, 0.0, 0.0)
>>> color = Color('blue')
>>> color('root')
4
>>> color('mpl')
(0.0, 0.0, 1.0)
>>> color = Color('0.25')
>>> color('mpl')
(0.25, 0.25, 0.25)
>>> color('root')
924
"""
def __init__(self, color):
_StyleContainer.__init__(self, color, convert_color)
if __name__ == "__main__":
import doctest
doctest.testmod()