Skip to content

Commit 2aa7b96

Browse files
committed
reordering, override some objs after type() creation
1 parent 9bb41f2 commit 2aa7b96

File tree

1 file changed

+107
-124
lines changed

1 file changed

+107
-124
lines changed

Diff for: plotly/graph_objs/graph_objs.py

+107-124
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
from collections import OrderedDict
4040

4141

42+
# (1) Make primitive graph objects
4243
class PlotlyList(list):
4344
"""A container for PlotlyDicts, inherits from standard list.
4445
@@ -690,17 +691,97 @@ def force_clean(self, caller=True):
690691
del self[key]
691692

692693

693-
class Data(PlotlyList):
694-
"""A list of traces to be shown on a plot/graph.
694+
class PlotlyTrace(PlotlyDict):
695+
"""A general data class for plotly.
695696
696-
Any operation that can be done with a standard list may be used with Data.
697-
Instantiation requires an iterable (just like list does), for example:
697+
The PlotlyTrace object is not meant for user interaction. It's sole
698+
purpose is to improve the structure of the object hierarchy established
699+
in this module.
698700
699-
Data([Scatter(), Heatmap(), Box()])
701+
Users should work with the subclasses of PlotlyTrace: Scatter, Box, Bar,
702+
Heatmap, etc.
700703
701-
Valid entry types: (dict or any Trace subclass, e.g. Scatter, Box, etc.)
704+
For help with these subclasses, run:
705+
`help(plotly.graph_objs.Obj)` where Obj == Scatter, Box, Bar, Heatmap, etc.
702706
703707
"""
708+
def __init__(self, *args, **kwargs):
709+
super(PlotlyTrace, self).__init__(*args, **kwargs)
710+
if self.__class__.__name__ == 'PlotlyTrace':
711+
warnings.warn("\nThe PlotlyTrace class is a base class of "
712+
"dictionary-like plot types.\nIt is not meant to be "
713+
"a user interface.")
714+
715+
def to_string(self, level=0, indent=4, eol='\n',
716+
pretty=True, max_chars=80):
717+
"""Returns a formatted string showing graph_obj constructors.
718+
719+
Example:
720+
721+
print obj.to_string()
722+
723+
Keyword arguments:
724+
level (default = 0) -- set number of indentations to start with
725+
indent (default = 4) -- set indentation amount
726+
eol (default = '\n') -- set end of line character(s)
727+
pretty (default = True) -- curtail long list output with a '...'
728+
max_chars (default = 80) -- set max characters per line
729+
730+
"""
731+
self.to_graph_objs()
732+
if self.__class__.__name__ != "Trace":
733+
trace_type = self.pop('type')
734+
string = super(PlotlyTrace, self).to_string(level=level,
735+
indent=indent,
736+
eol=eol,
737+
pretty=pretty,
738+
max_chars=max_chars)
739+
self['type'] = trace_type
740+
else:
741+
string = super(PlotlyTrace, self).to_string(level=level,
742+
indent=indent,
743+
eol=eol,
744+
pretty=pretty,
745+
max_chars=max_chars)
746+
return string
747+
748+
749+
class Trace(PlotlyTrace):
750+
"""A general data class for plotly. Never validated...
751+
752+
This class should be used only for the right reason. This class does not
753+
do much validation because plotly usually accepts more trace specifiers
754+
and more value type varieties, e.g., 'x', 'y', 'r', 't', marker = [
755+
array], etc.
756+
757+
If you are getting errors locally, you might try using this case if
758+
you're sure that what you're attempting to plot is valid.
759+
760+
Also, when getting figures from plotly, you may get back `Trace` types if
761+
the figure was constructed with data objects that don't fall into any of
762+
the class categorizations that are defined in this api.
763+
764+
"""
765+
pass
766+
767+
768+
# (2) Generate graph objects using OBJ_MAP
769+
# With type(name, bases, dict) :
770+
# - name will be the new class name
771+
# - bases are the base classes that the new class inherits from
772+
# - dict holds attributes for the new class, e.g., __doc__
773+
for obj in OBJ_MAP:
774+
base_name = graph_objs_tools.OBJ_MAP[obj]['base_name']
775+
if base_name == 'PlotlyList':
776+
doc = graph_objs_tools.make_list_doc(obj)
777+
else:
778+
doc = graph_objs_tools.make_dict_doc(obj)
779+
base = globals()[base_name]
780+
globals()[obj] = type(obj, (base,), {'__doc__': doc, '__name__': obj})
781+
782+
783+
# (3) Patch 'custom' methods into some graph objects
784+
def patch_Data(Data):
704785
def to_graph_objs(self, caller=True): # TODO TODO TODO! check logic!
705786
"""Change any nested collections to subclasses of PlotlyDict/List.
706787
@@ -736,25 +817,13 @@ def to_graph_objs(self, caller=True): # TODO TODO TODO! check logic!
736817
),
737818
)
738819
super(Data, self).to_graph_objs(caller=caller)
820+
Data.to_graph_objs = to_graph_objs # override method!
821+
return Data
739822

823+
Data = patch_Data(Data)
740824

741-
class Annotations(PlotlyList):
742-
"""A list-like object to contain all figure notes.
743-
744-
Any operation that can be done with a standard list may be used with
745-
Annotations. Instantiation requires an iterable (just like list does),
746-
for example:
747-
748-
Annotations([Annotation(), Annotation(), Annotation()])
749-
750-
This Annotations list is validated upon instantiation, meaning exceptions
751-
will be thrown if any invalid entries are found.
752825

