Skip to content

Commit 328cf51

Browse files
check length of overrides; allow (0-255) format for rgb
1 parent fb9e6ff commit 328cf51

File tree

6 files changed

+104
-27
lines changed

6 files changed

+104
-27
lines changed

examples/marketcolor_overrides.ipynb

+41-6
Large diffs are not rendered by default.

src/mplfinance/_arg_validators.py

+8-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import matplotlib.dates as mdates
2-
import matplotlib.colors as mcolors
32
import pandas as pd
43
import numpy as np
54
import datetime
6-
from mplfinance._helpers import _list_of_dict
5+
from mplfinance._helpers import _list_of_dict, _mpf_is_color_like
76
import matplotlib as mpl
87
import warnings
98

@@ -364,19 +363,20 @@ def _is_marketcolor_object(obj):
364363
if not isinstance(obj,dict): return False
365364
market_colors_keys = ('candle','edge','wick','ohlc')
366365
return all([k in obj for k in market_colors_keys])
367-
368366

369-
def _mco_validator(value): # marketcolor overrides validator
370-
if isinstance(value,dict): # not yet supported, but maybe we will have other
371-
if 'colors' not in value: # kwargs related to mktcolor overrides (ex: `mco_faceonly`)
367+
368+
def _mco_validator(value): # marketcolor overrides validator
369+
if isinstance(value,dict): # not yet supported, but maybe we will have other
370+
if 'colors' not in value: # kwargs related to mktcolor overrides (ex: `mco_faceonly`)
372371
raise ValueError('`marketcolor_overrides` as dict must contain `colors` key.')
373372
colors = value['colors']
374373
else:
375374
colors = value
376375
if not isinstance(colors,(list,tuple,np.ndarray)):
377376
return False
378-
return all([(c is None or mcolors.is_color_like(c) or _is_marketcolor_object(c)) for c in colors])
379-
377+
return all([(c is None or
378+
_mpf_is_color_like(c) or
379+
_is_marketcolor_object(c) ) for c in colors])
380380

