Dash callback not producing multiple outputs - plotly-dash

I'm trying to do the following in one single callback:
route the user to the right layout (page_1_layout or page_2_layout) depending on the URL
at the same time, update a dataframe and the relevant graph according to the URL (the idea is that the URL parameter will help filtering the dataframe and generate the related visualization).
According to the Dash documentations, callbacks can produce multiple outputs. In this case, I'm trying to generate the right layout (output #1) and update the graph (output #2).
I've tried also using the dataframe as output but that would require the dataframe to be global.
Here's the layout code:
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
index_page = html.Div([
dcc.Link('Go to Page 1', href='/CA'),
html.Br(),
dcc.Link('Go to Page 2', href='/WY'),
])
page_1_layout = html.Div([
html.H1('Page 1'),
html.Div(id='page-1-content'),
dcc.Graph(id='graph-output'),
html.Br(),
dcc.Link('Go to Page 2', href='/WY'),
html.Br(),
dcc.Link('Go back to home', href='/'),
])
Here's the callback code:
#app.callback(Output('page-content', 'children'), Output('graph-output', 'figure'), [Input('url', 'pathname')])
def display_page(pathname):
pathname = str(pathname)
if pathname.startswith('/CA'):
country = pathname.split('/')[-1]
print(country)
dff = df.loc[df['state'] == country.lower()]
print(dff)
fig = px.pie(dff, values='median_listing_price', names="state", title="xxx")
return page_1_layout, fig
elif pathname == '/WY':
country = pathname.split('/')[-1]
print(country)
dff = df.loc[df['state'] == country.lower()]
print(dff)
return page_2_layout, fig
else:
return index_page, fig
This is the error message:
A nonexistent object was used in an Output of a Dash callback. The id >of this object is graph-output and the property is figure. The string >ids in the current layout are: [url, page-content]
I've specified the additional output in the callback, so I'm wondering why it is not recognising it?

The problem is that the graph-output component does not exist before the page layout is rendered. One solution to the problem would be to render the graph as part of the layout, i.e. something like this,
def render_graph():
# Put your graph logic here.
return dcc.Graph(id='graph-output')
def page_1_layout():
return html.Div([
html.H1('Page 1'),
html.Div(id='page-1-content'),
render_graph(),
html.Br(),
dcc.Link('Go to Page 2', href='/WY'),
html.Br(),
dcc.Link('Go back to home', href='/'),
])

Related

Django how to assign a function for sending emails from to an HTML button

I am new to django and i would like to know how i can give the function "Initial_Report(request):" to an html button so that every time is clicked it performs the given function.
Views code
def home(request):
return render(request, 'home.html')
def Initial_Report(request):
noc_emails = Employee.objects.exclude(Position__Position__contains='Customer').values_list('Email', flat=True)
cs_emails = Employee.objects.filter(Position__Position__contains = 'Customer').values_list('Email', flat=True)
noc_message = ('Initial Outage Report', 'This is a new outage report ,The information is in the document', 'from#example.com', noc_emails)
cs_message = ('Initial Outage Report', 'This is a new outage report ,The information is in the document', 'from#example.com', cs_emails)
send_mass_mail((noc_message,cs_message), fail_silently=False)
return render(request,'InitialReport.html')
Urls
urlpatterns = [
path('', views.home, name='home.html'),
path('admin/', admin.site.urls),
path('Initial_Report', views.Initial_Report, name = 'Initial_Report' ),
]
Home.html
<button> Send Initial Report</button>
since Initial_Report is called when /Initial_Report is triggered
path('Initial_Report', views.Initial_Report, name = 'Initial_Report' ),
You can add a link to the path
Send Initial Report

Creating a function using value_counts in a for loop

