BBL : Plotly

Presenter: F. Torregrossa

What is plotly ?

A company selling:

  • Tool to create dashboards
  • Cloud to store your plots
  • Consulting (how to use plotly with your data)

A python package

pip install plotly

Draw plots online (cloud storage) or offline (private usage).

Why plotly is a good tool ?

Because :

  • Object-oriented approach
  • Consider three main objects: Data / Figure / Layout
  • Do automatic preprocessing of your data
  • Interactive and responsive
  • Doc is well written / Loads of examples

Why not using old good matplotlib ?

Because :

  • No preprocessing
  • Not responsive
  • Complicated to dive into your data

How to use plotly ?

In a notebook

import plotly.offline as pyo
import plotly.graph_objs as go
pyo.init_notebook_mode()

pyo.iplot(MY_FIGURE)
# OU
MY_FIGURE.show()

In a scripts

import plotly.offline as pyo
import plotly.graph_objs as go

## DYNAMIC PLOT
pyo.plot(MY_FIGURE)

## STATIC EXPORT
MY_FIGURE.write_image('path/to/filename.[svg,jpg,png,pdf]')

Plotly express

  • Faster way to plot data
  • Less manageable

Covered use-cases

  • Plot datapoints / distribution
  • Draw functions
  • Draw Graphs
  • 2D / 3D Representations (Images, Surface)
  • Animationns

Representing a distribution

