Is Streamlit actually useful?

I was very excited for Streamlit when I heard about it. Iā€™ve built several applications using it, including a logs browser and a semantic search frontend. Iā€™ve also advocated for it at my workplace and convinced several colleagues to try it.

Unfortunately, the more I use Streamlit the more disenchanted I become. The biggest issue is that nearly all applications need some form of state, even if just for checkboxes and simple tiny things. Yes, I know that state features are being added. But Iā€™m concerned that fundamentally the approach that Streamlit has taken is not conducive to anything more advanced than a basic read-only data viewer. The model of re-running the entire application after anything changes is just fundamentally opposed to many kinds of basic user interaction.

I am sceptical that there is a good solution to managing state in a Streamlit application which doesnā€™t make it more complex than a Flask app. Flask is dead simple to reason about ā€“ you hit a route and the code in the route is run. Every person I know who has built a Streamlit app has had many WTF moments, very frustrating behaviour. The computational model of Streamlit just doesnā€™t make much sense if you are doing anything that isnā€™t entirely linear. I know there is an underlying logic and Iā€™m sure the developers are pretty comfortable with it, but the computational model is just not nice to think about. It isnā€™t fun to debug or to get user interaction to work right. I donā€™t want to have to reason about my entire application being re-run every time. And caching is its own set of wormsā€¦

Pretty much every issue Iā€™ve run in to, just really dumb simple things, the response is ā€œwe donā€™t support that currently, use this hackā€. Usually the hacks donā€™t work either ā€“ the app renders with state from the previous run, things are out of sync. God knows whatā€™s going on under the hood.

At the end of the day, for anything beyond the dead simple, a Streamlit user needs to become an expert at what is going on behind the scenes. Reasoning about application behaviour in the Streamlit computational model is like fitting a square peg in to a round hole. It just doesnā€™t feel good. Streamlit was supposed to be simple and fast. Itā€™s not either of those things.

Do other people feel this way?

Edit: When it works, for simple linear read-only apps, it works well. Iā€™m just concerned that the range of use cases is just much smaller than I had hoped for initially. And Iā€™m still not a fan of the computational model which seems simple but forces the user to reason about what is happening under the hood, making the apparently simple not so simple.

11 Likes

Hey @timforr, thanks for opening the conversation, as it is the kind of interaction that will drive Streamlit in the future :slight_smile: .

Sorry for the wall of text, I put a TLDR at the end XD

:speech_balloon:

As a preface, whatever the huge momemtum Streamlit has, it is still a very young product, barely a year since its open-sourcing, so it has yet to bring the features to push all of the use cases the community wants to build around Streamlit. So there comes the question : ā€œwhat use cases does it favor then ?ā€.


:mag_right:

I donā€™t want to speak for the founders of Streamlit there (Iā€™m not even a dev for them, I just happen to hang a lot around the forum :wink:), but my guess is, the very initial user journey for Streamlit was to provide a tool for Data Scientists to quickly design UIs that fits into their workflow. Just drop some st calls in my ML script and I have an interactive UI without rearchitecting my entire script around callbacks.

Iā€™m in my script, I just loaded a Dataframe let me render it, oh I see this column has a large variance, let me bring a selectbox to select the columns I want to apply coloring on to show the gradient, ok letā€™s do a PCA now, letā€™s have a multiselect to select columns to reduce and maybe a checkbox to choose a model, bam now the dataframe is reduced I can train a ML model. Awww the script is rerunning in its entirety I donā€™t want to recompute the PCA every time let me put @st.cache there so it does not recompute if I donā€™t change my checkbox for a model, there now I can finish it.

This is a ā€œlinearā€ script like you call it, and when you stay in this route where each interaction only impacts a small set of functions that follow, Streamlit is a beauty to use. I donā€™t ever need global state as everything runs in sequence so caching of expensive portions of the app is the only thing I need. And as a data scientist thatā€™s all I need. So it has totally replaced Jupyter notebooks in my workflow, I run interactive exploratory data analysis and machine learning modelling, and sometimes I show it to a customer in a matter of day and even he can play with the ML hyperparameters. I got a meetup video of me doing this in french, and @Jesse_JCharis has got plenty of Youtube videos too with this workflow in mind.

