39
39
from collections import OrderedDict
40
40
41
41
42
+ # (1) Make primitive graph objects
42
43
class PlotlyList (list ):
43
44
"""A container for PlotlyDicts, inherits from standard list.
44
45
@@ -690,17 +691,97 @@ def force_clean(self, caller=True):
690
691
del self [key ]
691
692
692
693
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 .
695
696
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.
698
700
699
- Data([Scatter(), Heatmap(), Box()])
701
+ Users should work with the subclasses of PlotlyTrace: Scatter, Box, Bar,
702
+ Heatmap, etc.
700
703
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.
702
706
703
707
"""
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 ):
704
785
def to_graph_objs (self , caller = True ): # TODO TODO TODO! check logic!
705
786
"""Change any nested collections to subclasses of PlotlyDict/List.
706
787
@@ -736,25 +817,13 @@ def to_graph_objs(self, caller=True): # TODO TODO TODO! check logic!
736
817
),
737
818
)
738
819
super (Data , self ).to_graph_objs (caller = caller )
820
+ Data .to_graph_objs = to_graph_objs # override method!
821
+ return Data
739
822
823
+ Data = patch_Data (Data )
740
824
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.
752
825
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 ):
758
827
def to_graph_objs (self , caller = True ):
759
828
"""Change any nested collections to subclasses of PlotlyDict/List.
760
829
@@ -788,91 +857,13 @@ def to_graph_objs(self, caller=True):
788
857
),
789
858
)
790
859
super (Annotations , self ).to_graph_objs (caller = caller )
860
+ Annotations .to_graph_objs = to_graph_objs # override method!
861
+ return Annotations
791
862
863
+ Annotations = patch_Annotations (Annotations )
792
864
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.
802
865
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 ):
876
867
def __init__ (self , * args , ** kwargs ):
877
868
if len (args ):
878
869
if ('data' not in kwargs ) and ('data' not in args [0 ]):
@@ -885,12 +876,13 @@ def __init__(self, *args, **kwargs):
885
876
if 'layout' not in kwargs :
886
877
kwargs ['layout' ] = Layout ()
887
878
super (Figure , self ).__init__ (* args , ** kwargs )
879
+ Figure .__init__ = __init__ # override method!
880
+ return Figure
888
881
882
+ Figure = patch_Figure (Figure )
889
883
890
- class Layout (PlotlyDict ):
891
- """A dictionary-like object holding plot settings for plotly figures.
892
884
893
- """
885
+ def patch_Layout ( Layout ):
894
886
def __init__ (self , * args , ** kwargs ):
895
887
super (Layout , self ).__init__ (* args , ** kwargs )
896
888
@@ -1055,8 +1047,16 @@ def force_clean(self, caller=True): # TODO: can't make call to super...
1055
1047
del self [key ] # clears empty collections!
1056
1048
elif self [key ] is None :
1057
1049
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
1058
1055
1056
+ Layout = patch_Layout (Layout )
1059
1057
1058
+
1059
+ # (4) Class-generating function
1060
1060
def _factory (name , * args , ** kwargs ):
1061
1061
"""All class creation goes through here.
1062
1062
@@ -1073,20 +1073,3 @@ def _factory(name, *args, **kwargs):
1073
1073
return globals ()[name ](** kwargs )
1074
1074
else :
1075
1075
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