pyqtgraph: add legend item for scatter plots - pyqtgraph

I'm using pyqtgraph and I'd like to add an item in the legend for scatter plots.
I've adapted the example code to demonstrate:
# -*- coding: utf-8 -*-
"""
Demonstrates basic use of LegendItem
"""
import initExample ## Add path to library (just for examples; you do not need this)
import pyqtgraph as pg
from pyqtgraph.Qt import QtCore, QtGui
plt = pg.plot()
plt.setWindowTitle('pyqtgraph example: Legend')
plt.addLegend()
c1 = plt.plot([1,3,2,4], pen='r', name='red plot')
c2 = plt.plot([2,1,4,3], pen='g', fillLevel=0, fillBrush=(255,255,255,30), name='green plot')
c3 = plt.plot([4,3,2,1], pen=None, symbol='o', symbolPen='y', symbolBrush='r', name="point plot")
## Start Qt event loop unless running in interactive mode or using pyside.
if __name__ == '__main__':
import sys
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()
What I get as a result is:
How do I add an appropriate legend item?

The current release of pyqtgraph does not support this feature.
However, it is supported in the unstable branch. You can copy LegendItem.py from the unstable branch here: http://bazaar.launchpad.net/~luke-campagnola/pyqtgraph/inp/view/head:/pyqtgraph/graphicsItems/LegendItem.py

Related

PySide2 UI Maya Find object names that contain specific names

I want to include in the argument an object name that contains a specific name from the ui file.
I have created pickers in QtDesigner and have imported them for Maya 2022.
It assigned a command to each button. But I realized I needed a huge number of commands.
It's just this scene.
from PySide2 import QtWidgets
from PySide2 import QtGui
from PySide2 import QtCore
from PySide2.QtUiTools import QUiLoader
from maya.app.general.mayaMixin import MayaQWidgetBaseMixin
import shiboken2 as shiboken
UIFILEPATH = 'D:/MAYA/pyside_pick/ui/PicsTest5.ui'
class MainWindow(MayaQWidgetBaseMixin,QtWidgets.QMainWindow):
def __init__(self,parent=None):
super(MainWindow,self).__init__(parent)
self.UI = QUiLoader().load(UIFILEPATH)
self.setWindowTitle(self.UI.windowTitle())
self.setCentralWidget(self.UI)
#PushButton
self.UI.pushButton_sphere.clicked.connect(self.PushedCmd)
#Comand
def PushedCmd(self):
bTEXT = str(self.UI.pushButton_sphere.text())
cmds.select('pSphere1')
print(bTEXT)
def main():
window = MainWindow()
window.show()
if __name__ == '__main__':
main()
If it is given an object name like above, it certainly works.
But there are commands that need to be directed only to objects containing "pushButton_".
I tried like this
button1 = self.findChild(QtWidgets.QPushButton, 'pushButton_*')
self.button1.clicked.connect(self.testPrint)
def testPrint(self):
print(self.button1)
I meant to define button1 as a QPushButton containing 'pushButton _' and print its name when clicked.
Unfortunately, I learned that asterisks can not be used as searches.
Then, I tried like this
button1 = self.findChild(QtWidgets.QPushButton, 'pushButton_sphere')
self.button1.clicked.connect(self.testPrint)
def testPrint(self):
print(self.button1)
The result was written as (PySide2.QtWidgets.QPushButton)already deleted.
This is probably rudimentary, but being Jap I couldn't find a workable solution.
Tell me how to output the object name when I press the button, please.
Also tell me if the notation is wrong.

pyqtgraph: How to link two PlotWidget windows to show the same plot?

