Center-align title in Pygal chart - python

I'm making a line chart in Pygal. I want to center the title of the chart, but I don't know how to do that.
I tried looking through the Pygal documentation, but I couldn't find anything relating to the alignment of a title. Here's what I have:
custom_style = Style(
background = 'transparent',
font_family='Avenir',
colors = ['#14A1FF', '#14FF47'],
opacity = .5)
chart = pygal.Line(
style=custom_style,
print_values=True,
interpolate='hermite',
fill=True, dots_size=4,
show_y_guides=False,
legend_at_bottom=True,
legend_at_bottom_columns=2)
chart.title = "Rubik's Cube Solve Times Recorded Over Five Days"
chart.x_labels = ["1", "2", "3", "4", "5"]
chart.x_title = "Day"
chart.y_title = "Seconds"
chart.add("Average of 100", ao100)
chart.add("Average of 25", ao25)
chart.render_to_file('times.svg')

As mentioned in the comments the figure title is centred relative to the figure, rather than axes. This behaviour is hard-coded in the rendering functions, there are no configuration options that will change it.
One workaround is to create your own class that inherits from pygal.Line and over-rides the function that renders the title (which isn't very large):
class MyLineChart(pygal.Line):
def __init__(self, *args, **kwargs):
super(MyLineChart, self).__init__(*args, **kwargs)
def _make_title(self):
"""Make the title"""
if self._title:
for i, title_line in enumerate(self._title, 1):
self.svg.node(
self.nodes['title'],
'text',
class_='title plot_title',
x=self.margin_box.left + self.view.width / 2, # Modified
y=i * (self.style.title_font_size + self.spacing)
).text = title_line
The _make_title function above was copied straight from the source code for the Graph class (the class that Line itself inherits from). The only change is in the line indicated with the comment 'Modified', this was taken from the function that renders the x axis label (because that is centred on the axes).
With this you can replace chart = pygal.Line with chart = MyLineChart, but leave the rest of the code as it is. You might also want to change the name of the class to something more meaningful.

By default you title has has property text-anchor:middle:
text-anchor attribute is used to align (start-, middle- or
end-alignment) a string of text relative to a given point.
You can manually change this value, .i.e., to end in finale svg file (open file in text editor and find .title ).

Related

Folium - add larger pop ups with data from XML file

I would like to create a table-like pop-up for my folium map but don't know how to do it (I'm a novice).
My data comes from an XML file that contains the gps coordinates, name, sales, etc. of stores.
Right now I can display the name of the stores in the pop-up, but I would also like to display the sales and other information below the name.
I reckon I should maybe use GeoJson but I don't know how to implement it in the code I already have (which contains clusterization) :
xml_data = 'Data Stores.xml'
tree = ElementTree.parse(xml_data)
counter = tree.find('counter')
name = counter.find('Name')
counter.find('Latitude').text
name = []
latitude = []
longitude = []
for c in tree.findall('counter'):
name.append(c.find('Name').text)
latitude.append(c.find('Latitude').text)
longitude.append(c.find('Longitude').text)
df_counters = pd.DataFrame(
{'Name' : name,
'Latitude' : latitude,
'Longitude' : longitude,
})
df_counters.head()
locations = df_counters[['Latitude', 'Longitude']]
locationlist = locations.values.tolist()
map3 = folium.Map(location=[31.1893,121.2781], tiles='CartoDB positron', zoom_start=6)
marker_cluster = folium.plugins.MarkerCluster().add_to(map3)
for point in range(0, len(locationlist)):
popup=folium.Popup(df_counters['Name'][point], max_width=300,min_width=300)
folium.Marker(locationlist[point],
popup=popup,
icon=folium.Icon(color='blue', icon_color='white',
icon='fa-shopping-bag', angle=0, prefix='fa')
).add_to(marker_cluster)
map3.save("WorldMap.html")`
Right now I have 4 other columns in my XML file besides 'Name' that have the information that I want to appear in the popup as well, kinda like this :
example popup
Thank you for your help
Edit :
I did some digging and changed my code a little bit by adding the folium.features.GeoJsonPopup instead of the simple folium.Popup that I had before :
for point in range(0, len(locationlist)):
popup=folium.features.GeoJsonPopup(
fields=[['Name'],['Opening']],
aliases=['Name','Opening'])
folium.Marker(locationlist[point],
popup=popup,
icon=folium.Icon(color='blue', icon_color='white',
icon='fa-shopping-bag', angle=0, prefix='fa')
).add_to(marker_cluster)
I added the 'Opening' data, however I don't know how to transfer it into the pop up along with the 'Name' since it comes from a panda DataFrame. Right now my popups are empty.
I have done something similar, steps were:
create an IFrame with the content you want to display (coded in HTML)
use this IFrame in a popup
connect this popup with your marker
htmlstr = ... # Here you can add your table, use HTML
# 1. iframe
iframe = folium.IFrame(htmlstr, # places your content in the iframe
width=200,
height=200 # adjust size to your needs
)
# 2. popup
fpop = folium.Popup(iframe)
# 3. marker
mrk = folium.Marker(location=latlng,
popup=fpop,
)
mrk.add_to( ... )

Python Folium MarkerCluster Color Customization

I'm creating a leaflet map in folium using MarkerCluster. I have been all over the documentation and searched for examples, but I cannot figure out how to customize the color for a given MarkerCluster or FeatureGroup (e.g., one set in green rather than default blue).
I tried creating the markers individually and iteratively adding them to the MarkerCluster, and that gave me the color I wanted, but then the iFrame html table woudn't function properly, and the popups were not appearing.
The code I've written works flawlessly (an html table used for popups is not supplied), but I'd really like to be able to change the color for one set of markers and retain the popups using the methods in my code. Any guidance would be greatly appreciated!
or_map = folium.Map(location=OR_COORDINATES, zoom_start=8)
res_popups, res_locations = [], []
com_popups, com_locations = [], []
for idx, row in geo.iterrows():
if row['Type'] == 'Residential':
res_locations.append([row['geometry'].y, row['geometry'].x])
property_type = row['Type']
property_name = row['Name']
address = row['address']
total_units = row['Total Unit']
iframe = folium.IFrame(table(property_type, property_name,
address, total_units), width=width,
height=height)
res_popups.append(iframe)
else:
com_locations.append([row['geometry'].y, row['geometry'].x])
property_type = row['Type']
property_name = row['Name']
address = row['address']
total_units = row['Total Unit']
iframe = folium.IFrame(table(property_type, property_name, address,
total_units), width=width,
height=height)
com_popups.append(iframe)
r = folium.FeatureGroup(name='UCPM Residential Properties')
r.add_child(MarkerCluster(locations=res_locations, popups=res_popups))
or_map.add_child(r)
c = folium.FeatureGroup(name='UCPM Commercial Properties')
c.add_child(MarkerCluster(locations=com_locations, popups=com_popups))
or_map.add_child(c)
display(or_map)
Instead of just dumping all your locations into the Cluster, you could loop over them and create a Marker for each of them - that way you can set the Marker's color. After creation, you can add the Marker to the desired MarkerCluster.
for com_location, com_popup in zip(com_locations, com_popups):
folium.Marker(com_location,
popup=com_popup
icon=folium.Icon(color='red', icon='info-sign')
).add_to(cluster)
A different approach would be to modify the style function, as shown here (In[4] and In[5]).

Python looping for label variables

I am trying to create a loop that will display each title of product for their individual labels (Tkinter module).
With the current loop i can get it to print my 10 "static_webpage_1_titles" in the list, but i am wanting to also increase the variable Label_1 by +1 increment each time.
For example, it should do somthing like this:
Label_1['text'] = static_webpage_1_titles[0]
Label_2['text'] = static_webpage_1_titles[1]
Label_3['text'] = static_webpage_1_titles[2]
Here is my current code:
def Generate_Product_Name_and_Price_1():
if Button_on:
Find_static_webpage_1()
for i in range(len(static_webpage_1_titles)):
Label_1['text'] = static_webpage_1_titles[i]
EDIT:
product_labels = [Label_1['text'], Label_2['text'], Label_3['text'],
Label_4['text'], Label_5['text'], Label_6['text'],
Label_7['text'], Label_8['text'], Label_9['text'],
Label_10['text']]
I have created a list above with each label widget and changed the last line of code in my loop to:
def Generate_Product_Name_and_Price_1():
if Button_on:
Find_static_webpage_1()
for i in range(len(static_webpage_1_titles)):
product_labels[i] = static_webpage_1_titles[i] +': $'+ static_webpage_1_price[i]
When i run this, i do not receive any IDLE error but my label widgets do not get populated with data.
You need to make a list of the Label instances, not the text attributes of Label instances. Like this:
product_labels = [Label_1, Label_2, Label_3,
Label_4, Label_5, Label_6,
Label_7, Label_8, Label_9,
Label_10]
Then you access the attribute like this:
for i in range(len(static_webpage_1_titles)):
product_labels[i]['text'] = static_webpage_1_titles[i] +': $'+ static_webpage_1_price[i]
You could also make this a little neater with zip():
for label, title, price in zip(product_labels, static_webpage_1_titles, static_webpage_1_price):
label['text'] = title +': $'+ price

Display and update text with Bokeh: settings glyph on update not working

I am trying to write a web app that displays graphs with Bokeh and also displays formatted text retrieved from an API. The display dynamically changes with the content of the graph when the user clicks a button. Is there a standard way to format and present text, and then update it, with Bokeh?
I thought I could do this with text glyphs, but so far I am failing. Here's what I'm trying to do for the update action:
def update_graph(attrname, old, new):
USER_ID = new
use_df = get_user_df(new, cur, date_from, date_to)
plot1.title = get_api_output(new, INSIGHT_DATE)
textplot.text(3, 3, text=["hellllllo"], text_color="firebrick", text_align="center", text_font_size="20pt")
source1.data['x'] = use_df[use_df['type'] == 0]['date'].values
source1.data['y'] = use_df[use_df['type'] == 0]['value'].values
This mostly works fine the way it is. I grab some data from a remote DB with get_user_df and update source1, which works appropriately. Similarly the title gets updated as desired.
However no text glyph appears on textplot and no error appears in the console. What's going on and how can I dynamically adjust text glyphs on a plot?
Also here is the code I use to set up the plots in case that is relevant:
#plot utilities
def mtext(p, x, y, text):
p.text(x, y, text=[text],
text_color="firebrick", text_align="center", text_font_size="10pt")
#PLOTS
textplot = Figure(toolbar_location = None, title = 'API text', title_text_font_size='8pt')
mtext(textplot, randint(2, 5), randint(2, 5), 'annotation')
plot1 = Figure(toolbar_location = None, title = 'Distance (k)', title_text_font_size='8pt')
source1 = ColumnDataSource(data = dict(x = use_df[use_df['type'] == 0]['date'].values, y = use_df[use_df['type'] == 0]['value'].values))
plot1.circle('x', 'y', line_color=None, source = source1, color = 'pink', size = 20)

Bokeh - get information about points that have been selected

I have a several points that I plot into scatter plot and show in web browser window (using Bokeh).
For selection, I use PolySelectTool or BoxSelectTool.
There are two things I would like to do:
1) Get information about points that have been selected in order to calculate some additional information.
2) As points represent URLs, I would like the chart to open a new browser tab and load a particular URL whenever I click a point (representing URL).
I don't think the code is important. But to make my question complete, here it is ...
Y = my_data
urls = get_urls(my_data)
TOOLS="pan,wheel_zoom,reset,hover,poly_select,box_select"
p = figure(title = "My chart", tools=TOOLS)
p.xaxis.axis_label = 'X'
p.yaxis.axis_label = 'Y'
source = ColumnDataSource(
data=dict(
xvals=list(Y[:,0]),
yvals=list(Y[:,1]),
url=urls
)
)
p.scatter("xvals", "yvals",source=source,fill_alpha=0.2, size=5)
hover = p.select(dict(type=HoverTool))
hover.snap_to_data = False
hover.tooltips = OrderedDict([
("(x,y)", "($x, $y)"),
("url", "#url"),
])
select_tool = p.select(dict(type=BoxSelectTool))
#
# I guess perhaps something should be done with select_tool
#
show(p)
You can get information with the source.selected property, if you want to be notified of every change you must create a callback, it would be something like this:
def callback(obj, attr, old, new):
...
source.on_change('selected', callback)
See this example for more details.

Categories