753-
Valid entry types: (dict or Annotation)
754-
755-
For help on Annotation, run `help(plotly.graph_objs.Annotation)`
756-
757-
"""
826+
def patch_Annotations(Annotations):
758827
def to_graph_objs(self, caller=True):
759828
"""Change any nested collections to subclasses of PlotlyDict/List.
760829
@@ -788,91 +857,13 @@ def to_graph_objs(self, caller=True):
788857
),
789858
)
790859
super(Annotations, self).to_graph_objs(caller=caller)
860+
Annotations.to_graph_objs = to_graph_objs # override method!
861+
return Annotations
791862

863+
Annotations = patch_Annotations(Annotations)
792864

793-
class PlotlyTrace(PlotlyDict):
794-
"""A general data class for plotly.
795-
796-
The PlotlyTrace object is not meant for user interaction. It's sole
797-
purpose is to improve the structure of the object hierarchy established
798-
in this module.
799-
800-
Users should work with the subclasses of PlotlyTrace: Scatter, Box, Bar,
801-
Heatmap, etc.
802865

803-
For help with these subclasses, run:
804-
`help(plotly.graph_objs.Obj)` where Obj == Scatter, Box, Bar, Heatmap, etc.
805-
806-
"""
807-
def __init__(self, *args, **kwargs):
808-
super(PlotlyTrace, self).__init__(*args, **kwargs)
809-
if self.__class__.__name__ == 'PlotlyTrace':
810-
warnings.warn("\nThe PlotlyTrace class is a base class of "
811-
"dictionary-like plot types.\nIt is not meant to be "
812-
"a user interface.")
813-
814-
def to_string(self, level=0, indent=4, eol='\n',
815-
pretty=True, max_chars=80):
816-
"""Returns a formatted string showing graph_obj constructors.
817-
818-
Example:
819-
820-
print obj.to_string()
821-
822-
Keyword arguments:
823-
level (default = 0) -- set number of indentations to start with
824-
indent (default = 4) -- set indentation amount
825-
eol (default = '\n') -- set end of line character(s)
826-
pretty (default = True) -- curtail long list output with a '...'
827-
max_chars (default = 80) -- set max characters per line
828-
829-
"""
830-
self.to_graph_objs()
831-
if self.__class__.__name__ != "Trace":
832-
trace_type = self.pop('type')
833-
string = super(PlotlyTrace, self).to_string(level=level,
834-
indent=indent,
835-
eol=eol,
836-
pretty=pretty,
837-
max_chars=max_chars)
838-
self['type'] = trace_type
839-
else:
840-
string = super(PlotlyTrace, self).to_string(level=level,
841-
indent=indent,
842-
eol=eol,
843-
pretty=pretty,
844-
max_chars=max_chars)
845-
return string
846-
847-
848-
class Trace(PlotlyTrace):
849-
"""A general data class for plotly. Never validated...
850-
851-
This class should be used only for the right reason. This class does not
852-
do much validation because plotly usually accepts more trace specifiers
853-
and more value type varieties, e.g., 'x', 'y', 'r', 't', marker = [
854-
array], etc.
855-
856-
If you are getting errors locally, you might try using this case if
857-
you're sure that what you're attempting to plot is valid.
858-
859-
Also, when getting figures from plotly, you may get back `Trace` types if
860-
the figure was constructed with data objects that don't fall into any of
861-
the class categorizations that are defined in this api.
862-
863-
"""
864-
pass
865-
866-
867-
class Figure(PlotlyDict):
868-
"""A dictionary-like object representing a figure to be rendered in plotly.
869-
870-
This is the container for all things to be rendered in a figure.
871-
872-
For help with setting up subplots, run:
873-
`help(plotly.tools.get_subplots)`
874-
875-
"""
866+
def patch_Figure(Figure):
876867
def __init__(self, *args, **kwargs):
877868
if len(args):
878869
if ('data' not in kwargs) and ('data' not in args[0]):
@@ -885,12 +876,13 @@ def __init__(self, *args, **kwargs):
885876
if 'layout' not in kwargs:
886877
kwargs['layout'] = Layout()
887878
super(Figure, self).__init__(*args, **kwargs)
879+
Figure.__init__ = __init__ # override method!
880+
return Figure
888881