(source https://plot.ly/python/2D-Histogram/)

In [ ]:
data = pd.read_csv('resources/data/gauss1.csv', header=None)
data.head(5)
In [ ]:
data.describe()

A Scatter plot

In [ ]:
fig = go.Figure([
    go.Scatter(
        x = data.iloc[::10, 0],
        y = data.iloc[::10, 1],
        mode = 'markers'
    )], layout=go.Layout(width=800)
)
In [ ]:
fig.show()

2D Histogram

Count repartition in the space

In [ ]:
fig = go.Figure([
    go.Histogram2d(
        x = data.iloc[:, 0],
        y = data.iloc[:, 1]
    )
], layout=go.Layout(width=800))
In [ ]:
fig.show()
In [ ]:
## Bins scale automatically
fig = go.Figure([
    go.Histogram2d(
        x = data.iloc[::100, 0],
        y = data.iloc[::100, 1]
    )
], layout=go.Layout(width=800))
In [ ]:
fig.show()

Contours

In [ ]:
fig = go.Figure([
    go.Histogram2dContour(
        x = data.iloc[:, 0],
        y = data.iloc[:, 1]
    )
], layout=go.Layout(width=800))
In [ ]:
fig.show()

Can we combine ?

In [ ]:
fig = go.Figure([
    go.Histogram2dContour(
        x = data.iloc[:, 0],
        y = data.iloc[:, 1]
    ), go.Scatter(
        x = data.iloc[2::10, 0],
        y = data.iloc[2::10, 1],
        mode = 'markers',
        marker=dict(size=2, color='rgba(0, 0, 0, 0.5)')
    )
], layout=go.Layout(width=800))
In [ ]:
fig.show()

Histogram 1D ?

In [ ]:
fig = go.Figure([
    go.Histogram(
        x = data.iloc[:, 0],
        opacity = 0.75,
        name = 'Dimension 1'
    ), go.Histogram(
        x = data.iloc[:, 1],
        opacity = 0.75,
        name = 'Dimension 2'
        
    )
], layout=go.Layout(width=800))
In [ ]:
fig.show()
In [ ]:
fig = go.Figure([
    go.Histogram2dContour(
        x = data.iloc[:, 0],
        y = data.iloc[:, 1]
    ), go.Scatter(
        x = data.iloc[2::10, 0],
        y = data.iloc[2::10, 1],
        mode = 'markers',
        marker=dict(size=2, color='rgba(0, 0, 0, 0.5)')
    ), go.Histogram(
        x = data.iloc[:, 0],
        yaxis = 'y2',
    ), go.Histogram(
        y = data.iloc[:, 1],
        xaxis='x2',
        
    )
], layout = go.Layout(
    autosize = False,
    xaxis = dict(
        zeroline = False,
        domain = [0,0.85],
        showgrid = False
    ),
    yaxis = dict(
        zeroline = False,
        domain = [0,0.85],
        showgrid = False
    ),
    xaxis2 = dict(
        zeroline = False,
        domain = [0.85,1],
        showgrid = False
    ),
    yaxis2 = dict(
        zeroline = False,
        domain = [0.85,1],
        showgrid = False
    ),
    bargap = 0,
    width = 800,
    hovermode = 'closest',
    showlegend = False
))
In [ ]:
fig.show()

Draw functions

In [ ]:
fig = go.Figure([
    go.Scatter(
        x = [0, 1, 2, 3, 4],
        y = [0, 1, 4, 9, 16],
        mode='markers+lines',
        name = "f",
        showlegend = True
    ),
], layout = go.Layout(
    xaxis = dict(   
        title='$x$'
    ),
    yaxis = dict(
        title='$x^2$'
    ),
    title = dict(
        x=0.5,
        text=r"$f(x) = x^2$"
    ),
    width=800
))
In [ ]:
fig.show()
In [ ]:
fig = go.Figure(
    data=go.Scatter(
        x = np.linspace(-math.pi, math.pi, 1000),
        y = np.cos(np.linspace(- math.pi, math.pi, 1000)),
        mode='lines',
        name = 'f',
        showlegend = True
    ),
    layout = go.Layout(
        xaxis = dict(   
            title='$x$'
        ),
        yaxis = dict(
            title='$cos(x)$'
        ),
        title = dict(
            x=0.5,
            text=r"$f(x) = cos(x)$"
        ),
        width=800
    )
)
In [ ]:
fig.show()
In [ ]:
fig = go.Figure(
    data=[
        go.Scatter(
            x = np.linspace(-math.pi, math.pi, 1000),
            y = f[1](np.linspace(- math.pi, math.pi, 1000)),
            mode='lines',
            name = f[0],
            showlegend = True
    ) for f in [
            (r'$\mathrm{cos}(x)$', np.cos),
            (r'$\mathrm{sin}(x)$', np.sin),
            (r'$\mathrm{cos}(x-\frac{\pi}{4})$', lambda x: np.cos(x - math.pi / 4))
        ]
    ], layout = go.Layout(
    xaxis = dict(   
        title='$x$'
    ),
    yaxis = dict(
        title='$f(x)$'
    ),
    width = 800
))
In [ ]:
fig.show()

Draw graphs

Example : Multiplication tables (from Micmaths https://www.youtube.com/watch?v=-X49VQgi86E)

In [ ]:
IFrame(src='resources/figure/table2mod50.html', width=700, height=750)

Build simple blocks

In [ ]:
## Draw a circle

def go_circle(r, n=1000):
    return go.Scatter(
        x = r * np.cos(np.linspace(0, 2 * math.pi, n)),
        y = r * np.sin(np.linspace(0, 2 * math.pi, n)),
        line = dict(color='black'),
        showlegend=False
    )
In [ ]:
fig = go.Figure([
    go_circle(1)
], layout=go.Layout(width=800))
fig.show()
In [ ]:
## Better layout
def nice_layout():
    return go.Layout(
        plot_bgcolor='white',
        width=800,
        yaxis=dict(
            scaleanchor="x",
            scaleratio=1,
            showgrid=False,
            zeroline=False,
            showticklabels=False
        ), xaxis=dict(
            showgrid=False,
            zeroline=False,
            showticklabels=False
        )
    )
In [ ]:
fig = go.Figure([
    go_circle(1)
], layout=nice_layout())
fig.show()
In [ ]:
## Set homogeneously dots on circle

def tickpos(n):
    return [2 * math.pi * k / n for k in range(n)]

def go_dots(N, r=1):
    return go.Scatter(
        x = r * np.cos(tickpos(N)),
        y = r * np.sin(tickpos(N)),
        text = list(map(str, range(N))),
        mode = "markers",
        showlegend=False
    )
In [ ]:
fig = go.Figure([
    go_circle(1),
    go_dots(50)
], layout=nice_layout())
fig.show()
In [ ]:
## Draw edges

def table(p, n):
    return [
        (
            2 * math.pi * x / n,
             2 * math.pi * int((x * p) % n) / n
        ) for x in range(n)]

def go_lines(p, n, r=1, showlegend=True, color='rgba(0,0,0,0.25)'):
    return go.Scatter(
        x = sum([[r * np.cos(x[0]), r * np.cos(x[1]), None] for x in table(p, n)], []),
        y = sum([[r * np.sin(x[0]), r * np.sin(x[1]), None] for x in table(p, n)], []),
        mode = 'lines',
        name='%.2f mod %d' % (p, n),
        showlegend=showlegend,
        line=dict(width=1, color=color)
    )
In [ ]:
fig = go.Figure([
    go_circle(1),
    go_dots(50),
    go_lines(2, 50)
], layout=nice_layout())
fig.show()
In [ ]:
IFrame(src='resources/figure/wn-musical.html', width=600, height=800)

2D / 3D Representations (Images, Surface)

In [ ]:
im = Image.open( 'resources/figure/flower.jpg' )
r, g, b = im.split()
In [ ]:
fig = go.Figure(
    go.Heatmap(
        z = np.mean(np.array(im.getdata()), axis=1).reshape((im.size[1], im.size[0]))[::-1],
        colorscale='gray'
    ),
    layout=nice_layout()
)
In [ ]:
fig.show()
In [ ]:
fig = go.Figure(
    go.Heatmap(
        z = np.mean(np.array(im.getdata()), axis=1).reshape((im.size[1], im.size[0]))[::-10, ::10],
        colorscale='gray'
    ),
    layout=nice_layout()
)
In [ ]:
fig.show()
In [ ]:
df = pd.read_csv('resources/data/gauss2.csv', header=None)
fig = go.Figure(
    go.Scatter3d(
        x = df.iloc[::10, 0],
        y = df.iloc[::10, 1],
        z = df.iloc[::10, 2],
        mode = 'markers',
        marker = dict(size=4)
    ),
    layout=nice_layout()
)
In [ ]:
fig.show()
In [ ]:
def helicoide(h, r, n=1000):
    return (
        r * np.cos(np.linspace(0, 10, n)),
        r * np.sin(np.linspace(0, 10, n)),
        h * np.linspace(0, 10, n)
    )
In [ ]:
X, Y, Z = helicoide(1, 1, n=100)
fig = go.Figure(
    go.Scatter3d(
        x = X,
        y = Y,
        z = Z,
        mode = 'markers',
        marker = dict(size=4)
    ),
    layout=nice_layout()
)
In [ ]:
fig.show()
In [ ]:
def f(x, y):
    return np.cos(x)  + y ** 2

X = np.linspace(-math.pi, math.pi, 1000)
Y = np.linspace(-1, 1, 1000)

Z = np.zeros((1000, 1000))
for i, x in enumerate(X):
    for j, y in enumerate(Y):
        Z[i, j] = f(x, y)
In [ ]:
fig = go.Figure(
    go.Surface(
        z=Z,
        x=X,
        y=Y
    ),
    layout=nice_layout()
)
In [ ]:
fig.show()
In [ ]:
fig = go.Figure(
    go.Contour(
        z=Z,
        x=X,
        y=Y,
    ),
    layout=go.Layout(width=800)
)
In [ ]:
fig.show()
In [ ]:
X, Y = np.meshgrid(X, Y)
fig = go.Figure([
    go.Scatter3d(
        x = X[:, i], 
        y =  Y[:, i], 
        z = Z[:, i],
        mode = 'lines',
        line = dict(color='blue'),
        showlegend=False,
        marker = dict(size=4)
    ) for i in range(0, X.shape[1], 20)] + [
        go.Scatter3d(
            x = X[i, :], 
            y =  Y[i, :], 
            z = Z[i, :],
            mode = 'lines',
            line = dict(color='blue'),
            showlegend=False,
            marker = dict(size=4)
    ) for i in range(0, X.shape[1], 20)],
    layout=nice_layout()
)
In [ ]:
fig.show()

Animations

In [ ]:
"""
fig = go.Figure(
    data = [
        go_lines(2, N, showlegend=False),
        go_circle(1),
    ],
    frames = [
        go.Frame(
            data=[go_lines(x, N, showlegend=False)], name="%.2f mod %d" % (x, N) 
        ) for x in np.linspace(2, 10, nframes)
    ]
)
"""
In [ ]:
#fig.show()
In [ ]:
#fig.show()
In [ ]: