Clojure/Incanter scatter-plot: controlling size of points - clojure

I am plotting a scatter-plot, using Clojure and Incanter.
I need to control the size of the points in the graph/plot.
This is the basic code that I have. I am using a different domain and range for my data, but the question is the same. This plots without errors.
(doto (scatter-plot (range 10) (range 10))
(set-stroke-color java.awt.Color/blue)
view)
But, what would be the code to modify the size of the points being plotted?
I have attempted the line:
(set-point-size :point-size 1)
but when I try to compile, I get the following error:
Exception in thread "main" java.lang.IllegalArgumentException: No value supplied for key: 1
I have a feeling that :point-size is the incorrect term.

Yes, just delete :point-size, i.e. use (set-point-size my-chart 1), or:
(doto (scatter-plot (range 10) (range 10))
(set-stroke-color java.awt.Color/blue)
(set-point-size 1)
view)

Related

How to get a 'for' in clojure/lisp to just return the values without creating a list?

In Clojure, running this code:
(for [i (range 5)] i)
creates the list:
(0 1 2 3 4)
But what I'd like the for clause to do would be just to output each of the numbers without creating a list. What do I have to change to achieve this?
clojure.core has doseq for just this purpose:
user=> (doseq [i (range 5)] (println i))
0
1
2
3
4
nil
the nil at the end is the repl printing the return value of the doseq call after it finishes processing all the values
Since I was trying to get the contents of the list inside of a separate list, what I did to achieve this was wrap the external list with an into clause like so:
(into
'("original" "list" "contents" ...)
(for [i (range 5)] i))
Making sure to close off the parentheses for the external list.

In Clojure: Why unable to resolve symbol: hdcit in this context

I tried to solve the find two numbers index in a list where nums[i]+nums[j]==target:
(defn two-sum [nums target]
"Find sum of two numbers equals to target"
(if (<= 1 (count nums))
nil)
(let [hdict (hash-map)]
(for [i (range 1 (count nums))]
(if (get hdict (nums i))
[(get hdict (nums i)) i] ;return hdict[nums[i]] and i
(assoc hdcit (- target (nums i)) i)))))
I got this error:
1. Caused by java.lang.RuntimeException
Unable to resolve symbol: hdcit in this context
I'm confused: I've alread bind hdict as a hash-map, why still unable solved?
The error is a simple typo, though there are a couple other points worth considering:
Clojure if expressions always return a value and if you don't specify an else clause (the second expression) then it defaults to nil
So the if in the code above basically says:
(if contition
nil ;; the true case
nil ;; the false case)
Always returns nil. Though since it's not the last expression in the function this value will be ignored because:
The return value of a function (and most other expressions) is the last value in the expression.
Most likely you want to move the ) after the nil to the end of the function.
Clojure data structure are immutable, calling assoc on a map produces a new map that has an additional value while leaving the old on unchanged because someone else might be working on it.
So the assoc on the last line will never do anything.
for is not a "for loop", rather it produces a sequence of new values, lazily, based on a very powerful expression "mini language" (DSL)
This means that it only produces a value when it's read. So this for loop will not run unless something prints the value. The REPL will print this and make this function work only in development. I call this "the lazy bug".
Immutable data is a core concept in Clojure and basically all the goodness of the language flows, at least in part, from it.
Clojure's for expression is powerful enough to completely solve this problem:
user> (let [data [1 2 3 4 5 6 7 42 12]
target 12]
(for [x data
y data
:when (= (+ x y) target)]
[x y]))
([5 7] [6 6] [7 5])

Why does (#(+ % 1) 3) work but (#(%) 3) not work in Clojure?

Title says it all. Why does (#(+ % 1) 3) work but (#(%) 3) not work in Clojure? instead, it gives an error:
1. Unhandled java.lang.ClassCastException
java.lang.Long cannot be cast to clojure.lang.IFn
Shouldn't #(%) be the same as the identity function?
No. #(%) is attempting to call %. It's the same as (fn [x] (x)). In your specific case, you're attempting to call 3 as a function.
An identity function would be #(do %) because do evaluates the expressions following it and returns the last one.

Why filter on a lazy sequence doesn't work in clojure?

I am hoping to generate all the multiples of two less than 10 using the following code
(filter #(< % 10) (iterate (partial + 2) 2))
Expected output:
(2 4 6 8)
However, for some reason repl just doesn't give any output?
But, the below code works just fine...
(filter #(< % 10) '(2 4 6 8 10 12 14 16))
I understand one is lazy sequence and one is a regular sequence. That's the reason. But how can I overcome this issue if I wish to filter all the number less than 10 from a lazy sequence...?
(iterate (partial + 2) 2)
is an infinite sequence. filter has no way to know that the number of items for which the predicate is true is finite, so it will keep going forever when you're realizing the sequence (see Mark's answer).
What you want is:
(take-while #(< % 10) (iterate (partial + 2) 2))
I think I should note that Diego Basch's answer is not fully correct in its argumentation:
filter has no way to know that the number of items for which the predicate is true is finite, so it will keep going forever
Why should filter know something about that? Actually filter works fine in this case. One can apply filter on a lazy sequence and get another lazy sequence that represent potentially infinite sequence of filtered numbers:
user> (def my-seq (iterate (partial + 2) 2)) ; REPL won't be able to print this
;; => #'user/my-seq
user> (def filtered (filter #(< % 10) my-seq)) ; filter it without problems
;; => #'user/filtered
user>
Crucial detail here is that one should never try to realize (by printing in OP's case) lazy sequence when actual sequence is not finite for sure (so that Clojure knows that).
Of course, this example is only for demonstration purposes, you should use take-while here, not filter.

cond in Clojure with thousands of clauses

Running the following code in Clojure gives a StackOverflow Error:
(cond
(= 1 2) 1
(= 2 3) 2
(= 3 4) 3
...
(= 1022 1023) 1022
(= 1023 1024) 1023
:else 1024)
I would like to create a function/macro that can handle a huge number of clauses without creating a stack that overflows.
Please advise as to how I might attempt this.
If you look at the full stack trace, you'll see that cond emits a deeply-nested if structure; the exception then occurs when the compiler tries to parse this structure. The problem might have more to do with simply compiling deeply nested Clojure code than the specific use of cond.
I was able to come up with the following macro that takes a list of clauses, wraps them in thunks to provide the deferred evaluation that you get with if, and then uses some to find the first logical true test expression. Its performance probably isn't as good due to the creation of so many anonymous functions, but it gets around the stack overflow exception.
(defmacro cond' [& clauses]
`(:result
(some (fn [[pred-thunk# val-thunk#]]
(if (pred-thunk#) {:result (val-thunk#)}))
(partition 2 (list ~#(map (fn [c] `(fn [] ~c)) clauses))))))
Note the wrapping and unwrapping of the returned value in a map, to ensure that some correctly handles a value clause that evaluates to nil.
A cond with 513 clauses in unlikely to be used in practice.
Here is a functional implementation of your example.
(or (some identity (map #(if (= %1 %2) %1)
(range 1 1024)
(range 2 1025)))
1024)
The requirement is like this:
Given a list of condition and result mappings, e.g.
[ [cond1 r1] [cond2 r2] ...], where
cond1: (= 1 1),
r1: 1
Find the result - rn - where condn evaluates to true
Solution using some is perfect here in solving the problem, but I think we can avoid using macro.
(defn match [[condition result]]
(when condition result))
(some match [[(= 1 2) 100] [(= 2 3) 200] [(= 3 3) 300]]) ;; => 300