I'm using a QwtPlotSpectrogram with a custom QwtRasterData to plot 2D data with widely varying values. I would like to plot using a logarithmic color scale instead of a linear one. Is there a simple way to do this?
My alternative is to feed log(value(x,y)) when QwtRasterData calculates the value. However, then my color bar will show the values in log, rather than the absolute values which is what I want - any suggestions there?
Thanks!
In case this is still interesting for anyone:
I had the same problem and wrote the following simple class:
class LogarithmicColorMap : public QwtLinearColorMap
{
public:
LogarithmicColorMap(const QColor &from, const QColor &to)
: QwtLinearColorMap(from, to)
{
}
QRgb rgb(const QwtInterval &interval, double value) const
{
return QwtLinearColorMap::rgb(QwtInterval(std::log(interval.minValue()),
std::log(interval.maxValue())),
std::log(value));
}
};
And for the color bar you can use something like:
setAxisScaleEngine(QwtPlot::yRight, new QwtLog10ScaleEngine())
Related
it's been years since I coded anything, and now I need to pick up p5.js. As practice I was trying to make a simple drawing program - I want my program to draw in black by default, and switch the color to red when I click on the red rectangle in the corner of the screen. I had the following very sloppy code (I know the mouse-press doesn't exactly line up with the red rectangle, the 'drawing' mechanism isn't the best, etc. I'm just messing around with it atm)
function setup() {
createCanvas(600, 600);
fill ('red');
rect(570,20,5,5);
//creates red rectangle at top right corner of screen
}
var color = 0;
function mousePressed(){
if ( mouseX > 570) {
if( mouseY > 20){
color = 4;
ellipse (10,20,50,50);
}
}
}
function draw() {
stroke(color);
if (mouseIsPressed) {
ellipse(mouseX, mouseY, 1, 1)
//creates colored dot when mouse is pressed
}
}
function keyTyped(){
if (key === 'c'){
clear();
}
}
If I don't use the 'color' variable and instead just set the stroke to 0, I can draw in black well enough. And the mousePressed function seems to work - when I press the rectangle, it draws the ellipse that I put in to test. However, I can't seem to reference var 'color' in my draw function - it's probably a silly problem, but I admit to being stumped! What am I doing wrong?
You have to be careful when naming variables. Specifically, you shouldn't name them the same thing as existing functions!
From the Processing.js help articles:
One of the powerful features of JavaScript is its dynamic, typeless nature. Where typed languages like Java, and therefore Processing, can reuse names without fear of ambiguity (e.g., method overloading), Processing.js cannot. Without getting into the inner-workings of JavaScript, the best advice for Processing developers is to not use function/class/etc. names from Processing as variable names. For example, a variable named line might seem reasonable, but it will cause issues with the similarly named line() function built-into Processing and Processing.js.
Processing.js is JavaScript, so functions can be stored in variables. For example, the color variable is the color() function! So when you create your own color variable, you're overwriting that, so you lose the ability to call the color() function.
The simplest fix is to just change the name of your color variable to something like myColor.
I want to have an interactive legend inside my canvas, however I'm having trouble getting it to work. I am using qwt6.1.2 and this version no longer has the option to insert the legend as an "ExternalLegend", but instead has the class qwtPlotLegendItem to handle legends inside the canvas. However when I read the docs I see:
In opposite to QwtLegend the legend item is not interactive.
An external QwtLegend with a transparent background on top the plot
canvas might be another option with a similar effect.
My question is: how do I show an QwtLegend on top of the plot canvas?
In the documentation for QwtPlot I read:
Legends, that are not inserted into the layout of the plot widget need
to connect to the legendDataChanged() signal. Calling updateLegend()
initiates this signal for an initial update.
I have connected the legendDataChanged signal and triggered it by calling updateLegend(), but now I'm stuck on what to do next. Any tips on how to proceed?
Ok I got it to work:
QwtPlot* plot;
// Attach some plots/histograms to the plot.
MyLegend* legend = new MyLegend(plot);
MyLegend ::MyLegend (QwtPlot * pPlot)
: m_pPlot(pPlot)
{
setParent(m_pPlot);
setGeometry(0, 0, 100, 100);
connect(m_pPlot, &QwtPlot::legendDataChanged,
this, &MyLegend ::LegendDataChanged);
m_pPlot->updateLegend();
}
void MyLegend ::LegendDataChanged(const QVariant &itemInfo, const QList< QwtLegendData > &data)
{
updateLegend(itemInfo, data);
}
I have a QGraphicsScene with rather small point markers. I would like to enlarge the area of these markers to make dragging easier. The marker is a cross, +/- 2 pixels from the origin. I have reimplemented
QGraphicsItem::contains(const QPointF & point ) const
{
return QRectF(-10,-10,20,20);
}
and
void hoverEnterEvent(QGraphicsSceneHoverEvent* event)
{
setPen(QPen(Qt::red));
update();
}
but the marker only turns red when it is directly hit by the cursor (and even that is a bit picky). How can I enlarge the "hover area"?
As stated in the short comment:
Usually those things are handled via the bounding rect or the shape function, try overloading those. Take a look into the qt help of QGraphicsItem under shape (http://doc.qt.io/qt-4.8/qgraphicsitem.html#shape):
Returns the shape of this item as a QPainterPath in local coordinates.
The shape is used for many things, including collision detection, hit
tests, and for the QGraphicsScene::items() functions.
The default implementation calls boundingRect() to return a simple
rectangular shape, but subclasses can reimplement this function to
return a more accurate shape for non-rectangular items. For example, a
round item may choose to return an elliptic shape for better collision
detection. For example:
QPainterPath RoundItem::shape() const {
QPainterPath path;
path.addEllipse(boundingRect());
return path; } The outline of a shape can vary depending on the width and style of the pen used when drawing. If you want to include
this outline in the item's shape, you can create a shape from the
stroke using QPainterPathStroker.
This function is called by the default implementations of contains()
and collidesWithPath().
So what basically happens is that all functions that want to access the "Zone" which is associated with an item, call shape and then do e.g. a containment or collision detection with the resulting painterpath.
Thus if you have small items you should enlargen the shape zone.
Lets for instance consider a line that is your target, than your shape implementation could look like the following:
QPainterPath Segment::shape() const{
QLineF temp(qLineF(scaled(Plotable::cScaleFactor)));
QPolygonF poly;
temp.translate(0,pen.widthF()/2.0);
poly.push_back(temp.p1());
poly.push_back(temp.p2());
temp.translate(0,-pen.widthF());
poly.push_back(temp.p2());
poly.push_back(temp.p1());
QPainterPath path;
path.addPolygon(poly);
return path;
}
Pen is a member of the segment, and I use its width to enlarge the shape zone. But you can take anything else as well that has a good relation to the actual dimension of your object.
Has anyone used the photo filter in Photoshop? Edit > Adjustments > Photo Filter...
It produces a really nice image tint that I've been unable to reproduce with blending modes. Has anyone got any idea of the pixel maths behind this filter? - So I can build a shader based on it.
It seems to basically be a luminosity preserving colour tint.
Has variables: Color, Amount and Preserve Luminosity.
Any ideas?
Filters (in light) are multiplicative, as in:
red_filter = ( 1 , 0 , 0 ) * color
I don't think any blend-modes exist for it, since any transparent overlay with that system would darken the image to some degree.
It's incredibly simple, but if anyone wants the hlsl code for this:
// Photoshop PhotoFilter style effect.
// Input filter color.
float4 FilterColor;
// Implicit texture sampler.
sampler TextureSampler : register(s0);
float4 PhotoFilter(float4 color : COLOR0, float2 texCoord : TEXCOORD0) : COLOR0
{
return tex2D(TextureSampler, texCoord) * FilterColor;
}
technique GeneralEffect
{
pass Pass1
{
PixelShader = compile ps_2_0 PhotoFilter();
}
}
I am trying to rotate a Sprite in three dimensions around its centerpoint, and I am struggling to understand some of the behavior of matrix3D.
Ive overridden the set rotationX, rotationY, and rotationZ methods of the Sprite as follows:
override public function set rotationX (_rotationX:Number) : void {
this.transform.matrix3D.prependTranslation(this.width/2.0, this.height/2.0, 0);
this.transform.matrix3D.prependRotation(-this.rotationX, Vector3D.X_AXIS);
this.transform.matrix3D.prependRotation(_rotationX, Vector3D.X_AXIS);
this.transform.matrix3D.prependTranslation(-(this.width/2.0), -(this.height/2.0), 0);
}
override public function set rotationY (_rotationY:Number) : void {
this.transform.matrix3D.prependTranslation(this.width/2.0, this.height/2.0, 0);
this.transform.matrix3D.prependRotation(-this.rotationY, Vector3D.Y_AXIS);
this.transform.matrix3D.prependRotation(_rotationY, Vector3D.Y_AXIS);
this.transform.matrix3D.prependTranslation(-(this.width/2.0), -(this.height/2.0), 0);
}
override public function set rotationZ (_rotationZ:Number) : void {
this.transform.matrix3D.prependTranslation(this.width/2.0, this.height/2.0, 0);
this.transform.matrix3D.prependRotation(-this.rotationZ, Vector3D.Z_AXIS);
this.transform.matrix3D.prependRotation(_rotationZ, Vector3D.Z_AXIS);
this.transform.matrix3D.prependTranslation(-(this.width/2.0), -(this.height/2.0), 0);
}
I am using prependTranslation to correct the centerpoint of the rotation, and the first prependRotation to cancel out any previously-applied rotation.
Testing it out, rotationX works exactly as expected, and the Sprite rotates around its horizontal axis.
rotationY and rotationZ also appear to work fine. However, there is one problem: whenever rotationY or rotationZ are set, all of the other rotation values change as well. This is not a problem with rotationX -- if I set rotationX, nothing else changes. But if I set rotationY or rotationZ all the rotation values change, which is a problem for my app (which is trying to save and restore values).
I think I am just lacking some understanding about what is going on with matrix3D. How can I implement this so there is no interdependence between the values?
Another easy solution is to add the object and center it within a container sprite and do the 3D transformations on the containing sprite.
I know nothing about AS3 etc. But just looking at your code, I wonder why you translate on the z-axis using what I understand to be x and y values (width and height). Shouldn't the z-axis be translated using something like "depth"?
This is very simple, you can try use the following code:
var matrix3d:Matrix3D = s.transform.matrix3D;
matrix3d.appendRotation( -1, Vector3D.Z_AXIS , new Vector3D( 390, 360, 0 ) );
while s is your sprite, the third parameter, Vector3D indicate your sprite's center position.
The Above code will make the sprite s rotate more -1 degree.