Could you @philippjfr confirm that it would be the right Server
to use? Thanks.
(I’m also using the Panel Server
here https://github.com/ideonate/bokeh-root-cmd/blob/c26eee1414d3305749a8724b8740d9a4eaca0cf7/bokeh_root_cmd/main.py#L169).
Could you @philippjfr confirm that it would be the right Server
to use? Thanks.
(I’m also using the Panel Server
here https://github.com/ideonate/bokeh-root-cmd/blob/c26eee1414d3305749a8724b8740d9a4eaca0cf7/bokeh_root_cmd/main.py#L169).
i followed @t-houssain following link and shifted my three panel app in fastApi server
and Now my dashboards is blazing fast and upload in browsers in less then a minute.
Thanks @t-houssian
one problem i am facing
if two people access the same dashbaord on their browsers they work asynchronously.
i.e. if one access any page on its browser other person’s dashboard which is loaded in browser updated to same page
Hi @khannaum
Could you post a minimum reproducible example?
Hi @khannaum I’m glad you were able to get this up and running. I ran into a similar issue a little bit ago when using a django server with panel. For me the issue came from using widgets as class variables. I had to only use params as class variables within my Parameterized class. Could you share what your code looks like in your panel.py files?
@t-houssian @Marc
Thanks for the e-mails
I donot test it with django server and but it’s loading time amazing fast in fastApi.
iI donot understand how it has slow loading-rendering time in browsers when run from panel command line
You can view the code and working example i mentioned in following below my previous post mentioned slow loading-rendering-time-in-browser .
Br,
Nauman Ahmad Khan
@khannaum Thanks for sharing your code. It looks like in your cust_mapping function there you will need to change your widgets that are set to variables like here
RBU_select = pn.widgets.Select(name='RBUs', options=list(cust_group_by_work_projected.RBU.unique()))
City_select = pn.widgets.Select(name='CityLevel', options=list(sorted(cust_group_by_work_projected.cityname.unique())))
Complaint_select = pn.widgets.MultiSelect(name='Complaints', options=list(sorted(cust_group_by_work_projected.compl.unique())))
To params like this:
RBU_select = param.ObjectSelector(label='RBUs', objects=list(cust_group_by_work_projected.RBU.unique()))
City_select = param.ObjectSelector(label='CityLevel', objects=list(sorted(cust_group_by_work_projected.cityname.unique())))
Complaint_select = param.ListSelector(label='Complaints', objects=list(sorted(cust_group_by_work_projected.compl.unique())))
For the multi select, you can also render the equivalent param.ListSelector like this:
widgets = pn.WidgetBox(City_select,pn.Param(apex.param.Complaint_select, widgets={'Complaint_select': pn.widgets.CheckBoxGroup}),
To get the same functionality.
I think after converting some of your widgets into params and possibly using a parameterized class that might help your mutliple users problem (At least for me it did). Check out the guide on this example to maybe get some ideas on refactoring your code.
https://panel.holoviz.org/gallery/param/reactive_tables.html#param-gallery-reactive-tables
@Marc I ended up getting it to work without a thread and without the middleware. Here is what main.py looks like now:
import panel as pn
from bokeh.embed import server_document
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from panelApps.pn_app import createApp
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/")
async def bkapp_page(request: Request):
script = server_document('http://127.0.0.1:5000/app')
return templates.TemplateResponse("base.html", {"request": request, "script": script})
pn.serve({'/app': createApp},
port=5000, allow_websocket_origin=["127.0.0.1:8000"],
address="127.0.0.1", show=False)
and pn_app.py simply is:
import panel as pn
from .app1 import SineWave
def createApp():
sw = SineWave()
return pn.Row(sw.param, sw.plot).servable()
Full code here https://github.com/t-houssian/FastAPI-Panel
Beautiful
Question: should panel not be running in a separate process and file?
Possibly, what exactly do you mean by that?
Seems like there are already solutions here, but, FWIW, I’m accomplishing something similar using Nginx as a reverse proxy:
nginx.conf
events {}
http {
server {
listen 1001; # The port where clients should connect
location /api/ { # forward requests with this prefix to FastAPI (or any other app)
rewrite ^/api/(.*)$ /$1 break;
proxy_pass http://127.0.0.1:1002; # The other app should be listening here
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
location / { # forward the rest to Panel
proxy_pass http://127.0.0.1:1003; # Panel should be listening here
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_redirect off;
proxy_buffering off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
}
}
}
For FastAPI, you’ll have to set the root_path to /api.
If running in something like Docker, it might also be helpful to use something like supervisord to manage all three processes:
supervisord.conf
[supervisord]
user = root
nodaemon = true # this expects supervisord to be run as the main command in a Docker container
logfile = /dev/null # don't log to a file - only stdout/stderr
logfile_maxbytes = 0 # disable log file rotation
[program:fastapi]
command = gunicorn --bind 0.0.0.0:1002 ... # However you want to run FastAPI
startsecs = 5
autostart = true
autorestart = true
stopwaitsecs = 300
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0 # disable log file rotation
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0 # disable log file rotation
[program:panel]
command = panel serve --port 1003 --allow-websocket-origin ... # However you want to run Panel
startsecs = 5
autostart = true
autorestart = true
stopwaitsecs = 300
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0 # disable log file rotation
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0 # disable log file rotation
[program:nginx]
command = nginx -c /path/to/nginx.conf -g 'daemon off;'
startsecs = 5
autostart = true
autorestart = true
stopwaitsecs = 300
stderr_logfile = /dev/stderr
stderr_logfile_maxbytes = 0 # disable log file rotation
stdout_logfile = /dev/stdout
stdout_logfile_maxbytes = 0 # disable log file rotation
Might be more moving parts and more processes to monitor… but I imagine it should work for any framework, not just FastAPI.
@t-houssian @Marc @philippjfr thank you all, this is very useful and I have been using it, as described in the online doc at Integrating Panel with FastAPI — Panel v1.3.9a1 (holoviz.org).
However, I have come up with an issue for me.
My app has a large amount of shared state. This particular piece of data is purely read-only, and needs to be read exactly once. Ideally, I would read and cache it during the startup of the FastAPI server, and then reuse it for all apps and all documents.
Of course, my app also has a smaller amount of dynamic things to do, which do not need to be in the shared state.
Now, here is my problem. I started up the panel server with pn.serve
, as described. But I do not know how to pass a reference to the shared state from the main FastAPI startup code to the panel createApp
function.
I did find a workaround: I put the createApp
function in a separate python file and did initializations in it’s global space, before the createApp
function definition. This works!
But it only allows me to create global variables for the panel server’s createApp
function, and I may need the global variables to be available to some of my other FastAPI-based functionality.
Any ideas please?
Thank you!
GPN
Does putting things in pn.state.cache work?
@philippjfr Thank you! I was not aware of the pn.state object. I looked for documentation and I found documentation from version 0.14:
Session State and Callbacks — Panel v0.14.0 (holoviz.org)
Is this 0.14 doc up to date, or should I look elsewhere?
Thank you
GPN
Most up to date docs are at https://panel.holoviz.org/