381381
def _check_for_external_axes(config):
382382
'''

src/mplfinance/_helpers.py

+38-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
"""
22
Some helper functions for mplfinance.
3+
NOTE: This is the lowest level in mplfinance:
4+
This file should have NO dependencies on
5+
any other mplfinance files.
36
"""
47

58
import datetime
6-
import matplotlib.dates as mdates
9+
import matplotlib.dates as mdates
10+
import matplotlib.colors as mcolors
711
import numpy as np
812

913
def _adjust_color_brightness(color,amount=0.5):
@@ -82,3 +86,36 @@ def roundTime(dt=None, roundTo=60):
8286
seconds = (dt.replace(tzinfo=None) - dt.min).seconds
8387
rounding = (seconds+roundTo/2) // roundTo * roundTo
8488
return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond)
89+
90+
91+
def _is_uint8_rgb_or_rgba(tup):
92+
""" Deterine if rgb or rgba is in (0-255) format:
93+
Matplotlib expects rgb (and rgba) tuples to contain
94+
three (or four) floats between 0.0 and 1.0
95+
96+
Some people express rgb as tuples of three integers
97+
between 0 and 255.
98+
(In rgba, alpha is still a float from 0.0 to 1.0)
99+
"""
100+
if isinstance(tup,str): return False
101+
if not np.iterable(tup): return False
102+
L = len(tup)
103+
if L < 3 or L > 4: return False
104+
if L == 4 and (tup[3] < 0 or tup[3] > 1): return False
105+
return not any([not isinstance(v,(int,np.unsignedinteger)) or v<0 or v>255 for v in tup[0:3]])
106+
107+
def _mpf_is_color_like(c):
108+
"""Determine if an object is a color.
109+
110+
Identical to `matplotlib.colors.is_color_like()`
111+
BUT ALSO considers int (0-255) rgb and rgba colors.
112+
"""
113+
if mcolors.is_color_like(c): return True
114+
return _is_uint8_rgb_or_rgba(c)
115+
116+
def _mpf_to_rgba(c, alpha=None):
117+
cnew = c
118+
if _is_uint8_rgb_or_rgba(c) and any(e>1 for e in c[:3]):
119+
cnew = tuple([e/255. for e in c[:3]])
120+
if len(c) == 4: cnew += c[3:]
121+
return mcolors.to_rgba(cnew, alpha)

src/mplfinance/_styles.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import matplotlib.pyplot as plt
2-
import matplotlib.colors as mcolors
32
import copy
43
import pprint
54
import os.path as path
65

76
from mplfinance._arg_validators import _process_kwargs, _validate_vkwargs_dict
87
from mplfinance._styledata import _styles
8+
from mplfinance._helpers import _mpf_is_color_like
99

1010

1111
def _get_mpfstyle(style):
@@ -70,7 +70,7 @@ def _valid_make_mpf_style_kwargs():
7070
'Validator' : lambda value: isinstance(value,dict) },
7171

7272
'mavcolors' : { 'Default' : None,
73-
'Validator' : lambda value: isinstance(value,list) }, # TODO: all([mcolors.is_color_like(v) for v in value.values()])
73+
'Validator' : lambda value: isinstance(value,list) }, # TODO: all([_mpf_is_color_like(v) for v in value.values()])
7474

7575
'facecolor' : { 'Default' : None,
7676
'Validator' : lambda value: isinstance(value,str) },
@@ -153,10 +153,10 @@ def make_mpf_style( **kwargs ):
153153

154154
def _valid_mpf_color_spec(value):
155155
'value must be a color, "inherit"-like, or dict of colors'
156-
return ( mcolors.is_color_like(value) or
156+
return ( _mpf_is_color_like(value) or
157157
( isinstance(value,str) and value == 'inherit'[0:len(value)]) or
158158
( isinstance(value,dict) and
159-
all([mcolors.is_color_like(v) for v in value.values()])
159+
all([_mpf_is_color_like(v) for v in value.values()])
160160
)
161161
)
162162

@@ -190,13 +190,13 @@ def _valid_mpf_style(value):
190190
def _valid_make_marketcolors_kwargs():
191191
vkwargs = {
192192
'up' : { 'Default' : None,
193-
'Validator' : lambda value: mcolors.is_color_like(value) },
193+
'Validator' : lambda value: _mpf_is_color_like(value) },
194194

195195
'down' : { 'Default' : None,
196-
'Validator' : lambda value: mcolors.is_color_like(value) },
196+
'Validator' : lambda value: _mpf_is_color_like(value) },
197197

198198
'hollow' : { 'Default' : None,
199-
'Validator' : lambda value: mcolors.is_color_like(value) },
199+
'Validator' : lambda value: _mpf_is_color_like(value) },
200200

201201
'alpha' : { 'Default' : None,
202202
'Validator' : lambda value: ( isinstance(value,float) and
@@ -208,17 +208,17 @@ def _valid_make_marketcolors_kwargs():
208208
'wick' : { 'Default' : None,
209209
'Validator' : lambda value: isinstance(value,dict)
210210
or isinstance(value,str)
211-
or mcolors.is_color_like(value) },
211+
or _mpf_is_color_like(value) },
212212

213213
'ohlc' : { 'Default' : None,
214214
'Validator' : lambda value: isinstance(value,dict)
215215
or isinstance(value,str)
216-
or mcolors.is_color_like(value) },
216+
or _mpf_is_color_like(value) },
217217

218218
'volume' : { 'Default' : None,
219219
'Validator' : lambda value: isinstance(value,dict)
220220
or isinstance(value,str)
221-
or mcolors.is_color_like(value) },
221+
or _mpf_is_color_like(value) },
222222

223223
'vcdopcod' : { 'Default' : False,
224224
'Validator' : lambda value: isinstance(value,bool) },
@@ -282,7 +282,7 @@ def _check_and_set_mktcolor(candle,**kwarg):
282282
else:
283283
colors = dict(up=value, down=value)
284284
for updown in ['up','down']:
285-
if not mcolors.is_color_like(colors[updown]):
285+
if not _mpf_is_color_like(colors[updown]):
286286
err = f'NOT is_color_like() for {key}[\'{updown}\'] = {colors[updown]}'
287287
raise ValueError(err)
288288
return colors

src/mplfinance/_utils.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from mplfinance._arg_validators import _alines_validator, _bypass_kwarg_validation
1818
from mplfinance._arg_validators import _xlim_validator, _is_datelike
1919
from mplfinance._styles import _get_mpfstyle
20+
from mplfinance._helpers import _mpf_to_rgba
2021

2122
from six.moves import zip
2223

@@ -603,7 +604,7 @@ def _construct_candlestick_collections(dates, opens, highs, lows, closes, market
603604
faceonly = config['mco_faceonly']
604605

605606
colors = _make_updown_color_list('candle',marketcolors,opens,closes,overrides)
606-
colors = [mcolors.to_rgba(c,alpha) for c in colors] # include alpha
607+
colors = [ _mpf_to_rgba(c,alpha) for c in colors ] # include alpha
607608
if faceonly: overrides = None
608609
edgecolor = _make_updown_color_list('edge',marketcolors,opens,closes,overrides)
609610
wickcolor = _make_updown_color_list('wick',marketcolors,opens,closes,overrides)

src/mplfinance/plotting.py

+4
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,10 @@ def plot( data, **kwargs ):
306306
err = "`addplot` is not supported for `type='" + config['type'] +"'`"
307307
raise ValueError(err)
308308

309+
if config['marketcolor_overrides'] is not None:
310+
if len(config['marketcolor_overrides']) != len(dates):
311+
raise ValueError('`marketcolor_overrides` must be same length as dataframe.')
312+
309313
external_axes_mode = _check_for_external_axes(config)
310314

311315
if external_axes_mode:

0 commit comments

Comments
 (0)