How to insert a Python Plotted Graph to HTML file? - python
I had been searching for ways to do this but I seem couldn't get any helpful answer online thus I have to directly ask here.
What I want is simple: Process some data from CSV, plot it into graph and post it to my HTML. I do not own any web-domain, the HTML is put in a shared drive and could be view by a certain allowed crowd using Chrome.
Here is my python code snippet:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from jinja2 import Environment, FileSystemLoader
import plotly as py
import numpy as np
import plotly.tools as plotly_tools
import plotly.plotly as py
from plotly.graph_objs import *
def dashboard_plot_graph():
html_template = __Html_path__.get_template("PublishPG.html")
curr_mcl_res = pd.read_csv(os.path.join(__Result_path__, __Chart_csv__))
print curr_mcl_res.head()
x = curr_mcl_res['TestSuite']
my_plot = curr_mcl_res.plot(x, kind='bar', stacked=True, title='Latest Trend')
fig = my_plot.get_figure()
fig.savefig("./my_img.png")
html_template_vars = {"curr_mcl_div_placeholder": curr_mcl_res.to_html()}
html_out = html_template.render(html_template_vars)
f = open ('file.html', 'w')
f.write( html_out )
f.close()
plt.show()
Here is my HTML code snippet:
<html>
<head>
<title> Testing Webpage </title>
</head>
<body>
<h1> Hello World! </h1>
<p> This is a test page </p>
{{ curr_mcl_div_placeholder }}
</body>
<html>
This is the plot I wish to see in my webpage:
I have tried:
Follow online tutorial which seem to say plotly able to insert the plot to HTML... however it failed... the most I can do is to
insert the data frame (table) as shown in the code snippet above.
I tried to think work around such as save the plotted graph as image and try to insert the image to html. But it does not allow to
take image from local drive for security reason. It only able to
pull image if I uploaded the image somewhere to the cloud /
web-domain. But the data is not suitable to be exposed on any social
media site.
Any suggest for me to get through this limitation?
have a look at Bokeh, it's an amazing framework.
Here some instructions for the graph you're looking to do
The short answer, if you just want to move on, is that you don't insert an image directly into HTML, but instead make a reference to the image file. Something like:
<html>
<head>
<title> Testing Webpage </title>
</head>
<body>
<h1> Hello World! </h1>
<p> This is a test page </p>
<img src="my_img.png" title="My plot" />
</body>
<html>
But Gsk's suggestion has a lot of merit.
I recently did a Google Map project by plotting a matplotlib generated chart on a web page without using Bokeh and without saving the file into hard disk (as it is slow when involving hardware i/o).
I also chose to plot the graph in svg instead of png, as svg is valid html that can be easily inject into html template.
Python standard library has io.BytesIO object for writing binary streams, such as images, to a buffer in memory with the same syntax as used for writing binary data to files. The idea is to let Matplotlib write to a io.BytesIO object in the memory and afterwards retrieve the series of bytes in the plot file from this object and embed it in the HTML file directly.
from io import BytesIO
# prepare your plt.plot here as you normally do
svg_file = BytesIO()
plt.savefig(svg_file, format='svg') # save the file to io.BytesIO
svg_file.seek(0)
svg_data = svg_file.getvalue().decode() # retreive the saved data
svg_data = '<svg' + svg_data.split('<svg')[1] # strip the xml header
The saved SVG image contain the xml header which we don't need it so I split the header and only keep the part that started with <svg tag.
You can then add svg_data directly in your template like this:
{{ svg_data|safe }}
Related
plotly graph not rendering in Jinja2 template
Plotly version = '5.12.0' Jinja2 version = '3.1.2' I am creating some visuals for a HTML report in python and then emailing them to relevant people. I am using redmail to send the emails. I am creating a graph using plotly and then converting it to html. This is the code to recreate the graph and produce the html output. import plotly import plotly.express as px from redmail import EmailSender import jinja2 fig =px.scatter(x=range(10), y=range(10)) graph = fig.to_html(full_html = False, include_plotlyjs ='cdn') I am then inserting this into my Jinja HTML template which looks as follows <!DOCTYPE html> <html> <body> <script src="https://cdn.plot.ly/plotly-latest.min.js"></script> {{graph}} </body> </html> Next, I send the email to the relevant parties using this code email = EmailSender( host='smtp.gmail.com', port=587, username='email#gmail.com', password=pwd ) email.set_template_paths( html="", text="", ) # Create an env jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader('')) email.templates_html = jinja_env email.templates_text = jinja_env email.send( subject="An example email", sender="example#gmail.com", receivers=['example#live.co.uk'], html_template='template_file.html', body_params= {'graph':graph} ) The problem is, when I receive the email, it is completely blank, with no data/visuals in it. I should expect to see the plotly scatter plot, or at the minimum the raw text of the plotly graph html. I have tried pasting the div elements stored in the graph variable into an online HTML viewer, and the graph appears. I have seen other posts suggesting adding {{graph|safe}} to the graph variable in the jinja template, but that does not work either. I am completely lost as why it is not appearing/rendering in the Jinja template. It is not a problem with redmail as I have used it in the past for other templating work and have managed to insert HTML tables successfully. Any help would be greatly appreciated. EDIT: Here is the output of the graph variable outputted by plotly.to_html() <div> <script type="text/javascript">window.PlotlyConfig = {MathJaxConfig: \'local\'};</script>\n <script src="https://cdn.plot.ly/plotly-2.17.1.min.js"></script> <div id="6a72d392-1672-450b-9d7f-5ad0cd478fd4" class="plotly-graph-div" style="height:100%; width:100%;"></div> <script type="text/javascript"> window.PLOTLYENV=window.PLOTLYENV || {}; if (document.getElementById("6a72d392-1672-450b-9d7f-5ad0cd478fd4")) { Plotly.newPlot( "6a72d392-1672-450b-9d7f-5ad0cd478fd4", [{"hovertemplate":"x=%{x}<br>y=%{y}<extra></extra>","legendgroup":"","marker":{"color":"#636efa","symbol":"circle"},"mode":"markers","name":"","orientation":"v","showlegend":false,"x":[0,1,2,3,4,5,6,7,8,9],"xaxis":"x","y":[0,1,2,3,4,5,6,7,8,9],"yaxis":"y","type":"scatter"}], {"legend":{"tracegroupgap":0},"margin":{"t":60},"template":{"data":{"barpolar":[{"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"barpolar"}],"bar":[{"error_x":{"color":"#2a3f5f"},"error_y":{"color":"#2a3f5f"},"marker":{"line":{"color":"#E5ECF6","width":0.5},"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"bar"}],"carpet":[{"aaxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"baxis":{"endlinecolor":"#2a3f5f","gridcolor":"white","linecolor":"white","minorgridcolor":"white","startlinecolor":"#2a3f5f"},"type":"carpet"}],"choropleth":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"choropleth"}],"contourcarpet":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"contourcarpet"}],"contour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"contour"}],"heatmapgl":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmapgl"}],"heatmap":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"heatmap"}],"histogram2dcontour":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2dcontour"}],"histogram2d":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"histogram2d"}],"histogram":[{"marker":{"pattern":{"fillmode":"overlay","size":10,"solidity":0.2}},"type":"histogram"}],"mesh3d":[{"colorbar":{"outlinewidth":0,"ticks":""},"type":"mesh3d"}],"parcoords":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"parcoords"}],"pie":[{"automargin":true,"type":"pie"}],"scatter3d":[{"line":{"colorbar":{"outlinewidth":0,"ticks":""}},"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatter3d"}],"scattercarpet":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattercarpet"}],"scattergeo":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergeo"}],"scattergl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattergl"}],"scattermapbox":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scattermapbox"}],"scatterpolargl":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolargl"}],"scatterpolar":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterpolar"}],"scatter":[{"fillpattern":{"fillmode":"overlay","size":10,"solidity":0.2},"type":"scatter"}],"scatterternary":[{"marker":{"colorbar":{"outlinewidth":0,"ticks":""}},"type":"scatterternary"}],"surface":[{"colorbar":{"outlinewidth":0,"ticks":""},"colorscale":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"type":"surface"}],"table":[{"cells":{"fill":{"color":"#EBF0F8"},"line":{"color":"white"}},"header":{"fill":{"color":"#C8D4E3"},"line":{"color":"white"}},"type":"table"}]},"layout":{"annotationdefaults":{"arrowcolor":"#2a3f5f","arrowhead":0,"arrowwidth":1},"autotypenumbers":"strict","coloraxis":{"colorbar":{"outlinewidth":0,"ticks":""}},"colorscale":{"diverging":[[0,"#8e0152"],[0.1,"#c51b7d"],[0.2,"#de77ae"],[0.3,"#f1b6da"],[0.4,"#fde0ef"],[0.5,"#f7f7f7"],[0.6,"#e6f5d0"],[0.7,"#b8e186"],[0.8,"#7fbc41"],[0.9,"#4d9221"],[1,"#276419"]],"sequential":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]],"sequentialminus":[[0.0,"#0d0887"],[0.1111111111111111,"#46039f"],[0.2222222222222222,"#7201a8"],[0.3333333333333333,"#9c179e"],[0.4444444444444444,"#bd3786"],[0.5555555555555556,"#d8576b"],[0.6666666666666666,"#ed7953"],[0.7777777777777778,"#fb9f3a"],[0.8888888888888888,"#fdca26"],[1.0,"#f0f921"]]},"colorway":["#636efa","#EF553B","#00cc96","#ab63fa","#FFA15A","#19d3f3","#FF6692","#B6E880","#FF97FF","#FECB52"],"font":{"color":"#2a3f5f"},"geo":{"bgcolor":"white","lakecolor":"white","landcolor":"#E5ECF6","showlakes":true,"showland":true,"subunitcolor":"white"},"hoverlabel":{"align":"left"},"hovermode":"closest","mapbox":{"style":"light"},"paper_bgcolor":"white","plot_bgcolor":"#E5ECF6","polar":{"angularaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"bgcolor":"#E5ECF6","radialaxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"scene":{"xaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","gridwidth":2,"linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white"},"yaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","gridwidth":2,"linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white"},"zaxis":{"backgroundcolor":"#E5ECF6","gridcolor":"white","gridwidth":2,"linecolor":"white","showbackground":true,"ticks":"","zerolinecolor":"white"}},"shapedefaults":{"line":{"color":"#2a3f5f"}},"ternary":{"aaxis":{"gridcolor":"white","linecolor":"white","ticks":""},"baxis":{"gridcolor":"white","linecolor":"white","ticks":""},"bgcolor":"#E5ECF6","caxis":{"gridcolor":"white","linecolor":"white","ticks":""}},"title":{"x":0.05},"xaxis":{"automargin":true,"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","zerolinewidth":2},"yaxis":{"automargin":true,"gridcolor":"white","linecolor":"white","ticks":"","title":{"standoff":15},"zerolinecolor":"white","zerolinewidth":2}}},"xaxis":{"anchor":"y","domain":[0.0,1.0],"title":{"text":"x"}},"yaxis":{"anchor":"x","domain":[0.0,1.0],"title":{"text":"y"}}}, {"responsive": true} ) }; </script> </div>
Does html2image support the img tag?
I am trying to understand the html2image package. But it does not seem to find my locally stored images. I use the following code: from html2image import Html2Image hti = Html2Image() html_str =""" <!DOCTYPE html> <html> <body> <img src="example.jpg"> </body> </html> """ css_str = """ body { margin: 0; background: black; } """ hti.screenshot(html_str=html_str, css_str=css_str, save_as="test.png") Here "example.jpg" is an image of a flower saved in the same folder as the python script. The html_str copied into another file can be displayed by a browser without any problem. But when running the above python script, I end up with a mostly black image with corrupted file symbol in the upper left corner. Is there a way to fix this? Or does html2image not support the img tag?
Not sure if the best way, but I think you need to calculate the project path on the system from Python, and then serve the asset ahead of that URI. Assuming you can import os, here is how you would get current Python project directory: ROOT_DIR = os.path.dirname(os.path.abspath(__file__)) # This is your Project Root Once this is made, ROOT_DIR goes in the <img src='foo'> tag, then html2image should render, as the browser reads the system paths.
How to generate a PDF with a given template, with dynamic data in Python or NodeJS to be deployed on AWS
Looking for recommendation of a library in Python(first preference) or NodeJS that can generate a pdf file preferably from dynamic html template to be run in AWS. Requirement is to generate invoice pdf to be sent to customers. Have come across below 2 Node libraries: PDFKit jsPDF Here we might have to deal with numbers for X and Y. Better approach would be something where we can simply use html/css to generate template with placeholders which can be replaced with dynamic data(coming from database query). Any suggestions would be appreciated. Thanks!
This approach worked for me in Python using below libraries: Jinja2 - for generating HTML with custom data xhtml2pdf - for generating PDF from HTML Consider within your PROJECT DIR, there is a template file(invoice.html) and python file(pdf_generator.py) pdf_generator.py from xhtml2pdf import pisa import jinja2 templateLoader = jinja2.FileSystemLoader(searchpath="./") templateEnv = jinja2.Environment(loader=templateLoader) TEMPLATE_FILE = "invoice.html" template = templateEnv.get_template(TEMPLATE_FILE) # This data can come from database query body = { "data":{ "order_id": 123, "order_creation_date": "2020-01-01 14:14:52", "company_name": "Test Company", "city": "Mumbai", "state": "MH", } } # This renders template with dynamic data sourceHtml = template.render(json_data=body["data"]) outputFilename = "invoice.pdf" # Utility function def convertHtmlToPdf(sourceHtml, outputFilename): # open output file for writing (truncated binary) resultFile = open(outputFilename, "w+b") # convert HTML to PDF pisaStatus = pisa.CreatePDF( src=sourceHtml, # the HTML to convert dest=resultFile) # file handle to receive result # close output file resultFile.close() # return True on success and False on errors print(pisaStatus.err, type(pisaStatus.err)) return pisaStatus.err if __name__ == "__main__": pisa.showLogging() convertHtmlToPdf(sourceHtml, outputFilename) invoice.html <!DOCTYPE html> <html lang="en"> <body> Name: {{ json_data.company_name }} <br> City/State: {{ json_data.city }}, {{ json_data.state }} <br> Date: {{ json_data.order_creation_date }} <br> Order ID: {{ json_data.order_id }} <br> </body> </html>
https://www.npmjs.com/package/pdfmake The above library allows flexibility when it comes to dynamic invoices in node.js
With https://getpdfapi.com you can design PDF templates using a web-based editor and once you finish, a REST API endpoint will be created just for you. This endpoint can be used to send your data in JSON format to the PDF template you've just created. The only code you need to write is the code that integrates the API. You can check a quick demo here: https://www.youtube.com/watch?v=cv4ZYd_aJO8
Using AngularJS to show images from API (flask app)
I'm trying to show some badge images I made for a RANK APP I've been working for. It's 10 images that should be shown specific for each driver. I'm not an expert on coding, but I keep searching and studying ways to solve the problem I've been through. I firstly tried to send base64 images from the API to the browser, using this code: <!-- language: python --> for img in imglist: #loop for creating a list of base64 images from a list of image dir. imgcode = base64.encodestring(open(imgdir + img,"rb").read()) imgcodelist.append(imgcode) for driver in sortdriverList: #loop for taking drivers points and turn it into RANK img if (driver['Races'] < 21): driver['Rank'] = str(imgcodelist[9]) [...] The second loop is longer than that, stil what I've shown to you above makes any driver that wasn't participating in more than 21 races, be part of a 'NON CLASSIFIED' badge. I used AngularJS to try to show the base64 image using the code below. '<html>' <td><img src="data:image/png;base64,{{ '{{driver.Rank}}'}}"></td> [driver.Rank] should be the base64 code string. When I run the app, the image is not shown, instead I see the very code of the image inside the table =/ Then I tried to turn [driver.Rank] into a dir string for "img src=", using the codes below. <!-- language: python --> imglist = ["notclassified.png", etc...] imgdir = "static/images/" for item in sortdriverList: if (item['Races'] < 21): item['Points'] = imgdir + imglist[9] and in my HTML I changed the img src to: '<html>' <img src= {{ '{{driver.Rank}}' }}> and now it shows the directory of the images. I've been searching for CSS ways to make it possible. I coudn't find a solution yet.
It's hard to tell what's going on since only segments are pasted, but I'm guessing it has to do with how you are escaping the code. Maybe you could paste the generated code in chrome. Sometimes seeing a working example helps. angular.module('App', []) .controller('DriverCtrl', DriverCtrl); function DriverCtrl($scope) { // base64 encode 1x1 black pixel this.Rank = 'R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs='; } <div ng-app="App"> <div ng-controller="DriverCtrl as driver"> <div>Rank: {{driver.Rank}}</div> <span>Image:</span> <img ng-src="data:image/png;base64,{{driver.Rank}}"> </div> </div> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
How to refresh the flask web page?
Recently, I have a project is to implement the dynamic plotting on a web page. Here is my python code from flask import Flask #from flask import render_template import matplotlib.pyplot as plt import io import base64 app = Flask(__name__) #app.route('/plot') def build_plot(): img = io.BytesIO() y = [1,2,3,4,5] x = [0,2,1,3,4] plt.plot(x,y) plt.savefig(img, format='png') img.seek(0) plot_url = base64.b64encode(img.getvalue()).decode() return '<img src="data:image/png;base64,{}">'.format(plot_url) if __name__ == '__main__': app.run(debug=True, host='0.0.0.0') Here is my HTML code <!DOCTYPE html> <html> <head> <title> Plot</title> <meta content='5; url=http://127.0.0.1:5000/plot' http-equiv='refresh'> </head> <body> <img src="data:image/png;base64, {{ plot_url }}"> </body> </html> Although I add <meta content='5; url=http://127.0.0.1:5000/plot' http-equiv='refresh'> into my HTML code, it still can not refresh automatically. If I want to observe the change of the plotting, I still need to refresh it manually. Can anyone help me to solve this problem? Thanks a lot
You do not need to include the URL. Just use only the content attribute of meta tag. <meta http-equiv="refresh" content="5" > But to see the real time changes in your graph, you might want to look at sockets in flask. This will help server push changes to all clients using broadcasting. Using sockets is way better approach than to refresh your page at regular interval.