在 jupyter notebook 中,当我尝试渲染用 ipywidgets 编写的图形用户界面时,一切正常。
然后,当我使用 Voila 渲染进行渲染时,表格和地图呈现在屏幕宽度之外。Voila 中是否有任何设置可以控制渲染宽度?我基本上需要表格和地图在屏幕宽度内呈现。
附加信息。下面是代码
import ipywidgets
import glob
import json
import pandas as pd
import qgrid
import folium
from IPython.display import display
takeawayFolderPath = '/home/hd2900/Documents/Python/POS/takeawayOrders'
class GeoMapping:
def __init__(self, takeawayFolderPath, homeCoordinate, deliveryRadius):
self.takeawayFolderPath = takeawayFolderPath
self.homeCoordinate = homeCoordinate
self.deliveryRadius = deliveryRadius #The deliver radius is given in meters
currentSelectedRowNumber = None
self.refreshJson()
self.getOrderDataFrame()
self.buildGUI()
self.displayTable()
self.displayMap()
def buildGUI(self):
self.btn_update = ipywidgets.Button(description = 'Refresh')
self.btn_update.on_click(self.update_btn)
self.tableOutput1 = ipywidgets.Output()
self.btn_orderComplete = ipywidgets.Button(description = 'Complete', button_style = 'danger')
self.btn_orderComplete.on_click(self.orderComplete)
self.mapOutput = ipywidgets.Output()
self.VBox = ipywidgets.VBox([self.btn_update, self.tableOutput1, self.btn_orderComplete, self.mapOutput])
display(self.VBox)
def displayMap(self):
with self.mapOutput:
self.mapOutput.clear_output()
#Centering the map at home coordinate
self.map = folium.Map(location= self.homeCoordinate, zoom_start=12)
#Add a red circle marker to show home. This is not the delivery
folium.CircleMarker(
location= self.homeCoordinate,
radius=5,
popup= "Home",
color="#FF0000",
fill=True,
fill_color="#FF0000",
).add_to(self.map)
#Add delivery radius ring
folium.Circle(
radius = self.deliveryRadius,
location= self.homeCoordinate,
popup="",
color="crimson",
fill=False).add_to(self.map)
#Take time into account and plot the maps in different color. The color order
for orderid in self.orderDF['Order Id']:
latitude, longitude, deadline = self.getGeoCoordinateFromOrderId(orderid)
#Plot the coordinates in map
folium.Marker(
[latitude, longitude], popup=f"<h1>{orderid} {deadline}</h1>", tooltip = "more info"
).add_to(self.map)
display(self.map)
def displayTable(self):
with self.tableOutput1:
self.tableOutput1.clear_output()
self.qgrid = qgrid.show_grid(
self.orderDF,
grid_options = {'sortable': False, 'filterable': False, 'maxVisibleRows': 100},
)
self.qgrid.observe(self.qgridTableRowSelected)
display(self.qgrid)
def orderComplete(self,b):
if not self.currentSelectedRowNumber:
return
#Get the order id of the selected row
orderId = self.orderDF['Order Id'][self.currentSelectedRowNumber[0]]
#Find the json file with the order id and write a new key in the dictionary
filePath = self.getJsonFilePathFromOrderId(orderId)
order = self.readJsonFile(filePath)
order['Complete'] = True
self.saveJsonFile(order, filePath)
self.update()
def getJsonFilePathFromOrderId(self, orderId):
'''
Given the order Id integer, this method returns the json file full path
'''
files = glob.glob(self.takeawayFolderPath + '/*.json')
for fileName in files:
order = self.readJsonFile(fileName)
if order['order']['id'] == orderId:
return fileName
def update_btn(self, b):
self.update()
def update(self):
self.refreshJson()
self.getOrderDataFrame()
self.displayTable()
self.displayMap()
def qgridTableRowSelected(self, change):
with self.tableOutput1:
if change['name'] == '_selected_rows' and change['new']:
self.currentSelectedRowNumber = self.qgrid.get_selected_rows()
def refreshJson(self):
'''
Used for refresh all the latest json files
'''
files = glob.glob(self.takeawayFolderPath + '/*.json')
self.orders = list()
for fileName in files:
order = self.readJsonFile(fileName)
#Check if the order is a delivery
if order['order']['delivery']:
#Check if the key Complete exists
if 'Complete' not in order:
tmp = dict()
tmp['id'] = order['order']['id']
tmp['fullName'] = order['order']['fullName']
tmp['email'] = order['order']['email']
tmp['mobile'] = order['order']['mobile']
tmp['deliveryAddress'] = order['order']['deliveryAddress']
tmp['latitude'] = order['order']['latitude']
tmp['longitude'] = order['order']['longitude']
tmp['comments'] = order['order']['comments']
tmp['deadline'] = order['order']['deliveryTime']
self.orders.append(tmp)
def getOrderDataFrame(self):
'''
Convert the content in self.orders into a pandas data frame
'''
#The data frame contain the following columns
self.orderDF = dict()
self.orderDF['Order Id'] = list()
self.orderDF['Name'] = list()
self.orderDF['Address'] = list()
self.orderDF['Mobile'] = list()
self.orderDF['Comments'] = list()
self.orderDF['Deadline'] = list()
for order in self.orders:
self.orderDF['Order Id'].append(order['id'])
self.orderDF['Name'].append(order['fullName'])
self.orderDF['Address'].append(order['deliveryAddress'])
self.orderDF['Mobile'].append(order['mobile'])
self.orderDF['Comments'].append(order['comments'])
self.orderDF['Deadline'].append(order['deadline'])
self.orderDF = pd.DataFrame.from_dict(self.orderDF)
def getGeoCoordinateFromOrderId(self, orderId):
for order in self.orders:
if order['id'] == orderId:
latitude = order['latitude']
longitude = order['longitude']
deadline = order['deadline']
return latitude, longitude, deadline
def readJsonFile(self, filePath):
with open(filePath,'r') as fileId:
data = json.load(fileId)
return data
def saveJsonFile(self, dataDict, filePath):
'''
Given the dictionary dataDict and the filePath, this method saves it to json file
'''
with open(filePath, 'w') as fileId:
json.dump(dataDict, fileId)
hd2900Coordinate = (55.73228810541183, 12.575497656450752)
deliveryRadius = 8
deliveryRadius = deliveryRadius * 1000
GeoMap = GeoMapping(takeawayFolderPath, hd2900Coordinate, deliveryRadius)