Expand folium map size on mobile devices - python

I make a web app using Django, Folium. I have a navbar and a Folium map on the web page. It works fine om computers and landscape screen devices, but on portrait screen devices the map has a free space.
My code for map:
current_map = folium.Map(location=start_location, zoom_start=6)
fig = branca.element.Figure(height="100%")
fig.add_child(current_map)
context = {"current_map": current_map._repr_html_()}
return render(request, template_name="index.html", context=context)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
{{ current_map | safe }}
</body>
</html>
How do I fill it?

Well, I might to use Figure and modify folium package.
current_map = folium.Map(location=(48.51, 32.25), zoom_start=6)
map_container = branca.element.Figure(height="100%")
map_container.add_child(current_map)
...
context = {"current_map": map_container.render(), "form": form}
return render(request, template_name="hub/index.html", context=context)
I downloaded folium-0.12.1.post1.tar.gz, and from folium/folium.py removed mentions about old versions of Bootstrap from lists _default_js and _default_css. But I use Bootstrap in base.html.
And in requirements.txt I use this local modified distr:
./distr/folium-0.12.1.post1.tar.gz

You could use
current_map._repr_html_()
That give you representation for jupitier notebook.
And use it in template by
{{current_map|safe}}
In teality this is a syring content tat easely could be modified by
.replace()
and you coud add height, or change proportion.
Also you could use
f=folium.Figure(height="100%"
current_map.add(f)
And in this case
current_map._repr_html_()
will return
Sou you could manage size of follium window.

I also had this similar problem while back
I solved it by changing the style of the map where i rendered it position:fixed;

Try this:
context = {'map': map.get_root().render()}
return render(request, template_name="index.html", context=context)
index.html:
<html>
{{map|safe}}
</html>

Related

is there any way to call a function(in another python file) and get the same return in Django view

I am trying to get a return from a function that is in similarity.py (function name returnTablewithURL) to Views.py. When I print the variable df in similarity.py it gives the output in dataframe. Like this:
Similarity (%)
https://en.wikipedia.org/wiki/The_quick_brown_f... 0.876818
https://knowyourphrase.com/the-quick-brown-fox 2.371295
I want to get the same output for fileupload function in views.py. So I tried to call the function from views (meaning from fileupload function) but it shows something in numbers. Output( with the help of print statement to check if it is same):
<function returnTableWithURL at 0x000001D3631311F0>
I have tried some other methods but in vain. It would be really helpful if i could use some suggestion and help
Views.py:
def fileupload(request):
# Handel file upload
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
#Process for handeling the file snd store it on mongodb
newdoc = Document(docfile = request.FILES['docfile'])
#Contain process for extracting data in a file and storing them in DB as textfield
newdoc.fileData = request.FILES['docfile'].read()
newdoc.username = request.user
newdoc.save()
# Redirect to the document list after post
result(newdoc.fileData)
# Here i am trying to get the result from
# returnTableWithURL function. This function is in
# another python
dframe = returnTableWithURL
print(dframe)
return render(request, 'report.html',{'df':
dframe})
else:
form = DocumentForm() #A empty, unbound form
# Load documents for the list page
documents = Document.objects.filter(username=request.user)
# Render list page with the documents and the form
return render(request,
'home.html',
{'documents': documents, 'form': form})
Here is the function and python file. function takes an parameter.
Similarity.py
def returnTableWithURL(dictionary):
df = pd.DataFrame({'Similarity (%)':dictionary})
print(df)
return df
Here is the HTML page where I want to show the dataframe
report.html
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Plagirism Report</title>
</head>
<body>
{{ df }}
</body>
</html>
Alright, so i failed to do it in normal process like by calling the df variable but I succeded it using json. I followed this solution https://www.geeksforgeeks.org/rendering-data-frame-to-html-template-in-table-view-using-django-framework/
I hope it helps other

Unable to embed JSON Bokeh Plot in Django template

I have a script which takes uploaded data, munges it together, turns it into a plot (using Bokeh) and then exports it to a directory as JSON.
At some point in the future, a user can hit the right URL and the appropriate plot should be displayed to the user as part of the HTML template.
I can generate the plot. I can save it as JSON. I can get the URL to retrieve it as JSON, but I cannot get the JSON plot to render within the template.
I've had a dig around the Bokeh documentation and examples, but they all seem to use a flask app to serve the pages.
I think I'm on the right track, using views.py to find and return JSON as part of a render() response, and then have Bokeh.embed.embed_items() do the work in the template to make it look right, but it's not working out - everything but the plot is displayed.
1) Create the plot and puts it in the directory for later use (app/results/1)
create plot.py
import os
import json
from django.conf import settings
from bokeh.embed import json_item
from bokeh.plotting import figure
x=[1,2,3,4,5]
y=[0,-1,-2,3,4]
p=figure(title="test_example")
p.line(x, y)
#json_export = json_item(p, "result")
json_export = json_item(p)
with open(os.path.join(settings.RESULTS_DIR,"1", "test.json"), 'w') as fp:
fp.write(json.dumps(json_export))
2) Set up the url
urls.py
urlpatterns=[
path('result/<int:pk>', views.resultdetailview, name='result-detail'),
]
3) Take the request, use the pk to find the plot json and render it all in the appropriate template.
views.py
def resultdetailview(request, pk):
results=str(pk)
with open(os.path.join(settings.RESULTS_DIR, results, "test.json"), 'r') as fp:
#data=json.load(fp)
data=json.loads(fp.read())
#context={'result':data}
#return render(request, 'app/sandbox_detail.html', context)
return render(request=request,
context={'json_object':data, 'resources':CDN.render()})
NB: If I instead use return JsonResponse(data, safe=False) then the url returns the json successfully ...
I think therefore that the issue is in the template.
4) Show the wonderous plot to the user
sandbox_detail.html
<header>
<link rel="stylesheet" href="http://cdn.bokeh.org./bokeh/release/bokeh-0.11.1.min.css" type="text/css" >
<script type="text/javascript" src="http://cdn.bokeh.org./bokeh/release/bokeh-0.11.1.min.js"> </script>
</header>
<h1> Title: Test </h1>
<div>Test</div>
<body>
<div id="result"></div>
<script>
Bokeh.embed.embed_item({{json_object}}, "result");
</script>
</body>
This template renders everything but the 'result' div.
What have I missed?
This is what I see so far:
FIRST: You are mixing 2 methods for injecting plot json data into the page.
According to documentation you can do it using either of these two methods:
1) specify the div directly:
Python: json_data = json.dumps(json_item(p, "myplot"))
JavaScript: Bokeh.embed.embed_item(item);
2) specify the div in embed_item function:
Python: json_data = json.dumps(json_item(p))
JavaScript: Bokeh.embed.embed_item(item, "myplot");
But not both of them at the same time. Could this be the problem?
SECOND: Preferably don't insert Bokeh resources by hand: rather use CDN.render() or INLINE.render() to automatically include all that your script needs:
import json
from bokeh.resources import CDN
return render(request = request,
template_name = 'app/sandbox_detail.html',
context = { json_object = json.loads(json_string),
resources = CDN.render() } )
sandbox_detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
{{ resources }}
</head>
<body>
<div id="result"></div>
<script>
Bokeh.embed.embed_item({{ json_object }}, "result");
</script>
</body>
</html>
THIRD: Make sure what you embed in the page is json object not a string (see variable naming above)
It helps when you debug your rendered template in your browser's debug tool.
I tried a very similar approach and found one large flaw: My browser noted that it could not find the None object. The reason here is that python stores the empty value as None, while JavaScript expects a null object.
The solution? Python already translates None to null, when you run json.dumps. To keep it that way, read the json string as a string. So instead of your data=json.loads(fp.read()) use data=fp.read().