For my Data Scientist hat, Streamlit is a must-have, itā€™s simple, itā€™s fast, and with Custom components coming around, it will bring custom functions like Streamlit direct call to pandas profiling or echarts directly in my analysis.


:gear:

Now let me change hat from Data Scientist to Software engineer, where I want to build a data web app around Python, and immediately you can see the mental model is not the same and maybe not considered a native use case. Iā€™m much more concerned with tight coupling of user interactions and state change, where a single user interaction should affect many different parts of the application. One of my colleagues is running into this as he tries to do a realtime dashboard to study the effects of the parameters on some KPIs, and we have trouble saving and rerunning the app whenever he wants to fetch data from a database or remove data points from the graph because they are outside the time window. So I can say I hear your frustrations :grimacing:

While Streamlit has hacks and itā€™s in the roadmap as ā€œprogrammable stateā€, I want to draw a parallel with the story of React and global state (which I heard on episode ā€œReact Fundamentals with Ryan Florenceā€ of the ā€œSoftware Engineering Dailyā€ podcast, and I hope some React devs appear here to correct me or add more to the story !). I am running into the exact same problems as yours in React, where it looks like every component is rerendered every time I interact with something somewhere (even though it looks optimized, I donā€™t know how it works under the hood), and I want to control it with some global state. In its design React doesnā€™t easily provide that and it makes me want to throw it away. React Redux came later in the party and now with the very recent context + React hooks we got another way of doing it.

I feel Streamlit is still very much in this very early React phase, concerned about rendering components in a sequence and not much about global state. I see a part of the forums worried about state and checkbox too on the forums, itā€™s like top 3 most searched term hereā€¦ History shows React is very much one of the preferred libraries for web UIs while missing the feature in the first place thanks to people rambling about global state :slight_smile: and how to add it. Weā€™re at this place of the history with Streamlit, devs are very present on this forum and open to any feedback !


:thought_balloon:

TL;DR; Streamlit is young, initially focused on the Data Scientist workflow (not concerned with callback/coupling of user interaction to state) rather than Web Software Engineer. React also lacked easy global state initially while it focused on rerendering everything everytime then it got solutions that got it where it is today. So we still got a lot of time to help design the API for global programmable state which is in the roadmap and that will help drive Streamlit into what React is today in the JS ecosystem :wink:

8 Likes

I agree with almost everything youā€™ve said here. I still think streamlist has a lot of potential but even really simple apps need state. My 8yr old daugter made a simple game using ScratchJr - and Scratch has built in state where it manages the hard things behind the scenes like multiple users because it turns out kids understand the concept of state and use it, and their friends login at the same time and the scratch app just autobehaves differently for each of them.

I disagree with this bit:

I am sceptical that there is a good solution to managing state in a Streamlit application which doesnā€™t make it more complex than a Flask app.

In flask you have to think carefully about state and users and so on and deal with it often by using flask addons or writing code. I think Streamlit could easily abstract a lot of this away. I assume its not easy thats why its taking so long.

Iā€™m just concerned that the range of use cases is just much smaller than I had hoped for initially.

This is true, and like with all computing things, you pick what works for that use, but it does concern me that my use cases for streamlit keep shrinking the more I have used it. Iā€™m waiting on how the new roadmap improves things though before coming to any decisions.

3 Likes

Streamlit is massively useful for me, and Iā€™d rather it was simple and dealt with some use cases rather than try to deal with all.

Streamlit is a dropin replacement for cli apps and notebooks, adding interactivity while removing a bunch of hassle. Itā€™s saved me a lot of time and will continue to do so.

Iā€™d rather store state elsewhere if I needed it, and if I want more control I could just use dash.

5 Likes

Indeed. Iā€™m a novice in the science of data (as is our team), but there are some clear advantages to Streamlit which has allowed our small team to make significant strides toward more organizationally-accessible data to provide answers to some tough questions.

Perhaps it would be good to have state management, but I would point out that there are many cases where simple apps can function just fine [without state] to meet very low-bar requirements even for the vast majority of non-technical users. In our group, we often get questions about expanding the use of Streamlit and thatā€™s a simple matter of setting expectations and weighing costs and development alternatives.

We pretty much have a love affair going with Streamlit because it provides some affordable luxuries that also allow us to allow a broader base of developers to craft data science solutions.

