Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

updating the underlying data does not change the plots and charts on the web page #60

Open
m2ai opened this issue Sep 7, 2017 · 4 comments

Comments

@m2ai
Copy link

m2ai commented Sep 7, 2017

hello,
i try to use pyxley in a production environment but i found that when i change the underlying data the plots and charts in the web page don't get affected with these data changes.
i follow all the instructions in this url:
http://pyxley.readthedocs.io/en/latest/production.html
but it doesn't solve the problem.
this is the code for the metrics graphics example after i modified it as mentioned in the above link

def create_line_plot(df):
""" create a mg line plot

    Args:
        df (pandas.DataFrame): data to plot
"""
fig = Figure("/mg/line_plot/", "mg_line_plot")
fig.graphics.transition_on_update(True)
fig.graphics.animate_on_load()
fig.layout.set_size(width=450, height=200)
fig.layout.set_margin(left=40, right=40)
myData = MyDataWrapper(df, "Date", ["value"])
lc = LineChart(df, fig, "Date", ["value"], route_func=myData.my_route_function,timeseries=True)
return lc
print ("after rtuuuuuurn")

#return LineChart(df, fig, "Date", ["value"],init_params={"Data": "Steps"}, timeseries=True)

def create_histogram(df):
""" create a mg line plot

    Args:
        df (pandas.DataFrame): data to plot
"""
fig = Figure("/mg/histogram/", "mg_histogram")
fig.layout.set_size(width=450, height=200)
fig.layout.set_margin(left=40, right=40)
fig.graphics.animate_on_load()

# Make a histogram with 20 bins
return Histogram(df, fig, "value", 20, init_params={"Data": "Steps"})

def create_scatterplot(df):
""" create a mg line plot

    Args:
        df (pandas.DataFrame): data to plot
"""
fig = Figure("/mg/scatter/", "mg_scatter")
fig.layout.set_size(width=450, height=200)
fig.layout.set_margin(left=40, right=40)
fig.graphics.animate_on_load()

init_params = {"Data": "Steps"}

def get_data():
    y = request.args.get("Data", "Steps")
    return jsonify(ScatterPlot.to_json(df, "Steps", y))

# Make a histogram with 20 bins
return ScatterPlot(df, fig, "Steps", "Distance",
    init_params={}, route_func=get_data)

def make_mg_layout(filename):
# load a dataframe
df = pd.read_csv(filename)
#global lc
# Make a UI
ui = UILayout("FilterChart")

# Make a Button
cols = [c for c in df.columns if c != "Date"]
btn = SelectButton("Data", cols, "Data", "Steps")


# add the button to the UI
ui.add_filter(btn)

# stack the dataframe
_stack = df.set_index("Date").stack().reset_index()
_stack = _stack.rename(columns={"level_1": "Data", 0: "value"})

# Make a Figure, add some settings, make a line plot
ui.add_chart(create_line_plot(_stack))
ui.add_chart(create_histogram(_stack))
ui.add_chart(create_scatterplot(df))

return ui

def get_layouts(mod, filename):

# metrics graphics
print ('hiiiiiiiiiiiiii')
print ('wiiiiiiiiii')
mg_ui = make_mg_layout(filename)
mg_ui.assign_routes(mod)
mg_props = mg_ui.build_props()

_layouts = OrderedDict()
_layouts["mg"] = {"layout": [mg_props], "title": "metrics-graphics"}

register_layouts(_layouts, mod)
del mg_ui

class MyDataWrapper(object):

""" We are building a simple wrapper for our data """
def __init__(self,df, x, y, timeseries=True):

    self.df = df
    self.x = x
    self.y = y
    self.timeseries = timeseries

def my_route_function(self):

    # put args check here 
    args = {}
    init_params = {"Data": "Steps"}
    for c in init_params:

        if request.args.get(c):
            args[c] = request.args[c]
        else:
            args[c] = init_params[c]

    return jsonify(LineChart.to_json(Chart.apply_filters(self.df, args), self.x, self.y, timeseries=self.timeseries))

Plz if somebody can help me to solve this problem i will appreciate it a lot

@nmkridler
Copy link
Contributor

I suspect the problem is that the chart objects only get built once, so when you include MyDataWrapper in the chart functions, your data is never actually updated. If you make MyDataWrapper an argument of create_line_plot and pass it in, then you can update df outside of the make_mg_layout and it should work.

