JFreeChart histogram with varying bin sizes - scala
How would I go about creating a histogram plot with JFreeChart, where the bins are exponentially growing, e.g. having intervals [0, 0.1), [0.1, 0.2), [0.2, 0.4), [0.4, 0.8) etc.
There is a HistogramBin class but it only seems to be used by HistogramDataset, which in turn doesn't seem to support varying bin sizes.
I can use a regular XY bar chart with pre-binning. Here is an example using scala-chart and a few extra numeric operations:
import de.sciss.numbers.Implicits._
import scalax.chart.{ChartFactories, Charting}
import Charting._
def mkHisto(durations: Seq[Double]): Chart[_] = {
// ..., -0.54, -0.18, -0.06, +0.06, +0.18, +0.54, ....
def bin(dur: Double) =
((dur.abs / 0.06).log / 3.log + 1).toInt.clip(0, 10) * dur.signum
val binned = durations.map(bin).counted.toSeq.sortBy(_._1)
val ds = binned.toXYSeriesCollection()
val ch = ChartFactories.XYBarChart(ds,
domainAxisLabel = "bin", rangeAxisLabel = "frequency", legend = false)
ChartFactories.XYBarChart(ds)
}
implicit class RichIterable[A, CC[~] <: Iterable[~]](it: CC[A]) {
def counted: Map[A, Int] = (Map.empty[A, Int].withDefaultValue(0) /: it)((m, e) =>
m.updated(e, m(e) + 1))
}
Without further plot/renderer customisation, this looks like this, given particular input data:
Test data:
val x = Vector(22.23312925170068, 15.460136054421769, 10.453968253968254, 0.7362131519274376, 1.9141043083900227, -80.39263038548752, 5.153378684807256, 44.46625850340136, -0.2944897959183673, -192.94580498866213, 7.566507936507937, -295.0935827664399, -11.909251700680272, -16.433492063492064, -15.60591836734694, 23.64532879818594, -22.69950113378685, 108.23530612244897, 2.352925170068027, 27.058820861678004, -22.352925170068026, -4.705873015873016, -4.5397278911564625, -1.7646938775510204, 81.76471655328798, -6.470589569160998, 30.967732426303854, 13.76344671201814, 2.867392290249433, 26.379931972789116, -17.51825396825397, 23.746961451247167, -30.410430839002267, -13.722630385487529, -146.28009070294786, -130.3674603174603, 1.4976643990929706, 0.936031746031746, 2.3244444444444445, -61.95258503401361, -50.051859410430836, -47.48528344671202, -69.55430839002267, -119.96390022675737, -3.2929931972789115, -3.2929931972789115, -5.447936507936508, -18.498798185941045, -18.78934240362812, 18.498798185941045, 58.11138321995465, 33.510884353741496, 44.55206349206349, 30.02421768707483, -113.5108843537415, 27.40918367346939, -1.1934920634920634, -120.73696145124717, 5.617437641723356, 5.617437641723356, 3.8740816326530614, 3.8740816326530614, -126.38659863945578, 17.820839002267572, 18.5956462585034, -26.731224489795917, -16.920226757369615, -52.91142857142857, -24.26716553287982, 7.346938775510204, -11.354353741496599, -11.13172335600907, -1.7810657596371882, -0.7305215419501134, -117.56074829931973, -2.240249433106576, 0.12176870748299319, -113.44839002267574, -13.12498866213152, -86.2028798185941, -5.47891156462585, -2.240249433106576, -0.09741496598639456, -1.168843537414966, -10.227256235827664, -4.577936507936508, -51.70156462585034, -0.4870068027210884, -0.7548752834467121, -5.405827664399093, 6.185079365079365, -29.959365079365078, -1.6558503401360545, -7.183424036281179, -1.0714285714285714, -16.747414965986394, -2.897732426303855, -0.9740362811791383, -63.77263038548753, -8.098163265306123, -18.388820861678006, -6.699387755102041, 17.079750566893424, 33.644172335600906, -37.55328798185941, -6.772993197278912, 28.564421768707483, -3.7546031746031745, -14.47281179138322, -5.963197278911565, 26.282222222222224, 16.35233560090703, 11.564761904761905, 12.0, 9.015555555555556, -13.994920634920636, -4.041451247165533, -4.103628117913832, -9.994149659863945, -3.35750566893424, -0.7461224489795918, -0.6839455782312925, -21.39922902494331, -1.7409297052154196, -4.414512471655329, -2.4248526077097505, -5.4714965986394555, -32.42954648526077, -2.549206349206349, 11.626938775510204, -18.03108843537415, -7.150272108843537, 2.7357596371882087, -0.06217687074829932, 0.18653061224489795, -2.3005215419501135, -39.17097505668934, -0.3730612244897959, 0.6217687074829932, 1.181360544217687, 1.1191836734693879, 0.13990929705215419, 0.09326530612244897, 0.09326530612244897, 0.21759637188208616, 0.1554421768707483, 0.1554421768707483, 46.169160997732426, 1.1940136054421768, 60.49750566893424, 6.965192743764172, -5.572154195011338, 19.041315192743763, 109.88430839002268, 54.30657596371882, -5.252517006802721, 202.51149659863947, 4.96172335600907, -50.526326530612245, -1.1271655328798187, -10.404625850340135, -31.21387755102041, -1.7774603174603174, -3.8150340136054424, -4.638730158730159, -86.35839002267574, -14.132947845804988, 6.936417233560091, -107.85619047619048, 0.8880498866213152, -9.766190476190475, 3.8756009070294786, 65.26315192743765, -283.5050793650794, -0.5741723356009071, -0.1953061224489796, 0.5524943310657596, -37.47823129251701, -21.6, -6.4, -19.771428571428572, -100.0, -22.514285714285716, 18.742857142857144, -16.9443537414966, -2.0285714285714285, 13.057142857142857, -5.457142857142857, -15.342857142857143, 11.257142857142858, -15.480544217687076, -8.657142857142857, 1.7428571428571429, 3.914285714285714, 4.857142857142857, -8.485714285714286, 0.8857142857142857, -0.7714285714285715, -0.6857142857142857, 92.43299319727892, -5.503673469387755, -12.972993197278912, -8.255510204081633, -181.06972789115648, -180.77814058956915, -25.25798185941043, -25.25798185941043, -30.27027210884354, -31.449637188208616, -13.759229024943311, -11.007392290249433, -2.358730158730159, -1.2226757369614512, 9.106235827664399, -307.3968934240363, 2.0236054421768706, -10.522766439909297, -9.409773242630385, -8.600340136054422, -8.39798185941043, -7.48734693877551, 44.11467120181406, 66.37437641723356, 58.988185941043085, 92.58009070294784, 62.7318820861678, -82.63780045351474, -76.79596371882086, -65.26138321995465, -103.40639455782313, -139.21777777777777, 77.70657596371882, 93.18718820861677, 93.18716553287982, -31.044104308390022, 33.69308390022676, -32.37773242630386, 50.084331065759635, 48.971337868480724, -5.261383219954649, -19.189886621315193, 1.9224263038548752, 0.8094557823129251, -1.5177097505668935, -1.6188888888888888, -0.6078911564625851, 0.089297052154195, -21.281791383219954, -2.2843990929705216, -1.9088662131519274, 1.3155555555555556, -2.734308390022676, -26.930340136054422, 135.16766439909298, -112.22884353741496, 21.358548752834466, -31.16079365079365, -16.921768707482993, 30.02580498866213, -33.637142857142855, -21.874467120181407, -0.5675056689342404, 90.3869387755102, -35.49442176870748, -3.0954421768707485, 3.0954421768707485, -15.033968253968254, -0.6792290249433106, 0.9962131519274376, 14.671700680272108, -6.520748299319728, 0.8603854875283447, 4.709433106575964, 7.290566893424036, -25.17736961451247, -28.8, -3.079251700680272, -0.9962358276643991, 145.2679365079365, -113.0264172335601, 41.660385487528345, -1.0868027210884355, -119.54716553287982, 22.0981179138322, -279.7477551020408, -47.021519274376416, 3.227641723356009, 3.006802721088435, -0.9173242630385487, 1.2910430839002267, -153.88185941043085, 1.0074603174603174, 2.0149433106575962, -1.5671655328798186, 0.5596825396825397, -154.90068027210884, -34.02984126984127, -34.25371882086168, -41.082086167800455, -37.16417233560091, -0.11192743764172336, -37.879886621315194, -24.738798185941043, -2.4626757369614514, -19.25374149659864, -24.40299319727891, -6.380589569160998, -0.27984126984126984, -0.3078231292517007, -0.13990929705215419, -0.13990929705215419, -1.063424036281179, -1.7910430839002267, -0.12594104308390022, 0.30784580498866215, -0.09938775510204081, -0.10480725623582766, -0.10480725623582766, -39.196507936507935, 18.213061224489795, 13.785895691609978, -6.266326530612245, -0.8355102040816327, 14.830272108843538, -2.786077097505669, -9.43718820861678, 0.23512471655328798, 0.2821315192743764, -26.80249433106576, 0.721655328798186, -84.25963718820861, 27.050362811791384, 27.050362811791384)
Test:
mkHisto(x).show()
What remains to be done is customising x-axis labelling. The following addition to mkHisto changes colours and puts the proper x-axis labels:
import java.awt.Color
import org.jfree.chart.axis.{NumberTickUnit, NumberAxis}
import org.jfree.chart.plot.ValueMarker
import org.jfree.chart.renderer.xy.{StandardXYBarPainter, XYBarRenderer}
def lim(idx: Int) =
if (idx == 0) 0.0 else ((idx.abs - 1) * 3.log).exp * 0.06 * idx.signum
val plot = ch.plot
plot.getRenderer.asInstanceOf[XYBarRenderer].setBarPainter(new StandardXYBarPainter())
plot.addDomainMarker(new ValueMarker(0))
plot.setBackgroundPaint (Color.white )
plot.setDomainGridlinePaint (Color.lightGray)
plot.setRangeGridlinePaint (Color.lightGray)
plot.getRenderer.setSeriesPaint(0, Color.darkGray )
val xAxis = plot.getDomainAxis.asInstanceOf[NumberAxis]
xAxis.setTickUnit(new NumberTickUnit(1) {
override def valueToString(bin: Double) = {
val sig = if (bin < 0) "\u2212" else if (bin > 0) "+" else ""
f"""$sig${lim(bin.toInt).abs}%1.2f""""
}
})
xAxis.setVerticalTickLabels(true)
val yAxis = plot.getRangeAxis
yAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits())
Final result:
Related
CallBack Error updating graph.figure - DASH
New here and to the world of python. Generating a histogram plot where it changes color when a postcode is selected. Now I have the main histogram but when the postcode is selected from the dropdown it gives the error. Unable to figure out how to resolve this. I have provided my full code below. Let me know if more info is required to figure out the error. Something to do with input import pandas as pd import plotly.express as px from dash import Dash, html, dcc, Input, Output app = Dash(__name__) app.title = "EGMs in NSW" # Load your data : br = ..... datalist=pd.read_excel('premises-list-Aug-2022.xlsx',skiprows=[0,1,2]) datalist['Licence type'] = datalist['Licence type'].str.split(" - ").str.get(1) datalist['Licence type'] = datalist['Licence type'].str.title() postcode = datalist['Postcode'] postcode = postcode.sort_values(ascending=True) postcode=list(dict.fromkeys(postcode)) pd.Series(datalist['Postcode'].unique()).sort_values(ascending=True) def make_histogram_plot(): # Create scatter plot fig=px.histogram( data_frame = datalist, x='Licence type',y='EGMs',color='Postcode',title='EGMs by Licence Type in NSW', histfunc='avg' ) fig.update_traces(marker=dict(color="#002664")) fig.update_layout( plot_bgcolor='#EAEDF4', xaxis_title=None, yaxis_title='Average EGMs' ) return fig app.layout = html.Div(children=[ html.Div([ dcc.Dropdown(postcode,value=[], placeholder="Select postcodes", multi=True, id='postcodes') ]), dcc.Graph(id = 'graph',figure = make_histogram_plot()) ]) #app.callback( Output('graph','figure'), Input('postcodes','value') ) def dropdown_changed(postcodes): if postcodes==[]: fig = make_histogram_plot() else: datalist2 = datalist[datalist['Postcode'].isin(postcodes)], # Create scatter plot fig=px.histogram( data_frame = datalist2, x='Licence type',y='EGMs',color='Postcode',title='EGMs by Licence Type in NSW', histfunc='avg' ) fig.update_traces(marker=dict(color="#002664")) fig.update_layout( plot_bgcolor='#EAEDF4', xaxis_title=None, yaxis_title='Average EGMs' ) return fig # Start the server if __name__ == '__main__': app.run_server(debug=True)
How to get filepath from droped file with pyqt5?
I want to get path of the file dropped on QLabel. So I code like this, but label doesn't accept the file. What is the problem..? Here is my code. So long code sorry and thank you! import random import sys import pygame import time from PyQt5.QtGui import QPixmap from PyQt5.QtCore import Qt, QTimer from PyQt5.QtWidgets import QWidget, QLabel, QApplication, QDesktopWidget class Example(QWidget): size=100 imgNum=0 frameCount=4 isXmin = False isXmax = False isYmin = False isYmax = False isLeft= True def __init__(self): super().__init__() self.initUI() def initUI(self): sizeObject = QDesktopWidget().screenGeometry() # print(" Screen size : " + str(sizeObject.height()) + "x" + str(sizeObject.width())) self.xMax=sizeObject.width()-10 self.yMax=sizeObject.height()-10 print(self.xMax) print(self.yMax) self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.setStyleSheet("background-color:transparent;") self.setGeometry(100, 100, 100, 100) self.setWindowFlags(Qt.SplashScreen | Qt.WindowStaysOnTopHint) self.setAcceptDrops(True) self.label=QLabel(self) self.label.setAcceptDrops(True) self.pixmaps=[QPixmap('left.png'),QPixmap('stand.png'),QPixmap('right.png'),QPixmap('stand.png'),QPixmap('leftR.png'),QPixmap('standR.png'),QPixmap('rightR.png'),QPixmap('standR.png')] for x in range(len(self.pixmaps)): self.pixmaps[x]=self.pixmaps[x].scaled(self.size,self.size,Qt.KeepAspectRatio) self.resize(self.pixmaps[2].width(),self.pixmaps[2].height()) self.label.setPixmap(self.pixmaps[len(self.pixmaps)-1]) self.changeTimer=QTimer(self) self.changeTimer.timeout.connect(self.changeFoot) self.moveTimer=QTimer(self) self.moveTimer.timeout.connect(self.moving) self.setAcceptDrops(True) pygame.init() pygame.mixer.music.load('hoi_imtemmie.mp3') pygame.mixer.music.play() self.show() def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ingore() def dropEvent(self, event): self.path=event.mimeData.urls() def moving(self): if self.distance == 0: print(self.distance) print(self.x(),"x",self.y()) self.label.setPixmap(self.pixmaps[1]) self.moveTimer.stop() self.changeTimer.stop() time.sleep(3) self.setMovement() return 0 else: self.move(self.x()+self.direct[0],self.y()+self.direct[1]) self.distance-=1 if self.x()<=-10 : self.distance=0 print("xm") self.isXmin = True if self.y()<=-10 : self.distance=0 print("ym") self.isYmin = True if self.x()>=self.xMax: self.distance=0 print("xM") self.isXmax=True if self.y()>=self.yMax : self.distance=0 print("yM") self.isYmax=True def setMovement(self): self.direct=[0,0] while(self.direct[0]==0 and self.direct[1]==0): self.direct=[random.randint(-1,1),random.randint(-1,1)] if self.isXmax: self.direct[0]=-1 if self.isXmin: self.direct[0]=1 if self.isYmin: self.direct[1]=1 if self.isYmax: self.direct[1]=-1 if self.direct[0]== -1: self.isLeft=True self.imgNum=0 elif self.direct[0]== 1: self.isLeft=False self.imgNum=4 self.isXmax = False self.isXmin = False self.isYmin = False self.isYmax = False # if direct[0]*direct[1]==0 : self.delta = QPoint(dX*direct[0],dY*direct[1]) # else: self.delta=QPoint(direct[0]*(dX**(1/2)),direct[1]*(dY**1/2)) self.distance=random.randint(200,400) self.changeTimer.start(300) self.moveTimer.start(30) def changeFoot(self): self.label.setPixmap(self.pixmaps[self.imgNum]) if self.isLeft: if self.imgNum<self.frameCount-1: self.imgNum+=1 else : self.imgNum=0 else: if self.imgNum<2*self.frameCount-1: self.imgNum+=1 else : self.imgNum=self.frameCount def mousePressEvent(self, QMouseEvent): self.setMovement() pygame.mixer.music.load('hoi_imtemmie.mp3') pygame.mixer.music.play() def keyPressEvent(self, QKeyEvent): if QKeyEvent.key() == Qt.Key_Escape: sys.exit() # if QKeyEvent.key() == Qt.Key_G: if __name__ == '__main__': app = QApplication(sys.argv) ex = Example() sys.exit(app.exec_()) i set AcceptDrops(True) self.setAcceptDrops(True) and code about get filepath ▼ def dragEnterEvent(self, event): if event.mimeData().hasUrls: event.accept() else: event.ingore() def dropEvent(self, event): self.path=event.mimeData.urls()
Try to loop through event.mimeData().urls() for url in event.mimeData().urls(): self.path = url.toLocalFile()
leafletR map doesn't load in shiny on start
I have the following little piece of code (more less as described HERE) - I want to control the number of points to be shown by a slider in shiny. You can see that the initial map is loaded after a little while (watch console output), but it will only show up after you used the slider once. But I'd like the map to show up after it is created during launch of the shiny app - any hints how to do that? ## app.R ## library(shiny) library(shinydashboard) library(httr) library(leafletR) data(quakes) # dest_dir=tempdir() dest_dir="foo_map" dest_file = paste(dest_dir,"quakes","quakes.html",sep="\\") dat = quakes createMapHTML <- function(inputFreq=1) { q.dat <- toGeoJSON(data=dat[seq(from = 1, to = nrow(dat), by=inputFreq), ], dest=dest_dir, name="quakes") sty <- styleSingle(col="darkblue", fill="darkblue", rad=6) # create map q.map <- leaflet(data=q.dat, dest=dest_dir, size = c(1200, 600), incl.data=TRUE, base.map=list("osm"), style=sty, popup="*", controls="all") } # createMapHTML() runApp(list( ui = dashboardPage( dashboardHeader(title = "quakes"), dashboardSidebar( sliderInput("slider", "#observations frequency:", 1, 100, 1) ), dashboardBody( htmlOutput("inc") ) ), server = function(input, output, session) { createMap <- reactive({ createMapHTML(input$slider) return(includeHTML(dest_file)) }) output$inc<-renderUI({ createMap() }) } ))
so the bottleneck with the leafletR package is the conversion to GeoJson. Additionally the "includeHTML & htmlOutput" workaround for embedding the html out is flaky.. To avoid both I just switched to the leaflet packackage: ## app.R ## library(shiny) library(shinydashboard) library(leaflet) data(quakes) dat = quakes runApp(list( ui = dashboardPage( dashboardHeader(title = "quakes"), dashboardSidebar( sliderInput("slider", "#observations frequency:", 1, 100, 1) ), dashboardBody( leafletOutput("map", height = 600) ) ), server = function(input, output) { output$map <- renderLeaflet({ map <- leaflet() %>% addTiles() map %>% addCircles(data=dat[seq(from = 1, to = nrow(dat), by=input$slider), ], #input$slider lat = ~lat, lng = ~long, fillOpacity = 1.0) }) } ))
scala sortWith: negative numbers are not getting sorted
val reslist = List(200.0,-100.00,50.80,-400.83, 800.003,-6.513214114672146E85, -1.2425461624057028E86, -4.7624471630469706E86, -3.6046499228286203E86, 0.0, -8.833653923554989E85, 0.000, -4.795843631190487E85, -5.34142100270833E86, -3.48087737474366E85, -2.811146396971388E86, -6.923235225460886E86, -6.513214114672146E85, 0.00000, -1.2425461624057028E86, -7.073704018243951E85, -9.633244016491059E86, -1.1418901590222212E86, -2.115257701350766E86, -1.1418901590222212E86, -3.48087737474366E85,-1.0676381955303372E86,500.56, 2.900556,400.56,-48956.00,4509.0005); val weightlistzi = reslist.zipWithIndex // List((200.0,0), (-100.0,1), (50.8,2), (-400.83,3), (800.003,4), (-6.513214114672146E85,5), (-1.2425461624057028E86,6), (-4.7624471630469706E86,7), (-3.6046499228286203E86,8), (0.0,9), (-8.833653923554989E85,10), (0.0,11), (-4.795843631190487E85,12), (-5.34142100270833E86,13), (-3.48087737474366E85,14), (-2.811146396971388E86,15), (-6.923235225460886E86,16), (-6.513214114672146E85,17), (0.0,18), (-1.2425461624057028E86,19), (-7.073704018243951E85,20), (-9.633244016491059E86,21), (-1.1418901590222212E86,22), (-2.115257701350766E86,23), (-1.1418901590222212E86,24), (-3.48087737474366E85,25), (-1.0676381955303372E86,26), (500.56,27), (2.900556,28), (400.56,29), (-48956.0,30), (4509.0005,31)) // I am sorting it here. val resultlist = weightlistzi.sortWith { (x: (Double,Int), y: (Double,Int)) => x._1 > y._1 } Here is the resulting list. As you can see, -100.0, -400.83, -48956.0 are occurring before -3 and the rest.... // List[(Double, Int)] = List((4509.0005,31), (800.003,4), (500.56,27), (400.56,29), (200.0,0), (50.8,2), (2.900556,28), (0.0,9), (0.0,11), (0.0,18), (-100.0,1), (-400.83,3), (-48956.0,30), (-3.48087737474366E85,14), (-3.48087737474366E85,25), (-4.795843631190487E85,12), (-6.513214114672146E85,5), (-6.513214114672146E85,17), (-7.073704018243951E85,20), (-8.833653923554989E85,10), (-1.0676381955303372E86,26), (-1.1418901590222212E86,22), (-1.1418901590222212E86,24), (-1.2425461624057028E86,6), (-1.2425461624057028E86,19), (-2.115257701350766E86,23), (-2.811146396971388E86,15), (-3.6046499228286203E86,8), (-4.7624471630469706E86,7), (-5.34142100270833E86,13), (-6.923235225460886E86,16), (-9.633244016491059E86,21))
There is E character in your numbers. This is Scientific notation. -1.1E86 means -1.1 * (10^86). And -1.1 * (10^86) is less than -400.83 (-4.0083 * 10^2).
NameError: global name 'Carnage' is not defined
I know it was asked a million times before, but I need a little help getting this working, as the code is not mine. so like that i update a code hope it will make some undarstands of it # coding=utf-8 import urllib, re, sys, threading, cookielib, urllib2 from BeautifulSoup import BeautifulSoup ### Головная функция def main(): agent = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)' aCarnage = Carnage('YourNick', 'YourPass', 'arkaim.carnage.ru', 'cp1251', agent) aCarnage.login() me = aCarnage.inf(aCarnage.user) # Если ранен - выйти if me['inj']: aCarnage.logout() exit(1) aCarnage.urlopen('main.pl') # Подождать пока здоровье восстановится while(me['hp_wait']): time.sleep(me['hp_wait']) me = aCarnage.inf(aCarnage.user) # Найти подходящую заявку aCarnage.find() me = aCarnage.inf(aCarnage.user) # Если заявка состоялась - в бой! if me['battle']: aCarnage.fight() # После боя - выход из игры aCarnage.logout() class Opener: def __init__(self, host, encoding, agent): self.host = host self.encoding = encoding self.agent = agent self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookielib.CookieJar())) def urlopen(self, goto, data = None): f = self.opener.open(urllib2.Request( "http://%s/%s" % (self.host, goto), self.urlencode(data), {"User-agent" : self.agent} )) result = f.read() self.soup = BeautifulSoup(result) def urlencode(self, data): if data is None: return None for key in data: data[key] = data[key].encode(self.encoding, 'ignore') return urllib.urlencode(data) class CarnageBot(Opener): ### Конструктор принимает логин, пароль, кодировку (cp1251) и идентификатор браузера def __init__(self, user, password, host, encoding, agent): self.user = user self.password = password Opener.__init__(self, host, encoding, agent) ### Получить информацию об игроке - например о самом себе def inf(self, user): self.urlopen('inf.pl?' + self.urlencode({'user': user})) # Кол-во жизни onmouseover = self.soup.find('img', onmouseover = re.compile(unicode('Уровень жизни:', 'utf8'))) m = re.search('([0-9]+).([0-9]+)', onmouseover['onmouseover']) hp = int(m.group(1)) hp_max = int(m.group(2)) hp_wait = (100 - (hp * 100) / hp_max) * 18 # Уровень td = self.soup.find('td', text = re.compile(unicode('Уровень:', 'utf8'))) level = int(td.next.string) # Ранен или нет inj = 0 if self.soup.find(src = re.compile(unicode('travma.gif', 'utf8'))): inj = 1 # В бою или нет battle = 0 if self.soup.find(text = re.compile(unicode('Персонаж находится в бою', 'utf8'))): battle = 1 hero = {'level': level, 'hp': hp, 'hp_max': hp_max, 'hp_wait': hp_wait, 'inj': inj, 'battle': battle} return hero ### Войти в игру def login(self): data = {'action': 'enter', 'user_carnage': self.user, 'pass_carnage': self.password} self.urlopen('enter.pl', data) self.urlopen('main.pl') ### Выйти из игры def logout(self): self.urlopen('main.pl?action=exit') ### В бой!!! def fight(self): self.urlopen('battle.pl') while True: # Добить по таймауту if self.soup.find(text = re.compile(unicode('Противник потерял сознание', 'utf8'))): self.urlopen('battle.pl?cmd=timeout&status=win') break if self.soup.find(text = re.compile(unicode('Бой закончен.', 'utf8'))): break reg = re.compile(unicode('Для вас бой закончен. Ждите окончания боя.', 'utf8')) if self.soup.find(text = reg): break cmd = self.soup.find('input', {'name' : 'cmd', 'type' : 'hidden'}) to = self.soup.find('input', {'name' : 'to', 'type' : 'hidden'}) # Есть ли по кому бить?! if cmd and to: a = random.randint(1, 4) b0 = random.randint(1, 4) b1 = random.randint(1, 4) while b1 == b0: b1 = random.randint(1, 4) pos = 2 arg = (cmd['value'], to['value'], pos, a, a, b0, b0, b1, b1) self.urlopen('battle.pl?cmd=%s&to=%s&pos=%s&A%s=%s&D%s=%s&D%s=%s' % arg) else: self.urlopen('battle.pl') time.sleep(random.randint(5, 30)) ### Найти заявку - подающий заявку должен быть на 1 уровень ниже нашего def find(self): me = self.inf(self.user) while True: v = '' self.urlopen('zayavka.pl?cmd=haot.show') reg = re.compile(unicode('Текущие заявки на бой', 'utf8')) script = self.soup.find('fieldset', text = reg).findNext('script') m = re.findall('.*', script.string) for value in m: if value.find('group.gif') < 0: continue if value.find('(%i-%i)' % (me['level'] - 2, me['level'])) < 0: continue t = re.search(',([0-9]{1,2}),u', value) if not t: continue t = int(t.group(1)) v = re.search('tr\(([0-9]+)', value).group(1) print 'Found battle t=%i v=%s' % (t, v) break if v: break time.sleep(80) nd = self.soup.find('input', {'name' : 'nd', 'type' : 'hidden'}) self.urlopen('zayavka.pl?cmd=haot.accept&nd=%s&battle_id=%s' % (nd['value'], v)) time.sleep(t + 30) if __name__ == '__main__': main() The error is: NameError: global name 'Carnage' is not defined
The cause of your error is that Carnage has not been defined. Maybe you forgot to import a library which provides Carnage? Also, your code as posted is incorrectly indented, which is a syntax error. Update: Apparently you took this code from http://github.com/Ejz/Common/tree/master/carnage-bot . Reading that source, it looks like the line aCarnage = Carnage('YourNick', 'YourPass', 'arkaim.carnage.ru', 'cp1251', agent) Should be aCarnage = CarnageBot('YourNick', 'YourPass', 'arkaim.carnage.ru', 'cp1251', agent) Because the methods called on aCarnage are defined further down the file for class CarnageBot.