I am attempting to create a function that calls on the value_counts function for every variable in the list that I pass through it. Admittedly, I have no idea what I am doing and have oversimplified "hello world" tutorials as an example. My sample code is attached. Thank you for your help.
data1.columns = ['Year', 'Rank', 'Company', 'Revenue', 'Profit']
def vc(*args):
for x in args:
value_counts()
return
vc(['Year', 'Rank', 'Company', 'Revenue', 'Profit'])
I have also tried
def vc(args):
for x in args:
value_counts(x)
return
vc(['Year', 'Rank', 'Company', 'Revenue', 'Profit'])
I get an error stating that value_counts is not defined.
You're not passing x to value_counts.
for x in args:
value_counts()
should be
for x in args:
value_counts(x)
Also, vc takes *args param, which means you don't need to give it a list. You can call with vc('Year', 'Rank', 'Company', 'Revenue', 'Profit'), and when you reference args inside vc you will get a list. You can call vc with a list like you are doing now, but you would change the def vc(*args) definition to vc(args) so that everything matches up.
Does this help?

Build dropdown from database table names

I have this application where I want to deploy some web interface to a syslog server.
So the syslogserver does write his stuff into a mysql database. I already have build
some parts for the application except for this specific part where I want to build a dropdown select form, to select the hosttables inside the database.
Actually I am using flask, flask-sqlalchemy and wtforms. So I tried to implement this over the 'QuerySelectField', somehow I only get a dropdown with no table name entries shown.
I should mention that the tables inside the database itself are created on the fly. For my model I used the automap_base() Feature from sqlalchemy:
model.py
Base = automap_base()
engine = create_engine("mysql://sumuser:tehpass#127.0.0.1/syslog")
Base.prepare(engine, reflect=True)
session = Session(engine)
This is whats inside my forms:
forms.py
def factoryHelper():
return session.query("information_schema.tables.table_name from information_schema.tables where information_schema.tables.table_name like 'messages_hostname0'")
class HostSelectForm(Form):
title = TextField('Fooblah')
hostTables = QuerySelectField(query_factory=factoryHelper,allow_blank=True)
and this inside the views:
views.py
#app.route('/index/', defaults={'page':1})
#app.route('/index/page/<int:page>')
def index(page):
form = HostSelectForm()
count = session.execute("select host,facility,level,msg from messages_hostname0").rowcount
pagination = Pagination(page, PER_PAGE, count)
return render_template('index.html', pagination=pagination, form=form)
So is there anyway I can create a dropdown menu from dynamically created table names? Also if I use the automap feature? Thanks in advance.
Somehow i managed to solve this issue with this in the model.py:
def reflectTables():
for i in Base.classes.items():
yield i[0]
def stripTables():
tablelist = []
datelist = []
re0 = r"^(?P<prefix>[a-zA-Z]*)\_(?P<mid>[a-zA-Z,0-9]*)\_(?P<suffix>[0-9]*)"
myre = re.compile(re0, re.MULTILINE)
for x,table in enumerate(reflectTables()):
striptablename = re.match(myre, table.strip("\n"))
if striptablename:
tablelist.append((x, striptablename.group(2)))
datelist.append((x, striptablename.group(3)))
return dicht(tablelist,datelist)
the forms.py:
AVAILABLE_CHOICES = stripTables()
class HostSelectForm(Form):
tableSelect = SelectField('LogHost', choices=AVAILABLE_CHOICES, default=0)
and finnaly inside the views.py:
if request.method == "GET":
count = session.query("* from mytable_monitory_counts")
items = session.execute("select * from mytable_%s_%s limit %s, %s" % \
(tableslector[int(request.values['tableSelect'])][1],\
datelist[int(request.values['tableSelect'])][1], my_start_range, PER_PAGE)).fetchall()
pagination = Pagination(page=page, total=count.count(), search=search, record_name='hosts')
if not items and page != 1:
in_error()
return render_template('index.html', pagination=pagination, form=form, items=items)

Ruby - Scraping HTML : If url does not exist then skip to next

