My Folium does not output anything, just a blank image - python

In the first image, I have a map when I enter a certain range of numbers. As you can see on the second map, it maps out blank. I tried out different range and some of them crashes and outputs a blank map. For example, 300th address does not work even if I put the range from 299 to 301 and 450 does not work either. There are certain addresses block me from mapping it out. I already set the data limit to max through terminal as well.

I've found the answer to my own question. As for the popup, I added parse_html=True on popup which fixed my problem. Also I have just put the popup and icon function separately for clarity
map2 = folium.Map(location=[43.7, -79.4], tiles='cartodbpositron',
zoom_start=11) # set default location on the map
marker_cluster = folium.plugins.MarkerCluster().add_to(map2) # add the
location to the marker cluster
for point in range(len(locationlist)): # loop through the plots
# include popup
popup1 = folium.Popup(df['Condo Address'][point], parse_html=True)
# include icon
icon1 = folium.Icon(color=df['color'][point])
# mark every addresses in the map from the data
folium.Marker(locationlist[point],popup=popup1,icon =
icon1).add_to(marker_cluster)

Related

How to update Span (Bokeh) using ColumnDataSource?

I am trying to update Span using ColumnDataSource, but the information is not being passed onto the source. Span unfortunately does not have a paremeter "source", so is there a better way?
I have defined my sources, figure and line like so:
m1_source = ColumnDataSource(data=dict(x1=[], y1=[]))
m1_spans = ColumnDataSource(data=dict(x1=[]))
p = figure(x_axis_type="datetime", title="", sizing_mode="fixed", height = 500, width = 1400)
p.line(x ="x1", y="y1", color = 'blue', source=m1_source)
Then I have a for loop that should ideally plot multiple spans, each 'i' will be a separate timestamp:
for i in m1_spans.data['x1']:
p.add_layout(Span(location=i, dimension='height', line_color='red', line_dash='solid', line_width=1))
This is taken from my update() function:
m1_source.data = dict(
x1=machine_1_vals['mpTimestamp'],
y1=machine_1_vals['Value'])
m1_spans.data = dict( x1=ToolsDF.loc[ToolsDF['Value'] == float(vals['Tool_val'])]['Timestamp'])
I have checked this, and m1_spans does successfully return multiple timestamps, so the error shouldn't be here.
The reason I am confused, is because my p.line will successfully update with no issues, but it does have a source parameter, while span does not.
I would be really appreciative for any advice about how to solve this issue.
If I should have supplied more information, I apologize and can update as needed, I just tried to keep it brief for you.
Thanks.
Span objects do not currently have an ability to be "powered" by a ColumnDataSource. Each Span only draws one span, specified by its own location property.
You will need to update the location property individually on each Span object in order to update it. Alternatively, if you absolutely want to be able to drive updates through a CDS, you could look at using a multi_line, segment, or ray glyph instead. Those all have different ways to configure their coordinates, so you'd have to see which is most convenient to your use-case. But they all come with one trade-off, which is that none of them have the full "infinite extent" that a Span supports.

How can I accurately set the new cursor positions after text replacements have been made

