4

I have a large dataset that I want to explore. However I don't want to create multiple plots. I just want a single plot where I can interactively change the columns used for the x and y axis and the plot will update itself.

I'm trying to do this with Python/Bokeh using Bokeh to serve my script to a browser. However I'm not clear how to get the plot to update. I see a lot of examples where the underlying datasource is changed, but I don't want to do this I just want to change which columns are being plotted.

I've made a simplified example of what I want to do below. It uses two 'Select' widgets for choosing the x and y columns of the datasource. These have callbacks that attempt to change the column that the 'Line' glyph is referring to. However this does not seem to work. Any advice would be welcome.

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select,TextInput
from bokeh.models.glyphs import Line
from bokeh.models.layouts import HBox, VBox
from bokeh.io import curdoc


#==============================================================================
#%% Define some Data
#==============================================================================
N = 200

# Define the data to be used
x = np.linspace(0,4.*np.pi,N)
y = 3*np.cos(2*np.pi*x + np.pi*0.2)
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4)

source = ColumnDataSource({'x':x,'cos':y,'sin':z})


#==============================================================================
#%% Layout
#==============================================================================


TOOLS = "box_select,lasso_select,help"

# create a new plot 
plot = Figure(tools=TOOLS,  title=None)

# Make a line and connect to data source
glyph = Line(x="x", y="cos", line_color="#F46D43", line_width=6, line_alpha=0.6)
plot.add_glyph(source, glyph)

# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                           options=['x','cos','sin'])


xaxis_select = Select(title="X axis:", value="x",
                           options=['x','cos','sin'])


# Text input as a title
text = TextInput(title="title", value='my sine wave plotter')

# Layout widgets next to the plot                     
controls = VBox(text,yaxis_select,xaxis_select)

layout = HBox(controls,plot,width=800)


#==============================================================================
#%% Callbacks
#==============================================================================
# Put callbacks on the list boxes so that when they are changed the columns being
# plotted get changed.

def update_x_axis(attr, old, new):
    # Change the column used for the x axis
    glyph.x = xaxis_select.value


def update_y_axis(attr, old, new):
    # Change the column used for the y axis
    glyph.y = yaxis_select.value



yaxis_select.on_change('value', update_y_axis)
xaxis_select.on_change('value', update_x_axis)



#==============================================================================
#%% Add to document root
#==============================================================================

curdoc().add_root(layout)
curdoc().title = "Plotting app"
Redlegjed
  • 187
  • 2
  • 11

3 Answers3

5

To edit the actual source field that the glyphs take their co-ordinates from, you need a variation of the code found in this question. A revision of ImportanceOfBeingErnest's code yields the correct result with no need to change the original ColumnDataSource or hide any keys from the Select widgets:

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select, TextInput
from bokeh.models.layouts import HBox, VBox
import bokeh.io
from bokeh.io import curdoc
from bokeh.models import CustomJS

N = 200

# Define the data to be used
x = np.linspace(0, 4. * np.pi, N)
y = 3 * np.cos(2 * np.pi * x + np.pi * 0.2)
z = 0.5 * np.sin(2 * np.pi * 0.8 * x + np.pi * 0.4)

data = {'x': x, 'cos': y, 'sin': z}
source = ColumnDataSource(data=data)

codex = """
            var column = cb_obj.value;
            line1.glyph.x.field = column;
            source.trigger('change')
        """
codey = """
            var column = cb_obj.value;
            line1.glyph.y.field = column;
            source.trigger('change')
        """

# create a new plot
plot = Figure(title=None)

# Make a line and connect to data source
line1 = plot.line(x="x", y="cos", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source)

callbackx = CustomJS(args=dict(line1=line1, source=source), code=codex)
callbacky = CustomJS(args=dict(line1=line1, source=source), code=codey)

# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                      options=data.keys(),
                      callback=callbacky
                      )

xaxis_select = Select(title="X axis:", value="x",
                      options=data.keys(),
                      callback=callbackx
                      )

# Text input as a title
text = TextInput(title="title", value='my sine wave plotter')