Django and Folium integration

Django newbie here: my aim is to integrate Folium to an html page. so what I have at the moment:
polls/views.py
def show_map(request):
#creation of map comes here + business logic
m = folium.Map([51.5, -0.25], zoom_start=10)
test = folium.Html('<b>Hello world</b>', script=True)
popup = folium.Popup(test, max_width=2650)
folium.RegularPolygonMarker(location=[51.5, -0.25], popup=popup).add_to(m)
context = {'my_map': m}
return render(request, 'polls/show_folium_map.html', context)
polls/urls.py
urlpatterns = [
path('show_my_map', views.show_map, name='show_map'),
]
and show_folium_map.html
<h1>map result comes here</h1>
{{ my_map }}
problem is that I get the 'to_string' value of the map (I promise you I saw that coming). So how can I integrate the map in such way that I can actually see the map and also define the size?
In order to really include folium into custom django template you have to render your figure first before adding it to context (This will recursivly load all parts of the map into the figure). Afterwards in your template, you have to access header, html and script parts of figure seperatly by calling their render function. Additionally, those parts have to marked as "safe" by django template tag in order to allow html insertion. See example below.
Example:
views.py:
import folium
from django.views.generic import TemplateView
class FoliumView(TemplateView):
template_name = "folium_app/map.html"
def get_context_data(self, **kwargs):
figure = folium.Figure()
m = folium.Map(
location=[45.372, -121.6972],
zoom_start=12,
tiles='Stamen Terrain'
)
m.add_to(figure)
folium.Marker(
location=[45.3288, -121.6625],
popup='Mt. Hood Meadows',
icon=folium.Icon(icon='cloud')
).add_to(m)
folium.Marker(
location=[45.3311, -121.7113],
popup='Timberline Lodge',
icon=folium.Icon(color='green')
).add_to(m)
folium.Marker(
location=[45.3300, -121.6823],
popup='Some Other Location',
icon=folium.Icon(color='red', icon='info-sign')
).add_to(m)
figure.render()
return {"map": figure}
templates/folium_app/map.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{{map.header.render|safe}}
</head>
<body>
<div><h1>Here comes my folium map:</h1></div>
{{map.html.render|safe}}
<script>
{{map.script.render|safe}}
</script>
</body>
</html>
You can try the below way. I also had faced the same issue and it worked great for me.
views.py
def show_map(request):
#creation of map comes here + business logic
m = folium.Map([51.5, -0.25], zoom_start=10)
test = folium.Html('<b>Hello world</b>', script=True)
popup = folium.Popup(test, max_width=2650)
folium.RegularPolygonMarker(location=[51.5, -0.25], popup=popup).add_to(m)
m=m._repr_html_() #updated
context = {'my_map': m}
return render(request, 'polls/show_folium_map.html', context)
show_folium_map.html
{{ my_map|safe }}
You can get the html as a string by triggering the rendering on the (internal) parent of Map:
m = folium.Map()
html: str = m.get_root().render()
Note that this returns a full html page, so you may need to put it in an iframe.
Alternatively, you can render the head, body and script parts separately. That way you can put each part on your page where it belongs and you don't need an iframe:
m = folium.Map()
html_head: str = m.get_root().header.render()
html_body: str = m.get_root().html.render()
html_script: str = m.get_root().script.render()