I am developing an orbital analysis tool using PyQT5 and pyqtgraph!
See: https://github.com/3fon3fonov/trifon
My tool has a plotting area with ~15 plots shown in different tab windows, which show different aspects of the data analysis.
The tool it self is assembled with the Designer-qt5, while the QGraphicView widgets are promoted to pyqtgraphs's PlotWidgets
For example in the gui.py I initialize the plots like this:
def initialize_plots(self):
global p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,pe
p1 = self.graphicsView_timeseries_RV
p2 = self.graphicsView_timeseries_RV_o_c
p3 = self.graphicsView_timeseries_phot
p4 = self.graphicsView_timeseries_phot_o_c
p5 = self.graphicsView_timeseries_activity
p6 = self.graphicsView_timeseries_correlations
# ...
pe = self.graphicsView_extra_plot
# ...
so p1-p6 in this case are different PlotWidget objects on which I add Items/Plot data, i.e. p1.plot(x,y), p1.addItem(), etc.
What I want is to link pe to any of p1-p6!. pe is an extra plot so the user can choose from those already available/created.
Thus the user can select which plot he/she wants to see next to the main plot.
Lets imagine that the ComboBox dropdown menu selects between p1-p6 objects, so
pe = p1, or later: pe = p4
for example.
Is there any way this to be done with PyQtgraph?
I really tried all kind things in the last two weeks and nothing seems to work.
I am aware of the
pe.setXLink(p1)
pe.setYLink(p2)
but this only links the axes not the plot object itself. It doesn't work for me.
I implemented something like that using Docks and a DockArea. I simply added several docks stacked below each other.
They can be shown using either by clicking on the labels or by using the raiseDock() method of each dock.
You can simply add the PlotWidget (or any other Widget) to the dock using the addWidget() method of each dock.
The labels can be hidden or locked if you don't want the user to be able to move the docks at runtime.
import sys
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui
from pyqtgraph.dockarea import DockArea, Dock
class Accel_GUI():
def __init__(self, window, dock_area):
self.testing = 0
self.pen = pg.mkPen(color='y')
"""Setup the UI"""
self.window = window
self.dock_area = dock_area
self.window.setCentralWidget(self.dock_area)
self.spec_dock = []
self.spec_dock.append(Dock("Spectro 1",
size=(1200, 600),
autoOrientation=False))
self.spec_dock.append(Dock("Spectro 2",
size=(1200, 600),
autoOrientation=False))
self.dock_area.addDock(self.spec_dock[0], "top")
self.dock_area.addDock(self.spec_dock[1], "below", self.spec_dock[0])
if __name__ == "__main__":
app = QtGui.QApplication.instance()
if app is None:
app = QtGui.QApplication(argv)
win = QtGui.QMainWindow()
area = DockArea()
pyqtplot = Accel_GUI(win, area)
win.show()
app.exec_()
There is also an example in the pyqtgraph library that shows how to work with docks.

How to add edge labels (interactive or permanent ones) for networkx graph in bokeh?

I would like to add label for edges in networkx graph using bokeh. How can I do this?
This question is similar to How to add permanent name labels (not interactive ones) on nodes for a networkx graph in bokeh? but different enough to warrant its own reply. As discussed in the other issue, this is currently a task that is probably harder than it should be to accomplish. I'd really encourage you to open a GitHub Issue to start a discussion of how this can be improved for users.
Here is complete example.
import networkx as nx
from bokeh.io import output_file, show
from bokeh.models import CustomJSTransform, LabelSet
from bokeh.models.graphs import from_networkx
from bokeh.plotting import figure
G=nx.barbell_graph(3,2)
p = figure(x_range=(-3,3), y_range=(-3,3))
p.grid.grid_line_color = None
r = from_networkx(G, nx.spring_layout, scale=3, center=(0,0))
r.node_renderer.glyph.size=15
r.edge_renderer.glyph.line_alpha=0.2
p.renderers.append(r)
This part is all fairly standard. To put labels on edges we must define transforms to extract the start and end coordinates from the layout provider. This code just averages the coordinates to put a label in the center of each edge (labelled by the start-end node numbers):
from bokeh.transform import transform
# add the labels to the edge renderer data source
source = r.edge_renderer.data_source
source.data['names'] = ["%d-%d" % (x, y) for (x,y) in zip(source.data['start'], source.data['end'])]
# create a transform that can extract and average the actual x,y positions
code = """
const result = new Float64Array(xs.length)
const coords = provider.get_edge_coordinates(source)[%s]
for (let i = 0; i < xs.length; i++) {
result[i] = (coords[i][0] + coords[i][1])/2
}
return result
"""
xcoord = CustomJSTransform(v_func=code % "0", args=dict(provider=r.layout_provider, source=source))
ycoord = CustomJSTransform(v_func=code % "1", args=dict(provider=r.layout_provider, source=source))
# Use the transforms to supply coords to a LabelSet
labels = LabelSet(x=transform('start', xcoord),
y=transform('start', ycoord),
text='names', text_font_size="12px",
x_offset=5, y_offset=5,
source=source, render_mode='canvas')
p.add_layout(labels)
show(p)
Edit 07/2022: Added missing var keyword to JavaScript part, would not show labels otherwise in current bokeh version.
I faced the same problem, I did check https://docs.bokeh.org/en/latest/docs/user_guide/styling.html and found it seems bokeh does not support well for the knowledge graph, including edge labels.