# Layout widgets next to the plot
controls = VBox(text, yaxis_select, xaxis_select)

layout = HBox(controls, plot, width=800)

# bokeh.io.show(layout)
curdoc().add_root(layout)
curdoc().title = "Sliders"

I separated the code strings for clarity, but ImportanceOfBeingErnest's string.format() use was quite neat.

Unfortunately I couldn't get a fully Python solution for editing these particular fields, although ImportanceOfBeingErnest's solution doesn't actually need JavaScript at all (but does change the datasource)

Community
  • 1
  • 1
MInvertedM
  • 51
  • 1
  • 4
  • 1
    This worked for me, with a few updates for Bokeh v 0.13: [1] I use `source.change.emit();` instead of `source.trigger('change')` [2] I use `column` instead of `HBox.` – Dustin Michels Aug 29 '18 at 20:39
3

The following script seems to work just fine. It does not use the Bokeh Server but the CustomJS client side style instead.

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select,TextInput
from bokeh.models.layouts import HBox, VBox
import bokeh.io 
from bokeh.models import CustomJS

N = 200

# Define the data to be used
x = np.linspace(0,4.*np.pi,N)
y = 3*np.cos(2*np.pi*x + np.pi*0.2)
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4)

source = ColumnDataSource(data={'x':x,'y':y, 'X': x, 'cos':y,'sin':z})


code="""
        var data = source.get('data');
        var r = data[cb_obj.get('value')];
        var {var} = data[cb_obj.get('value')];
        //window.alert( "{var} " + cb_obj.get('value') + {var}  );
        for (i = 0; i < r.length; i++) {{
            {var}[i] = r[i] ;
            data['{var}'][i] = r[i];
        }}
        source.trigger('change');
    """

callbackx = CustomJS(args=dict(source=source), code=code.format(var="x"))
callbacky = CustomJS(args=dict(source=source), code=code.format(var="y"))

# create a new plot 
plot = Figure(title=None)

# Make a line and connect to data source
plot.line(x="x", y="y", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source)


# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                           options=['X','cos','sin'], callback=callbacky)


xaxis_select = Select(title="X axis:", value="x",
                           options=['X','cos','sin'], callback=callbackx)


# Text input as a title
text = TextInput(title="title", value='my sine wave plotter')

# Layout widgets next to the plot                     
controls = VBox(text,yaxis_select,xaxis_select)

layout = HBox(controls,plot,width=800)

bokeh.io.show(layout)

However, I tinkered it together until it did what it should. And I am not sure why the part in the CustomJS-code needs to be so complicated.

Especially it seems that both lines inside the for-loop in the JS-part are actually needed, although they seem to do the same thing.

Thus I wouldn't call this question answered until someone can actually come up with something that is explainable.

ImportanceOfBeingErnest
  • 321,279
  • 53
  • 665
  • 712
  • I was hoping that I wouldn't need to get my hands dirty with Javascript. I would prefer to stay in Python if possible. However this seems to work and gets me over a roadblock. Thanks. – Redlegjed Jul 01 '16 at 11:26
1

I could not get the above answers working on Bokeh 2.02. After some modifications to the answers resulted in the following code which works on BOKEH 2.02.

You can also try out "Run Code Snippet" at the bottom of the page to see this example in action.

import numpy as np

from bokeh.models import ColumnDataSource
from bokeh.plotting import Figure

from bokeh.models.widgets import Select,TextInput
from bokeh.models.layouts import Column, Row
import bokeh.io 
from bokeh.models import CustomJS

N = 200

# Define the data to be used
x = np.linspace(0,4.*np.pi,N)
y = 3*np.cos(2*np.pi*x + np.pi*0.2)
z = 0.5*np.sin(2*np.pi*0.8*x + np.pi*0.4)

source = ColumnDataSource(data={'x':x,'y':y, 'X': x, 'cos':y,'sin':z})


code="""
        var column = cb_obj.value;
        line.glyph.{var}.field = column;
        source.change.emit();
    """