I am trying to adapt a plugin for automated text replacement in a Sublime Text 3 Plugin. What I want it to do is paste in text from the clipboard and make some automatic text substitutions
import sublime
import sublime_plugin
import re
class PasteAndEscapeCommand(sublime_plugin.TextCommand):
def run(self, edit):
# Position of cursor for all selections
before_selections = [sel for sel in self.view.sel()]
# Paste from clipboard
self.view.run_command('paste')
# Postion of cursor for all selections after paste
after_selections = [sel for sel in self.view.sel()]
# Define a new region based on pre and post paste cursor positions
new_selections = list()
delta = 0
for before, after in zip(before_selections, after_selections):
new = sublime.Region(before.begin() + delta, after.end())
delta = after.end() - before.end()
new_selections.append(new)
# Clear any existing selections
self.view.sel().clear()
# Select the saved region
self.view.sel().add_all(new_selections)
# Replace text accordingly
for region in self.view.sel():
# Get the text from the selected region
text = self.view.substr(region)
# Make the required edits on the text
text = text.replace("\\","\\\\")
text = text.replace("_","\\_")
text = text.replace("*","\\*")
# Paste the text back to the saved region
self.view.replace(edit, region, text)
# Clear selections and set cursor position
self.view.sel().clear()
self.view.sel().add_all(after_selections)
This works for the most part except I need to get the new region for the edited text. The cursor will be placed to the location of the end of the pasted text. However since I am making replacements which always make the text larger the final position will be inaccurate.
I know very little about Python for Sublime and like most others this is my first plugin.
How do I set the cursor position to account for the size changes in the text. I know I need to do something with the after_selections list as I am not sure how to create new regions as they were created from selections which are cleared in an earlier step.
I feel that I am getting close with
# Add the updated region to the selection
self.view.sel().subtract(region)
self.view.sel().add(sublime.Region(region.begin()+len(text)))
This, for some yet unknown to me reason, places the cursor at the beginning and end of the replaced text. A guess would be that I am removing the regions one by one but forgetting some "initial" region that also exists.
Note
I am pretty sure the double loop in the code in the question here is redundant. but that is outside the scope of the question.
I think your own answer to your question is a good one and probably the way I would go if I was to do something like this in this manner.
In particular, since the plugin is modifying the text on the fly and making it longer, the first way that immediately presents itself as a solution other than what your own answer is doing would be to track the length change of the text after the replacements so you can adjust the selections accordingly.
Since I can't really provide a better answer to your question than the one you already came up with, here's an alternative solution to this instead:
import sublime
import sublime_plugin
class PasteAndEscapeCommand(sublime_plugin.TextCommand):
def run(self, edit):
org_text = sublime.get_clipboard()
text = org_text.replace("\\","\\\\")
text = text.replace("_","\\_")
text = text.replace("*","\\*")
sublime.set_clipboard(text)
self.view.run_command("paste")
sublime.set_clipboard(org_text)
This modifies the text on the clipboard to be quoted the way you want it to be quoted so that it can just use the built in paste command to perform the paste.
The last part puts the original clipboard text back on the clipboard, which for your purposes may or may not be needed.
So, one approach for this would be to make new regions as the replaced text is created using their respective lengths as starting positions. Then once the loop is complete clear all existing selections and set the new one we created in the replacement loop.
# Replace text accordingly
new_replacedselections = list()
for region in self.view.sel():
# Get the text from the selected region
text = self.view.substr(region)
# Make the required edits on the text
text = text.replace("\\","\\\\") # Double up slashes
text = text.replace("*","\\*") # Escape *
text = text.replace("_","\\_") # Escape _
# Paste the text back to the saved region
self.view.replace(edit, region, text)
# Add the updated region to the collection
new_replacedselections.append(sublime.Region(region.begin()+len(text)))
# Set the selection positions after the new insertions.
self.view.sel().clear()
self.view.sel().add_all(new_replacedselections)

Python friends network visualization

