Does anyone know how to display an incanter chart to jpanel without reverting to jfreechart?
An Incanter chart is a JFreeChart under the hood so it's impossible to avoid the JFreeChart library altogether.
However, if you just want to include an incanter chart inside a Panel that you can use in a normal Swing application then there is a ready-made class called org.jfree.chart.ChartPanel which can do this for you.
Example code:
(ns my.chart
(:import [org.jfree.chart ChartPanel])
(:import [java.awt Component Dimension])
(:import [javax.swing JFrame])
(:use [incanter core stats charts]))
(defn show-component [^Component c]
"Utility Function to display any Java component in a frame"
(let [^JFrame frame (JFrame. "Test Window")]
(doto frame
(.add c)
(.setSize (Dimension. 640 480))
(.setVisible true))))
(show-component (ChartPanel. (function-plot sin -10 10)))
Related
We are using chart.js with clojurescript and Reagent. Now I know that Chart.js has a chart.update() method to update the chart with new data. So the question is, how can I setup my component so that it renders the chart on :reagent-render but probably get :component-will-update to call the chart.update() method ?
Basically, is there a way to get a handle on the chart that is created from :reagent-render function in :component-will-update function ?
The usual pattern you follow in this case is to wrap the stateful/mutable object in a React component and use React's lifecycle methods.
The approach is described in detail in re-frame's Using-Stateful-JS-Component but this is how I tend to do it with D3:
(defn graph-render [graph-attrs graph-data]
;; return hiccup for the graph here
(let [width (:width graph-attrs)
height (:height graph-attrs)]
[:svg {:width width :height height}
[:g.graph]]))
(defn graph-component [graph-attrs graph-data]
(r/create-class
{:display-name "graph"
:reagent-render graph-render
:component-did-update (fn [this]
(let [[_ graph-attrs graph-data] (r/argv this)]
(update! graph-attrs graph-data)))
:component-did-mount (fn [this]
(let [[_ graph-attrs graph-data] (r/argv this)]
(init! graph-attrs graph-data)))}))
(defn container []
[:div {:id "graph-container"}
[graph-component
#graph-attrs-ratom
#graph-data-ratom]])
It is important to keep the outer/inner combination because React won't populate its props correctly otherwise.
Another thing to be carefully of is the return of the reagent/argv vector, which, as you can see, contains the props after the first item. I have seen (reagent/props comp) in the wiki page above but I have never tried it myself.
The following code displays 5 different emojis at the bottom of the screen, and 1 emoji in the upper center. I am trying to make it so that when one of the emojis on the bottom is clicked, that same emoji appears at the top center. I am able to update the atom that contains the emoji history with :on-click, but the image does not update with the current url.
(def emoji-history
(atom {:current "img/sad-tears.png"}))
(defn Img40 [src reaction]
[:img {:src src
:style {:width "60px"
:padding-right "20px"}
:on-click #(do
(js/console.log (get #emoji-history :current))
(swap! emoji-history assoc :current src)
(js/console.log (get #emoji-history :current)))}])
(defn CurrentEmoji []
[:img {:style {:width 40 :margin-top 15}
:src (get #emoji-history :current)}])
(defn EmojiDisplay []
[:div {:style {:text-align "center"}}
[CurrentEmoji]
[:div {:style {:text-align "center"
:margin-top "200px"
:padding-left "20px"}}
[Img40 "img/smile.png" "happy"]
[Img40 "img/sad-tears.png" "sad"]
[Img40 "img/happy-tears.png" "amused"]
[Img40 "img/surprised.png" "surprised"]
[Img40 "img/angry.png" "angry"]]])
Refer to the reagent.core namespace and use a Reagent atom like this:
(ns my-name.space.etc
(:require [reagent.core :as r]))
(def emoji-history
(r/atom {:current "img/sad-tears.png"}))
The line of code that you have here...
(swap! emoji-history assoc :current src)
...where you swap! your atom's value, that is correct :-)
Unlike a plain old Clojure atom, when a Reagent atom's value (state) is changed, a re-render of the UI is triggered.
Rarely is the entire UI re-rendered, though. Because Reagent wraps React, the React system will work out the minimal required changes to the DOM, so it's pretty efficient.
I want to align my x-axis labels in Incanter's histogram (based on JFreeChart) so that they are centered under the bars. I also want to get rid of the fractional axis tick marks.
My question is very similar to JFreeChart: Aligning domain axis with histogram bins.
Here are related questions for other languages:
R: Align bars of histogram centered on labels
Python: How to center labels in histogram plot
(require '[incanter.charts :refer [histogram]])
(require '[incanter.core :refer [view]])
(def data [1 1 1 1 3 6])
(view (histogram data))
P.S. The histogram is also unappealing in that the bar for 6 is to the left of the tick mark. The other bars are to the right of their tick marks!
Update: See also:
Relevant, but I don't see a solution here: How to center bars on tick marks
Based on reviewing the Incanter source code and the JFreeChart documentation, I don't believe that org.jfree.chart.ChartFactory/createHistogram exposes the functionality to customize the axis. (I could be wrong -- perhaps you can modify the axis after using that factory method.)
In any case, I found it easier (and perhaps necessary) to use the bar-chart directly:
(ns custom-incanter
(:require
[incanter.charts :as ic]
[incanter.core :as i]))
(defn hist
[values title]
{:pre [(sequential? values)]}
(let [freq (frequencies values)
f #(freq % 0)
ks (keys freq)
a (apply min ks)
b (apply max ks)
x-values (range a (inc b))
x-labels (map str x-values)
y-values (map f x-values)]
(i/view (ic/bar-chart x-labels y-values :title title))))
Use it like this:
(hist [1 1 1 1 3 6] "Using Bar Chart")
I've used lein-fruit to generate a basic Clojure project that targets iOS through RoboVM. I've introduced core.async to pass button taps along a channel, but mutating the button in the go block doesn't seem to have an effect.
Is there reason to believe the Java implementation of core.async doesn't work under RoboVM?
Here's my code, slightly modified from the basic lein-fruit template.
(ns core-async-demo.core
(:require [core-async-demo.core-utils :as u]
[clojure.core.async :refer [go chan put! <!]]))
(def window (atom nil))
(def taps (chan))
(defn init
[]
(let [main-screen (u/static-method :uikit.UIScreen :getMainScreen)
button-type (u/static-field :uikit.UIButtonType :RoundedRect)
button (u/static-method :uikit.UIButton :fromType button-type)
normal-state (u/static-field :uikit.UIControlState :Normal)
click-count (atom 0)]
(doto button
(.setFrame (u/init-class :coregraphics.CGRect 115 121 91 37))
(.setTitle "Click me!" normal-state)
(.addOnTouchUpInsideListener
(proxy [org.robovm.cocoatouch.uikit.UIControl$OnTouchUpInsideListener] []
(onTouchUpInside [control event]
(put! taps true)))))
(reset! window (u/init-class :uikit.UIWindow (.getBounds main-screen)))
(go
(loop [_ (<! taps)]
(.setTitle button (str "Click #" (swap! click-count inc)) normal-state)
(recur (<! taps))))
(doto #window
(.setBackgroundColor (u/static-method :uikit.UIColor :lightGrayColor))
(.addSubview button)
.makeKeyAndVisible)))
I don't know about core.async on RoboVM specifically, but background threads in general are not supposed to interact with UIKit. It's a documented limitation of the framework. I would try something simpler to test out core.async on RoboVM and, if it works, you should be able to use Grand Central Dispatch to run your code on the main queue.
I'm binding an instance to a Var:
(ns org.jb
(:import (java.awt PopupMenu
TrayIcon
Toolkit
SystemTray)
(javax.swing JFrame
Action)))
(def ^:dynamic popupmenu)
(def ^:dynamic image)
(def ^:dynamic trayicon)
(def ^:dynamic tray)
(defn start-app [appname icon]
(binding [popupmenu (new PopupMenu)
image (.. Toolkit (getDefaultToolkit) (getImage icon))
trayicon (new TrayIcon image appname popupmenu)
tray (. SystemTray getSystemTray)]
(. trayicon setImageAutoSize true)
(. tray add trayicon)))
(start-app "escap" "res/escap_icon.png")
Error:
ClassCastException clojure.lang.Var$Unbound cannot be cast to java.awt.Image org.jb/start-app (org\jb.clj:17)
I am predefining the Var with
(def image)
even tried
(def ^:dynamic image)
Unable to understand what is expected from the message.
Using let in place of binding works within the lexical scope however. However want to achieve dynamic binding.
All I see here is an empty binding form with no code. The variable binding goes out of scope once you leave the binding form. Based on your error message, it looks like you're trying to use the image var outside of the binding form. You need to make sure that all code that uses image is placed inside the binding.
So, instead of this:
(binding [*image* (.. Toolkit (getDefaultToolkit) (getImage "icon.png"))])
(display-image *image*)
Do this:
(binding [*image* (.. Toolkit (getDefaultToolkit) (getImage "icon.png"))]
(display-image *image*))
Another possible issue is that the binding expressions are evaluated in parallel whereas expressions in let are evaluated in sequence. This means that if you're binding multiple vars and one depends on the other, it will use the value that was in scope before the binding was evaluated.
So, this will throw an exception:
(def ^:dynamic *a*)
(def ^:dynamic *b*)
(binding [*a* 2
*b* (+ *a* 3)]
(+ *a* *b*)) ; => ClassCastException clojure.lang.Var$Unbound cannot be cast
; to java.lang.Number clojure.lang.Numbers.multiply
; (Numbers.java:146)
Instead you would have to use nested binding forms:
(binding [*a* 2]
(binding [*b* (+ *a* 3)]
(+ *a* *b*))) ; => 8
Note that I've placed "earmuffs" around the var name. This is the naming convention for dynamic vars in Clojure, so other people can easily tell that it's dynamic. Also, if you're able to dynamically bind a var without declaring it with ^:dynamic metadata, that means you're using a pretty old version of Clojure. I'd suggest you upgrade - 1.5.1 is the latest stable release.
There is no point using binding in your example. You should use binding only when you want to rebind global variable to create some context. In your case you don't need global variables, so you should use let instead:
(ns org.jb
(:import (java.awt PopupMenu
TrayIcon
Toolkit
SystemTray)
(javax.swing JFrame
Action)))
(defn start-app [appname icon]
(let [popupmenu (new PopupMenu)
image (.. Toolkit (getDefaultToolkit) (getImage icon))
trayicon (new TrayIcon image appname popupmenu)
tray (. SystemTray getSystemTray)]
(. trayicon setImageAutoSize true)
(. tray add trayicon)))
(start-app "escap" "res/escap_icon.png")
But if you'll decide to stick with binding then Alex's answer shuld help you with your problem.
But you should avoid using things like binding unless they are absolutely necessary.
Update
If your goal is to save some state for future calculations then binding won't be able to help you. It only binds variables with new values inside its body, leaving them intact for the rest of your app.
So, when you want to change a global state you should use alter-var-root instead:
(def ^:dynamic *app-state* {})
(defn set-state! [new-state]
(alter-var-root #'*app-state* (constantly new-state)))
(defn update-state! [mixin]
(alter-var-root #'*app-state* merge mixin))
You should also try to keep the most of your functions as close to "functional paradigm" as you can:
(defn start-app
"Creates new app with given appname and icon and returns it"
[appname icon]
(let [popupmenu (new PopupMenu)
image (.. Toolkit (getDefaultToolkit) (getImage icon))
trayicon (new TrayIcon image appname popupmenu)
tray (. SystemTray getSystemTray)]
(. trayicon setImageAutoSize true)
(. tray add trayicon)
{ :popupmenu popupmenu
:image image
:trayicon trayicon
:tray }))
(update-state! (start-app "escap" "res/escap_icon.png"))