Is there a way to make an IPython Notebook output interactivly create an input and execute it?

I was wondering if I can make an output interactively run a piece of code. So if for example I had a class (parts in pseudo-code):
import numpy as np
class test(object):
def __init__():
self.a = np.random.randn(10)
print ## Interactive Output: Click me to view data array##
def show():
print a
So when I create a class instance it should output some interactive link (maybe in html) or something like that and when I click it, the show() method should be called. However, I have no idea how to achieve that.
You could use the widgets shipped with the notebook (for jupyter they are an independent package).
Something like this could do what you want (Python 3):
from IPython.html import widgets
from IPython.display import display
import numpy as np
class Test(object):
def __init__(self, arraylen):
self.a = np.random.randn(arraylen)
self.button = widgets.Button(description = 'Show')
self.button.on_click(self.show)
display(self.button)
def show(self, ev = None):
display(self.a)
self.button.disabled = True
test = Test(10)
You create a button widget when you initialise the class widgets.Button(description = 'Show')
Attach an event to it button.on_click(self.show)
And display the button display(self.button)
In the show method I included a way to disable the button functionality once the array is showed self.button.disabled = True. You can comment this line if you want to show more times the array.

link to view changes axis range pyqtgraph

Assume that I have two views\plots created in pyqtgraph and then they are linked.
using lines
p2.setYLink('Plot1')
p2.setXLink('Plot1')
Question is that when we link the views, the ranges of both the views are made equal, which raises issue as one plot appears to be too much zoomed out or zoomed in.
We just want to link the views to zoom together but don't want the ranges to change as the plot looks changed.
Below is sample code that explains the issue visually
import sys
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import pyqtgraph as pg
#QtGui.QApplication.setGraphicsSystem('raster')
try:
app = QtGui.QApplication(sys.argv)
except RuntimeError:
app = QtCore.QCoreApplication.instance()
x1 = [1,2,3,4,5]
y1 = x1
x2 = [10,20,30,40,50]
y2 = x2
win = pg.GraphicsWindow(title="pyqtgraph example: Linked Views")
win.resize(800,600)
win.addLabel("Linked Views", colspan=2)
win.nextRow()
p1 = win.addPlot(x=x1, y=y1, name="Plot1", title="Plot1")
p2 = win.addPlot(x=x2, y=y2, name="Plot2", title="Plot2: Y linked with Plot1")
p2_state = p2.vb.getState()
p1_state = p1.vb.getState()
p2.setLabel('bottom', "Label to test offset")
p2.setYLink('Plot1') ## test linking by name
p2.setXLink('Plot1')
app.exec_()
To restate the question: you want to have two views that can have different ranges and scales, but when you zoom with the mouse in one view, the other view will zoom by the same amount.
This is not the intended function of the setXLink/setYLink methods, so you will need to implement this by subclassing or monkey-patching the viewboxes. For example:
import pyqtgraph as pg
p1 = pg.plot([1,6,2,4,3])
p2 = pg.plot([30,50,10,70,20])
def scaleBy(*args, **kwds):
pg.ViewBox.scaleBy(p1.plotItem.vb, *args, **kwds)
pg.ViewBox.scaleBy(p2.plotItem.vb, *args, **kwds)
p1.plotItem.vb.scaleBy = scaleBy
p2.plotItem.vb.scaleBy = scaleBy
There is a problem, however, that you need know two things when scaling: how much to scale by (this is the same for both views, so not a problem), and around what point to scale (this is different between the views, so a bit more difficult to determine). The solution to this depends on your desired behavior.

Resources