Why does Django think my query string is empty?

I've been having trouble with a query string in one of my views in Django. I've successfully handled query strings in other views, so I'm not sure what I did wrong here. I stripped things down to a really basic view, and I'm still not getting anything.
My URL:
localhost/query_view/?foo=foo
My template:
<html>
<head>
<title>Title</title>
</head>
<body>
<p>{{ query_string }}</p>
</body>
</html>
My view:
def query_view(request):
query_string = request.META['QUERY_STRING']
return render(request, 'query_view.html', {'query_string': query_string})
I should expect foo=foo to be displayed on the page, right? Currently, I'm getting nothing.
Edit: Django version 1.9.4, Python version 3.4.3
try
def query_view(request):
query_string = request.GET.get('foo',None)
print(query_string)
return render(request, 'query_view.html', {'query_string': query_string})
and check if query_string value is None or not .
Let me know, if it didn't work out!
Inaddition mention your django and python version also.
I would put a debugger before the return to see what's actually in the request. But usually something like request.GET.get('foo') would get you what you want. Also, you can provide a default value if foo is actually empty. request.GET.get('foo', 'blah')

Create a webpage with charts or tables from csv data using the pyramid framework

I have data in csv format and I want to create a webpage with charts or tables. I'm using the Pyramid Framework, chameleon, and deform_bootstrap.
I'm new to web development and there doesn't seem to be any tutorials for this out there. Can anyone point me in the right direction?
Without knowing more details its difficult to say. However, basically you will need a route registered in your config (in the root __init__.py file), a view callable (this can be just a method) to read the file and pass the data to a renderer and a chameleon template to render the data.
First set a route in your configuration. For example, to add a route for the table and one for the chart you could do something like this in your __init__.py file.
config.add_route('show_table', '/table')
config.add_route('show_chart', '/chart')
The choice of names and paths is up to you of course.
Then, you need to implement a view callable for each route. These would read the file and return a dictionary containing the data. They also tie the data to a particular renderer, in your case a chameleon template. Something like this might be right for your case where both routes need the same data.
from pyramid.view import view_config
def read_file():
"""read the file and return the data in a suitable format"""
return [1,4,2,4,56,7,45,3]
#view_config(route_name='show_table', renderer='templates/table.pt')
def table_view(request):
data = read_file()
return {'data': data}
#view_config(route_name='show_chart', renderer='templates/chart.pt')
def chart_view(request):
data = read_file()
return {'data': data}
Finally, you will need to implement the template files. These will be different depending on what you need.
<!DOCTYPE html>
<html xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
</head>
<body>
<table>
<tr><th>Data</th></tr>
<tr tal:repeat="datum data"><td>${datum}</td></tr>
</table>
</body>
</html>
To make charts I use d3.js but this is another question I think. Here is a simple example based on the first steps in this tutorial. First your template needs to make the data available to javascript. One way is to write the data into a javascript variable. This will work but is a bit messy - see this question for alternative approaches. In a real app you might want to use ajax so you would be writing the url to access the data here.
<!DOCTYPE html>
<html xmlns:tal="http://xml.zope.org/namespaces/tal">
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
</head>
<body>
<div class="chart"></div>
<script type="text/javascript">
var data = ${data};
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([0, 420]);
d3.select(".chart")
.selectAll("div").data(data)
.enter().append("div")
.style("width", function(d) { return x(d) + "px"; })
.text(function(d) { return d; });
</script>
</body>
</html>
This should work but is untested, if you have any problems let me know and I will update it when I have a moment.

Categories

Resources