I am currently working on a html scraper that takes a list of anime-planet url's from a text file and then loops through them, parses and stores the data in a database.
The scraper is working nicely however if I put in a large list then the chances of the url not linking to a series properly and throwing an error is quite high. I want to try make it so that IF the url does not work then it notes down the url in an array named 'error-urls' and just skips the record.
The end result being that the script finishes all working url's and returns a list of non working urls i can work with later (maybe in a text file, or just display in console).
I am currently using a rake task for this which is working quite nicely. If anyone could help me with implementing the error handling functionality it would be much appreciated. Cheers!
scrape.rake:
task :scrape => :environment do
require 'nokogiri'
require 'open-uri'
text = []
File.read("text.txt").each_line do |line|
text << line.chop
end
text.each do |series|
url = "http://www.anime-planet.com/anime/" + series
data = Nokogiri::HTML(open(url))
title = data.at_css('.theme').text
synopsis = data.at_css('.synopsis').text.strip
synopsis.slice! "Synopsis:\r\n\t\t\t\t\t"
eps = data.at_css('.type').text
year = data.at_css('.year').text
rating = data.at_css('.avgRating').text
categories = data.at_css('.categories')
genre = categories.css('li').text.to_s
image = data.at_css('#screenshots img')
imagePath = "http://www.anime-planet.com" + image['src']
anime = Series.create({:title => title, :image => imagePath, :description => synopsis, :eps => eps, :year => year, :rating => rating})
anime.tag_list = genre
anime.save()
end
end
Small example of list.txt
5-Centimeters-Per-Second
11Eyes
A-Channel
Air
Air-Gear
Aishiteru-Ze-Baby
You can use open-uri's error handling. See this for more details.
url = "http://www.anime-planet.com/anime/" + series
begin
doc = open(url)
rescue OpenURI::HTTPError => http_error
# bad status code returned
// do something here
status = http_error.io.status[0].to_i # => 3xx, 4xx, or 5xx
puts "Got a bad status code #{status}"
# http_error.message is the numeric code and text in a string
end
data = Nokogiri::HTML(doc)

Passing Django forms' result to a page