I have hundreds of lists (each list corresponds to 1 person). Each list contains 100 strings, which are the 100 friends of that person.
I want to 3D visualize this people network based on the number of common friends they have. Considering any 2 lists, the more same strings they have, the closer they should appear together in this 3D graph. I wanted to show each list as a dot on the 3D graph without nodes/connections between the dots.
For brevity, I have included only 3 people here.
person1 = ['mike', 'alex', 'arker','locke','dave','david','ross','rachel','anna','ann','darl','carl','karle']
person2 = ['mika', 'adlex', 'parker','ocke','ave','david','rosse','rachel','anna','ann','darla','carla','karle']
person3 = ['mika', 'alex', 'parker','ocke','ave','david','rosse','ross','anna','ann','darla','carla','karle', 'sasha', 'daria']
Gephi Setup steps:
Install Gephi and then start it
You probably want to upgrade all the plugins now, see the button in the lower right corner.
Now create a new project.
Make sure the current workspace is Workspace1
Enable Graph Streaming plugin
In Streaming tab that then appears configure server to use http and port 8080
start the server (it will then have a green dot underneath it instead of a red dot).
Python steps:
install gephistreamer package (pip install gephistreamer)
Copy the following python cod to something like friends.py:
from gephistreamer import graph
from gephistreamer import streamer
import random as rn
stream = streamer.Streamer(streamer.GephiWS(hostname="localhost",port=8080,workspace="workspace1"))
szfak = 100 # this scales up everything - somehow it is needed
cdfak = 3000
nodedict = {}
def addfnode(fname):
# grab the node out of the dictionary if it is there, otherwise make a newone
if (fname in nodedict):
nnode = nodedict[fname]
else:
nnode = graph.Node(fname,size=szfak,x=cdfak*rn.random(),y=cdfak*rn.random(),color="#8080ff",type="f")
nodedict[fname] = nnode # new node into the dictionary
return nnode
def addnodes(pname,fnodenamelist):
pnode = graph.Node(pname,size=szfak,x=cdfak*rn.random(),y=cdfak*rn.random(),color="#ff8080",type="p")
stream.add_node(pnode)
for fname in fnodenamelist:
print(pname+"-"+fname)
fnode = addfnode(fname)
stream.add_node(fnode)
pfedge = graph.Edge(pnode,fnode,weight=rn.random())
stream.add_edge(pfedge)
person1friends = ['mike','alex','arker','locke','dave','david','ross','rachel','anna','ann','darl','carl','karle']
person2friends = ['mika','adlex','parker','ocke','ave','david','rosse','rachel','anna','ann','darla','carla','karle']
person3friends = ['mika','alex','parker','ocke','ave','david','rosse','ross','anna','ann','darla','carla','karle','sasha','daria']
addnodes("p1",person1friends)
addnodes("p2",person2friends)
addnodes("p3",person3friends)
Run it with the command python friends.py
You should see all the nodes appear. There are then lots of ways you can lay it out to make it look better, I am using the Force Atlas layouter here and you can see the parameters I am using on the left.
Some notes:
you can get the labels to show or disappear by clicking on the T on the bottom status/control bar.
View the data in the nodes and edges by opening Window/Data Table.
It is a very rich program, there are more options than you can shake a stick at.
You can set more properties on your nodes and edges in the python code and then they will show up in the data table view and can be used to filter, etc.
You want to pay attention to that update button in the bottom right corner of Gephi, there are a lot of bugs to fix.
This will get you started (as you asked), but for your particular problem:
you will also need to calculate weights for your persons (the "p" nodes), and link them to each other with those weights
Then you need to find a layouter and paramters that positions those nodes the way you want them based on the new weights.
So you don't really need to show the type="f" nodes, you need just the "p" nodes.
The weight between to "p" nodes should be based on the intersection of the sets of the friend names.
There are also Gephi plugins that can then display this in 3D, but that is actually a completely separate issue, you probably want to get it working in 2D first.
This is running on Windows 10 using Anaconda 4.4.1 and Python 3.5.2 and Gephi 0.9.1.

Text boxes in xmgrace (preferably with GracePlot.py)

I am currently plotting figures with xmgrace from python using GracePlot.py and I would like to make text annotations in the graph and place them inside a box, in order to make the reading easy when the grid is on.
Does anybody know how to do it with GracePlot.py? Or from xmgrace GUI?
The code I use is similar to the following:
import GracePlot as xg
import math
from numpy import arange
x=arange(0,10,0.1)
y=[math.exp(-q) for q in x]
grace=xg.GracePlot()
graph=grace[0]
data=xg.Data(x=x,y=y)
graph.plot(data)
graph.text('This should be placed inside a box',5,0.5)
I had a quick look through the latest GracePlot module source code. It seems that the author has not yet implemented the capability to make boxes.
Normally, the "Box" tool can be found under "Drawing Objects" when using the Grace/xmgrace GUI. Create a box and save the project, then view it in a text editor as the file is saved in an ASCII format. The following section can be found:
#with box
# box on
# box loctype view
# box 0.340196078431, 0.691176470588, 0.619607843137, 0.513725490196
# box linestyle 1
# box linewidth 1.0
# box color 1
# box fill color 1
# box fill pattern 0
#box def
As you can see by comparing similar chunks for text creation etc. with the source code, the GracePlot module is just printing similar commands for each of the things it is generating. It would be quite easy to add the capability to make boxes. Perhaps you have time yourself? :)
The capability for text has been implemented:
from GracePlot import *
p = GracePlot()
[....]
p.text('Hello, world!', 0.5, 0.4, color=violet, charsize=1.2)
will place some violet-colored text at (0.5, 0.4) with 1.2 character size.
Boxes in Grace do not have their own text, so in order to solve your question you can simply place a text object over the box you created.

