#pyqtgraph
1 messages ยท Page 6 of 1
Gah that's my bad--I try to keep the bulk of the messaging between the announcements as similar as possible and missed that--give me a moment
no problem!
(thankfully it's a simple edit)
and review pull requests in the
#pyqtgraph-sprint-chatchannel under theOPEN SOURCE PROJECTScategory which can be found in the left sidebar of the discord
That should be more clear
๐
not sure if you can sticky comments, I'm drafting a post to put on there with some more details that I felt might be overwhelming in the annoucement.
I can sticky mod comments, and yours will be distinguished since you were named in the post. If we need to I can make a stickied comment linking to yours
that should be fine
Also, question for all you pyqtgraph maintainers: How interested are you in keeping this channel around for y'all to use year round for organizing things for pyqtgraph in general?
#black-formatter has migrated to this server after the freenode irc debacle and you can see how they use it. You could use this channel for something similar (we could open this channel or a similar one for year-round interaction with folks on this server).
so, we have our own slack workspace, and while I'm preferential to discord myself (dat syntax highlighting + markdown), I'm reluctant to ask folks to migrate over. I would be good w/ maintaining the channel; and I will certainly monitor it, but I make no promises regarding widespread adoption of the other maintainers.
That's entirely reasonable! Happy to leave the option on the table for y'all for the future
that's largely a question for admins here if they would be willing to have the channel here, ...they may not want to add to the noise if there isn't buy in from all the maintainers. If they do allow the channel to maintain, I would gladly monitor it tho (and low-key hope we migrate away from slack)
We can just keep this channel private to y'all and hidden from the general server members. We already have... quite a few channels that one more in this category won't hurt anything.
I can also always make a pretty snazzy proposal showcasing some of the nicer features we can offer in this discord, but it will always come with some downsides especially being part of a large server like ours
Are we going to move regular development discussion to the public channel here for the duration of the sprint? It doesn't really look like we'll be overwhelmed there...
Seems like pyqtgraph is the anti-hype, non-dashboard, "what's this 'data science'?" plotting library ๐
probably should move discussion to the sprint channel during the sprint unless it gets really noisy...which I'm not too concerned about.
@rough furnace Would you like a second post on reddit tomorrow, at the start of the sprint announcing it's kickoff?
great question, ugh, if it's not a significant amount of effort, sure... but if it's something that's going to take some substantial time,... probably ok to do w/o it given the amount of activity the first post generated ๐
Nah it's no problem at all! I'd be happy to!
I'll make a draft later today, what time would you like it posted? And is there any different content you'd like to highlight from the original announcement?
no need to change content; in terms of time to post, maybe 11 AM PDT?
Sounds great, I'll get one drafted and make the post announcing the sprint tomorrow! I should be decently responsive tomorrow as well if anything comes up! Prior to posting I'll drop a draft of it in this channel to make sure it looks good. Hopefully I won't mess the title up this time ๐
Thank you!!!!
@obsidian sapphire :chef-kiss:
heh; that's not exactly an improvement.
heh, before you ran pycln the error count incremented upward by over 100
this PR was never going to address the static code checker stuff anyway
mm. it looks like we're -106 from earlier this evening, though, so nice work on #2002!
yup, waiting for lgtm.com to rescan our repo and see if we get bumped up from "A" code quality to "A+"
(which I'm not sure if that says more about our repo or their service)
dumb question, does pycharm have type-completion now when using pyqtgraph.Qt ?
(also I'm giggling on the inside every time I see the diff in a commented out code chunk)
I have a Qt.pyi file that usually does it for me, but I haven't looked at it closely to know if I'm doing it correctly in all environments.
Nils gave it to me, I think? it's just a series of nested try/except-import-error blocks that go through all the possible versions of qt
No, that's not a thing I'd be good at ๐
Pretty sure that was @mortal grotto
I would equally believe that!
@obsidian sapphire this PR LGTM; do you want to merge or should I?
do eet!
no? it has some very large automated things and some small, hand-made things, which might be useful to keep separate someday.
good point
๐ฏ
alright, i'm going to call it a night, ...and i'll briefly say hello tomorrow morning but I have some kid related errands I gotta run so I won't be particularly active on here until mid-day my time.
cheers! see you then.
and back to 25 PRs ๐
@fervent vale I'll take another look at the jupyter example, last time I used it it was in pretty good shape
Yeah that was me, lol. A loop would be wonderful, but everything has to be statically determinable for PyCharm to recognize the libraries involved
Was hoping to get feedback on how people think they want to use pyqtgraph in a notebook
Don't think many of us have an idea of that
@wide prism has been an advocate for pyqtgraph in the notebook, so he may be a good first person to ask; I'll take a look at the issue tracker as this has come up on a few occasions
I like the idea because I think that is how many science people use Python now. As a cheap/capable Matlab/Mathematica alternative.
the use-case I'm imagining comes w/ future integration w/ pandas, often with scatter plots zooming in/out to evaluate stuff in more detail.
I think I would have liked an easy way to plot an image and then to play inter actively with the levels
For line plots pyqtgraph allows the user to zoom
For images the speed of pyqtgraph allows the user to play with intensity levels
But my own use case is to run in %matplotlib qt mode:
I like to keep the plots out of the notebook itself, because that notebook sits in a git repository for versioning/backup/distribution.
If I understand the current effort correctly, the framebuffer is what allows plots inside the notebook, right?
But there's no image view widget now
going to be afk for the next hour+
Yes, the plots are in-line within the notebook but are not static
Before you go, is there an open pull request you'd like me to flag in the post as an example of what you're working on?
How does it handle saving the notebook? Keep a frozen image around?
for newcomers to the library, I think getting more eyes on the jupyter notebook integration PR would be great:
Thank you! I'll drop a draft of the post here when it's ready then post it in an hour and a half, unless you'd like it up when it's written
Operating mode aside, my main application is exclusively line/scatter plots. So what you have already seems REALLY useful.
Yes. A static image gets saved into the notebook, so that can get large.
I suppose you could plot lots of points, pan and zoom it to the view that you want, then click save
random plot
Having linked axes on the time series data would be really cool. And I need to jump around in the data and look for glitches, so pyqtgraph pan/zoom would be awesome.
I have the opposite problem with saving:
I keep fiddling with the view, and it ends up saving a new version of the large file every time. And that clutters up my repo. Which distributes to a bunch of computers.
So currently, I store the images separately (they don't need versioning, really).
(edit) I am just saying that I probably won't be able to switch my "production" environment to use your framebuffer pyqtgraph.
That's why none of the included example notebooks has images saved in them...
I was trying to setup mybinder.org but it gives me a ubuntu 18.04 container and the kernel crashes the moment I create a QApplication
Oh, that sounds neat ๐ (mybinder.org, not the crash)
For the pull request above (2055)--is it fair to say this pull request aims to "improve plot interactivity in the Jupyter Notebook environment"? Or is there a better way to quickly explain it?
If @fervent vale isn't around right now:
I think that is a good description.
Fantastic, thank you!
Oh, look at our ci pipeline, we have to install some supplimental packages to get our test suite to run
Hey Keith I would say enable interactivity, presently we can't do interactivity at all
Oh, but it improves interactivity over the MatPlotLib version ๐
Title: Join the PyQtGraph Code Sprint!
Body:
Join the PyQtGraph maintainers today, November 13th and 14th for a Code Sprint hosted by our sister community the Python Discord!
PyQtGraph frequently finds use in scientific computing/research applications especially when you need to view data in realtime. The Python Discord be hosting a coding sprint on the server to tackle open issues and to submit and review pull requests in the #pyqtgraph-sprint-chat channel under the OPEN SOURCE PROJECTS category which can be found in the left sidebar of the discord.
During the sprint we hope to:
- Submit PRs that address existing open issues
- Test, review and merge existing PRs
- Identify documentation that can be improved, and submit PRs to do so
If this is interesting to you, an example pull request we hope to tackle can be found here: Jupyter PlotWidget Example which aims to enable interactivity in the Jupyter Notebook environment.
Office hours will be at November 13, 2021 3:00 PM (2100-2300 UTC on Saturday, November 13) where @j9ac9k (u/ogi010), @ntjess, @outofculture will be available to answer any questions you might have while contributing!
If you're interested in helping contribute to this library then check out the following:
- Read and abide by the code of conduct https://github.com/pyqtgraph/pyqtgraph/blob/master/CODE_OF_CONDUCT.md
- Setup your contributing environment https://github.com/pyqtgraph/pyqtgraph/blob/master/CONTRIBUTING.md
- Get ready to have fun and support an awesome library!
Basic Plotting Example Using PyQtGraph
Exploring a Scatter Plot
Highlighting Regions of Interest
A pColorMesh which generates pseudocolor plot with convex polygons
Ok it dropped the links, but roughly, how's that?
It's almost identical to the previous one, but this adds a reference to the pull request you're focusing as an example of what to expect
"especially when you need to view data in realtime" --> "especially when there is a need to view data in realtime"
"The Python Discord be hosting" --> "The Python Discord is hosting"
๐ดโโ ๏ธ Arr!
"Office hours will be at November 13, 2021 3:00 PM (" needs a timezone?
Additionally, if you'd like to make the submission, I can and pin it
"then check out the following:" --> "then"
Is it PST (daylight savings time messes me up on what the timezone is currently called)
@rough furnace , can we pick one of the images to actually have in the post, instead of links to four of them?
In the new editor they look like this: https://new.reddit.com/r/Python/comments/qm0bmz/pyqtgraph_code_sprint_on_november_13th_and_14th/ for a visual of how noisy they are
I think it's fine, but I am time and time again not the person to ask about data science visuals. I go far too noisy all the time
I don't think Reddit supports embedding images, extensions like Reddit enhancement suite can automatically put them inline
Four images is certainly overload. The color mesh looks kinda-clean, though ๐
Really? Interesting. Why that one specifically? I liked the basic plotting example personally
Keith, thank you for helping us out with that. The post is great as it is, I can always find something to nitpick on ๐
Well the basic example would also work
It's a better example of functionality, but the other one seemed like a better eye catcher ๐
not really AFK any more but not really not-AFK
What's your timezone?
No problem at all! I'm excited and hope the reddit post can encourage some contributors to take a look
Let's drop the other two then. That should reduce the noise but show the scope of what PyQtGraph can do
I think PST is the correct timezone? @rough furnace can you confirm that time for the office hours?
ugh, we just had daylight savings time lol, "office hours" starts ~2 hours from now ๐
haha yeah daylight savings is what's messing my timing up. I think UTC is still correct: 2100-2300 UTC
yeah maybe just put UTC and be done with it ๐
Ok listen here! I just had a full tom scott timezones moment: https://www.youtube.com/watch?v=-5wpm-gesOY ๐
A web app that works out how many seconds ago something happened. How hard can coding that be? Tom Scott explains how time twists and turns like a twisty-turny thing. It's not to be trifled with!
A Universe of Triangles: http://www.youtube.com/watch?v=KdyvizaygyY
LZ Compression in Text: http://www.youtube.com/watch?v=goOa3DGezUA
Characters, Sym...
Wait JST is a time zone?
you hush
I got, "Joint Services Transcript." when I looked so I assumed you were messing with me. Full tom scott timezones now.
Oh that 'Difference from Local Standard Time' is a nice feature
So that section now reads,
Office hours will be at 2100-2300 UTC on Saturday November 13, where @j9ac9k (u/ogi010), @ntjess, @outofculture will be available to answer any questions you might have while contributing!
perfect
How do you monitor your feeds? It's unwieldy for me to have reddit, discord, slack, GH discussions, and issues open... I suppose I should get better at configuring notifications, haha.
Just bringing it up in case we wanted to recommend a contact method in the post
Ok I think I've got all the changes, dropping the links it looks like this:
PyQtGraph frequently finds use in scientific computing/research applications especially when there is a need to view data in realtime.
The Python Discord is hosting a coding sprint on the server to tackle open issues and to submit and review pull requests in the #pyqtgraph-sprint-chat channel under the OPEN SOURCE PROJECTS category which can be found in the left sidebar of the discord.
During the sprint we hope to:
- Submit PRs that address existing open issues
- Test, review and merge existing PRs
- Identify documentation that can be improved, and submit PRs to do so
If this is interesting to you, an example pull request we hope to tackle can be found here: Jupyter PlotWidget Example which aims to enable interactivity in the Jupyter Notebook environment.
Office hours will be at 2100-2300 UTC on Saturday November 13, where @j9ac9k (u/ogi010), @ntjess, @outofculture will be available to answer any questions you might have while contributing!
If you're interested in helping contribute to this library then:
- Read and abide by the code of conduct https://github.com/pyqtgraph/pyqtgraph/blob/master/CODE_OF_CONDUCT.md
- Setup your contributing environment https://github.com/pyqtgraph/pyqtgraph/blob/master/CONTRIBUTING.md
- Get ready to have fun and support an awesome library!
Basic Plotting Example Using PyQtGraph
A pColorMesh which generates pseudocolor plot with convex polygons```
Pepe Silvia is a reference to one of the most famous scenes of Itโs Always Sunny In Philadelphia in which the character Charlie goes on a conspiratorial rant about how he believes a person named โPepe Silviaโ does not exist. The scene has gone on to be a favorite in the Always Sunny fandom and has found use as a reaction image on Twitter.
The reddit post should refer to the discord, and shouldn't need much monitoring. I'll be watching it on and off through the day as well to help manage that as needed
only other suggestion I have is potentially linking the comment I made in the previous post about some more of the speciifcs
let me dig up the link
Got it! Give me just a moment
Office hours will be at 2100-2300 UTC on Saturday November 13, where @j9ac9k (u/ogi010), @ntjess, @outofculture will be available to answer any questions you might have while contributing! u/ogi010's introduction to the event and project can be found [here](https://www.reddit.com/r/Python/comments/qm0bmz/pyqtgraph_code_sprint_on_november_13th_and_14th/hj6jl6n/?context=3)
how's that addition?
:chef-kiss:
Ok, the post is ready then. Want me to post it or would you like to? I can pin it regardless
why don't you do it, no doubt I'll still screw it up ๐
Haha I screwed it up last time so that's not a big deal at all
(Lets see if the image embeds work)
embedded links I think require reddit enhancement suite; on a plain browser they just show up as hyper-links
The factorio reddit has images; That's about the full extent of my reddit usage.
I *think* that's how reddit behaves if it's not specifically a gallery post
Ah, alright then ๐
Did the old post show the links more correctly?
No. Just links; That's why I brought it up. I thought it did that because there were too many images.
left is safari, no extensions, right is chrome with reddit enhancement suite
I honestly don't know. Their whole embedded content is weird. *grumbles in moderating on reddit*
hahaha naw leave this as is, it's fine. ... probably should look into it at some point, not worried about it now tho
Agreed, no need to worry! ( @rough furnace , is it just me, or is it a little hard to tell how exactly that is "enhanced"?)
reddit enhancement suite has a ton of functionality and I only use a micro-fraction of it.
truth be told I don't often like to stray from defaults, when I installed it to begin with, it was much more essential than it likely is at this point... I honestly haven't done a good comparison of what functionality it provides that I find very useful
Reddit is a cobweb of weirdly well supported things, poorly supported things, and community supported things. I have res default to old reddit because I'm adverse to change (Where as Joe drives us to try the new features and actually keeps the sub feeling up to date). Regardless, looks like the post is up and works, I'll be watching it throughout the day to make sure anyone who's got a question refers to the discord
Thank you so much @hexed tundra !
@wide prism I don't even want to do the math on what your current local time is ๐
No problem! Glad to help and hope the reddit side joins! We really wanted to work more with the greater python community this year and events like these are a fantastic opportunity to do so!
(j9ac9k) Well, you could click on the JST link above. But the answer is simple: Sleepy time! I won't solve any more ViewBox issues today ๐
Thanks for all of your help catching errors in the post! I really appreciate it!
between you and the admins here we've the thankful ones!
@rapid kestrel Thank you as well for helping get all of this running!
<@&267628507062992896> any chance we can white-list some folks to voice-verification that haven't been here for 3 days that just joined the server for the purposes of the sprint?
I can disable voice verification for this VC if you'd like
I'm good w/ that, provided you can re-enable it if it's a problem?
Yeah, np
thank you so much!
Everyone should be able to speak now
If someone still can't speak they will need to re-join the VC for the permission to update
way more people here than scipy sprints ๐ฌ
giving this a go now
at least in safari there is something funky happening w/ linear region items, let me check w/ chrome
ok, the linear region item is a safari specific issue
on the ROI examples, looks like the plot is cut-off?
same with the plotting example, although the cut-off isn't as extreme
baby is waking up, afk for a little while
If you close the left sidebar, you get more screen estate. Then you can resize the plot frame to show more
I am not sure if GraphicsLayoutWidget has some minimum size per plot
One thing is that a few of the examples in pyqtgraph set up really large screen geometries
If you'd like me to end the office hours event let me know
@fervent vale I'll do another run through on your jupyter PR in a bit (few hours), I'm a bit bummed about the safari mouse behavior but I suspect there isn't anything we can do about that one, maybe the jupyter_rfb folks.
just saw this, yeah looks like all the maintainers are offline, so probably a good time to end it
@fervent vale hmm... I collapsed the side, panel, unfortunately that didn't seem to buy me any space on google chrome:
same w/ plotting example
i'll try and take a closer look once I get the kids to bed in a few hours
after collapsing the side panel, you can drag the bottom right corner of the plot to resize it
right, in my case it seemed to stretch the image (at least on the plotting example, should check the ROI example)
the ROI example rescaled once i made it wider ๐
I have previously had gotten ~5 pycharm pro licenses for working on pyqtgraph (license could not be used for commercial work) if there is interest in getting those again let me know and I'll re-apply
@rapid kestrel we've had more newcomer activity than I thought we might. Thanks again for hosting/promoting us!
not sure when we should discuss if we want to keep and/or open this channel to the public, and what factors would go into that.
oh, and on queue, baby woke up from nap!
So! We're happy to keep this channel around for y'all closed if you want to use it for the future.
If you'd like a permanently open channel, that'd be closer to our partnership with #black-formatter, where this channel is more of a base for your operations and open to the community to participate in as well
I want to continue this convo later, with the baby being up, my attention is sort of taken there ...i'll be monitoring the sprint channel here for the rest of the weekend but probably won't be too active there (maybe after the kids are in bed)
NilsNemitz, I was trying to add an interactive ColorBarItem to the jupyter simple.ipynb image example. How are the handle bars meant to work? They keep on snapping to some other position?
The ColorBarItem example has a number of different settings.
The handles make the limits ("values") shift while pulled; the handles snap back when you let go.
So let's say in the ColorBarItem example I pull the lower handle to 5000, is the lower image level set to 5000?
The handle snaps back and it's not obvious what level got set
It's designed to work interactively by looking at what the axis says and how the image looks.
There's a quadratic dependence on selected position that gives you both close-in accuracy and the option to make large changes quickly.
The logic starts here:
""" internal: recalculate levels based on new position of adjusters """
if not self.region_changed_enable: return
bot, top = self.region.getRegion()
bot = ( (bot - 63) / 64 ) # -1 to +1 over half-bar range
top = ( (top - 191) / 64 ) # -1 to +1 over half-bar range
bot = math.copysign( bot**2, bot ) # quadratic behaviour for sensitivity to small changes
top = math.copysign( top**2, top )```
Qt also lets you drag the mouse outside the plot window, and it will still follow. Not sure if the notebook lets you do that?
Grabbing the top handle and moving it to the top of the bar should double the range.
Grabbing the top handle and moving it to the center of the bar collapses the range to the allowed minimum.
(same in reverse for the bottom handle)
Between the end points the response is quadratic: When the handle is moved up by half the distance to the end of the bar, the range will change to 1.25 x the previous range.
Okay, so I misunderstood the meaning of the handles. They don't indicate the levels
<@&267628507062992896> I think we're good w/ the removal of the #pyqtgraph-sprint-chat and associated voice channel at this point.
Thank you all for hosting us, we had a very successful sprint: https://github.com/pyqtgraph/pyqtgraph/pulls?q=is%3Apr+created%3A>2021-11-11+
whoo! ๐
We'll delete the voice channel and archive the pyqtgraph-sprint-chat
another day, another convert #python-discussion message
if we made any money, we would give you a commission ๐
@rapid kestrel debating how to handle people DMing me for support w/ random stuff (not pyqtgraph related, just ... "hey can you help me w/ <insert weird pyinstaller issue>" )
We have this pin in our staff channel, might work for you with a small amount of altering ```
Hey!
We do not offer programming help via DMs, so please ask your question in one of the available help channels (See #โ๏ฝhow-to-get-help). The main reason is that by asking your question in public, everyone can contribute to the answer or benefit from it. Also, as we're a fairly large server (275k+ members), it prevents our staff from getting flooded with DM requests for help.
Thanks!
The [#โ๏ฝhow-to-get-help](/guild/267624335836053506/channel/704250143020417084/) resolves to #โ๏ฝhow-to-get-help when you send it
was about to ask ๐
I'm pretty sure python community members have access to the !poll command FYI
๐ฆ - we
๐ง - migrate
๐จ - from
๐ฉ - our
๐ช - slack
๐ซ - workspace
๐ฌ - to
๐ญ - this
๐ฎ - discord
๐ฏ - channel?
ah sorry I should've provided an example
It's not just me!
!poll "your question" "option-1" "option-2"
๐ฆ - option-1
๐ง - option-2
than kyou!
I don't know how to use the polls either, so I'd have done the same
!poll "Should we attempt to migrate from Slack Workspace to this discord channel/server?" "Yes" "No"
๐ฆ - Yes
๐ง - No
Tagging some pyqtgraph members to answer above, check the thread for more explanations.
@wide prism @fervent vale @torn coyote @obsidian sapphire @mortal grotto @plush fulcrum @violet basin
I assume this server would retain full message history? (>5k)
yup! all message history is retained.
If you don't mind me asking, what sort of tools/niceties does slack provide y'all that you'd need here (if you were to theoretically switch)
there is really nothing slack provides us that is particularly useful other than it's an online place that everyone is already at. Discords screen/voice/video share capabilities are far better, the history/search capability is far better...
I do have a slack github bot that alerts us of new/closed PRs/issues but that's something that's just handy, hardly a requirement or something tempting....
The big hurtle here is asking people to migrate over, ...not sure if everyone (most people?) even had discord installed before the sprints (we did a sprint via discord at the scipy conference)
Hmm. The view from very much my perspective is
- I find it somewhat easier to scroll back and read up on Slack. Somehow discord's interface feels more focused on what's on now.
- The noise (of things happening in other channels, random messages, the "online users" bar on the right) is dangerously distracting for me.
- We would need to maintain some separate communications for "random" vs. "development". (And I don't want to chat with 100,000 python users.)
- I haven't found a way to follow individual channels on discord, and even on this weekend missed discussions in the one other channel
That said, I feel like this is much more accessible here to the users we would like to help out; and maybe get to contribute at some point. So it seems like the right move to migrate?
we should probably drop in on the #black-formatter channel and see how "noisy" that place is.
I could imagine that one option might be to set up a cozy little pyqtgraph discord server that I could usually hang out on? Jumping servers seems to be as convenient (or more so) on discord as on slack.
Scrolling back on the black-formatter channel, looks like most of the activity is the github bot (which I would probably not want); other than that, looks relatively quiet.
Anyway, work! (distractions, distractions)
fyi, that github bot is a webhook service provided by GitHub itself, so you can filter events (commits, pr comments, issue creation, etc.) as you please, plus this server has some custom filtering through cloudflare workers as well
I don't mind being on all the chats and servers, myself, and discord works as well as anything.
So, if you don't mind me commenting (I use slack on the daily for a non-profit I'm very involved in). I promise this will be neutral!
- Discord is definitely more IRC-like than Slack. Both a blessing and a curse. I will say that discord supports threads and they're a bit better than Slack (i.e. you can view it in full preview mode, see all threads in a channel at a high overview, opt into threads you care about)
- This server has been known to be very... alluring to those who like distractions. I find myself frequently sidetracked being helpful but not necessarily productive. It does help if I'm ruthless with muting channels + categories and then collapsing them so I only focus on what's necessary.
- As for communications, dawn mentioned a thing that worked for black, which is a private DM for the closed stuff, otherwise things go in this channel. I will say the these open source channels are relatively left alone. Not entirely because of this server's size, but we do have a team of moderators.
- Following individual channels gets difficult. You can change your settings to get notified for every message in this channel but that gets very noisy very quickly. The only other thing I've found is just ruthlessly muting and collapsing all the other categories.
Slack also has keyword notification ability which I very much miss for this discord.
I also would recommend y'all to see if setting up your own little server is maybe a better move. It'll be quieter, you'll have total control, and we can still whitelist the channel here if you want to post an invite.
Also, as dawn said, we have the ability to filter which github events you want. So if you want we could do something like: new PRs, new issues, and things like that.
Just to clarify: My thought was that it might work to have the private, low traffic, random channels on a separate server. Then stick to the one development channel on here.
But it also seems that once I figure out discord's muting/notify system I might feel a little healthier here (thanks @rapid kestrel , for pointing that out.)
we now also get the squid icon next to our names fwiw
Also, is there a way to hide the top-level threads I don't want? It would make navigation so much easier
if you right click on the category, you should get a mute option
you can then click it to collapse all channels in the category
After muting a number of groups, I must say the left channel is much more manageable (even though I had become accustomed to just using Ctrl/Cmd + K to navigate)
Thanks for the tip! Using those keywords I was able to find a helpful post online.
For others in the same boat, you can right-click the python discord and go to notification settings to mute multiple at once without having to right-click every individual channel
@rapid kestrel is there a way we can get the archived channel logs? we suspect there may have been a hint in there about something we now can't remember ๐ (and to think I thought archiving instead of deletion was silly)
I can give you access to the channel again (or ask an admin to do so). And yeah, we usually put channels in an archive state before deleting it because this happens so frequently with us too
#pyqtgraph-sprint-chat you should hopefully see it at the bottom of the channel list now
@mortal grotto while I don't see the channel in my left window, using Ctrl+K, it will show up as available, want to search there for what you were looking for?
@rapid kestrel thank you!
That worked, thanks!
@rough furnace why on earth wouldn't you want type hints?? ๐
I particularly like all the unions with Any in there, rendering the rest of the union useless
Interestingly, PyCharm doesn't treat them as useless. i.e. Union[Any, str] can still give string completion suggestions
@fervent vale, I finally got the jupyter notebooks to run on my machine, and just wanted to say that it is indeed awesome to have pyqtgraph interactions there!
Is there some way to lock the notebook files in the git repository? If I go play with them, they seem to keep autosaving, and then I have to avoid accidentally committing a changed version. I guess it might also be a good idea to gitignore the .ipynb_checkpoints subfolder?
I suppose one could copy the example notebooks to a local directory. I don't have a good idea how to deal with the auto-saved notebooks, except to run git restore .
Regarding discord vs. slack, I think I'd be fine with either as long as we are consistent (leaning toward discord just because of message history...)
It's becoming hard for me to search for things since now they could be under either service. It doesn't matter much, but it's enough of an inconvenience to take me off the fence ๐
Can someone remind me of the fix for the "model not found" error in pyqtgraph.jupyter? Where does offscreen need to be set?
Windows or Linux?
I suppose I couldn't find it because it was an issue comment, not slack/discord lol ๐คฆโโ๏ธ
This is linux
Windows ๐คฆโโ๏ธ๐คฆโโ๏ธ Don't know why I said that
For Windows, offscreen plugin doesn't work, so you can't use it. (There will be no fonts)
So just run jupyter-notebook.exe
On Linux, and especially so for WSL2, you can use offscreen plugin.
QT_QPA_PLATFORM=offscreen jupyter-notebook
I didn't manage to get QtWidgets.QApplication(['-platform', 'offscreen']) to work, even though web search says it should
But that said, I haven't come across this "model not found" error before
I found the issue. I thought if I restarted the kernel after installing jupyter_rfb I could interact with the widgets, but the server itself had to be restarted, not just the kernel. Not sure if there should be a blurb in the docs about this if users run into the same issue? I imagine many people will install jupyer_rfb for the first time in this setting and might open issues. Or, they will be smarter than me ๐
For me, installing jupyter_rfb was the thing that pulled in all the notebook dependencies for me. If you look at binder/requirements.txt, it is really short
Right, but I had a jupyter server running and installed jupyter_rfb while in a kernel. I got the "model not found" error until after I restarted the server, then everything was fine
All the requirements install properly, it just shows a static screenshot until you restart the entire server (instead of just the kernel, as many users might be accustomed to doing). Again, it could also be a non-issue
Fair enough. I was wondering if there is some well-known git magic that I've missed so far ๐
Same here on the static images on jupyter rfb. I installed the pacakges (conda on windows) and the notebook would only show static images. Today I tried again, and everything ran interactively. So I guess a restart of something is required at some point.
The way to do then would be to add them to I may have been way off base.gitignore which I don't think is a bad idea really
How does that work in this case? If they are in .gitignore, it won't add them as new files to the repo. But won't it keep updating them if they are already known?
It might be a good idea to add
.ipynb_checkpoints
*/.ipynb_checkpoints/*
``` ?
i would git ignore the directory; you can still commit stuff to git ignored files, there is just an extra check to do so on second thought not sure git ignore would ignore changes to already added files...
we have the best users โค๏ธ https://github.com/pyqtgraph/pyqtgraph/pull/1801#issuecomment-973101599
that's so sweet
we've been really lucky in that regard, we periodically get some impatient people with "new issue -> when are you doing the next release?" ...we had one individual that went a mini rant when we introduced a CoC but overwhelmingly our users have been super supportive
I'm not sure if this is because our library generally is tailored towards other scientists/engineers that may not be software devs, and there just isn't a good replacement.... anyway not sure the reasoning even matters
tag 7 people, get 1 vote ๐ clearly we are an opinionated lot
The last thing keeping me from wanting to migrate is being able to follow a thread. If you're late to the conversation, is there a way to see all replies to a post (if no thread was created)? Or do you really have to click through the linked list of replies?
you can make a new thread for each "post"
since can make unlimited threads
oh my bad
the answer is no
you will have to click through the linked list of replies since there is no way to filter out messages that are not related to the post
is that a thing in Slack?
I mean, it's not even necessary that all the responders used "reply"
In slack (to my knowledge) replies are treated as threads by default, i.e. they automatically nest and you can see all replies to a message. It doesn't work, though, when people respond in the top level channel. It also doesn't spam notifications when replying vs. in the main channel
I have a direct message from our github contributor Wubbzi / Inigo Montoya.
I would assume that we want to invite any active contributor to this channel?
feel free to ask the admins for anyone you may wish to add here
I think we'll wait for @rough furnace to wake up, but if anyone else has ideas on policies for the pyqtgraph discord club house, maybe speak up.
Since we don't usually have an excessively large number of people involved in discussions (on github and slack), I think we don't need to be particularly selective here either.
Oh yeah please invite them here
How's it work? Do I need to ask a server-level admin to set access to #pyqtgraph ? I don't want to waste anybody's time ๐
There's an "invite" button on the channel sidebar, but that seems to want to invite to the Python discord in general.
Yeah, this channel is limited to those with the pyqtgraph role, and only admins can assign roles
I guess I should ask then ๐
I can also assign roles, feel free to drop the ID here and we can handle it~
Dear <@&267628507062992896> , can we give access to #pyqtgraph to Chris_ ? He's one of our github contributors.
I Think it's @harsh ravine
Done
@wide prism need to add the #xxxx ...on "normal" sized servers, that's not an issue ๐
๐ @harsh ravine
Awesome, thanks lots!
Thank you @zealous magnet 
Couldn't find it...
time to take the kids to school ๐
Ah, doh... I was looking in the private messages window. The number does show up with the "@" search. Learning, learning.
Sorry @rapid kestrel , just noticed that I totally ignored you there. Apologies. Long day, time zones, scatterbrained. ๐
an admin can either:
give them the pyqtgraph role
or
manually give them read and send message permission in this channel
like, you can give an individual user permission to participate in the channel
I feel the latter should be done if they are not part of the org
Interesting. I guess we need to figure that out. The pyqtgraph "org" is basically @rough furnace over there.
Rest of us are just random squids.
oh lol
I'd wager a guess that some other communities are a tad larger.
But it's probably a good idea to invite some people in without the role first, and then assign a squid if they decide to keep hanging around. Thanks for the info, I didn't know that!
To give a bit of a more technical explanation, permissions are assigned to either roles or specific users. We can create more roles with the permission, or give existing ones the permission, or give the permission to specific users
I think I can safely say for everyone w/ the pyqtgraph role is that we don't want to wear out our welcome and we want to take every step to minimize workload on admins.
I'm not an admin, but pinging admins (or even mods) will not wear us out because we receive so many pings a day that we are not phased by it anymore
Now I don't foresee a flood of requests for giving people roles/permission to access this channel; but if there is something in this process we can do to minimize pings to you all, we'd love to do it.
And DO let us know if we are doing something the annoying way ๐
lol pings shouldnt be a concern Jack
I get so many pings a day by @runic umbra that it feels nice to have a human ping me once in a while
y'all are so great and amazing. you shouldn't hesitate to reach out to us/admins if you need anything. it's not a big deal anyway
If adding more people is something you foresee becoming routine, we can think of some sort of arrangement
I can see a case of adding a few people a week, but I can see that tapering off, there aren't that many pyqtgraph maintainers, and not that many regular contributors....
we can give you access to control the permissions of the channel yourself
If you're good w/ that, I'm good w/ that.
Nice, of course we can still assist if anything goes wrong or you need help ๐
thank you so much, you all have been great
let me just run it by the admins to make sure we're alright with that, should be fine ๐
I won't be offended if they say no ๐
ok that's funny
Zig already asked in our admin chat about it ๐
seems like we're ok with it ๐
"great minds think alike"
๐ so ugh, how do I manage permissions to this channel?
I've jsut given you access
you should be able to right click the channel and click edit
I think this guide may be useful https://support.discord.com/hc/en-us/articles/206029707-How-do-I-set-up-permissions-
๐
it's essentially add a role/member and then give them perms
My only suggestion is not to edit the everyone role on the channel
since that may make it public
Since everyone can send messages in the channel already, you only need to give new members read permissions
if you'd like to then remove them, you should have a big red button at the bottom of the permissions list for each role/user
going to read the discord FAQ ...took a quick look and I didn't notice how I actually grant a read permission to an individual ... but I'll sort that out ๐
You click the + icon next tole roles/members as a way to say, I want this role/member to have special permissions in this channel
find the person/role you want, add them, then tick the read messages permission
Yea ๐
that doesn't add them to this channel BTW
that just adds them to the list of people with bespoke perms
you then give them read messages perm
right...got that part ,...but thanks for the clarification
Cool cool
loosely related note, is this the largest discord server?
not by a long shot ๐
There are quite a few Discord servers at the member "cap" of 800k
!
If you click the compass icon on the left side of Discord you can see an ordered list of servers
you can see the largest server per category there too
We're the second largest Science&tech server
behind a gaming browser

we are the largest online Python community I believe
Yea, we are afaik
Only us and PySlackers are featured on https://www.python.org/community/
Hats off to lofi girl for 127,000 online users.
and PySlackers has ~40k members
Hah yea
iirc they did a lot of talent shows when stage channels were big
pyslackers have probably reached their terminal velocity for growth. they had 25k members when we had 20k members.
we're growing at a very different pace
yes. but it's been scary for a while and we keep managing.
double salary in December
it's a Christmas miracle!
... of zero lemons .. 
Hehe... I'd certainly be scared. Lemons or no.
I'm glad we're attracting lovely people like all of you at pyqtgraph to hang out with us and get closer to the community though ๐
i heard the president of Discord flies to your house with his private jet and gives you a second hoodie when you hit 300k
except this time it's not a physical hoodie it's an NFT
Wait, who gives you the first hoodie then?
they just mail that
that's just as good
I'm still grumpy I never got one.
Discord doesn't acknowledge non-dictatorial discord server hierarchies
our triumvirate is not sanctioned
๐ Thanks guys, keep up the great work!
(I am off to bed for today.)
good night ๐
๐ค
((For some reason, I have now totally identified the "president of Discord" as Snowcrash's Uncle Enzo.))
๐
I ping <@&267628507062992896> just for fun sometimes :D
(Truly you're fine and ping as often as you need)

oooh a new channel
๐
most of us are on a slack workspace; we're testing the waters here after the sprint for a bit
How does it compare so far?
personally I prefer discord myself; but would want there to be something resembling a consensus for us to permanently migrate; that said I've been on this discord server for some time, and I don't plan on going anywhere.
Work has slowly made me start to really dislike slack
Integration with Perforce, Targetprocess, Zendesk, etc that constantly flood the channels with automated messages.. its just too much
yeah slacks "best" feature is also its worst feature ...
Has there been any discussion about creating or symlinking .pyi files for widgets, gui and core?
@mortal grotto @obsidian sapphire are the two people that have that config, I've indicated I'm open to a PR to add that kind of stub file
right before the sprint, we pushed through a big PR that migrated our imports to follow Qt6 API standards (import widgets from QtWidgets not QtGui for example)
Oh cool, I made a small script to stay sane that copies the files over to the pg/Qt directory. I was just wondering if there was going to be something permanent in the future.
if memory serves, that stub file was recognized by PyCharm well enough, but not VSCode, ...not sure if there is a more robust way of handling that (or hope that VSCode reads/respects stub files within a project)
VSCode is weird. I do remember seeing an issue with the Qt.py bindings not being able to autocomplete using Jedi in VSCode
@mortal grotto @obsidian sapphire if either of you have a .pyi file you like using it and wouldn't mind sharing it, I'll try it against various editors and see how it works
(since I have an unhealthy obsession w/ switching editors every few weeks)
Yeah, I'd be happy to share what I have tomorrow. I refrained from submitting a PR since I didn't know if the pyi file opened up other scopes...
it might ๐คทโโ๏ธ I think a pyi file to get auto-complete, even if for dev quality of life is worthwhile
The way I set mine up is pretty awful. It gives me auto complete but if I cmd+click on anything it opens the .pyi file instead of a .py
Still, its better than no auto complete
@wide prism
3/5, would read.
๐คฃ
I'm scared of checking the time-stamps on slack to know how long I've been going at this
omg....
omg, it's worse than that, it's been almost an hour:
If it's any consolation, the bullet points do look much better.
How hard would it be to set the table text to normal size in the style sheet?
The failure mode here is that the text tries to be both "table formatted" and "bullet list fomatted" and sphinx fails to merge that correctly.
QT_LIB: str
QtVersion: str
def exec_() -> QtWidgets.QApplication: ...
def mkQApp(name: Union[str, None] = None) -> QtWidgets.QApplication: ...
def isQObjectAlive(obj: QtCore.QObject) -> bool: ...
@mortal grotto ^ that's stuff I added to the pyi file you gave me.
you could probably add App: QtWidgets.QApplication, as well.
Oh, that's in my pyi file already.
technically you would want a getattr defined in QtGui until the widgets accessors are deprecated
Here's what I have, YMMV depending on your editor
Looks like I'm missing a few of your additions and you're missing some of mine ๐
oh, exec does return int. yeah, yours is better, then.
downloading it and seeing if sublime text works.... just put that inside the ./pyqtgraph/Qt/ directory?
๐
sublime text w/ lsp doesn't seem to recognize what's up ๐ฆ
Can you test with pyi files in general?
https://github.com/microsoft/vscode-python/issues/16807
Here's a quick mwe you can unzip to try out
wait.... in pycharm I'm not getting auto-complete either
Oh, my bad! Put it in ./pyqtgraph, not under Qt
๐
It has to have the same module resolution as pyqtgraph.Qt. By nesting it you're effectively typing pyqtgraph.Qt.Qt
haha, was just thinking about that; anyway PyCharm auto-complete is good now ๐
Side note -- what theme are you using? It's โจcrispierโจ than mine
๐
using the "nord" theme
(I frequently switch themes)
whops, actually using Vuesion
Same. I even devolve to using the light theme during the day, waiting for apps to develop time-of-day based theming
i just can't get behind that, sorry
๐
Zorin OS does it, it's great
vscode doesn't appear to be reading the .pyi file either ๐ฆ
Mine didn't work with Pylance, but did with Jedi
Try changing your language server
was seeing something in the issue tracker about adding extraPaths bit where the pyi file(s) is/are,...but that didn't seem to work for me :/
seeing some libraries using __init__.pyi should we be doing that with our Qt.pyi file? (that didn't help vscode pylance auto-complete fwiw)
Did Jedi work for you? Yeah, I wasn't sure about the easiest way to use extraPaths, but then again I am not yet heavily invested in vscode
you know, forgot to try jedi ๐ will do that right now
it does!
jedi still works when I move ./pyqtgraph/Qt.pyi to ./pyqtgraph/Qt/__init__.pyi which I have a slight preference for __init__.pyi... need to test pycharm still
looks like pycharm works with __init__.pyitoo
still feel like there is some magic setting for Pylance but I'll have to do a lot more tinkering
seems like connect='pairs' would be trivial to add for enableExperimental if anyone actually cared for it. it's already done in GLLinePlotItem
I think connect='pairs' would be a really worthwhile thing to add, as I suspect future downsampling methods might make use of connect='pairs'
It's not magic, probably just not in mainstream fix yet. I encountered an issue with it a while back, marked as closed Oct 6
Who are the users who use (and actually need) useOpenGL and enableExperimental?
One of the side effects of using useOpenGL: https://github.com/pyqtgraph/pyqtgraph/issues/1371
@mortal grotto Let me know if you're available sometime this weekend to talk about adding the slider to the ParameterTree. I've added it, and I think I've got the code working for all of the bindings but the slider isn't interpreting the min/max values correctly.
I have a few other related questions as well
Nice, is it in a viewable branch/pr?
No, I haven't created a pull request yet. I was hoping to at least have it working in a minimal form before doing that if possible.
I'm happy to open a draft so you can take a look if you'd like
A draft would be good, but if you didn't feel like doing that yet you could also just let me know your fork. Is it already publicly available on github?
No, its not on github. I'll create a branch for the slider and send you a link when my kid gets to sleep.
@mortal grotto There is a slider example in the examples app, so you can see how it should actually work
A draft PR is good, I think it meets the criteria, open a PR when you're ready to have enough code to have a discussion about it
I think edumur, who posted that issue, was quite active on github previously. Maybe asking him in the discussion for that issue might be interesting? The other ultra-performance user showing up on slack was goodboy.
the 1-million points use-case still made me do the blinking meme; .... if someone is trying to plot 1m points, probably would be better served by implementing a fast downsampling method
There are users who enable useOpenGL just because there's some stackoverflow code that does it
I can't think of a better reason to do it ๐
I would love to know more use-cases of useOpenGL but not use enableExperimental
I remember from before that useOpenGL ends up disabling subpixel font rendering
or rather, doesn't have
I suspect a lot of useOpenGL is premature optimization. You are coming off Matplotlib, and are googling "how do I make my plots fast?" Then you find
- pyqtgraph
- weird optimization options that may not actually be needed in your case
The main downside of this is that I don't know if anybody will read the documentation on the goals and trade-offs of useOpenGL...
There was also issue #1918 with the user enabling useNumba for boolean types
oh, I should close out that issue
the actual error was not fixed
I mean, is that really an error?
but it seemed strange to me to have to fix it
to plot boolean dtypes, the user could change the view of the data to np.uint8
I mean, I guess it's an exception; and we should try to avoid those...
the question to me is: to what extent does the user expect the library to handle arbitrary data types?
and arbitrary data ranges
dtypes are tough; would definitely think we can't (shouldn't?) try and handle arbitrary ones, lots of optimization work has been put in to optimize what we can...
for ranges, i'm generally of the mind-set we should try and make stuff work as best possible, a value range is tough to predict; ... and we've taken steps to try and avoid weird cases (like avoiding qFuzzyIsNull)
issue #1964 is also strange to me too... the user doesn't want to change their data prior to sending it to ImageItem
nevermind that ImageItem itself might make many memory copies of their data...
it's tough to plan for people's workflows like that; ...no doubt plenty of people mid-understand the constraints they're under; or attempt to do pre-mature optimization... vs. a real world effect. I'm good knowing we won't be able to cover all use-cases, and especially in the case of #1964, users may need to do a little pre-processing
I suspect @wide prism is right, people are using useOpenGL as a form of pre-mature optimization; I can see myself doing that.
This is partly why I'd like to document the benefits/downsides of each of those options
#1964 seems like a valid misunderstanding of the implementation. The colormaps do promise that there is a "repeats" mode... It isn't the most unreasonable expectation that this is there for using the color map for false color images.
Now I don't really know what you would want a repeating color map for. Render Plasma effect demos? https://upload.wikimedia.org/wikipedia/commons/8/8d/Plasma_effect.jpg
If that's what you are doing, then it would indeed be nicer to have the internal colormap lookup use adjusted_index % color_map_length rather than reconditioning the bitmap every time...
If you are really old-fashioned, maybe you like seeing your height maps as Newton's rings-stlye interference pattern? https://en.wikipedia.org/wiki/Newton's_rings
my understanding of the lookup functionality of ImageItem is to use it to map some range of values A to some other range of colors B.
It is not to use A as an integer index into B.
Yeah, sorry, that was oversimplfied. Although I think Nathan is also trying to abuse it in that way ๐
What I meant was that if the value range 0 to 1 maps to the color range, then 1.5 could map to the same value as 0.5 does. This is - I think - what the color map itself does when you ask it to repeat.
This doesn't translate to ImageItem, because this does not use the ColorMap lookup functions, it uses the LUT directly.
A perfectly "do-what-I-want" version of ImageItem would replicate that behavior. But I wouldn't exactly rate that as a "must have". Or even as a "would be nice".
But in case you see a neat way to implement a flag to add this behavior to the internal lookup, then we could have a plasma demo in the examples, though ๐ตโ๐ซ
but the notion of setLevels itself is to clip the data to get a good contrast
Well, that's why ColorMap calls that CLIP mode. But there is also
Parameters
----------
mapping: int or str
Sets mapping mode to
- `ColorMap.CLIP` or 'clip': Values are clipped to the range 0 to 1. ColorMap defaults to this.
- `ColorMap.REPEAT` or 'repeat': Colors repeat cyclically, i.e. range 1 to 2 repeats the colors for 0 to 1.
- `ColorMap.MIRROR` or 'mirror': The range 0 to -1 uses same colors (in reverse order) as 0 to 1.
- `ColorMap.DIVERGING` or 'diverging': Colors are mapped to -1 to 1 such that the central value appears at 0.
I'll say that I haven't yet found the need to apply these to an ImageItem. But the operations themselves would seem to be well-defined even in that case.
It would then be repeating the range of values set by setLevels to be well-defined
(Except for diverging, which I find to be uncomfortable because it changes the basic mapping over the 0 to 1 range)
Yes. If REPEAT mode is active, and the range is 1000 to 1562, then the value 1564 is the same as 1002. Next loop is 3126: same again.
I am not good at coming up with pseudo-code for this, but if the normal lookup is with clip( val,0.0, 1.0), then repeat would look up with val - floor(val) ?
Incidentally, the last example that I gave for issue #1886 has plotting artifacts if I change the span to span=(49.999,50.001)
instead of just 2 colors divided at 50, it becomes a repeating band of red and green
Interesting...
that's what you get for abusing the system!
ouch
I think it makes a gradient bar over 49.999 to 50.001, so length of 0.002. The internal coordinates of that run 0 to 1 to map colors.
It seems to break around 15 or so... that is... ~7500 in internal coordinates? No idea why it would overflow at that point ๐ฆ
I was expecting it to be 65,536 or something.
... See? It's all repeating anyway ๐
I really liked your example there; I have been wondering if there is a way to conveniently set a colormap with a hard break like that.
I was expecting the next complaint to be that if you zoom in far enough, you can actually see the red-green interpolation gradient.
@rough furnace could you clarify what you meant here: https://github.com/pyqtgraph/pyqtgraph/pull/2101#issuecomment-971800603
At this point I feel like I'm not sure what the goal is for this PR anymore
Sorry about that.
I am always pushing towards a better color implementation, but I won't claim that I know how the pieces fit together.
I have been meaning to test-run your PR, but I keep getting interrupted by work and stuff.
I think we don't want to hard-code color values in the GroupParameterItem if we can avoid it.
But we certainly don't want to hard-code a palette that is different from what we have now, and I am pretty sure the comment did not mean to say that.
if we were still using functions.applyLookupTable, then perhaps changing np.take to wrap mode would have done the trick
It's not your fault.. There have been so many comments on the PR its hard to keep track of what the current goal is. I took the comment I linked above, and the back and forth you and I had to mean I should detect dark mode and set the palette on the app if darkMode is active
There's 0 difference when applying the palette with a QDarkStylesheet
I looked into their code and they are actually changing the palette slightly
Yes, pretty much. I think that if you are looking at the right part of code, changing the type of look-up is not so difficult. But by now, I have no idea where I would even be looking!
Their stylesheet is so thorough that any palette is completely overridden.
Yes. That was what I found before. If I then go and try to use the palette for an item NOT covered in the qdarkstyle sheet, then it is totally wrong.
Maybe they improved that recently.
Pulling the colors from the stylesheet seems to be hard. So I wouldn't recommend that for your PR.
Pulling colors from the palette is easy, and could be used in a lot of other places, too.
So, without TRYING to derail your PR, this would be a good opportunity to move the GroupParameterItem to use a sane, palette based color lookup.
The rest of the discussion results from that. Some touch-up to the palette is required on some system configurations, otherwise we are in the same place as where we started: GroupParameterItem looks like some insane combination of light and dark mode.
You are on Mac?
I am
Does your QApplication automatically have a different (and reasonable) QPalette in light and dark mode?
((I already know that alternateBase is weird))
Yeah, the only real difference is that the group items have the color of whichever alternating color row they are on instead of the outermost being a slightly different color than the groups it encloses
So what is the original bug, then? There it seemed like some cells rendered white background in a dark scheme.
I am on Windows, nothing changes color without pushing it.
The original bug was caused by hardcoding the colors, when mac goes in to dark mode, it does weird things, dark roles become lighter.
The easiest thing to do to solve only the groupParameter problem would be to pick some colors for both light and dark themes and hard code them exactly like they were before.
what exactly changes on Mac? Is that reflected in the application QPalette or not?
If we want to stick them in a palette to grab them, I'm fine with that
How does the rest of the stuff know to change color? Qt has hard-coded colors, stylesheets and the palette.
Does any of that change, or does every pyqtgraph widget detect the darkmode flag and set manual colors based on that?
Do your QLabels and QLineEdits change color in darkmode?
What I am hoping for is that the application's palette does what the documentation seems to promise: Automatically hold a palette of colors that works with your system. And ideally works with dark mode / light mode...
It doesn't really do that on Windows, but I mean, that's Windows...
So this is with no palette in dark mode
This is when a set the background role on app.palette to #111
What are the baseColor and textColor roles in dark mode? What are they in light mode?
What you are showing is that the applications DOES rely on the palette to have a dark background role in dark mode.
That means that this basically seems to be working: The palette goes dark, and some elements automatically change to be dark.
Other elements are (annoyingly) hard-coded to ignore the palette and set "seemed-like-a-good-idea" fixed color values.
dark
#1e1e1e base
#ffffff text
light
#ffffff base
#000000 text
โค๏ธ
I think that makes the goal of your PR the following:
Derive some colors from the palette that make the GroupItem look good <on MAC> in both light and dark modes.
I think you want to grab the baseColor and push it a little towards gray to make the alternate color. That should work with both light and dark schemes, and with any actual base color that the user might set.
alternateBase would have been nicer, conceptually, but it seems that Qt and or Mac OS disagree with us on what that color would be good for.
What you showed there on github (thanks!) is not usable.
There is a separate PR here (which leaked into yours):
Now that things on Mac use the palette correctly, we need to make this work on Windows again. On Windows, you get "dark mode" typically by applying qdarkstyle.
Which stupidly leaves a light mode palette in place. So if we catch that, and fix up the palette ONLY in that case, things should work nicely.
Once we get bug reports from other platforms, we add palette fixes there, too ๐
Err... Does any of that make sense?
Yeah... Sorry, I was just thinking how I could change the items in both light and dark mode without changing anything but a modifier. I think using HSV might be the best way, like you suggested.
I think that is reasonably simple because Qt already has all the functions in QColor. The first thing I would try are to move L in HSL or V in HSV toward 0.5
I still don't understand why this behaves the way it does
alternate base is #989898, which is clearly not that color
but if I set the background on the groupItems
It turns to #989898
the background using alternate base
Normal widgets don't have a background, they are often transparent.
You might be seeing some other background
How do you set the background?
If I specify the base and alternate base after creating the app the colors are consistent.
Its a treeWIdgetItem that is getting the background, I don't think thats a QWidget but I'm not 100% sure
I just don't understand why when there is no palette set, qt doesn't use the base and alternate base for the items
Is that possibly related to manual darkmode overrides?
mkQApp sets that flag on startup, looking at the palette base color, I think.
I call item.setBackground(columnNum, color)
And then it turns the color that you set? Or it turns a DIFFERENT color?
I don't think so, I've tested with QtWidgets.QApplication([]) also
It turns the color I set, which is alternate base, the light gray color.
when there is no specific palette set on the app, the alternateBase is no where to be found in the tree
Makes sense, because it is ugly.
thats with no palette
Ok...
By the way, the double labels on the buttons are a different bug, right?
...and if you re-apply the same palette, colors change???
Yeah, the buttons in dark mode are transparent and the itemWidget that the button is within has the same text
but we shall ignore that for now, right?
we know what the problem is and a couple of different ways to get around it
If I ever finish this I'll do that ๐
My interpretation of the behavior I have seen so far is that out of all the pyqtgraph-provided items, nothing uses alternateBase. So if you change alternateBase in the palette, nothing should change color. If it does, I need to update my working theory.
Yeah, I guess they actually don't, and thats whats confusing.. The docs say that the alternateBase is what is supposed to be used for tables/trees/lists with alternating row colors
The docs also say "QPalette::Dark 4 Darker than Button." which wasn't true last time I tried.
QPalette is not used very much by the Qt devs, it seems to me.
Here's the theory:
pyqtgraph should be using the palette, but instead colors are hard-coded all over the place.
Goal: Fix it.
Today's goal: Fix the tiny litle bit of the large problem that is in GroupParameterItem ๐
modes = light / dark?
yep
"dark" is the "dark"color role?
I assume because button is transparent here
yes, palette.button and palette.dark
This is what I meant when I said in dark mode some color roles change the behavior
"dark" is not a background color, I think. QPalette.dark() returns a brush, not a color. So whatever the devs have in mind for that, we are probably using it wrong.
Its supposed to be used for button bevels/shadows iirc
Highlighted text is supposed to be "HighlightedText" on "HighLight" background.
This seems to be drawing "textColor" on "Dark", which isn't a combination anybody promised would look decent.
I would promise that this was coded before anything actually did dark mode. And it -randomly- happens to look decent in light mode. And then it didn't look terrible enough in dark mode for anybody to change it.
Oh, absolutely.. I'm pretty sure it hasn't changed since before Qt4
You might still be assuming there is some grand plan. But it's squids all the way down. 
yeah I'm slowly learning that ๐
You can either ignore the "dark" color. Or you can change it to something more reasonable and robust, as long as it does not look MORE TERRIBLE than the current version.
I'll back you up, although usually @rough furnace makes the merge decisions.
Yeah, I'm going to get it done here with in the next 30 minutes.
What do you think about using html color names?
seems like it would be less messy than converting and modifying the lightness
But wouldn't you still be hardcoding colors in that case?
Assume that in the future I want to set a palette on my application and see it actually work ๐
...and my palette might be monochrome green or retrowave teal and purple.
well you and your PR make a good point
Hmm. Did I never screenshot the later version? Anyway, like so:
The text bits are still boring, they should be able to work with a weird palette, too.
that's going to be an awesome feature
It breaks so many things that I don't know if it will ever work... Dreams, man, gotta have dreams! ๐
Suggestions for either one?
If I understand correctly, the setStyleSheet override would only be visible to Python, not to the C++
All of the changes to mkQApp have been reverted.
That's part II now ๐
@fervent vale , the goal would be to react to the user specifically setting a stylesheet, would it catch that?
We do not need to react to anything Qt does internally, we want to read the user's mind if they apply a dark mode style.
Yes, that would be the "visible to Python" part
Thank you for the clarification. I am dumb and have no idea what I am talking about. ๐
Do you have other concerns where this kind of override might cause us trouble?
๐
I like it a lot (assuming this isn't all hardcoded colors now), but we might need to give the ParameterTree experts some time to comment.
There seems to be a few issues listed on PYSIDE issue tracker concerning QApplication
I think it was something about there being a single C++ QApplication instance, but the Python side might have more than 1 wrapper to it
So if you assigned a Python attribute to the Python instance of QApplication, is it really going to be visible to everyone
That's all hearsay on my part, I haven't encountered it since I steer clear of such things ๐
So in pyqtgraph, we assign the QApplication instance to QAPP. If the user always accesses QApplication via a call to mkQApp, then that should be clear of any such issues
Do you happen to have a good alternative suggestion how to catch the user applying a stylesheet?
I think we can ask the user to keep the main qApp object around if they want later stylesheet updates to work.
I mean, they can already totally break that part by not using mkQApp...
There is an event we can watch but you have to patch an eventFilter onto the QApp
I recently found that PyQt would crash if one instantiates a QApplication using QtWidgets.QApplication() and then not hold a Python reference to it
I have to admit that I didn't even know that mkQApp did stuff outside of conveniently accessing Qt. None of my own programs use it so far...
Breakage with garbage collected Qt objects seems fairly normal. I had some fun time with QTimers before.
I think we can steer users towards mkQApp.
@harsh ravine , did you update the PR? I'd like to check later how badly it breaks on Windows.
Oh, no I haven't. Check back in a couple of minutes.
sorry I realized I ran a code cleanup in qt/__init__.py so I had to put all the trailing whitespace and empty lines back before committing
it should be there now
@wide prism could you test with qdarkstyle if you have it installed. I'm not 100% sure if what I did there is going to work on every platform.
I will, but I have some non-programming things to do first.
no rush!
hehe, maybe we have some more work to do.
Another interesting thing: The QDarkStyleSheet has a length of 50355 characters.
I think we might not want to run a full text search against that three times per update ๐
How does the collaps button work on Mac?
self.collapseBtn = PathButton(path=self.openPath, size=(12, 12), margin=0)
self.collapseBtn.setStyleSheet("""
border: none;
""")
self.collapseBtn.setPen('k')
self.collapseBtn.setBrush('w')
doesn't seem very adaptive. [GroupBox.py]
Good morning everyone; looks like I have some reading to do
๐
ok, .... i'm soooo glad there seems to be some kind of confusion on the "correct" implementation for this fix among everyone else, not just me
more important than the length of the qdarkstylesheet is that I don't believe the style-sheet string "language" conforms to a "regular language" which will make regular expressions not a particularly great tool
Well, we are only trying to detect the name of the stylesheet.
i.e. if '/* QDarkStyleSheet' in stylesheet:
Windows, with QDarkStyle and patched up application palette:
Without palette and stylesheet:
This is without mode distinctions in basetypes.py
that looks good! is this the PR in its current form?
No, current form is the four-panel image above ๐
o; yeah...
Hmm... How do I live dangerously and patch the setStyleSheet call in mkQApp?
def patched_setStyleSheet(self, styleSheet):
print('hi! I have been patched!')
if '/* QDarkStyleSheet' in styleSheet[:512]:
print('this is QDarkStyle!')
self._setStyleSheet(styleSheet)
# QAPP.setStyleSheet(styleSheet)
original_setStyleSheet = QAPP.setStyleSheet
QAPP._setStyleSheet = QAPP.setStyleSheet
QAPP.setStyleSheet = patched_setStyleSheet.__get__(QAPP.setStyleSheet, QtWidgets.QApplication)
QAPP._setStyleSheet = original_setStyleSheet
works, as far as getting called, but I cannot call the original setStyleSheet from there: AttributeError: 'builtin_function_or_method' object has no attribute '_setStyleSheet'
The commented out QAPP.setStyleSheet(styleSheet) line seems to work, but that seems a little beyond the level of crazy I wanted to sink to today.
dumb question; why do we need _setStyleSheet to be a method of QApp? can we not pass the QApplication instance into a general function (basically we don't want to modify class attributes of QApplication instances if I remember right
oh, ...we have to do that or else we don't intercept the setStyleSheet calls ... yeah that's a problem
and we can't catch/intercept the events because we're not subclassing QApplication either...
There's even a comment that says stuff blows up if we do.
generally messing w/ QApplication outside of the Qt API has been risky if memory serves (might be better now that we've deprecated Qt4 and Qt < 5.12 support)
We might want to open an issue on the qdarkstylesheet repo and ask them for input
This works for me
pijyoi's interpretation is that the patch will probably not be valid if another instance of app is retrieved through app = QtWidgets.QApplication.instance()
But it might work as long as the user holds onto the original app returned by mkQApp, at least until the stylesheet is applied.
Note that we don't need to patch the internal calls Qt might make. The only thing we want to know is if the USER has called the python wrapper to setStyleSheet().
@harsh ravine , if you want to have a look, the only change needed in the ParameterTree example is to add
import qdarkstyle
app = pg.mkQApp("Parameter Tree Example")
app.setStyleSheet(qdarkstyle.load_stylesheet())
Let me know if I need to do anything to the code on my fork. I don't want to steal Chris's credit by posting my own PR.
ok ok, that's an easy fix...
what happened is those fields didn't update when the palette changed...
but when I loaded the example when I was already in light mode, it looks good
when launched w/ system already being in light mode
the first two involved switching on the fly while starting in dark mode
you can detect the change by tying into the qapp.paletteChanged signal
we do this w/ the Example App
hmm... good point, probably not, let me check
(starting in dark, changing to light)
Weeeeelllll......
@wide prism w/ QDarkStyleSheet does the example app look ok?
The example app? Never tried that. probably not. I'd have to manually add that to the python file, too.
forgot to set darkMode property ๐ updated my fork
if we have custom widgets with manually encoded colors, we should try and update the colors with changes of the QApplication palette, lucky with the paletteChanged(QPalette) signal this is not too difficult to do.
but handling the stylesheet change stuff is another beast :/
(and that's certainly something I can help with if @harsh ravine would like my help with)
Then let's not support complicated stylesheet stuff.
Require the user to supply a decent palette (works on Mac), use one of a limited number of recognized stylesheets (works for QDarkStyle), or manually select our dark palette (goes on the todo list).
yeah; I'm good w/ breaking this up into 2 parts, handle light/dark palettes, and changes, then reaching out to QDarkStyleSheet maintainer(s?) for help w/ integrating from there
The palette update is really easy now, since there is no light/dark mode specific code in the GroupSomethingItem anymore. You just need to rerun the color setting.
Can you rig something up for that, maybe?
- I am terrible at writing code I can't test
- I need to get up for work in five hours
haha you go to bed ๐
I think we don't need anything from QDarkStyle. Maybe they could put the name of the stylesheet somewhere into the first characters...
If we want to rip the palette from the stylesheet, we need a CSS parser; which probably exists. It would only need to run on a setStyleSheet call, so it can be slow.
Then we pull colors into the application palette and use that.
Medium term development goal is to turn off the stylesheet and make things work with just the palette on Windows.
Right now, the buttons break in that case:
But the buttons are also broken on Mac, so that needs looking at anyway.
I think setting methods on the class should work. Setting methods on the instance is unknown
I have this now
def mkQApp():
QAPP = QtWidgets.QApplication.instance()
# code of mkQApp, illustration only up here
def patched_setStyleSheet(self, styleSheet):
QAPP._setStyleSheet(styleSheet) # I would rather call this as self._setStyleSheet, but that fails
if '/* QDarkStyleSheet' in styleSheet[:512]:
# print('this is QDarkStyle!')
app = QtWidgets.QApplication.instance()
palette = app.palette()
if palette.base().color().lightnessF() > 0.5:
# need to fix light palette background in dark style sheet
app.setPalette( dark_QPalette() )
app.setProperty('darkMode', True )
QAPP._setStyleSheet = QAPP.setStyleSheet
QAPP.setStyleSheet = patched_setStyleSheet.__get__(QAPP.setStyleSheet, QtWidgets.QApplication)
If you have some pointers how to make this a little more robust, they would be very welcome!
Good night! ๐
(sorry, hope the indents make more sense now)
It seems that we are already propagating the 'darkMode' property through the QtWidgets.QApplication.instance() ,but since that really only works on Mac, it probably isn't a good global test.
(in __init__.py, somewhere around L450)
Could the monkey patching not follow the style of QGraphicsItem.scale done earlier up in the same file?
I.e. modify the class not the instance
That seems to have worked
Although QApplication is special
But this wouldn't work of qapplication is instantiated before pyqtgraph is imported no?
Is the scope to cover such a case or only to cover cases where the application was instantiated via mkQApp?
I think everything in the library right now works with existing instantiations
Does QAPP.setStyleSheet = types.MethodType(patched_setStyleSheet, QAPP) work in lieu of using __get__?
In the upper right hand image, QDarkStyle is loaded, so maybe windows handles the transparent background different than macOS does. That doesn't really explain why the text is black though. The foreground text is set to almost pure white when the dark stylesheet is loaded.
Python won't read the entire contents of the file using in. It should only check up to the point where the string is found, which is with in the first 30ish lines.
Except when it isn't in there ๐
touchรฉ
If we're concerned about user created stylesheets then shouldn't we be doing a basic check to see if there is a non-qdarkstyle stylesheet and opt not to change the bg/fg colors if there is?
I think the latest code specifically looks for QDarkStyle, and only makes changes if that is found. Ideally we would parse the style sheet to extract colors, but that may be hard.
What would we be looking for specifically?
In parsing the style?
I think that is a few steps in the future. A recurring pattern of background-color and color, I guess.
But I think it is probably more productive to let our own widgets be styled by stylesheet. I hope Qt would mostly do the parsing for us in that case.
hmm, alright.
I'm kind of confused by the picture in the bottom left corner. The text color was set to #F0F0F0 when a dark stylesheet is detected. I'm curious why that wasn't applied for windows but is for mac.
I think your logic was upside down.
The only thing I could think of is the background is set to a color with 0 alpha, but I wouldn't think that would change the appearance of the FG brush
It applied black text when it detected QDarkstyle. On Mac, there is no stylesheet, and it left the colors alone.
Sorry, have to run to work now
hmm, I'll look at the PR
@fervent vale I may have been mistaken on the instantiation bit. I believe the hidpi settings won't work if QApplication was instantiated before PyQtGraph got imported
I commented the important parts of the PR explaining what should be happening when a qdarkstyle stylesheet is detected. Which part is upside down?
# set textColor to None so we can `or` with it later
textColor = None
if '/* Light Style' in stylesheet or '/* Dark Style' in stylesheet:
# either a dark or light QDarkStyle stylesheet was found
# regardless of which one was found - set full transparency on the background brush
background = QtGui.QColor(255,255,255,0)
altBackground = background
# Assume the stylesheet is the LightPalette stylesheet and set a dark text color
textColor = QtGui.QColor('#000000')
if '/* Light Style' in stylesheet:
# If the stylesheet is the DarkPalette, apply a light text color
textColor = QtGui.QColor('#F0F0F0')
...
if depth == 0:
background = altBackground
...
# set the background brush to transparent
self.setBackground(c, background)
# since we assigned a text color for both versions of the style sheet
# the palette.text().color() is only applied if the elif/else run
self.setForeground(c, textColor or palette.text().color())
This is how everything looks on macos with the code from the PR
from PyQt6 import QtWidgets
import types
_setStyleSheet = None
def monkey_patch(text):
global _setStyleSheet
def setStyleSheet(self, sheet):
print(text)
_setStyleSheet(sheet) # already bound
qapp = QtWidgets.QApplication.instance()
_setStyleSheet = qapp.setStyleSheet # already bound
qapp.setStyleSheet = types.MethodType(setStyleSheet, qapp)
app1 = QtWidgets.QApplication([])
monkey_patch('HEY')
app2 = QtWidgets.QApplication.instance()
app2.setStyleSheet('')
this is essentially the same as what Nils showed, except that the old bound method is stored within the module
I think it would be preferable not to monkey patch if the QApplication has already been instantiated. At the very least, this allows the user to have a way of preventing pyqtgraph from installing its monkey patching. And if we ever suspect that our monkey patching is causing issues, that would also allow us to test it out easily.
(In some other C++ development, it was really annoying that merely linking to some library caused side effects)
I had a similar function in the previous PR but it was using the application instance. What is this going to be used for?
The short snippet was just me verifying (for my own benefit) that monkey patching the instance after the QApplication had already been instantiated works
ohh, gotcha. I didn't run into any issues when testing either.
It would sure be nice if we were able to subclass the app
Oh, the comment about the crashing if we subclass was added by me
Ah, you saw it happen?
The thing was that, not all the examples crashed
It took a long time before it was pinpointed to the subclassing
oh, so some worked? Do you remember any specific ones that worked or crashed?
I bet so, it would be one of the last things I'd check
As I recall, it started crashing regularly on program close with Python 3.9 series and the later versions of 3.8
So one of the first times I encountered it was on ArchLinux on the Raspberry Pi, which is more bleeding edge.
So at first I just thought it was because it was running on the RPI
hmm, by chance did you try a signal handler before removing the subclass?
No
Maybe it's an implementation issue/detail with PySide2
In any case, PR 1605 now ensures that each example ends normally, so the CI will detect the crashes
@wide prism is unable to login here to contribute to the discussion due to technical issues, he'll be back in 12-13 hours
I'd like to know how you would approach the problem.
The way I see it, the signal would have to come from the treeWidget. setting one up is no problem, but I'm not sure about how to call updateDepth from with the signal from the tree, as it needs a depth.
Not at my laptop right now but if you look at ExamplApp.py you will see we catch the qApp,paletteChanged signal into a slot, and re-apply colors
Oh, yeah... that part is no problem. I set it up in groupItem without thinking about it and it kept toggling dark mode on and off ๐
I suppose I just need to think of a better system to track when and how the darkMode property has been set
Oh nice, thought that's what you were referring to
Anyway, you can go back to your evening, I'll figure something out!
I will be active here in a bit, have kids climbing me and otherwise bouncing off the walls
I know it all too well
k, got one kid to bed, second kid might take a bit but I can read up; I was missing what I needed to chime in on.
I had to run to the store, so not much has changed.
second kid is in bed; i think those windows screenshots look fine; if it handles macos light/dark mode, and the switch between them, is that effectively "everything" or is something else missing?
So, I think I need to set a flag on each item in the method that the paletteChanged signal connect to so I can check for that flag in the updateDepth method to let me know that we need to update the colors
... or something..
most things handle changes in the system palette; just the stuff we hard-code colors for
so like, if the alternateBase color worked as we thought it should, we could assign that and call it a day
(that still surprises me so much that that didn't work...)
Yeah, I should probably start looking at the source code for Qt as soon as something seems weird. It would probably save me a lot of time in the long run
Did you have a chance to test the most recent PR on Windows?
I'm not sure what was going on with Nils but when I tested on windows everything looked just like it did on the mac
the copy of windows wasn't activated so I wasn't able to change the themes or colors, so it could have something to do with that if he's customized the colors
So, I have the palette change working now.. but when the theme changes colors the items text are shifted down
Okay, well I guess that's working now.
@wide prism when you get back, can you check @harsh ravine 's PR on windows? sorry I got a bit tired, if you don't hear back tomorrow morning I'll fire up my windows machine and check things out, but yeah, things look great from the screen shots!
Sorry @harsh ravine I was hoping to check out your branch this weekend but real life interfered... Is it OK if I keep this on hold for a few more days? I promise I haven't forgotten!
No worries. Just let me know what you think after you've had a chance to play around with it.
from PySide2.QtWidgets import QApplication, QPushButton
class App(QApplication):
def __init__(self,l):
# QApplication.__init__(self,l)
# super(App, self).__init__()
super().__init__(l)
def fn():
# global app
app = App([])
button = QPushButton("Push")
button.show()
button.clicked.connect(app.quit)
app.exit(app.exec_())
if __name__ == '__main__':
fn()
@fervent vale if you run this, python will segfault, if you uncomment the first line in the function, it exits with code 0
I tested a slightly modified version of your script against all bindings and only PySide2 crashes. The thing is that previously pyqtgraph already held a global module reference QAPP to the instance. And the order of destruction of module level variables is undefined, if I understand correctly
So the end result was that which examples crashed or not on exit was dependent on the python interpreter version and also on what things that example had done. For a fixed python interpreter version, it was reproducible as to which example would crash
So yes, it seems like a PySide2 issue, and even if it has been fixed, users will be stuck with the version on PyPi
Hi, back from work ๐
if '/* Light Style' in stylesheet:
# If the stylesheet is the DarkPalette, apply a light text color
textColor = QtGui.QColor('#F0F0F0')
Sorry, on my system, I didn't find the terms "Light Style" or "Dark Style" in the style sheet. Maybe my version is outdated?
So I adjusted the test, but I assumed that the term "light style" would show up in a light mode palette, where the text color should be dark.
Can you send a screenshot of what you see on windows in QDarkStyle mode?
I would agree with only applying the patch as part of QAPP creating in mkQApp. Setting up everything by yourself should be a supported option.
If we are unsure that the monkey patch is safe, then there is also the option to simply provide a function or parameter such as mkQApp(style='dark') to let the user conveniently set a usable palette.
Then we just need to figure out how to document that so that it's easy to find when the app ends up in mixed colors.
I should point out that QDarkStyleSheet does have docs in their README with how to use their sheet with pyqtgraph specifically, we could certainly make a PR with them to update those instructions
I am not giving up on the monkey-patch just yet.
But agreed. Patching up the qapp to intercept style sheet changes is an optional bonus feature.
The main point would be to give the user a simple, one-line way to set a usable palette on systems where that is not automatic.
#pyqtgraph message Heres one of light and dark mode on Windows.
Could be, I've only tested whatever the most recent version available from pip a few days ago
The line it checks for should be on line 10 of the stylesheet.
@rough furnace Do you want the palette changed fix to be part of the current stylesheet shenanigans PR or separate?
whatever is easiest at this point, this PR ballooned in complexity so rapidly. If you already have the logic to handle that in your branch, by all means keep it.
I feel bad that this happened on your first (or second?) PR
ahh it's ok stuff like this happens sometimes
I'll keep it in the current branch since it relies on updateDepth where the colors are applied.
What binding are you running there? I am on PyQt5, and I don't see integration with the Windows display scheme. Does that actually work in a different configuration?
pretty sure that's not just Qt but something else (doens't quite look like qdarkstylesheet) as dark mode on windows QWidgets has not been implemented yet: https://bugreports.qt.io/browse/QTBUG-72028
I've been using PySide2 to test
Interesting!
By the way, the stylesheet that I read back from the qapp starts like like:
/* ---------------------------------------------------------------------------
Created by the qtsass compiler v0.1.1
The definitions are in the "qdarkstyle.qss._styles.scss" module
WARNING! All changes made in this file will be lost!
--------------------------------------------------------------------------- *//* QDarkStyleSheet -----------------------------------------------------------
This is the main style sheet, the palette has nine colors.
It is based on three selecting colors, three greyish (background) colors
plus three whitish (foreground) colors. Each set of widgets of the same
type have a header like this:
------------------
GroupName --------
------------------
And each widget is separated with a header like this:
Is that what you are also seeing? I tried running an update, but I am on the conda version, so that might be behind, too.
hmm, thats a different qtsass compiler version than mine. I'm not sure if thats from Qt or QDarkStyle
/* ---------------------------------------------------------------------------
WARNING! File created programmatically. All changes made in this file will be lost!
Created by the qtsass compiler v0.3.0
The definitions are in the "qdarkstyle.qss._styles.scss" module
--------------------------------------------------------------------------- */
/* Dark Style - QDarkStyleSheet ------------------------------------------ */
/*
So... the conda version is behind, and is on a version that does not know about the Light Style verson yet.
this is so much fun! ๐
This is the worst part of the library to pick for working on. I don't think anything else is different across OSs / versions AND bindings.
How often does the styling code run in the widget? Looping over a 50k stylesheet once during setup is no problem, but I'd feel a little guilty about doing that every redraw.
It's better for me to work on than someone else thats more familiar with pyqtgraph who could spend their time adding useful functionality
I fixed that part of the code
Hehe... Instead you've got everybody bound up looking at this, mentally coming up with their own solutions ๐
textColor = None
if self.styleSheet:
background = QtGui.QColor(255, 255, 255, 0)
altBackground = background
if self.styleSheet == 'Light':
textColor = QtGui.QColor('#000000')
else:
textColor = QtGui.QColor('#F0F0F0')
.....
.....
@cached_property
def styleSheet(self):
stylesheet = mkQApp().styleSheet()[:500]
if not stylesheet:
return None
palette = None
if "/* Light Style -" in stylesheet:
palette = 'Dark'
elif "/* Dark Style -" in stylesheet:
palette = 'Light'
return palette
What do you think about just getting the user to tell us what style we are on?
The more the detection escalates, the less I like having it in each graphical item that needs it.
I also changed it so the if/else in updateDepth so it makes sense
hmm, i'd like to not have to run the check, but it only needs to one the one time
with the way the code in updateDepth is right now we'd still have to check what colors to use based on what the user inputs
Can I see the latest updateDepth code on github?
and I don't know how we could deal with what happens if they don't
sure, just a second
I am now tending towards
- fail fast and ugly
- have a very google-able one-line fix in the docs.
We need a summary of what breaks down where. I think
the code is up
- Everything works on Windows / PyQt5, but is always light mode.
- Everything works on MacOSX / KDE / Windows+Pyside if we pull from the palette.
What breaks is using QDarkStyle by itself, but we can make that work by setting a palette, and we can document that - both in our docs and the QDarkStyle docs, which already has a specific section on pyqtgraph.
I can test more with PyQt5, but everything on mac works. OS Dark/Light themes and Dark/Light with QDarkStyle(at least with pyside2) and everything on windows works on PySide2/QDarkStyle.
Although I'm not sure if you saw the message I sent last night, my windows version isn't activated, so I can't change the system color theme, so I don't know what, if anything that breaks
@wide prism and I can test on windows (w/ this kind of cross-platform-ness, you have to rely on others to verify this stuff ๐ )
Sounds good to me. I'll make sure i get the PyQt5/Mac stuff tested
is the self.styleSheet property basically the same as the darkMode Flag that we already have?
I think you've managed to simplify the code to the point where it really only needs to check that, right?
No, stylesheet only checks if there is a stylesheet, and if its a qdarks tyle stylesheet
And otherwise you just leave the colors alone?
No, we then check if the dark mode property is set and applies dark colors, if not we apply the light mode colors
those parts are all still in updateDepth
So, if we make sure darkMode is properly set, then we don't need to check the stylesheet?
If we have a stylesheet we don't want to change the background colors, just let it be responsible for the style
at least I think thats what we want
stylesheet has the highest priority
if we have one we dont care what mode the OS is in
qdarkstyle breaks the small combo boxes in a great way
I'd read the darkMode flag to specifiy what mode the app is in... Either from OS or stylesheet. But that's not really defined.
Can you remind me why we need to adjust the background if we don't have a stylesheet?
I believe the original intention was to distinguish between the outermost groups and the groups they contain
which is why alternateBase not working really hurts as that's exactly what we want.
Makes sense. But we'd still want to do that if there is a stylesheet, right?
I don't see why. The person who chose that stylesheet knew exactly what they were going to get when they applied it
Can that even be styled by stylesheet now?
that said, i thought what we had earlier when a stylesheet was applied looked pretty good
I believe you can access properties from objects that inherit from qwidgets in a stylesheet
But do we do that?
Well, that would have to be done in the stylesheet and we don't write the code for that
I honestly haven't looked past the top of the stylesheet except to grab a couple of colors
I'll check to see what the pyqtgraph specific stuff is though
we could make sure that the people who want to modify the stylesheet to do that could
we just need to set a property on the groupItem that returns its depth, then they could add their own colors/css
My working assumption is that the specific aspects of ParameterTree are not customizable by styelsheet. But I may be wrong. My main hint towards this is that there are hard-coded colors....
I thought grabbing colors from the palette was the simple solution here, otherwise I wouldn't have made so much trouble ๐
This is the only pyqtgraph stuff in the stylesheet
PlotWidget {
/* Fix cut labels in plots #134 */
padding: 0px;
}
QDockWidget::title
{
background-color: #C9CDD0;
text-align: center;
height: 12px;
}
QTabBar::close-button {
padding: 2px;
}
QMenu::item {
padding: 4px 24px 4px 6px;
}
ParameterTree is a TreeWidget, which is a QTreeWidget, so i don't see why it wouldn't be
I also could be wrong about this
Does that have the depth levels? If it does, why do we need to make our own colors? (In non-stylesheet mode, I mean)
The parameterTree? No, we would have to set a property on each groupItem(QTreeWidgetItem) with a property that returns the depth, or something that indicates whether or not its an inner widget or not
Or... we actually might be able to do it from the tree... something like TreeWidget::item['depth=1']{//css here}
rather, they might be able to style their group items this way if we were to set a depth property
WARNING DETOUR:
You can set an objectName on the QtWidgets, and the stylesheet can be applied based on these. That would be a neat way to get the depth levels into QDarkStyle. Maybe we should set these by default. setObjectName('groupitem_depth_1') etc.
To come back to the main track:
I feel like the depth level coloring is a hack. If we need it in palette mode, we also need it in stylesheet mode.
If we can get rid of it in stylesheeet mode, we should try to get rid of it in palette mode ๐
So I would still vote to ditch the new stylesheet / no stylesheet distinction and stick with just the one global light/dark info flag.
And since that seems to work automatically on a growing number of systems, I would say let's force the user to handle it for the exceptions.
Like forcing dark mode on PyQt5 / windows.
The problem with a global color for dark mode and dark stylesheet is that, atleast on macos, dark mode is grey and the stylesheet is dark blue. That means the tree would look weird in at least one of those situations
Solved by getting the user to supply a palette that matches the stylesheet they want.
Yeah
That would also solve another issue that would happen if we did that. A light stylesheet in dark mode would cause the bg colors in the tree to be super dark
How would we handle the case where the user has a light stylesheet applied, but switches to dark mode in the OS?
should we change their stylesheet also?
Well, I didn't think anyone did that until @rough furnace said we needed to fix it ๐
We should be able to provide the following:
- the default colors change as expected
- it is possible to use custom colors without total breakage when the light/dark mode toggles
But the second part is a problem with any stylesheet application in Qt, so there should be a solution already. We just have to make sure we don't break it.
True, but normally when a Qt application uses a stylesheet to style the app, they have a light and dark so they can swap them out when needed
But they still need to actively swap! So it's user responsibility already.
or they just have one stylesheet
well, I meant that the program would detect the palette change and the app would automatically set the correct stylesheet
I'm mostly talking about closed source, paid applications that use Qt
That's a level of sophistication where I'd think they'd also be able to catch a system applied palette change and undo it.
we're doing that now in the most recent PR
In ParameterTree or at the app level?
Those changes are in ParameterTree and ParameterItem because it was the easiest place to detect and respond to the change
The only thing that it does is run updateDepth again after the palette has changed so the colors match when some psycho changes their theme while the app is running
That's precisely what it should be doing. ๐
What I think I am trying to get to:
If you use a stylesheet, you have to be aware that the system might change your palette.
Either update your stylesheet to match, or make sure that the palette change does not affect your app at all.
If we can provide example code (ready to copy-and-paste)
- that gets called when the palette changes
- that can either block the change, or just immediately reset back to a stored palette
Then @rough furnace 's example can be managed.
I don't think we can do that 100% automatic, since we will never know what is a system call, and what is a psycho with bad taste in colors.
But it only affects the "manually applied stylesheet" case, which requires custom user code already, so adding a little to that is not a big deal.
My (non-authoritative) wishlist for the PR is now this:
- ditch the hard-coded colors for palette colors as much as possible
- make sure it works in the default mode on each system (that is only light mode on [my] broken Windows/PyQt)
- ideally handle light/dark switching on mac
- stylesheets can work, but put responsibility on the user to set a matching palette (which also updates the darkMode flag)
So, basically don't worry about the stylesheet anymore.
Okay, I need to think about how we can do that for a few minutes.
Awesome. I hope we can come up with something that ports over to other parts of the library that now rely on hard-coded colors... ๐
Right now the only hard coded colors are the colors for text when a stylesheet is applied. The only reason we do that is because if the system is in dark mode, the palette.text() color is going to be white, but if the user has the lightPalette stylesheet enabled, they won't be able to see the text.
User's problem.
Ignore the fact that the message i replied to is on a completely different topic
I'd agree with that, but someone, somewhere is going to report the issue in the PR.
even if it gets merged like that, how will they know whats going on without digging into the code
I can always use the text palette color and bump the brightness on it, but thats pretty much whats happening now with less messy code
We write a doc that says "if you are seeing a white text on white background after applying a stylesheet, you need to make sure the palette matches the the stylesheet. This code applies a general dark palette to a QApplication that fixes this problem:
pg.configureApplication(qapp, style='dark')
The user should be able to find that the problem results from the stylesheet, so they have a good basis to search from.
There is already a default foreground option. Could we just use that?
No, but we can add the palette explanation to the docs in that part of the code, too.
There is a separation of text and graphics palettes. I don't think the scheme should leak over.
If we wanted to allow that, the default foreground should pull from the palette, not the other way around.
(Note that we now default to black text on white for UI, but light text on black for plots)
Oh, in the comments it said labels, I assumed that meant QLabels
I mean, we have so many crazy flags, maybe you found one I am not aware of ๐
CONFIG_OPTIONS = {
'useOpenGL': useOpenGL, ## by default, this is platform-dependent (see widgets/GraphicsView). Set to True or False to explicitly enable/disable opengl.
'leftButtonPan': True, ## if false, left button drags a rubber band for zooming in viewbox
# foreground/background take any arguments to the 'mkColor' in /pyqtgraph/functions.py
'foreground': 'd', ## default foreground color for axes, labels, etc.
'background': 'k', ## default background for GraphicsWidget
'antialias': False,
'editorCommand': None, ## command used to invoke code editor from ConsoleWidgets
'exitCleanup': True, ## Attempt to work around some exit crash bugs in PyQt and PySide
'enableExperimental': False, ## Enable experimental features (the curious can search for this key in the code)
'crashWarning': False, # If True, print warnings about situations that may result in a crash
'mouseRateLimit': 100, # For ignoring frequent mouse events, max number of mouse move events per second, if <= 0, then it is switched off
'imageAxisOrder': 'col-major', # For 'row-major', image data is expected in the standard (row, col) order.
# For 'col-major', image data is expected in reversed (col, row) order.
# The default is 'col-major' for backward compatibility, but this may
# change in the future.
'useCupy': False, # When True, attempt to use cupy ( currently only with ImageItem and related functions )
'useNumba': False, # When True, use numba
}
from pyqtgraph/__init__
background is the default blac"K" background of the plots, and the axes are a "D"ark gray foreground color.
Gotcha, so changing that would fix one thing and break the other if we used that color for text on a light theme
It would certainly change everybody's pyqtgraph apps dramatically โ๏ธ
๐
That looks vaguely unhealthy.
I think it's supposed to be a moon, representing dark mode ๐
Do you have any thought/preferences about any of this @rough furnace ?
been a bit afk, if I can summarize, and please correct me if I'm wrong....
what works: macos (maybe kde linux) toggling light/dark mode, starting applications in light/dark mode, windows...which is effectively always light mode (w/o style sheets)
what doesn't work: when style-sheets enter the picture, and if light/dark mode are toggled while a style-sheet is applied
style-sheets need a little help from the user side.
can we not make a PR w/ qdarkstylesheet?
This works, If a stylesheet is applied I just set the background to QColor(255,255,255,0)
and completely ignore style-sheet related issues on our end?
(sorry, should let you all finish typing before I post non-sense ๐ )
Problems:
- I believe that we need to do some work to make the tree fully style-able. If we have that, then we can indeed work with QDarkStyle to style it.
Unless I am wrong, though, that would be yet another dramatic change in direction for this PR.
Problem 2:
- the current workarounds rely a lot on hard-coding colors for various cases, which --> I <-- am allergic to.
so first question, does this PR make the parameter-tree any less styleable than it is now (or IOW, do we make things worse with respect to QDarkStyleSheet (or any style-sheet that may be applied globally?)
-> No, but it could make it infinitely more style-able with very little work.
fwiw, hard-coding colors is what got us in this mess a bit so I'm pretty allergic to that too
hmm...if we don't break the styling any more, I think we should give @harsh ravine the option to take the exit ramp and merge the improvement as-is, and then do whatever other work is needed to make style-sheets work more robustly
Acceptable; and all the talk has already given us a lot more ideas for how to handle this in the future. โค๏ธ
The ParameterTree looks exactly the same with qdarkstylesheets as it would if we weren't modifying the colors at all
If any other stylesheet is applied... I think we change the colors with the system theme... I need to look again
I legit thought this issue was replacing the hard-coded color w/ qapp.palette.alternateBase().color().base()
We're pulling colors from palette.window.color and changing the brightness level based on the color theme for the background and foreground. For the text colors they are hard coded either black or white to match theme
(Thats when a stylesheet is applied)
when no stylesheet is applied the color is just the palette.text.color
wait... is that a thing?
Oh... yeah Alternate base is a thing.. I just didn't know it had a base attribute i could use