I have worked on this for sometime now and I have decided to seek for your help. I have an ongoing project and I am using the django framework to build the site.
I have an html page that requests for user input, I have been able to extract the given data using the form.cleaned_data['']. A
#This is my views.py;
from django.shortcuts import render_to_response
from django.template import RequestContext
from forms import CarloanForm
def index(request):
form = CarloanForm()
if request.POST:
form = CarloanForm(request.POST)
if form.is_valid():
form.save()
else:
form = CarloanForm()
return render_to_response('carloan/index.html', {'form': form},
context_instance=RequestContext(request))
#I am extracting the user inputs using;
amount_of_vehicle = form.cleaned_data['cost_of_vehicle_Naira']
tenure = form.cleaned_data['loan_repayment_tenure_Months']
interest_rate = form.cleaned_data['interest_rate_Percentage']
equity = form.cleaned_data['equity_contrib_rate_Percentage']
depreciation_rate = form.cleaned_data['depreciation_rate_Percentage']
What I need to do and don't know how to go about it are;
Carry out some operations on the data (extracted using form.cleaned_data['']) and I have written some lines of code to that effect;
class LoanCalc:
def __init__(self,amount_of_vehicle,tenure,interest_rate,equity,depreciation_rate):
self.amount_of_vehicle = float(amount_of_vehicle)
self.tenure = float(tenure)
self.interest_rate = float(interest_rate)
self.equity = float(equity)
self.depreciation_rate = float(depreciation_rate)
def interest(self):
return (self.interest_rate/100) * self.amount_of_vehicle *(self.tenure/12)
def management_fee(self):
return 0.01 * (self.amount_of_vehicle + user.interest())
def processing_fee(self):
return 0.0025 *(self.amount_of_vehicle + user.interest())
def legal_fee(self):
return 0.0075 * (self.amount_of_vehicle + user.interest())
def residual_amount(self):
return 0.01 * (self.amount_of_vehicle - ((self.depreciation_rate/100) * self.amount_of_vehicle *(self.tenure/12)))
def equity_contribution(self):
return (self.equity/100) * self.amount_of_vehicle
def LoanPaymentPlan(self):
months = 1
total_amount = self.amount_of_vehicle+user.interest()+user.management_fee()+user.processing_fee()+user.legal_fee()+user.residual_amount()
upfront_payment = user.management_fee()+user.processing_fee()+user.legal_fee()+user.equity_contribution()+user.residual_amount()
opening_balance = total_amount - upfront_payment
balance = opening_balance
while months <= self.tenure:
if balance > 0:
monthly_instalment =(opening_balance/self.tenure)
monthly_interest = (((self.interest_rate/100) * balance)/ 12)
loan_payment = monthly_instalment - monthly_interest
closing_balance = balance - monthly_instalment
print' ',months,' ',round(balance,2),' ', round(monthly_instalment,2),' ',round(monthly_interest,2) \
, ' ',' ',round(loan_payment,2),' ',round(closing_balance,2)
balance = closing_balance
months += 1
return 'Thank you for using the Loan Calculator App'
and i want to carry out the operations in the code above on the extracted data.
I am thinking of doing it in such a way like this;
Create an empty dictionary;
user = {}
user = LoanCalc(amount_of_vehicle,tenure,interest_rate,equity,depreciation_rate)
result= user.interest()
result1 = user.management_fee()
. .
. .
. .
result10 = user.LoanPaymentPlan()
Pass the result(s) obtained from (question 2) to the same template that generated the form.
Please help me out guys, i am still very new to django. Thanks
This is the full stack of the referenced error am getting:
Environment:
Request Method: GET
Request URL: http://127.0.0.1:9000/result/
Django Version: 1.4.1
Python Version: 2.5.4
Installed Applications:
('django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin',
'carloan')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware')
Traceback:
File "C:\Python25\Lib\site-packages\django\core\handlers\base.py" in get_response
111. response = callback(request, *callback_args, **callback_kwargs)
File "C:\Users\AJIBIKE\Documents\Circuit Atlantic\calculator\carloan\views.py" in result_page
226. 'carloan': instance,
def result_page(request):
if request.POST:
form = Carloan_formForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.interest = (instance.interest_rate/100) * instance.amount_of_vehicle * (instance.tenure/12)
instance.save()
else:
form = Carloan_formForm()
return render_to_response('carloan/result.html', {'carloan': instance,'form': form},
context_instance=RequestContext(request))
Exception Type: UnboundLocalError at /result/
Exception Value: local variable 'instance' referenced before assignment
Latest
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect, HttpResponse
from forms import Carloan_formForm
def index(request):
if request.POST:
form = Carloan_formForm(request.POST)
if form.is_valid():
instance = form.save()
return HttpResponseRedirect ('/result/')
form = Carloan_formForm()
kwvars = {
'form': form,
}
return render_to_response('carloan/index.html', kwvars,
context_instance=RequestContext(request))
def result_page(request):
instance = None
if request.POST:
form = Carloan_formForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.interest = (instance.interest_rate_Percentage/100) * instance.cost_of_vehicle_Naira * (instance.loan_repayment_tenure_Months/12)
instance.management_fee = 0.01 * (instance.cost_of_vehicle_Naira + instance.interest)
instance.processing_fee = 0.0025 * (instance.cost_of_vehicle_Naira + instance.interest)
instance.legal_fee = 0.0075 * (instance.cost_of_vehicle_Naira + instance.interest)
#i get syntax error starting from this line, and when i comment it out and the lines below, there is no syntax error.
instance.residual_amount = 0.01 * ((instance.cost_of_vehicle_Naira - ((instance.depreciation_rate_Percentage/100) * instance.cost_of_vehicle_Naira * (instance.tenure/12)))
instance.equity_contribution = (instance.equity_contrib_rate_Percentage/100) * instance.cost_of_vehicle_Naira)
instance.save()
else:
form = Carloan_formForm()
return render_to_response('carloan/result.html', {'instance': instance, 'form': form},
context_instance=RequestContext(request))
forms.py
from django import forms
from django.forms import ModelForm
from models import Carloan_form
class Carloan_formForm(ModelForm):
class Meta:
model = Carloan_form
exclude = ('interest', 'management_fee', 'processing_fee', 'legal_fee', \
'residual_amount', 'equity_contribution')
1 Save the result of the operations carried out on the extracted data in the Django Administration. (N.B: I already know how to save the user input)
Create a model to save the user's entries. app/models.py
class Carloan(models.Model) :
# In addition to your model fields add the functions that are part of your LoanCalc
...
Then create a ModelForm: app/forms.py
class CarLoanForm(forms.ModelForm) :
class Meta:
model = Carloan
Use CarLoanForm the same way you normally would except: app/views.py
if request.POST:
form = CarloanForm(request.POST)
if form.is_valid():
carloan = form.save()
#pass carloan (the instance) to the template and
#call its functions(from LoanCalc) instead of
#passing all of the values separately
Lastly, register this Model so it appears in the admin section app/admin.py
from django.contrib import admin
from app.models import Carloan
admin.sites.register(Carloan)
2 I have divided the page into two(one for the form and the other for
the result) and i want to pass the result to one-half of the page to
enable the user to see it.
Using the steps above, carloan will be passed to the view. go ahead and render its values.
Additionally:
Refactor index
your index definition should be refactored slightly, or your POST bound form will never make it to the template:
def index(request):
if request.POST:
form = CarloanForm(request.POST)
if form.is_valid():
instance = form.save()
else :
form = CarloanForm()
return render_to_response('carloan/index.html', {'form': form},
context_instance=RequestContext(request))
Refactor your ModelForm
Carry out some operations on the data (extracted using form.cleaned_data['']) and I have written some lines of code to that effect; - using a ModelForm instead of a regular django form you will get an instance of the model with the user's values already filled in, you reference them with instance.field.
and i want to carry out the operations in the code above on the extracted data. - the fields that you plan to calculate values for are listed in exclude they will not factor into form validation.
class CarLoanForm(forms.ModelForm) :
class Meta:
model = Carloan
# exclude fields that are calculated from user input
# NOTE: these fields must be in your model
exclude = ('interest', 'management_fee'...)
Refactor result page
Carry out some operations on the data (extracted using form.cleaned_data['']) and I have written some lines of code to that effect;
in results_page under the form.is_valid check, ther is a line: instance = form.save(commit=False) this gets all of the values that the user submitted in a instance of the Carloan Model that has NOT been saved yet.
further down: instance.interest = (instance.interest_rate/100) * instance.amount_of_vehicle *(instance.tenure/12) in this line I am calculating one of the excluded fields values (this calculation is a copy of your code).
lastly (after all of the operations on the data have been completed) I save the instance of the model.
then pass the instance to the template for display.
code:
def result_page(request):
if request.POST:
form = CarloanForm(request.POST)
if form.is_valid():
# get an instance from the form but don't save it
instance = form.save(commit=False)
# calculate excluded field values
instance.interest = (instance.interest_rate/100) * instance.amount_of_vehicle *(instance.tenure/12)
...
# after you have calculated all of the excluded fields save the instance
instance.save()
else :
form = CarloanForm()
return render_to_response('carloan/result.html', {'carloan' : instance, 'form' : form},
context_instance=RequestContext(request))
Error:
reference before error assignment - What does it say was referenced before assignment? Paste the entire stack trace please.
One of the simpler ways would be to store the data in the session in one view, retrieve it in the next. The docs will help.1
Having said that - there are a few other ways to approach the problem. It has been discussed more than once on SO:
Django Passing data between views
How do you pass or share variables between django views?
how to pass a list between views in django