882+
Figure = patch_Figure(Figure)
889883

890-
class Layout(PlotlyDict):
891-
"""A dictionary-like object holding plot settings for plotly figures.
892884

893-
"""
885+
def patch_Layout(Layout):
894886
def __init__(self, *args, **kwargs):
895887
super(Layout, self).__init__(*args, **kwargs)
896888

@@ -1055,8 +1047,16 @@ def force_clean(self, caller=True): # TODO: can't make call to super...
10551047
del self[key] # clears empty collections!
10561048
elif self[key] is None:
10571049
del self[key]
1050+
Layout.__init__ = __init__
1051+
Layout.to_graph_objs = to_graph_objs
1052+
Layout.to_string = to_string
1053+
Layout.force_clean = force_clean # override methods!
1054+
return Layout
10581055

1056+
Layout = patch_Layout(Layout)
10591057

1058+
1059+
# (4) Class-generating function
10601060
def _factory(name, *args, **kwargs):
10611061
"""All class creation goes through here.
10621062
@@ -1073,20 +1073,3 @@ def _factory(name, *args, **kwargs):
10731073
return globals()[name](**kwargs)
10741074
else:
10751075
return globals()[name]()
1076-
1077-
1078-
# some magic... you can use `type` to create new classes:
1079-
# type(name, bases, dict)
1080-
# name will be the new class name
1081-
# bases are the base classes that the new class inherits from
1082-
# dict holds attributes for the new class, e.g., __doc__
1083-
# why? because __doc__ isn't writeable after-the-fact!
1084-
for obj in OBJ_MAP:
1085-
if obj not in globals():
1086-
base_name = graph_objs_tools.OBJ_MAP[obj]['base_name']
1087-
if base_name == 'PlotlyList':
1088-
doc = graph_objs_tools.make_list_doc(obj)
1089-
else:
1090-
doc = graph_objs_tools.make_dict_doc(obj)
1091-
base = globals()[base_name]
1092-
globals()[obj] = type(obj, (base,), {'__doc__': doc, '__name__': obj})

0 commit comments

Comments
 (0)