@@ -1425,6 +1425,12 @@ def return_figure_from_figure_or_data(figure_or_data, validate_figure):
1425
1425
_DEFAULT_INCREASING_COLOR = '#3D9970' # http://clrs.cc
1426
1426
_DEFAULT_DECREASING_COLOR = '#FF4136'
1427
1427
1428
+ DEFAULT_PLOTLY_COLORS = ['rgb(31, 119, 180)' , 'rgb(255, 127, 14)' ,
1429
+ 'rgb(44, 160, 44)' , 'rgb(214, 39, 40)' ,
1430
+ 'rgb(148, 103, 189)' , 'rgb(140, 86, 75)' ,
1431
+ 'rgb(227, 119, 194)' , 'rgb(127, 127, 127)' ,
1432
+ 'rgb(188, 189, 34)' , 'rgb(23, 190, 207)' ]
1433
+
1428
1434
1429
1435
class FigureFactory (object ):
1430
1436
"""
@@ -1442,6 +1448,333 @@ class FigureFactory(object):
1442
1448
more information and examples of a specific chart type.
1443
1449
"""
1444
1450
1451
+ @staticmethod
1452
+ def _unlabel_rgb (colors ):
1453
+ unlabelled_colors = []
1454
+ for color in colors :
1455
+ str_vals = ''
1456
+ for index in range (len (color )):
1457
+ try :
1458
+ float (color [index ])
1459
+ str_vals = str_vals + color [index ]
1460
+ except ValueError :
1461
+ if (color [index ] == ',' ) or (color [index ] == '.' ):
1462
+ str_vals = str_vals + color [index ]
1463
+
1464
+ str_vals = str_vals + ','
1465
+ numbers = []
1466
+ str_num = ''
1467
+ for char in str_vals :
1468
+ if char != ',' :
1469
+ str_num = str_num + char
1470
+ else :
1471
+ numbers .append (float (str_num ))
1472
+ str_num = ''
1473
+ unlabelled_tuple = (numbers [0 ], numbers [1 ], numbers [2 ])
1474
+ unlabelled_colors .append (unlabelled_tuple )
1475
+
1476
+ return unlabelled_colors
1477
+
1478
+ @staticmethod
1479
+ def _find_intermediate_color (tuple1 , tuple2 , t ):
1480
+ # Given two color tuples (in normalized RGB space)
1481
+ # and a value 0 < t < 1, spit out a color that is
1482
+ # t percent from tuple1 to tuple2.
1483
+ diff_0 = float (tuple2 [0 ] - tuple1 [0 ])
1484
+ diff_1 = float (tuple2 [1 ] - tuple1 [1 ])
1485
+ diff_2 = float (tuple2 [2 ] - tuple1 [2 ])
1486
+
1487
+ new_tuple = (tuple1 [0 ] + t * diff_0 ,
1488
+ tuple1 [1 ] + t * diff_1 ,
1489
+ tuple1 [2 ] + t * diff_2 )
1490
+ return new_tuple
1491
+
1492
+ @staticmethod
1493
+ def _unconvert_from_RGB_255 (colors ):
1494
+ un_rgb_colors = []
1495
+ for color in colors :
1496
+ un_rgb_color = (color [0 ]/ (255.0 ),
1497
+ color [1 ]/ (255.0 ),
1498
+ color [2 ]/ (255.0 ))
1499
+
1500
+ un_rgb_colors .append (un_rgb_color )
1501
+ return un_rgb_colors
1502
+
1503
+ @staticmethod
1504
+ def _map_z2color (zval , colormap , vmin , vmax ):
1505
+ # Map the normalized value zval to a
1506
+ #corresponding color in the colormap
1507
+ if vmin > vmax :
1508
+ raise ValueError ("Incorrect relation between vmin and vmax."
1509
+ " The vmin cannot be bigger than vmax." )
1510
+ t = (zval - vmin )/ float ((vmax - vmin )) # normalize val
1511
+ t_color = FigureFactory ._find_intermediate_color (colormap [0 ],
1512
+ colormap [1 ],
1513
+ t )
1514
+ t_color = (t_color [0 ]* 255.0 , t_color [1 ]* 255.0 , t_color [2 ]* 255.0 )
1515
+ labelled_color = 'rgb{}' .format (t_color )
1516
+
1517
+ return labelled_color
1518
+
1519
+ @staticmethod
1520
+ def _tri_indices (simplices ):
1521
+ return ([triplet [c ] for triplet in simplices ] for c in range (3 ))
1522
+
1523
+ @staticmethod
1524
+ def _plotly_trisurf (x , y , z , simplices , colormap = None ,
1525
+ plot_edges = None ):
1526
+ import numpy as np
1527
+ from plotly .graph_objs import graph_objs
1528
+ points3D = np .vstack ((x , y , z )).T
1529
+
1530
+ # vertices of the surface triangles
1531
+ tri_vertices = map (lambda index : points3D [index ], simplices )
1532
+ # mean values of z-coordinates of triangle vertices
1533
+ zmean = [np .mean (tri [:, 2 ]) for tri in tri_vertices ]
1534
+ min_zmean = np .min (zmean )
1535
+ max_zmean = np .max (zmean )
1536
+ facecolor = ([FigureFactory ._map_z2color (zz , colormap , min_zmean ,
1537
+ max_zmean ) for zz in zmean ])
1538
+ I , J , K = FigureFactory ._tri_indices (simplices )
1539
+
1540
+ triangles = graph_objs .Mesh3d (x = x , y = y , z = z , facecolor = facecolor ,
1541
+ i = I , j = J , k = K , name = '' )
1542
+
1543
+ if plot_edges is None : # the triangle sides are not plotted
1544
+ return graph_objs .Data ([triangles ])
1545
+
1546
+ else :
1547
+ # define the lists Xe, Ye, Ze, of x, y, resp z coordinates of
1548
+ # edge end points for each triangle
1549
+ # None separates data corresponding to two consecutive triangles
1550
+ lists_coord = ([[[T [k % 3 ][c ] for k in range (4 )]+ [None ]
1551
+ for T in tri_vertices ] for c in range (3 )])
1552
+ Xe , Ye , Ze = ([reduce (lambda x , y : x + y , lists_coord [k ])
1553
+ for k in range (3 )])
1554
+
1555
+ # define the lines to be plotted
1556
+ lines = graph_objs .Scatter3d (
1557
+ x = Xe , y = Ye , z = Ze , mode = 'lines' ,
1558
+ line = graph_objs .Line (color = 'rgb(50,50,50)' ,
1559
+ width = 1.5 )
1560
+ )
1561
+
1562
+ return graph_objs .Data ([triangles , lines ])
1563
+
1564
+ @staticmethod
1565
+ def create_trisurf (x , y , z , colormap = None , simplices = None ,
1566
+ title = 'Trisurf Plot' ,
1567
+ showbackground = True ,
1568
+ backgroundcolor = 'rgb(230, 230, 230)' ,
1569
+ gridcolor = 'rgb(255, 255, 255)' ,
1570
+ zerolinecolor = 'rgb(255, 255, 255)' ,
1571
+ height = 800 , width = 800 ,
1572
+ aspectratio = dict (x = 1 , y = 1 , z = 1 )):
1573
+ """
1574
+ Returns data for a triangulated surface plot.
1575
+
1576
+ :param (array) x: data values of x in a 1D array
1577
+ :param (array) y: data values of y in a 1D array
1578
+ :param (array) z: data values of z in a 1D array
1579
+ :param (str|list) colormap: either a plotly scale name, or a list
1580
+ containing 2 triplets. These triplets must be of the form (a,b,c)
1581
+ or 'rgb(x,y,z)' where a,b,c belong to the interval [0,1] and x,y,z
1582
+ belong to [0,255]
1583
+ :param (array) simplices: an array of shape (ntri, 3) where ntri is
1584
+ the number of triangles in the triangularization. Each row of the
1585
+ array contains the indicies of the verticies of each triangle.
1586
+ :param (str) title: title of the plot
1587
+ :param (bool) showbackground: makes background in plot visible
1588
+ :param (str) backgroundcolor: color of background. Takes a string of
1589
+ the form 'rgb(x,y,z)' x,y,z are between 0 and 255 inclusive.
1590
+ :param (str) gridcolor: color of the gridlines besides the axes. Takes
1591
+ a string of the form 'rgb(x,y,z)' x,y,z are between 0 and 255
1592
+ inclusive.
1593
+ :param (str) zerolinecolor: color of the axes. Takes a string of the
1594
+ form 'rgb(x,y,z)' x,y,z are between 0 and 255 inclusive.
1595
+ :param (int|float) height: the height of the plot (in pixels)
1596
+ :param (int|float) width: the width of the plot (in pixels)
1597
+ :param (dict) aspectratio: a dictionary of the aspect ratio values for
1598
+ the x, y and z axes. 'x', 'y' and 'z' take (int|float) values.
1599
+
1600
+ Example 1: Sphere
1601
+ ```
1602
+ # Necessary Imports for Trisurf
1603
+ import numpy as np
1604
+ from scipy.spatial import Delaunay
1605
+
1606
+ import plotly.plotly as py
1607
+ from plotly.tools import FigureFactory as FF
1608
+ from plotly.graph_objs import graph_objs
1609
+
1610
+ # Make data for plot
1611
+ u=np.linspace(0, 2*np.pi, 20)
1612
+ v=np.linspace(0, np.pi, 20)
1613
+ u,v=np.meshgrid(u,v)
1614
+ u=u.flatten()
1615
+ v=v.flatten()
1616
+
1617
+ x = np.sin(v)*np.cos(u)
1618
+ y = np.sin(v)*np.sin(u)
1619
+ z = np.cos(v)
1620
+
1621
+ points2D = np.vstack([u,v]).T
1622
+ tri = Delaunay(points2D)
1623
+ simplices = tri.simplices
1624
+
1625
+ # Create a figure
1626
+ fig1 = FF.create_trisurf(x=x, y=y, z=z,
1627
+ colormap="Blues",
1628
+ simplices=simplices)
1629
+ # Plot the data
1630
+ py.iplot(fig1, filename='Trisurf Plot')
1631
+ ```
1632
+
1633
+ Example 2: Torus
1634
+ ```
1635
+ # Necessary Imports for Trisurf
1636
+ import numpy as np
1637
+ from scipy.spatial import Delaunay
1638
+
1639
+ import plotly.plotly as py
1640
+ from plotly.tools import FigureFactory as FF
1641
+ from plotly.graph_objs import graph_objs
1642
+
1643
+ # Make data for plot
1644
+ u=np.linspace(0, 2*np.pi, 20)
1645
+ v=np.linspace(0, 2*np.pi, 20)
1646
+ u,v=np.meshgrid(u,v)
1647
+ u=u.flatten()
1648
+ v=v.flatten()
1649
+
1650
+ x = (3 + (np.cos(v)))*np.cos(u)
1651
+ y = (3 + (np.cos(v)))*np.sin(u)
1652
+ z = np.sin(v)
1653
+
1654
+ points2D = np.vstack([u,v]).T
1655
+ tri = Delaunay(points2D)
1656
+ simplices = tri.simplices
1657
+
1658
+ # Create a figure
1659
+ fig1 = FF.create_trisurf(x=x, y=y, z=z,
1660
+ colormap="Portland",
1661
+ simplices=simplices)
1662
+ # Plot the data
1663
+ py.iplot(fig1, filename='Trisurf Plot')
1664
+ ```
1665
+
1666
+ Example 3: Mobius Band
1667
+ ```
1668
+ # Necessary Imports for Trisurf
1669
+ import numpy as np
1670
+ from scipy.spatial import Delaunay
1671
+
1672
+ import plotly.plotly as py
1673
+ from plotly.tools import FigureFactory as FF
1674
+ from plotly.graph_objs import graph_objs
1675
+
1676
+ # Make data for plot
1677
+ u=np.linspace(0, 2*np.pi, 24)
1678
+ v=np.linspace(-1, 1, 8)
1679
+ u,v=np.meshgrid(u,v)
1680
+ u=u.flatten()
1681
+ v=v.flatten()
1682
+
1683
+ tp = 1 + 0.5*v*np.cos(u/2.)
1684
+ x=tp*np.cos(u)
1685
+ y=tp*np.sin(u)
1686
+ z=0.5*v*np.sin(u/2.)
1687
+
1688
+ points2D = np.vstack([u,v]).T
1689
+ tri = Delaunay(points2D)
1690
+ simplices = tri.simplices
1691
+
1692
+ # Create a figure
1693
+ fig1 = FF.create_trisurf(x=x, y=y, z=z,
1694
+ colormap=[(0.2, 0.4, 0.6),(1, 1, 1)],
1695
+ simplices=simplices)
1696
+ # Plot the data
1697
+ py.iplot(fig1, filename='Trisurf Plot')
1698
+ ```
1699
+ """
1700
+ from plotly .graph_objs import graph_objs
1701
+ plotly_scales = {'Greys' : ['rgb(0,0,0)' , 'rgb(255,255,255)' ],
1702
+ 'YlGnBu' : ['rgb(8,29,88)' , 'rgb(255,255,217)' ],
1703
+ 'Greens' : ['rgb(0,68,27)' , 'rgb(247,252,245)' ],
1704
+ 'YlOrRd' : ['rgb(128,0,38)' , 'rgb(255,255,204)' ],
1705
+ 'Bluered' : ['rgb(0,0,255)' , 'rgb(255,0,0)' ],
1706
+ 'RdBu' : ['rgb(5,10,172)' , 'rgb(178,10,28)' ],
1707
+ 'Reds' : ['rgb(220,220,220)' , 'rgb(178,10,28)' ],
1708
+ 'Blues' : ['rgb(5,10,172)' , 'rgb(220,220,220)' ],
1709
+ 'Picnic' : ['rgb(0,0,255)' , 'rgb(255,0,0)' ],
1710
+ 'Rainbow' : ['rgb(150,0,90)' , 'rgb(255,0,0)' ],
1711
+ 'Portland' : ['rgb(12,51,131)' , 'rgb(217,30,30)' ],
1712
+ 'Jet' : ['rgb(0,0,131)' , 'rgb(128,0,0)' ],
1713
+ 'Hot' : ['rgb(0,0,0)' , 'rgb(255,255,255)' ],
1714
+ 'Blackbody' : ['rgb(0,0,0)' , 'rgb(160,200,255)' ],
1715
+ 'Earth' : ['rgb(0,0,130)' , 'rgb(255,255,255)' ],
1716
+ 'Electric' : ['rgb(0,0,0)' , 'rgb(255,250,220)' ],
1717
+ 'Viridis' : ['rgb(68,1,84)' , 'rgb(253,231,37)' ]}
1718
+
1719
+ if simplices is None :
1720
+ raise exceptions .PlotlyError ("Make sure you enter 'simplices' "
1721
+ "in the trisurf function." )
1722
+
1723
+ # Validate colormap
1724
+ if colormap is None :
1725
+ colormap = [DEFAULT_PLOTLY_COLORS [0 ],
1726
+ DEFAULT_PLOTLY_COLORS [1 ]]
1727
+ colormap = FigureFactory ._unlabel_rgb (colormap )
1728
+ colormap = FigureFactory ._unconvert_from_RGB_255 (colormap )
1729
+
1730
+ if isinstance (colormap , str ):
1731
+ if colormap not in plotly_scales :
1732
+ raise exceptions .PlotlyError ("You must pick a valid "
1733
+ "plotly colorscale name." )
1734
+ colormap = [plotly_scales [colormap ][0 ],
1735
+ plotly_scales [colormap ][1 ]]
1736
+ colormap = FigureFactory ._unlabel_rgb (colormap )
1737
+ colormap = FigureFactory ._unconvert_from_RGB_255 (colormap )
1738
+
1739
+ else :
1740
+ if not isinstance (colormap , list ):
1741
+ raise exceptions .PlotlyError ("If 'colormap' is a list, then "
1742
+ "its items must be tripets of "
1743
+ "the form a,b,c or 'rgbx,y,z' "
1744
+ "where a,b,c are between 0 and "
1745
+ "1 inclusive and x,y,z are "
1746
+ "between 0 and 255 inclusive." )
1747
+ if 'rgb' in colormap [0 ]:
1748
+ colormap = FigureFactory ._unlabel_rgb (colormap )
1749
+ colormap = FigureFactory ._unconvert_from_RGB_255 (colormap )
1750
+
1751
+ data1 = FigureFactory ._plotly_trisurf (x , y , z , simplices ,
1752
+ colormap = colormap ,
1753
+ plot_edges = True )
1754
+ axis = dict (
1755
+ showbackground = showbackground ,
1756
+ backgroundcolor = backgroundcolor ,
1757
+ gridcolor = gridcolor ,
1758
+ zerolinecolor = zerolinecolor ,
1759
+ )
1760
+ layout = graph_objs .Layout (
1761
+ title = title ,
1762
+ width = width ,
1763
+ height = height ,
1764
+ scene = graph_objs .Scene (
1765
+ xaxis = graph_objs .XAxis (axis ),
1766
+ yaxis = graph_objs .YAxis (axis ),
1767
+ zaxis = graph_objs .ZAxis (axis ),
1768
+ aspectratio = dict (
1769
+ x = aspectratio ['x' ],
1770
+ y = aspectratio ['y' ],
1771
+ z = aspectratio ['z' ]),
1772
+ )
1773
+ )
1774
+ fig1 = graph_objs .Figure (data = data1 , layout = layout )
1775
+
1776
+ return fig1
1777
+
1445
1778
@staticmethod
1446
1779
def _validate_equal_length (* args ):
1447
1780
"""
0 commit comments