Receiving a CSV dataset in python Flask - python

I am having a python program that receives a CSV file (using pandas.read_csv option) from the user and returns the size of the CSV file as output.
My requirement is to have a GUI with an upload button and show the size of dataset in that GUI itself. I am a beginner in Python and Flask. Could anyone guide me here how to achieve this requirement in Python Flask?
I tried the following code but it says "Internal Server Error" and I don't know how to implement upload button.
import pandas as pd
from flask import Flask
app = Flask(__name__)
#app.route('/')
def data_shape():
data = pd.read_csv('iris.csv') # there should be an upload option / button for this dataset in the flask webservice
return data.shape
if __name__ == '__main__':
app.run(host='0.0.0.0')
I have to upload the csv file in the webservice and get the output of the python code in the webservice itself.

app.py
import os
import shutil
from flask import Flask, flash, request, redirect, render_template
from werkzeug.utils import secure_filename
from flask import Flask, session
from fastai.vision import *
basedir = os.path.abspath(os.path.dirname(__file__))
UPLOAD_FOLDER = os.path.join('static', 'csv')
app = Flask(__name__)
app.secret_key = "secret key"
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024
ALLOWED_EXTENSIONS = set(['csv','xls'])
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
#app.route('/')
def upload_form():
return render_template('index.html')
#app.after_request
def add_header(response):
"""
Add headers to both force latest IE rendering engine or Chrome Frame,
and also to cache the rendered page for 10 minutes.
"""
response.headers['X-UA-Compatible'] = 'IE=Edge,chrome=1'
response.headers['Cache-Control'] = 'public, max-age=0'
return response
#app.route('/', methods=['POST'])
def upload_file():
# shutil.rmtree(UPLOAD_FOLDER)
# os.mkdir(UPLOAD_FOLDER)
disp_div = 'none'
disp_div_tumor = 'none'
d = request.form.to_dict()
# print("dddd;",d)
button_name = 'None'
if (len(d)!=0):
button_name = list(d.items())[-1][0]
file = request.files['file']
print("file:",file)
if file.filename == '':
flash('No file selected for uploading','red')
# return redirect(request.url)
return render_template('index.html', disp_div = disp_div)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
shutil.rmtree(UPLOAD_FOLDER)
os.mkdir(UPLOAD_FOLDER)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
flash('File successfully uploaded!', 'green')
print(UPLOAD_FOLDER)
print("==>",os.path.join(UPLOAD_FOLDER, sorted(os.listdir(app.config['UPLOAD_FOLDER']))[0]))
csv_file = pd.read_csv(os.path.join(UPLOAD_FOLDER, sorted(os.listdir(app.config['UPLOAD_FOLDER']))[0]))
csv_shape = csv_file.shape
return render_template('index.html', csv_shape=csv_shape)
# return redirect('/')
else:
flash('Allowed file types are txt, pdf, png, jpg, jpeg, gif', 'red')
# return redirect(request.url)
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=False, port=5006)
## For deploying the app use `app.run(debug=False, host="0.0.0.0", port=80)`
templates/index.html
<link rel="stylesheet" type="text/css" href="/static/css/main.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="static/js/index.js"></script>
<script>
$(document).ready(function(){
$("#target").on('submit',function(){
// alert("It works");
});
});
</script>
<!doctype html>
<html>
<head>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body>
<form id="target" method="post" enctype="multipart/form-data">
<div name ="up" class="upload-btn-wrapper">
<button name="upload" class="btn">Upload CSV File</button>
<input type="file" id="file" value="go" name="file" onchange="$('#target').submit();"/>
</div>
</form>
<p>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<div class=flashes>
{% for category_color, message in messages %}
<p class="error_text" style="color:{{ category_color }};width:500px;">{{ message }}</p>
{% endfor %}
</div>
{% endif %}
{% endwith %}
</p>
===> {{ csv_shape }}
</body>
</html>
static/css/main.css:
.upload-btn-wrapper {
position: absolute;
overflow: hidden;
display: inline-block;
top:0;
left:5%;
}
.btn {
width: 15vw;
height: 4vh;
padding: 0 0 2px;
font-size: 2.2vh;
/* font: 90% "Trebuchet MS", Tahoma, Arial, sans-serif; */
font-family: sans-serif;
font-weight: bold;
line-height: 32px;
text-transform: uppercase;
margin: 0.2em auto;
display: block;
outline: none;
position: relative;
cursor: pointer;
border-radius: 3px;
color: #ffffff;
text-shadow: 1px 1px #024bde;
border: 1px solid #507def;
border-top: 1px solid #2f73ff;
border-bottom: 1px solid #2a67ff;
box-shadow: inset 0 1px #4a82ff, inset 1px 0 #2653b9, inset -1px 0 #2d69e8, inset 0 -1px #4372e8, 0 2px #1c3d9e, 0 6px #2553a2, 0 4px 2px rgba(0,0,0,0.4);
background: -moz-linear-gradient(top, #cae285 0%, #a3cd5a 100%);
background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cae285), color-stop(100%,#a3cd5a));
background: -webkit-linear-gradient(top, #6292ff 0%,#2b6cff 100%);
background: -o-linear-gradient(top, #cae285 0%,#a3cd5a 100%);
background: -ms-linear-gradient(top, #cae285 0%,#a3cd5a 100%);
background: linear-gradient(top, #cae285 0%,#a3cd5a 100%);
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#cae285', endColorstr='#a3cd5a',GradientType=0 );
background-color: #1c3c9e;
}
.btn::-moz-focus-inner{border:0}
.btn:active {
/*top: 3px;*/
/* border: 1px solid #88A84E;
border-top: 1px solid #6E883F;
border-bottom: 1px solid #95B855;
background: #A7CF5F;*/
box-shadow: inset 0 1px 2px #779441;
transform: translateY(3px);
}
.pred {
position: absolute;
left: 10%;
bottom: 0;
}
.upload-btn-wrapper input[type=file] {
font-size: 100px;
position: absolute;
left: 0;
top: 0;
opacity: 0;
}
.submit_btn {
border: 2px solid gray;
color: gray;
background-color: white;
padding: 8px 20px;
border-radius: 8px;
font-size: 20px;
font-weight: bold;
}
.error_text {
position: absolute;
top: 2.7vh;
font-weight: bold;
font-size: 2vh;
left: 5%;
}
Directory structure:
|-- fapp.py
|-- static
| |-- css
| | `-- main.css
| `-- csv
`-- templates
`-- index.html
Edit:

Related

jinja2.exceptions.UndefinedError is undefined

I had a problem with this jinja2.exception and I was totally confused why. I wanted to post data to my .html, which I got from an API.
#app.route("/playerstats", methods = ["GET"])
def statsget():
return render_template("stats.html")
#app.route("/playerstats", methods = ["POST"])
def statspost():
player_uri = "https://www.balldontlie.io/api/v1/players?search={}%20{}"
playerinput = request.form["nm"]
player_split = playerinput.split()
vn = player_split[0]
nn = player_split[1]
r = requests.get(player_uri.format(vn, nn)).json()
data = {
"player_id": r["data"][0]["id"],
"player_first_name": r["data"][0]["first_name"]
}
return render_template("stats.html", data=data)
<button type="button" class="btn btn-outline-secondary" style="height: 40px; width: 450px; margin-top: 5px; margin-bottom: 5px; border-width: 1px; border-color:lightgrey; text-align: start;">
{{data.player_first_name}} {{data.player_id}}
</button>
Running the webpage put out this exception: jinja2.exceptions.UndefinedError 'data' is undefined
My solution was to put the data I get from the api into an array and run a for-loop inside the html to give out all data:
inside main.py:
#app.route("/playerstats", methods = ["GET"])
def pstatsget():
return render_template("stats.html")
#app.route("/playerstats", methods = ["POST"])
def pstatspost():
player_uri = "https://www.balldontlie.io/api/v1/players?search={}%20{}"
playerinput = request.form["nm"]
player_split = playerinput.split()
vn = player_split[0]
nn = player_split[1]
r = requests.get(player_uri.format(vn, nn)).json()
data_group = []
data = {
"player_id": r["data"][0]["id"],
"player_first_name": r["data"][0]["first_name"]
}
data_group.append(data)
print(data_group)
return render_template("stats.html", data=data_group)
inside stats.html:
{% for d in data: %}
<button type="button" class="btn btn-outline-secondary" style="height: 40px; width: 450px; margin-top: 5px; margin-bottom: 5px; border-width: 1px; border-color:lightgrey; text-align: start;">
{{d.player_first_name}} {{d.player_id}}
</button>
{% endfor %}
I hope this works for you aswell!

Django Stripe payment does not respond after clicking the Submit Payment button

I have an e-commerce application that I'm working on. The app is currently hosted on Heroku free account. At the moment I can select a product, add it on the cart and can get up to the stripe form and type in the card details, but when I click the 'Submit Payment' button nothing happens. I don't even get an error message. I'm using Stripe test keys and 4242 four times as my card number. Can anyone help me to find out what's going on pliz. I have been stuck on it for days.
Here is the relevant code below:
Settings.py code:
from .base import *
import dj_database_url
DEBUG = (os.environ.get('DEBUG_VALUE') == 'True')
ALLOWED_HOSTS = ['.herokuapp.com', '127.0.0.1']
AUTH_PASSWORD_VALIDATORS = [
{'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator'},
{'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator'},
{'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator'},
{'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator'}
]
""" DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql_psycopg2',
'NAME': config('DB_NAME'),
'USER': config('DB_USER'),
'PASSWORD': config('DB_PASSWORD'),
'HOST': config('DB_HOST'),
'PORT': ''
}
}
"""
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
STRIPE_PUBLIC_KEY = os.environ.get('STRIPE_LIVE_PUBLIC_KEY')
STRIPE_SECRET_KEY = os.environ.get('STRIPE_LIVE_SECRET_KEY')
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_S3_FILE_OVERWRITE = False
AWS_DEFAULT_ACL = None
AWS_S3_REGION_NAME = "us-east-2"
AWS_S3_SIGNATURE_VERSION = "s3v4"
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto3.S3Boto3Storage'
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')
# Heroku: Update database configuration from $DATABASE_URL.
db_from_env = dj_database_url.config(conn_max_age=500)
DATABASES['default'].update(db_from_env)
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.1/howto/static-files/
# The absolute path to the directory where collectstatic will collect static files for deployment.
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static_in_env')]
# The URL to use when referring to static files (where they will be served from)
STATIC_URL = '/static/'
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
views.py (Specifically the class PaymentView(View)):
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ObjectDoesNotExist
from django.contrib.auth.decorators import login_required
from django.contrib.auth.mixins import LoginRequiredMixin
from django.shortcuts import render, get_object_or_404
from django.views.generic import ListView, DetailView, View
from django.shortcuts import redirect
from django.utils import timezone
from django.db.models import Q
from .forms import CheckoutForm, CouponForm, RefundForm, PaymentForm
from .models import Item, OrderItem, Order, Address, Payment, Coupon, Refund, UserProfile
import random
import string
import stripe
stripe.api_key = settings.STRIPE_SECRET_KEY
class PaymentView(View):
def get(self, *args, **kwargs):
order = Order.objects.get(user=self.request.user, ordered=False)
if order.billing_address:
context = {
'order': order,
'DISPLAY_COUPON_FORM': False
}
userprofile = self.request.user.userprofile
if userprofile.one_click_purchasing:
# fetch the users card list
cards = stripe.Customer.list_sources(
userprofile.stripe_customer_id,
limit=3,
object='card'
)
card_list = cards['data']
if len(card_list) > 0:
# update the context with the default card
context.update({
'card': card_list[0]
})
return render(self.request, "payment.html", context)
else:
messages.warning(
self.request, "You have not added a billing address")
return redirect("core:checkout")
def post(self, *args, **kwargs):
order = Order.objects.get(user=self.request.user, ordered=False)
form = PaymentForm(self.request.POST)
print('form')
userprofile = UserProfile.objects.get(user=self.request.user)
if form.is_valid():
token = form.cleaned_data.get('stripeToken')
# print('token')
save = form.cleaned_data.get('save')
use_default = form.cleaned_data.get('use_default')
if save:
if userprofile.stripe_customer_id != '' and userprofile.stripe_customer_id is not None:
customer = stripe.Customer.retrieve(
userprofile.stripe_customer_id)
customer.sources.create(source=token)
else:
customer = stripe.Customer.create(
email=self.request.user.email,
)
customer.sources.create(source=token)
userprofile.stripe_customer_id = customer['id']
userprofile.one_click_purchasing = True
userprofile.save()
amount = order.get_total() * 100
try:
if use_default or save:
# charge the customer because we cannot charge the token more than once
charge = stripe.Charge.create(
amount=amount, # cents
currency="usd",
customer=userprofile.stripe_customer_id
)
else:
# charge once off on the token
charge = stripe.Charge.create(
amount=amount, # cents
currency="usd",
source=token
)
# create the payment
payment = Payment()
payment.stripe_charge_id = charge['id']
payment.user = self.request.user
payment.amount = order.get_total()
payment.save()
# assign the payment to the order
order_items = order.items.all()
order_items.update(ordered=True)
for item in order_items:
item.save()
order.ordered = True
order.payment = payment
order.ref_code = create_ref_code()
order.save()
messages.success(self.request, "Your order was successful!")
return redirect("/")
except stripe.error.CardError as e:
body = e.json_body
err = body.get('error', {})
messages.warning(self.request, f"{err.get('message')}")
return redirect("/")
except stripe.error.RateLimitError as e:
# Too many requests made to the API too quickly
print(e)
messages.warning(self.request, "Rate limit error")
return redirect("/")
except stripe.error.InvalidRequestError as e:
# Invalid parameters were supplied to Stripe's API
print(e)
messages.warning(self.request, "Invalid parameters")
return redirect("/")
except stripe.error.AuthenticationError as e:
# Authentication with Stripe's API failed
# (maybe you changed API keys recently)
print(e)
messages.warning(self.request, "Not authenticated")
return redirect("/")
except stripe.error.APIConnectionError as e:
# Network communication with Stripe failed
print(e)
messages.warning(self.request, "Network error")
return redirect("/")
except stripe.error.StripeError as e:
# Display a very generic error to the user, and maybe send
# yourself an email
print(e)
messages.warning(
self.request, "Something went wrong. You were not charged. Please try again.")
return redirect("/")
except Exception as e:
# send an email to ourselves
print(e)
messages.warning(
self.request, "A serious error occurred. We have been notifed.")
return redirect("/")
messages.warning(self.request, "Invalid data received")
return redirect("/payment/stripe/")
payment.html:
{% extends "base.html" %}
{% block extra_head %}
<style>
#stripeBtnLabel {
font-family: "Helvetica Neue", Helvetica, sans-serif;
font-size: 16px;
font-variant: normal;
padding: 0;
margin: 0;
-webkit-font-smoothing: antialiased;
font-weight: 500;
display: block;
}
#stripeBtn {
border: none;
border-radius: 4px;
outline: none;
text-decoration: none;
color: #fff;
background: #32325d;
white-space: nowrap;
display: inline-block;
height: 40px;
line-height: 40px;
box-shadow: 0 4px 6px rgba(50, 50, 93, .11), 0 1px 3px rgba(0, 0, 0, .08);
border-radius: 4px;
font-size: 15px;
font-weight: 600;
letter-spacing: 0.025em;
text-decoration: none;
-webkit-transition: all 150ms ease;
transition: all 150ms ease;
float: left;
width: 100%
}
button:hover {
transform: translateY(-1px);
box-shadow: 0 7px 14px rgba(50, 50, 93, .10), 0 3px 6px rgba(0, 0, 0, .08);
background-color: #43458b;
}
.stripe-form {
padding: 5px 30px;
}
#card-errors {
height: 20px;
padding: 4px 0;
color: #fa755a;
}
.stripe-form-row {
width: 100%;
float: left;
margin-top: 5px;
margin-bottom: 5px;
}
/**
* The CSS shown here will not be introduced in the Quickstart guide, but shows
* how you can use CSS to style your Element's container.
*/
.StripeElement {
box-sizing: border-box;
height: 40px;
padding: 10px 12px;
border: 1px solid transparent;
border-radius: 4px;
background-color: white;
box-shadow: 0 1px 3px 0 #e6ebf1;
-webkit-transition: box-shadow 150ms ease;
transition: box-shadow 150ms ease;
}
.StripeElement--focus {
box-shadow: 0 1px 3px 0 #cfd7df;
}
.StripeElement--invalid {
border-color: #fa755a;
}
.StripeElement--webkit-autofill {
background-color: #fefde5 !important;
}
.current-card-form {
display: none;
}
</style>
{% endblock extra_head %}
{% block content %}
<main>
<div class="container wow fadeIn">
<h2 class="my-5 h2 text-center">Payment</h2>
<div class="row">
<div class="col-md-12 mb-4">
<div class="card">
<script src="https://js.stripe.com/v3/"></script>
{% if card %}
<div style="padding: 5px 30px;">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" name="use_default_card" id="use_default_card">
<label class="custom-control-label" for="use_default_card">Use default card:
**** **** **** {{ card.last4 }}
<span>Exp: {{ card.exp_month }}/{{ card.exp_year }}</span></label>
</div>
</div>
{% endif %}
<div class="current-card-form">
<form action="." method="post" class="stripe-form">
{% csrf_token %}
<input type="hidden" name="use_default" value="true">
<div class="stripe-form-row">
<button id="stripeBtn">Submit Payment</button>
</div>
<div id="card-errors" role="alert"></div>
</form>
</div>
<div class="new-card-form">
<form action="." method="post" class="stripe-form" id="stripe-form">
{% csrf_token %}
<div class="stripe-form-row" id="creditCard">
<label for="card-element" id="stripeBtnLabel">
Credit or debit card
</label>
<div id="card-element" class="StripeElement StripeElement--empty">
<div class="__PrivateStripeElement"
style="margin: 0px !important; padding: 0px !important; border: none !important; display: block !important; background: transparent !important; position: relative !important; opacity: 1 !important;">
<iframe frameborder="0" allowtransparency="true" scrolling="no" name="__privateStripeFrame5"
allowpaymentrequest="true"
src="https://js.stripe.com/v3/elements-inner-card-19066928f2ed1ba3ffada645e45f5b50.html#style[base][color]=%2332325d&style[base][fontFamily]=%22Helvetica+Neue%22%2C+Helvetica%2C+sans-serif&style[base][fontSmoothing]=antialiased&style[base][fontSize]=16px&style[base][::placeholder][color]=%23aab7c4&style[invalid][color]=%23fa755a&style[invalid][iconColor]=%23fa755a&componentName=card&wait=false&rtl=false&keyMode=test&origin=https%3A%2F%2Fstripe.com&referrer=https%3A%2F%2Fstripe.com%2Fdocs%2Fstripe-js&controllerId=__privateStripeController1"
title="Secure payment input frame"
style="border: none !important; margin: 0px !important; padding: 0px !important; width: 1px !important; min-width: 100% !important; overflow: hidden !important; display: block !important; height: 19.2px;"></iframe><input
class="__PrivateStripeElement-input" aria-hidden="true" aria-label=" " autocomplete="false"
maxlength="1"
style="border: none !important; display: block !important; position: absolute !important; height: 1px !important; top: 0px !important; left: 0px !important; padding: 0px !important; margin: 0px !important; width: 100% !important; opacity: 0 !important; background: transparent !important; pointer-events: none !important; font-size: 16px !important;">
</div>
</div>
</div>
<div class="stripe-form-row">
<button id="stripeBtn">Submit Payment</button>
</div>
<div class="stripe-form-row">
<div class="custom-control custom-checkbox">
<input type="checkbox" class="custom-control-input" name="save" id="save_card_info">
<label class="custom-control-label" for="save_card_info">Save for future purchases
{{ STRIPE_PUBLIC_KEY }} {{ STRIPE_SECRET_KEY }}</label>
</div>
</div>
<div id="card-errors" role="alert"></div>
</form>
</div>
</div>
</div>
{% include "order_snippet.html" %}
</div>
</div>
</main>
{% endblock content %}
{% block extra_scripts %}
<script nonce=""> // Create a Stripe client.
var stripe = Stripe('STRIPE_PUBLIC_KEY');
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element.
var card = elements.create('card', { style: style });
// Add an instance of the card Element into the `card-element` <div>.
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission.
var form = document.getElementById('stripe-form');
form.addEventListener('submit', function (event) {
event.preventDefault();
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error.
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
// Submit the form with the token ID.
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('stripe-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
var currentCardForm = $('.current-card-form');
var newCardForm = $('.new-card-form');
var use_default_card = document.querySelector("input[name=use_default_card]");
use_default_card.addEventListener('change', function () {
if (this.checked) {
newCardForm.hide();
currentCardForm.show()
} else {
newCardForm.show();
currentCardForm.hide()
}
})
</script>
{% endblock extra_scripts %}
You should pass the API key along with other variables in the context variable by adding:
'STRIPE_PUBLIC_KEY': settings.STRIPE_PUBLIC_KEY,
inside the context variable.

Plotly.offline plot output_type='div' not working inside HTML - How to embed Plotly to HTML

I have created a simple Flask app which renders a template 'index.html' and in that HTML I am attempting to list various plots as a sort of dashboard-style webpage with other content. I know the basics of Flask and Dash though am not using Dash as I want to have more control over the HTML/CSS hence using Flask to create a website to embed the graphs using Plotly.
So far I've had no luck with any of the official documentation or any medium.com or suchlike articles. The closest I have come to is this answer: Embedding dash plotly graphs into html
However, it isn't working when I run my app and the browser launches in localhost. Instead it just gives me a lot of text which is clearly the plotly figure, but it isn't turning into a graph.
Here is all my py/html/css even if the navbar stuff isn't relevant; just in case (I am still learning so I'm sure there will be some better ways to do things..)
Thanks for any help.
DataFrame class which grabs the latest Coronavirus data and returns as pandas.dataframe:
import pandas as pd
import requests
class DataFrame:
"""
Class which grabs the data live from the ECDC and returns it in a pandas dataframe
"""
def __init__(self):
"""
Creating the pandas dataframe of the ECDC JSON data
"""
self.url = "https://opendata.ecdc.europa.eu/covid19/casedistribution/json"
self.file = requests.get(self.url).json()
self.file = self.file['records']
self.df = pd.DataFrame(data=self.file)
def converter(self):
"""
Converting the dtypes from object to int for ints, and date to date
Also renames the columns to more visual-friendly names
:return: None
"""
self.df['cases'] = self.df['cases'].astype(int)
self.df['deaths'] = self.df['deaths'].astype(int)
self.df['popData2018'] = self.df['popData2018'].astype(str).replace('', 0).astype(int)
self.df['dateRep'] = self.df['dateRep'].to_timestamp
cols_rename = 'date day month year cases deaths country geo_id country_id population continent'.split()
cols_rename = [s.capitalize() for s in cols_rename]
self.df.columns = cols_rename
def return_df(self):
"""
:return: pandas DataFrame
"""
self.converter()
return self.df
app.py
from plotly.offline import plot
import plotly.graph_objects as go
from dataframe.dataframe import DataFrame
from flask import Flask, render_template, redirect, request, url_for
app = Flask(__name__)
def graph_maker():
df = DataFrame().return_df()
data = []
for continent in df['Continent'].unique():
df_filt = df[df['Continent'] == continent]
data.append(go.Scatter(x=df_filt["Cases"],
y=df_filt["Deaths"],
mode='markers',
text=df_filt['Country'],
name=continent))
layout = go.Layout(title="Deaths (Y) v Cases (X) by continent")
fig = go.Figure(data=data, layout=layout)
return plot(figure_or_data=fig,
include_plotlyjs=False,
output_type='div')
#app.route('/')
def index():
graph = graph_maker()
return render_template('index.html',
graph=graph)
if __name__ == '__main__':
app.run(debug=True)
index.html
{% extends "navbar.html" %}
<head>
<meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="..\static\master.css">
<link href="https://fonts.googleapis.com/css2?family=Maven+Pro&display=swap" rel="stylesheet">
<!-- Plotly.js -->
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>
{% block nbar %}
<body>
<div class="global-box" id="global-stats">
<h1>Global charts</h1>
<p>Title here</p>
<ul class="global-box-ul">
<li class="global-box-ul-li">
{{ graph }}
</li>
<li class="global-box-ul-li">
Another chart here
</li>
</ul>
</div>
</body>
{% endblock %}
navbar.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>C19DB</title>
<meta charset="UTF-8">
<link type="text/css" rel="stylesheet" href="..\static\master.css">
<link href="https://fonts.googleapis.com/css2?family=Maven+Pro&display=swap" rel="stylesheet">
</head>
<nav class="navbar">
<div class="logo">c19db</div>
<div class="list">
<ul class="navbar_items">
<li class="navbar_item">Dashboard</li>
<li class="navbar_item">About</li>
<li class="navbar_item">Register</li>
</ul>
</div>
</nav>
{% block nbar %}
{% endblock %}
</html>
master.css
html, body {
font-family: 'Maven Pro';
height: 700px;
margin: 0;
}
.navbar {
background: rgb(237, 232, 232);
vertical-align: middle;
}
.logo {
vertical-align: middle;
display: inline-block;
color: rgb(196, 69, 69);
font-size: 50px;
width: 250px;
padding: 5px 15px 5px 15px;
}
.list{
vertical-align: middle;
display: inline-block;
width: calc(100% - 285px);
text-align: right;
}
.navbar_items {
list-style: none;
font-size: 20px;
color: rgb(61, 61, 61)
}
.navbar_item{
display: inline-block;
padding: 5px 15px 5px 15px;
}
a {
text-decoration: none;
}
.navbar_item > a{
display: inline-block;
padding: 5px 15px 5px 15px;
color: rgb(61, 61, 61);
}
.navbar_item > a:hover {
display: inline-block;
padding: 5px 15px 5px 15px;
color: rgb(196, 69, 69);
}
.footer, .footer a {
position: relative;
background: rgb(237, 232, 232, 0.2);
width: 100%;
color: rgb(61, 61, 61, 0.2);
text-align: center;
}
span {
font-weight: bold;
}
.global-box {
text-align: center;
border: 2px black solid;
list-style: none;
margin: auto;
}
.global-box > h1, .global-box > p {
margin: 1px;
}
ul {
display: contents;
}
.global-box-ul-li {
display: inline-block;
border: 2px lightblue solid;
list-style: none;
margin: auto;
width: 48%;
height: 100%;
}
Thank you for any help!
I have solved this problem.
Nutshell:
Create a chart
Call pyo.plot() as normal passing through the fig, output_type='div' and include_plotlyjs=False
Have that output to a variable passed through Markup() (import from flask)
Have the Markup(variable) passed through the render_template like you would a form
Have the variable rendered in the html using {{ jinja template }}
First, create your Plotly chart like normal. I will not give a whole example but just the key points. I create charts in functions for import and use in multiple pages if necessary. In this case, it's necessary because the chart must be assigned to a variable.
def my_bar_chart():
*snip irrelevant*
my_bar_chart = pyo.plot(fig, output_type='div', include_plotlyjs=False)
return Markup(my_bar_chart)
Now import your function to your app.py / wherever your views are and pass it through render template as you would any form, for example.
Here is an example:
def my_page():
my_bar_chart_var = my_bar_chart()
return render_template('my_page.html',
bar_chart_1=my_bar_chart_var)
Then on the html for that page simply pass through bar_chart_1 in a jinja template like so:
{{ bar_chart_1 }}
And done.

Create matplotlib rounded corner table

Are there any ways to create a rounded corner table with matplotlib?
Expected result.
Current result.
table.py
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
'Name':['alice','bob','charlie','dave','eve','frank','Sum'],
'Age':[14,35,64,7,19,25,164]})[['Name','Age']]
fig, ax = plt.subplots(figsize=(2,2))
ax.axis('off')
ax.axis('tight')
ax.table(cellText=df.values,
colLabels=df.columns,
loc='center',
bbox=[0,0,1,1])
plt.savefig('table.png')
Run in docker container
$ export MPLBACKEND="agg"
$ python3 table.py
I tried to use the bbox of matplotlib.table, but it didn't work. I tried a different (and very tricky) way to deal with it, saving it in HTML format and cutting it into an image. (It's a very lame way to do it.)
import pandas as pd
import matplotlib.pyplot as plt
df = pd.DataFrame({
'Name':['alice','bob','charlie','dave','eve','frank','Sum'],
'Age':[14,35,64,7,19,25,164]})[['Name','Age']]
html_template = '''
<!DOCTYPE html>
<html lang="jp" dir="ltr">
<head>
<meta charset="utf-8">
<title>table</title>
<style type="text/css">
table {{
border: 1px solid #ccc;
border-collapse: separate;
border-radius: 5px;
border-spacing: 0;
}}
table th, table td {{
border-bottom: 1px solid #ccc;
padding: 10px 20px;
}}
table th {{
border-right: 1px solid #ccc;
background: #EEE;
}}
table tr:first-child th {{
border-radius: 5px 0 0 0;
}}
table tr:first-child td {{
border-radius: 0 5px 0 0;
}}
table tr:last-child th {{
border-bottom: none;
border-radius: 0 0 0 5px;
}}
table tr:last-child td {{
border-bottom: none;
border-radius: 0 0 5px 0;
}}
</style>
</head>
<body>
<div class="container">
{table}
</div>
</body>
</html>
'''
table = df.to_html(classes=['table',"table-bordered", "table-hover"])
html = html_template.format(table=table)
with open("table.html", "w") as f:
f.write(html)

Moving data from html form to a chart in a MySQL databse using python

I went through a basic web.py tutorial on how to set up a basic server using MySQL and I have a database named 'testdb' with a chart 'todo' inside of it. The values I'm trying to move into the chart are 'email', 'username', and 'password' from the form in index.html. I get the error message 405 method not allowed. And after breaking past 100+ error messages I'm stumped. I already have columns for the three but i have no value assigned to them.
I'm running on a Linux Ubuntu Desktop, in the gedit test editor.
MySQL chart as seen in Terminal
| Field | Type | Null | | Default |
_________________________________________________________
| email | varchar(50) | YES | | NULL |
| username | varchar(50) | YES | | NULL |
| password | varchar(50) | YES | | NULL |
The code for index.html
$def with (todos)
$for todo in todos:
<title>Red.Koala</title>
<body id="background">
<div id="header">
-> Red.Koala <-
</div>
<div id="sign">
<form action="LANForum" method="post">
<table id="tr">
<tr>
Sign In:<br>
</tr>
</table>
Email:<br>
<input id="signbox" type="text" name="email" placeholder="Ex: JoeSmith#example.com" required><br>
Username:<br>
<input id="signbox" type="text" name="username" placeholder="Username..."required><br>
Password:<br>
<input id="signbox" height="30" type="text" name="password" placeholder="Password..." required><br>
<input value="Submit" type="submit" id="signbox" style="margin-top: 20px; right: 5px; width: 50%;">
</div>
</form>
</div>
<div id="copyright">
#HaydnFleming
</div>
<style>
#background {
background: #ff3333;
margin-left: auto;
margin-right: auto;
width: 960px;
}
#header {
border: solid #cc0000;
border-width: 15px;
font-size: 65px;
text-align: center;
}
#sign{
border: solid #cc0000;
border-width: 15px;
font-size: 30px;
text-align: center;
width: 30%;
height: 40%;
margin:auto;
margin-top: 40px ;
margin-bottom: 20%;
}
#signbox {
width: 60%;
height: 10%;
margin-top: 10px;
}
#copyright{
bottom: 2%;
text-align: center;
position: absolute;
width:100%;
}
#tr {
border: solid #cc0000;
position: relative;
width: 100%;
border-bottom: transparent;
border-left: transparent;
border-right: transparent;
}
.dscrptn{
text-align: center;
width: 100%;
position: relative;
z-index: 5;
}
.dscrptn_p{
width: 60%;
text-align: center;
margin: auto;
margin-top: 4%;
position: relative;
border: solid #cc0000;
border-width: 0px;
}
</style>
</body>
The code for Code.py (using Web.py)
import web
render = web.template.render('templates/')
urls = (
'/', 'index', '/add', 'add', '/LANForum', 'LANForum'
)
db = web.database(dbn = 'mysql', user = 'testuser', pw = 'MServer', db = 'testdb')
class index:
def GET(self):
todos = db.select('todo')
return render.index(todos)
class add:
def POST(self):
i = web.input()
n = db.insert('todo', email=i.email, username=i.username, password=i.password)
raise web.seeother('LANForum')
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
The code for LANForum.html
<link type="text/css" rel="stylesheet" href="LANForum.css">
<title>Red.Koala</title>
<body id="background"> <!-- Only used to set up the main background colors/any images.-->
<div id="title">
<!-- I decided to use the title as a nest
for all the other divs to rest in that way
they could all run off of the same measurements,
and they could line up easily using similar
percentages and pixel distances-->
<down>Red.Koala</down>
<!--"down" is just a random word I used as a tag so that I could
separate the text form the divs. also the "+ [Current Forum Title]"
part means that when the website is actually running you will be able
to see the website name and then the forum title. example: Red.Koala/Funny -->
<div id="user">[This is where the current users information will go]</div><!-- User information in the top right-->
<div id="list">[This is where a list of pop. forum topics will go.]</div>
<!-- List of popular forums located on the middle right of the page.-->
<div id="mforum">[This is where your main forum will go.]
<!-- Forum that you are currently on displayed in the big box in the middle of the screen.-->
<div id="post-bar"><!-- Section of the Forum section where any and all posting/commenting will be done -->
<form action="" onsubmit=""><!-- Assigned to whatever server space we select -->
<textarea id="text-box" type="text" placeholder="Post..."></textarea>
<!-- The box which the user will type in to post or comment things -->
<input id="post-button" type="submit" value="Post" required>
</form>
</div>
</div>
</div>
<div id="buttons"><!-- page numbers on display for the user to switch between pages.--> <!--currently not working as buttons-->
<table>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
<td>4</td> <!-- Each cell contains a different page number-->
<td>5</td>
<td>6</td>
<td>7</td>
<td>8</td>
<td>9</td>
<td>10</td>
<td>...</td>
</tr>
</table>
</div>
</body>

Categories

Resources