ArcMap Data Driven Pages Dynamic Feature Labels

I am trying to work out a way to change between two sets of labels on a map. I have a map with zip codes that are labeled and I want to be able to output two maps: one with the zip code label (ZIP) and one with a value from a field I have joined to the data (called chrlabel). The goal is to have one map showing data for each zip code, and a second map giving the zip code as reference.
My initial attempt which I can't get working looks like this:
1) I added a second data frame to my map and add a new layer that contains two polygons with names "zip" and "chrlabel".
2) I use this frame to enable data driven pages and then I hide it behind the primary frame (I don't want to see those polygons, I just want to use them to control the data driven pages).
3) In the zip code labels I tried to write a VBScript expression like this pseudo-code:
test = "
If test = "zip" then
label = ZIP
else
label = CHRLABEL
endif
This does not work because the dynamic text does not resolve to the page name in the VBScript.
Is there some way to call the page name in VBScript so that I can make this work?
If not, is there another way to do this?
My other thought is to add another field to the layer that gets filled with a one or a zero. Then I could replace the if-then test condition with if NewField = 1.
Then I would just need to write a script that updates all the NewFields for the zipcode features when the data driven page advances to the second page. Is there a way to trigger a script (python or other) when a data driven page changes?
Thanks
8 months too late, but for posterity...
You're making things hard on yourself - it would be much easier to set up a duplicate layer and use different layers, then adjust layer visibility. I'm not familiar with VBScript for this sort of thing, but in Python (using ESRI's library) it would look something like so [python 2.6, ArcMap 10 - sample only, haven't debugged this but I do similar things quite often]:
from arcpy import mapping
## Load the map from disk
mxdFilePath = "C:\\GIS_Maps_Folder\\MyMap.mxd"
mapDoc = mapping.MapDocument(mxdFilePath)
## Load map elements
dataFrame = mapping.ListDataFrames(mapDoc)[0] #assumes you want the first dataframe; you can also search by name
mxdLayers = mapping.ListLayers(dataFrame)
## Adjust layers
for layer in mxdLayers:
if (layer.name == 'zip'):
zip_lyr = layer
elif(layer.name == 'sample_units'):
labels_lyr = layer
## Print zip code map
zip_lyr.visible = True
zip_lyr.showLabels = True
labels_lyr.visible = False
labels_lyr.showLabels = False
zip_path = "C:\\Output_Folder\\Zips.pdf"
mapping.ExportToPDF(mapDoc, zip_path, layers_attributes="NONE", resolution=150)
## Print labels map
zip_lyr.visible = False
zip_lyr.showLabels = False
labels_lyr.visible = True
labels_lyr.showLabels = True
labels_path = "C:\\Output_Folder\\Labels.pdf"
mapping.ExportToPDF(mapDoc, labels_path, layers_attributes="NONE", resolution=150)
## Combine files (if desired)
pdfDoc = mapping.PDFDocumentCreate("C:\\Output_Folder\\Output.pdf"")
pdfDoc.appendPages(zip_path)
pdfDoc.appendPages(labels_path)
pdfDoc.saveAndClose()
As far as the Data Driven Pages go, you can export them all at once or in a loop, and adjust whatever you want, although I'm not sure why you'd need to if you use something similar to the above. The ESRI documentation and examples are actually quite good on this. (You should be able to get to all the other Python documentation pretty easily from that page.)

Categories