@@ -277,6 +277,18 @@ def sort_keys(key):
277
277
278
278
279
279
def _key_parts (key ):
280
+ """
281
+ Split a key containing undescores into all its parts.
282
+
283
+ This function is aware of attributes that have underscores in their
284
+ name (e.g. ``scatter.error_x``) and does not split them incorrectly.
285
+
286
+ Also, the function always returns a list, even if there is only one item
287
+ in that list (e.g. `_key_parts("marker")` would return `["marker"]`)
288
+
289
+ :param (str|unicode) key: the attribute name
290
+ :return: (list[str|unicode]): a list with all the parts of the attribute
291
+ """
280
292
if "_" in key :
281
293
match = _underscore_attr_regex .search (key )
282
294
if match is not None :
@@ -313,6 +325,45 @@ def _key_parts(key):
313
325
314
326
315
327
def _underscore_magic (parts , val , obj = None , skip_dict_check = False ):
328
+ """
329
+ Set a potentially "deep" attribute of `obj` specified by a list of parent
330
+ keys (`parts`) to `val`.
331
+
332
+ :param (list[(str|unicode)] or str|unicode) parts: The path to the
333
+ attribute to be set on obj. If the argument is a string, then it will
334
+ first be passed to `_key_parts(key)` to construct the path and then
335
+ this function will be called again
336
+ :param val: The value the attribute should have
337
+ :param (dict_like) obj: A dict_like object that should have the attribute
338
+ set. If nothing is given, then an empty dictionary is created. If
339
+ a subtype of `plotly.graph_obsj.PlotlyDict` is passed, then the
340
+ setting of the attribute (and creation of parent nodes) will be
341
+ validated
342
+ :param (bool) skip_dict_check: Optional, default is False. If True and val
343
+ is a dict, then this funciton will ensure that all parent nodes are
344
+ created in `obj`.
345
+ :returns (dict_like) obj: an updated version of the `obj` argument (or
346
+ a newly created dict if `obj` was not passed).
347
+
348
+
349
+ Example:
350
+
351
+ ```
352
+ import plotly.graph_objs as go
353
+ from plotly.graph_objs.graph_objs_tools import _underscore_magic
354
+ layout = go.Layout()
355
+ _underscore_magic(["xaxis", "title"], "this is my xaxis", layout)
356
+ _underscore_magic("yaxis_titlefont", {"size": 10, "color": "red"}, layout)
357
+ print(layout)
358
+ ```
359
+
360
+ Results in
361
+
362
+ ```
363
+ {'xaxis': {'title': 'this is my xaxis'},
364
+ 'yaxis': {'titlefont': {'color': 'red', 'size': 10}}}
365
+ ```
366
+ """
316
367
if obj is None :
317
368
obj = {}
318
369
@@ -376,6 +427,61 @@ def _underscore_magic_dict(parts, val, obj=None):
376
427
377
428
378
429
def attr (obj = None , ** kwargs ):
430
+ """
431
+ Create a nested attribute using "magic underscore" behavior
432
+
433
+ :param (dict_like) obj: A dict like container on which to set the
434
+ attribute. This will be modified in place. If nothing is passed an
435
+ empty dict is constructed and then returned. If a plotly graph object
436
+ is passed, all attributes will be validated.
437
+ :kwargs: All attributes that should be set on obj
438
+ :returns (dict_like): A modified version of the object passed to this
439
+ function
440
+
441
+ Example 1:
442
+
443
+ ```
444
+ from plotly.graph_objs import attr, Scatter
445
+ my_trace = attr(Scatter(),
446
+ marker=attr(size=4, symbol="diamond", line_color="red"),
447
+ hoverlabel_bgcolor="grey"
448
+ )
449
+ ```
450
+
451
+ Returns the following:
452
+
453
+ ```
454
+ {'hoverlabel': {'bgcolor': 'grey'},
455
+ 'marker': {'line': {'color': 'red'}, 'size': 4, 'symbol': 'diamond'},
456
+ 'type': 'scatter'}
457
+ ```
458
+
459
+ Example 2: incorrect attribute leads to an error
460
+ ```
461
+ from plotly.graph_objs import attr, Scatter
462
+ my_trace = attr(Scatter(),
463
+ marker_mode="markers" # incorrect, should just be mode
464
+ )
465
+ ```
466
+
467
+ Returns an error:
468
+
469
+ ```
470
+ PlotlyDictKeyError: 'mode' is not allowed in 'marker'
471
+
472
+ Path To Error: ['marker']['mode']
473
+
474
+ Valid attributes for 'marker' at path ['marker'] under parents ['scatter']:
475
+
476
+ ['autocolorscale', 'cauto', 'cmax', 'cmin', 'color', 'colorbar',
477
+ 'colorscale', 'colorsrc', 'gradient', 'line', 'maxdisplayed',
478
+ 'opacity', 'opacitysrc', 'reversescale', 'showscale', 'size',
479
+ 'sizemin', 'sizemode', 'sizeref', 'sizesrc', 'symbol', 'symbolsrc']
480
+
481
+ Run `<marker-object>.help('attribute')` on any of the above.
482
+ '<marker-object>' is the object at ['marker']
483
+ ```
484
+ """
379
485
if obj is None :
380
486
obj = dict ()
381
487
0 commit comments