3939 from collections import OrderedDict
4040
4141
42+ # (1) Make primitive graph objects
4243class 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 ("\n The PlotlyTrace class is a base class of "
712+ "dictionary-like plot types.\n It 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 ("\n The PlotlyTrace class is a base class of "
811- "dictionary-like plot types.\n It 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
10601060def _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