So what I would do is remove the df and _stack dataframes from make_mg_layout and make them arguments. Or even better, make your MyDataWrapper object as an argument and only pass that in. Then when you pass the MyDataWrapper.my_route_function as a keyword argument to LineChart you can manipulate that object outside the scope of that function. Then you can update it where ever or when ever you want.

@m2ai
Copy link
Author

m2ai commented Sep 8, 2017

Dear nmkridler, thank you very much for your great help. but after i changed the code as you told me i tried it and i found the same problem ( changing the underlying data in (fitbit_data.csv file) don't affect the line plot after refreshing the web page. So, plz help me again.
this is my last code after changing it :

def create_line_plot(mydata):
""" create a mg line plot

    Args:
        df (pandas.DataFrame): data to plot
"""
fig = Figure("/mg/line_plot/", "mg_line_plot")
fig.graphics.transition_on_update(True)
fig.graphics.animate_on_load()
fig.layout.set_size(width=450, height=200)
fig.layout.set_margin(left=40, right=40)
return LineChart(mydata.df, fig, "Date", ["value"], route_func=mydata.my_route_function,timeseries=True)

# return LineChart(df, fig, "Date", ["value"],init_params={"Data": "Steps"}, timeseries=True)

def create_histogram(df):
""" create a mg line plot

    Args:
        df (pandas.DataFrame): data to plot
"""
fig = Figure("/mg/histogram/", "mg_histogram")
fig.layout.set_size(width=450, height=200)
fig.layout.set_margin(left=40, right=40)
fig.graphics.animate_on_load()

# Make a histogram with 20 bins
return Histogram(df, fig, "value", 20, init_params={"Data": "Steps"})

def create_scatterplot(df):
""" create a mg line plot

    Args:
        df (pandas.DataFrame): data to plot
"""
fig = Figure("/mg/scatter/", "mg_scatter")
fig.layout.set_size(width=450, height=200)
fig.layout.set_margin(left=40, right=40)
fig.graphics.animate_on_load()

init_params = {"Data": "Steps"}

def get_data():
    y = request.args.get("Data", "Steps")
    return jsonify(ScatterPlot.to_json(df, "Steps", y))

# Make a histogram with 20 bins
return ScatterPlot(df, fig, "Steps", "Distance",
    init_params={}, route_func=get_data)

def make_mg_layout(filename):

# load a dataframe
df = pd.read_csv(filename)
# Make a UI
ui = UILayout("FilterChart")

# Make a Button
cols = [c for c in df.columns if c != "Date"]
btn = SelectButton("Data", cols, "Data", "Steps")

# add the button to the UI
ui.add_filter(btn)

# stack the dataframe
_stack = df.set_index("Date").stack().reset_index()
_stack = _stack.rename(columns={"level_1": "Data", 0: "value"})

# Make a Figure, add some settings, make a line plot
ui.add_chart(create_line_plot(MyDataWrapper(_stack, "Date", ["value"])))
# ui.add_chart(create_line_plot(_stack))
ui.add_chart(create_histogram(_stack))
ui.add_chart(create_scatterplot(df))

return ui

def get_layouts(mod, filename):

# metrics graphics
print ('hiiiiiiiiiiiiii')
print ('wiiiiiiiiii')
mg_ui = make_mg_layout(filename)
mg_ui.assign_routes(mod)
mg_props = mg_ui.build_props()

_layouts = OrderedDict()
_layouts["mg"] = {"layout": [mg_props], "title": "metrics-graphics"}

register_layouts(_layouts, mod)
del mg_ui

class MyDataWrapper(object):

""" We are building a simple wrapper for our data """
def __init__(self,df, x, y, timeseries=True):

    self.df = df
    self.x = x
    self.y = y
    self.timeseries = timeseries

def my_route_function(self):

    # put args check here
    args = {}
    init_params = {"Data": "Steps"}
    for c in init_params:

        if request.args.get(c):
            args[c] = request.args[c]
        else:
            args[c] = init_params[c]

    return jsonify(LineChart.to_json(Chart.apply_filters(self.df, args), self.x, self.y, timeseries=self.timeseries))

@nmkridler
Copy link
Contributor

In your code it doesn't look like the application has any way to know that the data has changed. get_layouts gets called once once the application starts, so changing the data after the application starts won't do anything. You need to have a way to update MyDataWrapper at some point. One option is to put it in the same scope as the flask app and then have some event that triggers a reload. Unfortunately I don't have a good example that does this. In all of my production applications, I connect to a database and the route_funcs I supply all call the database.

@m2ai
Copy link
Author

m2ai commented Sep 8, 2017

okay fine...Please, could u send me a code example for an application that get the data from a database?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants