Matplotlib not working with Python 2.7 and Django on OSX - python

I am trying to use matplotlib and mpld3 to produce some html plots on my Django report app.
Basically I have a controller for the plot that is the following:
from django.shortcuts import render
import mpld3
from matplotlib.pyplot import figure, title, bar
def cpfLogin(request):
mpl_figure = figure(1)
xvalues = (1,2,3,4,5)
yvalues = (1,2,3,4,5)
width = 0.5 # the width of the bars
title(u'Custom Bar Chart')
bar(xvalues, yvalues, width)
fig_html = mpld3.fig_to_html(mpl_figure)
context = {
'figure': fig_html,
}
return render(request, 'reports/CPFReport.html', context)
The code for reports/CPFReport.html is:
{% load i18n %}
{% block extrahead %}
<style type="text/css">
.chart_title {
font-weight: bold;
font-size: 14px;
}
</style>
{% endblock %}
{% block content %}
<div id="content-main">
<div class="chart_title">
{% trans "Custom Bar Chart" %}
</div>
{{ figure|safe }}
</div>
{% endblock %}
The code is executed right and the plot is displayed correctly but after a couple of seconds the app terminates with the following error:
Assertion failed: (NSViewIsCurrentlyBuildingLayerTreeForDisplay() !=
currentlyBuildingLayerTree), function
NSViewSetCurrentlyBuildingLayerTreeForDisplay, file
/BuildRoot/Library/Caches/com.apple.xbs/Sources/AppKit/AppKit-1561.20.106/AppKit.subproj/NSView.m,
line 14480.
I found out that if I comment all the code this exception is thrown when any of the matplotlib libraries are called.
Does anyone has a workaround or solution for this problem?

In my case I had to avoid importing :
import matplotlib.pyplot as plt
fig,ax = plt.subplots(figsize=(8,9))
l = plt.plot(x,s, 'y-', label="line")
and substitute it with:
from matplotlib.figure import Figure
fig = Figure()
ax = fig.add_subplot(111))
l = ax.plot(x,s, 'y-', label="line")

Maybe I find the solution,
just add the follow code in top.
import matplotlib
matplotlib.use('Agg')
For my case, I use python3, flask and matplotlib.
reference:
https://gist.github.com/tebeka/5426211

Adding plt.close() after saving the figure using fig.savefig('../static/images/something.png') helped me.

To complete mapp mapp's answer, in this case it's linked to using matplotlib with a webserver. The solution recommended by matplotlib documentation is to use the Agg backend :
import matplotlib
matplotlib.use('Agg')
# then import pyplot and mpld3
import mpld3
from matplotlib.pyplot import figure, title, bar

Related

Is there a way to plot a plotly chart in a backend server, and to send the interactive results on a webapp?

So, I'm actually making all computations in backend, generate a chart in (.png), save it to a pathfile, and communicate through AJAX the link to this newly generated image. However, such process allows me to transfer an image only. I'm basically converting the plot to an image.
I wonder if there is a way to transfer the entire plotly output, as an interactive chart through AJAX.
import yfinance as yf
import plotly.graph_objects as go
aapl = yf.Ticker('AAPL')
ainfo = aapl.history(start=datemin, end=datemax)
#Plot the Chart
fig = go.Figure(data=go.Scatter(x=ainfo.index,y=ainfo.Close, mode='lines'),)
#DB inject plot
fig.write_image("/Users/Xlibidish/Desktop/Django/static/"+tickerZ+rx+".png")
#And then communicate the path through AJAX etc.
I'd like to send to my Webapp the plotly output. I have some hints:
Generate the plot in my Webapp directly in JS, so the backend sends only the data from yfinance and a directive to generate it. (Quite complex, especially knowing that I have various types of plots, which are all generated in python so the Webappp is only receiving Images at this time without differentiating them).
Create an iframe directing to the plotly output ports, but not sure about this one ! And also, I need to save the plot results in a DB.
Just to clarify:
#in the previous example:
fig.view()
# will be very different from
fig.write_image()
#One will be a png file, the other a pretty cool interactive chart.
```
try fig.to_html()
To be honest, I do not even know what AJAX is. So I am not using AJAX but I still manage to display the entire interactive chart on my "website".
Maybe this gives you some guidance and you can figure out the AJAX part for yourself.
def _give_fig():
data = # input your data here
layout = # input your layout here
fig = go.Figure(data=data, layout=layout) # build your figure with data and layout
fig.update_layout(template='simple_white') # modify your fig until ready
return fig.to_html(config={'displaylogo': False}, include_plotlyjs=False, default_width=790, default_height=600)
# returns chart as html
# displaylogo False to hide the plotly logo in chart
# default width and hight self explanatory
# include_plotlyjs --> important!
def your_view(request):
context = {"your_plot": _give_fig()}
return render(request, 'app/your_template.html', context)
Read more about include_plotlyjs here. You can put it to True and then it will directly include the javascript. It is about 3 mb I think. I personally use the CDN. So have a look at my template:
your_template.html:
{% extends 'base.html' %}
{% block styles %}
<script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
{% endblock %}
{% block content %}
{% autoescape off %}
{{ your_plot }}
{% endautoescape %}
{% endblock %}
Yeah, that works without the AJAX. Good luck trying to fiddle it in.

Trouble displaying Bokeh toolbar

I'm new to Bokeh and Flask python in general but i have managed to create a graph and then output it on my browser via flask. The only problem is that im not getting the "Bokeh tool bar" next to my graph.
My code looks like this
from flask import Flask, render_template, request
import pandas as pd
import csv
from bokeh.plotting import figure
from bokeh.io import show
from bokeh.embed import components
from bokeh.models import Range1d
from bokeh.resources import CDN
app = Flask(__name__)
# Create the main plot
def create_figure():
xvals = []
yvals = []
with open('test.csv') as csvfile:
readCSV = csv.reader(csvfile, delimiter=',')
for row in readCSV:
xvalue = row[0]
yvalue = row[1]
xvals.append(xvalue)
yvals.append(yvalue)
p = figure(plot_width=400, plot_height=400, x_range=(0, 20))
p.y_range = Range1d(0, 15)
p.circle(xvals, yvals, size=10)
return p
# Index page
#app.route('/')
def index():
plot = create_figure()
script, div = components(plot)
cdn_js = CDN.js_files[0]
cdn_css = CDN.css_files[0]
return render_template("index.html", script=script, div=div,
cdn_js=cdn_js,
cdn_css=cdn_css)
# With debug=True, Flask server will auto-reload
# when there are code changes
if __name__ == '__main__':
app.run(port=5000, debug=True)
and my index.html code looks like this:
<html>
<head>
<link href={{ cdn_css|safe }} type="text/css" />
<script type="text/javascript" src={{ cdn_js|safe }}></script>
</head>
<body>
<H1>First</H1>
{{ script|safe }}
{{ div|safe }}
</body>
</html>
Am i missing something? When i output the graph to a output_file i get the toolbar. Any help would be appreciated.
Most likely this is this https://github.com/bokeh/bokeh/issues/7497 issue. The available workarounds, as I posted in the thread, are as follows:
There are two options. If you want to keep the toolbar as part of a plot, then you will have to create a ToolbarPanel manually and add it with add_layout() to a plot. Alternatively you can have a toolbar detached from a plot, as an element of a bigger layout, like it happens with grid plots. In both cases the key is to set plot.toolbar_location = None, to disable creation of the default ToolbarPanel.
Please follow this issue so that you can be aware of future developments.
I had the same problem. I can't explain the reason, but this example works: realpython github

Python: How to show matplotlib in flask [duplicate]

This question already has answers here:
Converting matplotlib png to base64 for viewing in html template
(2 answers)
Save plot to image file instead of displaying it using Matplotlib
(24 answers)
How to serve static files in Flask
(24 answers)
Closed 4 years ago.
I'm very new to Flask and Matplotlib. I'd like to be able to show a simple chart I generated in some html, but I'm having a very hard time figuring out how. Here is my Python code:
from flask import Flask, render_template
import numpy as np
import pandas
import matplotlib.pyplot as plt
app = Flask(__name__)
variables = pandas.read_csv('C:\\path\\to\\variable.csv')
price =variables['price']
#app.route('/test')
def chartTest():
lnprice=np.log(price)
plt.plot(lnprice)
return render_template('untitled1.html', name = plt.show())
if __name__ == '__main__':
app.run(debug = True)
And here is my HTML:
<!doctype html>
<html>
<body>
<h1>Price Chart</h1>
<p>{{ name }}</p>
<img src={{ name }} alt="Chart" height="42" width="42">
</body>
</html>
You can generate the image on-the-fly in Flask URL route handler:
import io
import random
from flask import Response
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas
from matplotlib.figure import Figure
#app.route('/plot.png')
def plot_png():
fig = create_figure()
output = io.BytesIO()
FigureCanvas(fig).print_png(output)
return Response(output.getvalue(), mimetype='image/png')
def create_figure():
fig = Figure()
axis = fig.add_subplot(1, 1, 1)
xs = range(100)
ys = [random.randint(1, 50) for x in xs]
axis.plot(xs, ys)
return fig
Then you need to include the image in your HTML template:
<img src="/plot.png" alt="my plot">
As #d parolin pointed out, the figure generated by matplotlib will need to be saved before being rendered by the HTML. In order to serve images in flask by HTML, you will need to store the image in your flask file directory:
static/
images/
plot.png --> store plots here
templates/
Therefore, in your application, use plt.savefig:
#app.route('/test')
def chartTest():
lnprice=np.log(price)
plt.plot(lnprice)
plt.savefig('/static/images/new_plot.png')
return render_template('untitled1.html', name = 'new_plot', url ='/static/images/new_plot.png')
Then in untitled1.html:
<p>{{ name }}</p>
<img src={{ url}} alt="Chart" height="42" width="42">

Background color of bokeh layout

I'm playing around with the Bokeh sliders demo (source code here), and I'm trying to change the background color of the entire page. Though changing the color of the figure is easy using background_fill_color and border_fill_color, the rest of the layout still appears on top of a white background. Is there an attribute I can add to the theme that will allow me to set the color via curdoc().theme?
There's not currently any Python property that would control the HTML background color. HTML and CSS is vast territory, so instead of trying to make a corresponding Python property for every possible style option, Bokeh provides a general mechanism for supplying your own HMTL templates so that any standard familiar CSS can be applied.
This is most easily accomplished by adding a templates/index.html file to a Directory-style Bokeh App. The template should be Jinja2 template. There are two substitutions required to be defined in the <head>:
{{ bokeh_css }}
{{ bokeh_js }}
as well as two required in <body>:
{{ plot_div }}
{{ plot_script }}
The app will appear wherever the plot_script appears in the template. Apart from this, you can apply whatever HTML and CSS you need. You can see a concrete example here:
https://github.com/bokeh/bokeh/blob/master/examples/app/crossfilter
A boiled down template that changes the page background might look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
body { background: #2F2F2F; }
</style>
<meta charset="utf-8">
{{ bokeh_css }}
{{ bokeh_js }}
</head>
<body>
{{ plot_div|indent(8) }}
{{ plot_script|indent(8) }}
</body>
</html>
Changing the .bk-root style worked for me:
from bokeh.resources import Resources
from bokeh.io.state import curstate
from bokeh.io import curdoc, output_file, save
from bokeh.util.browser import view
from bokeh.models.widgets import Panel, Tabs
from bokeh.plotting import figure
class MyResources(Resources):
#property
def css_raw(self):
return super().css_raw + [
""".bk-root {
background-color: #000000;
border-color: #000000;
}
"""
]
f = figure(height=200, width=200)
f.line([1,2,3], [1,2,3])
tabs = Tabs( tabs=[ Panel( child=f, title="TabTitle" ) ], height=500 )
output_file("BlackBG.html")
curstate().file['resources'] = MyResources(mode='cdn')
save(tabs)
view("./BlackBG.html")
If you are using row or column for displaying several figures in the document, a workaround is setting the background attribute like this:
curdoc().add_root(row(fig1, fig2, background="beige"))
I know it is not the cleanest way to do it, but a workaround would be to modify file.html inside bokeh template folder
FILE PATH
CODE SNIPPET
From Bokeh documentation:
The background fill style is controlled by the background_fill_color
and background_fill_alpha properties of the Plot object:
from bokeh.plotting import figure, output_file, show
output_file("background.html")
p = figure(plot_width=400, plot_height=400)
p.background_fill_color = "beige"
p.background_fill_alpha = 0.5
p.circle([1, 2, 3, 4, 5], [2, 5, 8, 2, 7], size=10)
show(p)

Folium map not displaying

Running on canopy version 1.5.5.3123
With;
Folium Version: 0.1.2, Build: 1
The following code;
import folium
import pandas as pd
LDN_COORDINATES = (51.5074, 0.1278)
from IPython.display import HTML
import shapefile
#create empty map zoomed in on London
LDN_COORDINATES = (51.5074, 0.1278)
map = folium.Map(location=LDN_COORDINATES, zoom_start=12)
display(map)
Returns
<folium.folium.Map at 0x10c01ae10>
But nothing else.
How do i get to display a map within an ipython notebook?
You can also save the map as html and then open it with webbrowser.
import folium
import webbrowser
class Map:
def __init__(self, center, zoom_start):
self.center = center
self.zoom_start = zoom_start
def showMap(self):
#Create the map
my_map = folium.Map(location = self.center, zoom_start = self.zoom_start)
#Display the map
my_map.save("map.html")
webbrowser.open("map.html")
#Define coordinates of where we want to center our map
coords = [51.5074, 0.1278]
map = Map(center = coords, zoom_start = 13)
map.showMap()
_build_map() doesn't exist anymore. The following code worked for me
import folium
from IPython.display import display
LDN_COORDINATES = (51.5074, 0.1278)
myMap = folium.Map(location=LDN_COORDINATES, zoom_start=12)
display(myMap)
Considering the above answers, another simple way is to use it with Jupiter Notebook.
for example (on the Jupiter notebook):
import folium
london_location = [51.507351, -0.127758]
m = folium.Map(location=london_location, zoom_start=15)
m
and see the result when calling the 'm'.
I've found this tutorial on Folium in iPython Notebooks quite helpful. The raw Folium instance that you've created isn't enough to get iPython to display the map- you need to do a bit more work to get some HTML that iPython can render.
To display in the iPython notebook, you need to generate the html with the myMap._build_map() method, and then wrap it in an iFrame with styling for iPython.
import folium
from IPython.display import HTML, display
LDN_COORDINATES = (51.5074, 0.1278)
myMap = folium.Map(location=LDN_COORDINATES, zoom_start=12)
myMap._build_map()
mapWidth, mapHeight = (400,500) # width and height of the displayed iFrame, in pixels
srcdoc = myMap.HTML.replace('"', '"')
embed = HTML('<iframe srcdoc="{}" '
'style="width: {}px; height: {}px; display:block; width: 50%; margin: 0 auto; '
'border: none"></iframe>'.format(srcdoc, width, height))
embed
Where by returning embed as the output of the iPython cell, iPython will automatically call display.display() on the returned iFrame. In this context, you should only need to call display() if you're rendering something else afterwards or using this in a loop or a function.
Also, note that using map as a variable name may might be confused with the .map() method of several classes.
Is there a reason you are using an outdated version of Folium?
This ipython notebook clarifies some of the differences between 1.2 and 2, and it explains how to put folium maps in iframes.
http://nbviewer.jupyter.org/github/bibmartin/folium/blob/issue288/examples/Popups.ipynb
And the code would look something like this (found in the notebook above, it adds a marker, but one could just take it out):
m = folium.Map([43,-100], zoom_start=4)
html="""
<h1> This is a big popup</h1><br>
With a few lines of code...
<p>
<code>
from numpy import *<br>
exp(-2*pi)
</code>
</p>
"""
iframe = folium.element.IFrame(html=html, width=500, height=300)
popup = folium.Popup(iframe, max_width=2650)
folium.Marker([30,-100], popup=popup).add_to(m)
m
The docs are up and running, too, http://folium.readthedocs.io/en/latest/
There is no need to use iframes in 2022. To display the map, simply use the
{{ map | safe }} tag in html and _repr_html_() method in you view. It is also not necessary to save the map to the template
sample.py
#app.route('/')
def index():
start_coords = (46.9540700, 142.7360300)
folium_map = folium.Map(location=start_coords, zoom_start=14)
return folium_map._repr_html_()
template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ folium_map | safe }}
</body>
</html>
i have same error and nothing work for me
finally i found it
print(dir(folium.Map))
see method save dose not exist instead use

Categories