2 Likes

Frankly, I feel the same, especially because Iā€™m not a data scientist and because Iā€™m constantly trying to bend streamlitā€™s standard usage to fulfill particular needs.

However, the framework has so much to offer even outside the data science scope and Iā€™m convinced itā€™ll be able to cover more and more use cases as time goes by. That said, Streamlit is already quite useful to me. Just as @andfanilo and @Ian_Calvert said, itā€™s a great replacement (and improvement) for jupyter notebooks and even cli apps to some extent.

Well, the Streamlit way of handling things is just like calling a command line tool with a bunch of parameters.

But as you said, thereā€™s this issue of managing state. The current problem here is when an app reruns, you canā€™t access a widget value prior its declaration/execution. However Iā€™m not sceptical on this matter. One approach Iā€™m working on is to bind a widget to a state variable like so:

print(state.value)
st.text_input("Blabla.", state="value")
state.value = "Hello"  # This assignment updates the widget's value on screen

If you interact with a widget, the whole app will rerun with an up to date state directly from the beginning. Ideally youā€™d even be able to do something like the third line to set/update a widget value (or markdown text) without using st.empty(): a bi-directional binding.

Iā€™m really curious to see if something like this seems simple enough to use and could be a viable solution for state management with widgets.

You encountered the out of sync issue by doing something like this, right?

state.value = st.text_input("Blabla.", value=state.value)

If Iā€™m right about what youā€™re refering to, I guess something like this should help. I know this is your typical ā€œuse this hackā€ answer :joy:, but we have no other solution than using hacks or waiting for an official implementation :stuck_out_tongue:

I fully agree. I think the more I try to use streamlit the more I find that it is use case gets limited. A lot of folks here talk about ML and data science models but there is world of applications and use cases out there that is much broader. I am an environmental engineer and would like to build apps that help us design systems. I have friends trying to build chemical engineering apps. That really simply does not work without some kind sessions state or a simple layout. We have decided to drop streamlit and are building our app in panel now instead (because we donā€™t want to touch dash with its html and css!).

I used to be an enthusiast of streamlit but I am getting frustrated as I keep hitting walls in functionality. I get disheartened a bit because the communityā€™s feedback is that what there works good enough for data scientists but the world is much broader than just data science and ML. I hope the dev team consider that.

I will keep my eye open here to see how things develop.

We were early adopters shortly after the launch in October last year. We rapidly built and deployed a multi-page dashboard with reasonably flexible navigation using an extended version of the SessionState and rerun gists (instead of a single session state we use a stack of states, I posted this in the git issues board a while back). The key for us was wrapping that, page configuration loading, logging, and a template setup for the sidebar into a StreamlitPage class. All our pages subclass from this and navigation is implemented with a simple if ā€¦ elif ā€¦ dispatcher.

I rarely write a new page from scratch now. Usually I find the closest approximation and just modify the data handling and display. Calling the pageā€™s rerun method when switching to another page after saving the current pageā€™s state and next action is about all I have to remember.

This does rely on the two hacks, however those are almost totally wrapped in the base page class and I donā€™t anticipate any problems adapting to whatever approach Streamlit eventually adopt.

The release of components will further simplify the more complex cases. I just implemented a data annotator adapted from this and intend to modify it with the selectable DataFrame component, which should simplify it further.

All that said I have no experience with Flask (or other app builders) aside from a trivial web service with no UI. But weā€™ve been able to do pretty much everything we wanted for an end business user within the tool. Weā€™ve no plans to change.

1 Like

I am glad to hear you have figured out how to make it work for you.

From my experience streamlit is built for internal teams that want to demo ML based applications, trying to make any type of scalable or multi user application is where many problems start to arise.

For example just trying to get url parameters required a hack that doesnā€™t work at scale https://github.com/streamlit/streamlit/issues/798

As for being useful, I find it useful for personal/internal apps that may have just been a cli/python script and would have taken too much work to make a GUI around it. With Streamlit its super easy to add a GUI layer to exist.

A good example is https://github.com/explosion/spacy-streamlit For doing NLP its nice to be able to visualize sentences tokens, etcā€¦ and provide an ā€œappā€ that allows you to play around with spacy.

3 Likes