# create a new plot 
plot = Figure(title=None)

# Make a line and connect to data source
line = plot.line(x="x", y="y", line_color="#F46D43", line_width=6, line_alpha=0.6, source=source)

#Make a callbacks
callbackx = CustomJS(args=dict(source=source, line=line), code=code.format(var="x"))
callbacky = CustomJS(args=dict(source=source, line =line), code=code.format(var="y"))


# Add list boxes for selecting which columns to plot on the x and y axis
yaxis_select = Select(title="Y axis:", value="cos",
                           options=['X','cos','sin'])
yaxis_select.js_on_change('value', callbacky)


xaxis_select = Select(title="X axis:", value="x",
                           options=['X','cos','sin'])
xaxis_select.js_on_change('value', callbackx)


# Text input as a title
text = TextInput(title="title", value='my sine wave plotter for Bokeh 2.02')

# Layout widgets next to the plot                     
controls = Row(text,yaxis_select,xaxis_select)

layout = Column(controls,plot,width=800)

bokeh.io.show(layout)

# Generate standlone html documents to put into stackoverflow "RUN SNIPPET" 

#from bokeh.resources import CDN
#from bokeh.embed import file_html

#with open('callbacks_example.html','w') as f:
    #f.write(file_html(layout, CDN))
# Copy and pas the html contents into stackover flow

<!DOCTYPE html>
<html lang="en">

<head>

  <meta charset="utf-8">
  <title>Bokeh Application</title>

  <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-2.0.1.min.js" integrity="sha384-JpP8FXbgAZLkfur7LiK3j9AGBhHNIvF742meBJrjO2ShJDhCG2I1uVvW+0DUtrmc" crossorigin="anonymous"></script>
  <script type="text/javascript" src="https://cdn.bokeh.org/bokeh/release/bokeh-widgets-2.0.1.min.js" integrity="sha384-xZlADit0Q04ISQEdKg2k3L4W9AwQBAuDs9nJL9fM/WwzL1tEU9VPNezOFX0nLEAz" crossorigin="anonymous"></script>
  <script type="text/javascript">
    Bokeh.set_log_level("info");
  </script>
</head>


<body>
  <div class="bk-root" id="9f731289-378a-4669-8d6f-c89fab0041df" data-root-id="22440"></div>
  <script type="application/json" id="22529">
    {
      "c6047a88-1e40-473b-81b7-34ea9c8699eb": {
        "roots": {
          "references": [{
            "attributes": {},
            "id": "22415",
            "type": "PanTool"
          }, {
            "attributes": {
              "line_alpha": 0.1,
              "line_color": "#F46D43",
              "line_width": 6,
              "x": {
                "field": "x"
              },
              "y": {
                "field": "y"
              }
            },
            "id": "22431",
            "type": "Line"
          }, {
            "attributes": {},
            "id": "22445",
            "type": "BasicTickFormatter"
          }, {
            "attributes": {},
            "id": "22443",
            "type": "BasicTickFormatter"
          }, {
            "attributes": {
              "children": [{
                "id": "22439"
              }, {
                "id": "22397"
              }],
              "width": 800
            },
            "id": "22440",
            "type": "Column"
          }, {
            "attributes": {
              "title": "title",
              "value": "my sine wave plotter for Bokeh 2.02"
            },
            "id": "22438",
            "type": "TextInput"
          }, {
            "attributes": {
              "args": {
                "line": {
                  "id": "22432"
                },
                "source": {
                  "id": "22396"
                }
              },
              "code": "\n        var column = cb_obj.value;\n        line.glyph.x.field = column;\n        source.change.emit();\n    "
            },
            "id": "22434",
            "type": "CustomJS"
          }, {
            "attributes": {
              "children": [{
                "id": "22438"
              }, {
                "id": "22436"
              }, {
                "id": "22437"
              }]
            },
            "id": "22439",
            "type": "Row"
          }, {
            "attributes": {
              "axis": {
                "id": "22411"
              },
              "dimension": 1,
              "ticker": null
            },
            "id": "22414",
            "type": "Grid"
          }, {
            "attributes": {
              "source": {
                "id": "22396"
              }
            },
            "id": "22433",
            "type": "CDSView"
          }, {
            "attributes": {
              "formatter": {
                "id": "22443"
              },
              "ticker": {
                "id": "22412"
              }
            },
            "id": "22411",
            "type": "LinearAxis"
          }, {
            "attributes": {
              "js_property_callbacks": {
                "change:value": [{
                  "id": "22434"
                }]
              },
              "options": ["X", "cos", "sin"],
              "title": "X axis:",
              "value": "x"
            },
            "id": "22437",
            "type": "Select"
          }, {
            "attributes": {
              "args": {
                "line": {
                  "id": "22432"
                },
                "source": {
                  "id": "22396"
                }
              },
              "code": "\n        var column = cb_obj.value;\n        line.glyph.y.field = column;\n        source.change.emit();\n    "
            },
            "id": "22435",
            "type": "CustomJS"
          }, {
            "attributes": {
              "bottom_units": "screen",
              "fill_alpha": 0.5,
              "fill_color": "lightgrey",
              "left_units": "screen",
              "level": "overlay",
              "line_alpha": 1.0,
              "line_color": "black",
              "line_dash": [4, 4],
              "line_width": 2,
              "render_mode": "css",
              "right_units": "screen",
              "top_units": "screen"
            },
            "id": "22421",
            "type": "BoxAnnotation"
          }, {
            "attributes": {},
            "id": "22447",
            "type": "UnionRenderers"
          }, {
            "attributes": {},
            "id": "22418",
            "type": "SaveTool"
          }, {
            "attributes": {
              "active_drag": "auto",
              "active_inspect": "auto",
              "active_multi": null,
              "active_scroll": "auto",
              "active_tap": "auto",
              "tools": [{
                "id": "22415"
              }, {
                "id": "22416"
              }, {
                "id": "22417"
              }, {
                "id": "22418"
              }, {
                "id": "22419"
              }, {
                "id": "22420"
              }]
            },
            "id": "22422",
            "type": "Toolbar"
          }, {
            "attributes": {
              "overlay": {
                "id": "22421"
              }
            },
            "id": "22417",
            "type": "BoxZoomTool"
          }, {
            "attributes": {
              "below": [{
                "id": "22407"
              }],
              "center": [{
                "id": "22410"
              }, {
                "id": "22414"
              }],
              "left": [{
                "id": "22411"
              }],
              "renderers": [{
                "id": "22432"
              }],
              "title": null,
              "toolbar": {
                "id": "22422"
              },
              "x_range": {
                "id": "22399"
              },
              "x_scale": {
                "id": "22403"
              },
              "y_range": {
                "id": "22401"
              },
              "y_scale": {
                "id": "22405"
              }
            },
            "id": "22397",
            "subtype": "Figure",
            "type": "Plot"
          }, {
            "attributes": {},
            "id": "22405",
            "type": "LinearScale"
          }, {
            "attributes": {},
            "id": "22412",
            "type": "BasicTicker"
          }, {
            "attributes": {},
            "id": "22403",
            "type": "LinearScale"
          }, {
            "attributes": {},
            "id": "22416",
            "type": "WheelZoomTool"
          }, {
            "attributes": {},
            "id": "22419",
            "type": "ResetTool"
          }, {
            "attributes": {},
            "id": "22401",
            "type": "DataRange1d"
          }, {
            "attributes": {},
            "id": "22448",
            "type": "Selection"
          }, {
            "attributes": {
              "axis": {
                "id": "22407"
              },
              "ticker": null
            },
            "id": "22410",
            "type": "Grid"
          }, {
            "attributes": {
              "data_source": {
                "id": "22396"
              },
              "glyph": {
                "id": "22430"
              },
              "hover_glyph": null,
              "muted_glyph": null,
              "nonselection_glyph": {
                "id": "22431"
              },
              "selection_glyph": null,
              "view": {
                "id": "22433"
              }
            },
            "id": "22432",
            "type": "GlyphRenderer"
          }, {
            "attributes": {
              "line_alpha": 0.6,
              "line_color": "#F46D43",
              "line_width": 6,
              "x": {
                "field": "x"
              },
              "y": {
                "field": "y"
              }
            },
            "id": "22430",
            "type": "Line"
          }, {
            "attributes": {
              "data": {
                "X": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                },
                "cos": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                },
                "sin": {
                  "__ndarray__": "/1REEw5v3j8wEKrj9P/fP0LD681oXt4/l0KvSCG02T/kEcwBcHjSP0+unSuqyMI/IUzHMZT/g788VxTWpCjFv4w2R18SetO/UGX1Qatt2r9pP2frUL3ev5/42L+/+t+/6jxr30AG3r8YJNdL1RHZvx7iavk2nNG/uO5SJF/IwL+6HIEOdKeaP2uS/gIFHcc/nh2Z9PhK1D8YHohaaQDbP5Ls6lc9A98/1Js5F97s3z83RGIs9KXdP1clIpS8aNg/kLXnKTe70D919cCWDYe9PwpZXaLxo6W/Z11mSyALyb8SjkR9XhbVv7y01pLUi9u/SY6eYcBA379v0qqtU9bfv8nBctOcPd2/IoPn/gS5178wo300W6vPv0OjkqBadbm/2lB9n0rurT8hiKaqcPLKP2UATM4L3NU/AKM7GscP3D/7PWNZyXXfP2BXTaAmt98/aVOeIVfN3D+YqzI13gLXP+XwDhmx180/P6Q68b9ctT8qcPKrQhizv75mwPNx0sy/9ujWScub1r8Cd9omHYzcv+10stxJot+/JUTbY1+P37/aNZmKQVXcv+Pp1Z55Rta/tu8h2u77y7/m2E/zWT6xv+FBRSwyNLc/t4o19aGqzj9XoLztaFXXP83TVP+0AN0/Ld+E2TXG3z9m61zCCF/fP4jQh6B81ds/ceMDVQqE1T/3ql2ClRjKP9I8d0eNNqo/GlLQftZJu78c6itOQD3Qvw6hn2GyCNi/LBnwA29t3b/deZiRg+Hfv0yxO9gvJt+/fyApCytO27+IiXMUxbvUv3qFcSsoLsi/iQpQiErpob/vMq4GFFi/P94jAwzIINE/u0iVBHe12D/aOCm3LdLdP8EZFZ0r9N8/j6yzEOTk3j+yaHB+cb/aP89BEi/g7dM/Xy2G2is9xj+L11c0WC6TP2DXc5TorsG/v59mfar/0b+6Z1b6h1vZv+5jtMXVLt6/oKKO7Cj+379lB6UhN5vev/2ykLB2Kdq/ISZIfZMa07/HQSlcJ0bEv2gxDPY7J2S/w6BqTPuswz9OWTAuq9nSPxUL9Te4+tk/cWbmDU6D3j/TY2TKeP/fP7FCxgY9Sd4/htZ8T2OM2T+qWtJOGELSP0d2vR+jScI/83NyRHBKjL/HOvDRt6XFv7u/M/2OrtO/+g4UkNyS2r/arYWmf8/ev9A6fdsa+N+/wag4/Avv3b/12971YejYv9eXN1upZNG/HRl5EilIwL+LGD2RgcueP1xJSD6VmMc/C2tHLBx+1D8hKZ2+yyPbPwghAeVVE98/o0hgHxHo3z8RaIB4vIzdP8W8iR+fPdg/2R3bsYKC0D8xF/rziIS8P2Ybq124tKe/LShnQgyFyb+zhe5vGkjVv0I98nNerdu/rRoLY75O37+MM6rvX8/fv/j44SVpIt2/n6JoHUmM17/LxGRTwzfPvxucHJ0Dcbi/SnvE6EH9rz8uLaVLl2rLP7Ssnf5SDNY/ZvSWX28v3D9gAJcDqYHfP7sa3/4Nrt8/Qpsm2y6w3D/P5+4IkNTWPynOQ6EJYs0/NsX4Kd1WtD+rYHEgjx60v3ph+aeySM2/kCGXn5DK1r80sE8626ncv60cOPcHrN+/do2ZViSE37+C4MmTLDbcv0hIDLelFta/znMLtVeEy79zqX1wMjewvyVJuksIObg/V+Kxqdwezz9FRVq5n4LXP8Ecs8+AHN0/yovgv8/N3z9sBBdVrlHfPyNkkmeDtNs/vsSoqr1S1T//b9QfL5/JP1ZiUYtDJqg/SjPeie9MvL/NGFDlSnbQv650ol9ONNi/dckrB0GH3b/vNv8z9+bfvz6HIqq5Ft+/9veXgVYr27/96KsGDYnUv/SM83gTs8e/46hvvyqvn78qDljblCzAP4r3V2ewWNE/DnfxYGzf2D+DVWfs/undP9EG/IB3998/2FNeU1bT3j9ds7kWy5raPwk9k3/KudM/3INIOorAxT+FPgzHbBKOP5xzgOFOLsK/yU/vcmE20r9O1KFTy4PZv4znMLefRN6/eJ8RLUz/378hiu2Xlofev+18hlsIA9q/IcibTC7l0r/4/AmcGsjDvy4ykxMgDVo/9nNtgBorxD8ZnsXmIQ/TP6CIfaI+Ido/58+00gqX3j+xJYQYc/7fPw==",
                  "dtype": "float64",
                  "shape": [200]
                },
                "x": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                },
                "y": {
                  "__ndarray__": "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",
                  "dtype": "float64",
                  "shape": [200]
                }
              },
              "selected": {
                "id": "22448"
              },
              "selection_policy": {
                "id": "22447"
              }
            },
            "id": "22396",
            "type": "ColumnDataSource"
          }, {
            "attributes": {},
            "id": "22399",
            "type": "DataRange1d"
          }, {
            "attributes": {},
            "id": "22408",
            "type": "BasicTicker"
          }, {
            "attributes": {},
            "id": "22420",
            "type": "HelpTool"
          }, {
            "attributes": {
              "js_property_callbacks": {
                "change:value": [{
                  "id": "22435"
                }]
              },
              "options": ["X", "cos", "sin"],
              "title": "Y axis:",
              "value": "cos"
            },
            "id": "22436",
            "type": "Select"
          }, {
            "attributes": {
              "formatter": {
                "id": "22445"
              },
              "ticker": {
                "id": "22408"
              }
            },
            "id": "22407",
            "type": "LinearAxis"
          }],
          "root_ids": ["22440"]
        },
        "title": "Bokeh Application",
        "version": "2.0.1"
      }
    }
  </script>
  <script type="text/javascript">
    (function() {
      var fn = function() {
        Bokeh.safely(function() {
          (function(root) {
            function embed_document(root) {

              var docs_json = document.getElementById('22529').textContent;
              var render_items = [{
                "docid": "c6047a88-1e40-473b-81b7-34ea9c8699eb",
                "root_ids": ["22440"],
                "roots": {
                  "22440": "9f731289-378a-4669-8d6f-c89fab0041df"
                }
              }];
              root.Bokeh.embed.embed_items(docs_json, render_items);

            }
            if (root.Bokeh !== undefined) {
              embed_document(root);
            } else {
              var attempts = 0;
              var timer = setInterval(function(root) {
                if (root.Bokeh !== undefined) {
                  clearInterval(timer);
                  embed_document(root);
                } else {
                  attempts++;
                  if (attempts > 100) {
                    clearInterval(timer);
                    console.log("Bokeh: ERROR: Unable to run BokehJS code because BokehJS library is missing");
                  }
                }
              }, 10, root)
            }
          })(window);
        });
      };
      if (document.readyState != "loading") fn();
      else document.addEventListener("DOMContentLoaded", fn);
    })();
  </script>

</body>

</html>
plasmon360
  • 4,109
  • 1
  • 16
  • 19